เด•เตเดฑเดžเตเดž เดตเต‡เดคเดจเดคเตเดคเดฟเตฝ เดจเต€เดฒ-เดชเดšเตเดš เดตเดฟเดจเตเดฏเดพเดธเด‚

เดˆ เดฒเต‡เด–เดจเดคเตเดคเดฟเตฝ เดžเด™เตเด™เตพ เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เตเดจเตเดจเต เดฌเดพเดทเต, ssh, เดกเต‹เด•เตเด•เตผ ะธ nginx เดตเต†เดฌเต เด†เดชเตเดฒเดฟเด•เตเด•เต‡เดทเดจเตเดฑเต† เดคเดŸเดธเตเดธเดฎเดฟเดฒเตเดฒเดพเดคเตเดค เดฒเต‡เด”เดŸเตเดŸเต เดžเด™เตเด™เตพ เดธเด‚เด˜เดŸเดฟเดชเตเดชเดฟเด•เตเด•เตเด‚. เดจเต€เดฒ-เดชเดšเตเดš เดตเดฟเดจเตเดฏเดพเดธเด‚ เด’เดฐเตŠเดฑเตเดฑ เด…เดญเตเดฏเตผเดคเตเดฅเดจ เดชเต‹เดฒเตเด‚ เดจเดฟเดฐเดธเดฟเด•เตเด•เดพเดคเต† เด’เดฐเต เด†เดชเตเดฒเดฟเด•เตเด•เต‡เดทเตป เดคเตฝเด•เตเดทเดฃเด‚ เด…เดชเตเดกเต‡เดฑเตเดฑเต เดšเต†เดฏเตเดฏเดพเตป เดจเดฟเด™เตเด™เดณเต† เด…เดจเตเดตเดฆเดฟเด•เตเด•เตเดจเตเดจ เด’เดฐเต เดธเดพเด™เตเด•เต‡เดคเดฟเด•เดคเดฏเดพเดฃเต. เด‡เดคเต เดธเต€เดฑเต‹ เดกเต—เตบเดŸเตˆเด‚ เดตเดฟเดจเตเดฏเดพเดธ เดคเดจเตเดคเตเดฐเด™เตเด™เดณเดฟเตฝ เด’เดจเตเดจเดพเดฃเต, เด’เดฐเต เดธเดจเตเดฆเตผเดญเด‚ เด‰เดณเตเดณ เด†เดชเตเดฒเดฟเด•เตเด•เต‡เดทเดจเตเด•เตพเด•เตเด•เต เดเดฑเตเดฑเดตเตเด‚ เด…เดจเตเดฏเต‹เดœเตเดฏเดฎเดพเดฃเต, เดŽเดจเตเดจเดพเตฝ เดธเดฎเต€เดชเดคเตเดคเตเดณเตเดณ เดฐเดฃเตเดŸเดพเดฎเดคเตเดคเต†, เดฑเต†เดกเดฟ-เดŸเต-เดฑเตบ เด‡เตปเดธเตโ€Œเดฑเตเดฑเตปเดธเต เดฒเต‹เดกเต เดšเต†เดฏเตเดฏเดพเดจเตเดณเตเดณ เด•เดดเดฟเดตเต.

เดจเดฟเดฐเดตเดงเดฟ เด•เตเดฒเดฏเดจเตเดฑเตเด•เตพ เดธเดœเต€เดตเดฎเดพเดฏเดฟ เดชเตเดฐเดตเตผเดคเตเดคเดฟเด•เตเด•เตเดจเตเดจ เด’เดฐเต เดตเต†เดฌเต เด†เดชเตเดฒเดฟเด•เตเด•เต‡เดทเตป เดจเดฟเด™เตเด™เดณเตเดŸเต† เดชเด•เตเด•เดฒเตเดฃเตเดŸเต†เดจเตเดจเต เดชเดฑเดฏเดŸเตเดŸเต†, เด…เดคเดฟเดจเต เดฐเดฃเตเดŸเต เดธเต†เด•เตเด•เตปเดกเต เด•เดฟเดŸเด•เตเด•เดพเตป เด’เดฐเต เดตเดดเดฟเดฏเตเดฎเดฟเดฒเตเดฒ. เดจเดฟเด™เตเด™เตพ เดถเดฐเดฟเด•เตเด•เตเด‚ เด’เดฐเต เดฒเตˆเดฌเตเดฐเดฑเดฟ เด…เดชเตโ€Œเดกเต‡เดฑเตเดฑเต, เด’เดฐเต เดฌเด—เต เดชเดฐเดฟเดนเดฐเดฟเด•เตเด•เตฝ เด…เดฒเตเดฒเต†เด™เตเด•เดฟเตฝ เด’เดฐเต เดชเตเดคเดฟเดฏ เดฐเดธเด•เดฐเดฎเดพเดฏ เดซเต€เดšเตเดšเตผ เดชเตเดฑเดคเตเดคเดฟเดฑเด•เตเด•เต‡เดฃเตเดŸเดคเตเดฃเตเดŸเต. เด’เดฐเต เดธเดพเดงเดพเดฐเดฃ เดธเดพเดนเดšเดฐเตเดฏเดคเตเดคเดฟเตฝ, เดจเดฟเด™เตเด™เตพ เด†เดชเตเดฒเดฟเด•เตเด•เต‡เดทเตป เดจเดฟเตผเดคเตเดคเตเด•เดฏเตเด‚ เดฎเดพเดฑเตเดฑเดฟเดธเตเดฅเดพเดชเดฟเด•เตเด•เตเด•เดฏเตเด‚ เดตเต€เดฃเตเดŸเตเด‚ เด†เดฐเด‚เดญเดฟเด•เตเด•เตเด•เดฏเตเด‚ เดšเต†เดฏเตเดฏเต‡เดฃเตเดŸเดคเตเดฃเตเดŸเต. เดกเต‹เด•เตเด•เดฑเดฟเดจเตเดฑเต† เด•เดพเดฐเตเดฏเดคเตเดคเดฟเตฝ, เดจเดฟเด™เตเด™เตพเด•เตเด•เต เด†เดฆเตเดฏเด‚ เด…เดคเต เดฎเดพเดฑเตเดฑเดฟเดธเตเดฅเดพเดชเดฟเด•เตเด•เดพเด‚, เดคเตเดŸเตผเดจเตเดจเต เด…เดคเต เดชเตเดจเดฐเดพเดฐเด‚เดญเดฟเด•เตเด•เดพเด‚, เดชเด•เตเดทเต‡ เด†เดชเตเดฒเดฟเด•เตเด•เต‡เดทเดจเดฟเดฒเต‡เด•เตเด•เตเดณเตเดณ เด…เดญเตเดฏเตผเดคเตเดฅเดจเด•เตพ เดชเตเดฐเต‹เดธเดธเตเดธเต เดšเต†เดฏเตเดฏเดชเตเดชเต†เดŸเดพเดคเตเดค เด’เดฐเต เด•เดพเดฒเดฏเดณเดตเต เด‡เดจเดฟเดฏเตเด‚ เด‰เดฃเตเดŸเดพเด•เตเด‚, เด•เดพเดฐเดฃเด‚ เดธเดพเดงเดพเดฐเดฃเดฏเดพเดฏเดฟ เด†เดชเตเดฒเดฟเด•เตเด•เต‡เดทเตป เด†เดฆเตเดฏเด‚ เดฒเต‹เดกเต เดšเต†เดฏเตเดฏเดพเตป เด•เตเดฑเดšเตเดšเต เดธเดฎเดฏเดฎเต†เดŸเตเด•เตเด•เตเด‚. เด…เดคเต เด†เดฐเด‚เดญเดฟเด•เตเด•เตเด•เดฏเตเด‚ เดŽเดจเตเดจเดพเตฝ เดชเตเดฐเดตเตผเดคเตเดคเดจเดฐเดนเดฟเดคเดฎเดพเดฏเดฟ เดฎเดพเดฑเตเด•เดฏเตเด‚ เดšเต†เดฏเตเดคเดพเดฒเต‹? เด‡เดคเดพเดฃเต เดชเตเดฐเดถเตเดจเด‚, เดเดฑเตเดฑเดตเตเด‚ เด•เตเดฑเดžเตเดž เดฎเดพเตผเด—เด™เตเด™เดณเดฟเดฒเต‚เดŸเต†เดฏเตเด‚ เด•เดดเดฟเดฏเตเดจเตเดจเดคเตเดฐ เด—เด‚เดญเต€เดฐเดฎเดพเดฏเตเด‚ เดจเดฎเตเด•เตเด•เต เด‡เดคเต เดชเดฐเดฟเดนเดฐเดฟเด•เตเด•เดพเด‚.

เดจเดฟเดฐเดพเด•เดฐเดฃเด‚: เดฒเต‡เด–เดจเดคเตเดคเดฟเดจเตเดฑเต† เดญเต‚เดฐเดฟเดญเดพเด—เดตเตเด‚ เด’เดฐเต เดชเดฐเต€เด•เตเดทเดฃเดพเดคเตเดฎเด• เดซเต‹เตผเดฎเดพเดฑเตเดฑเดฟเตฝ เด…เดตเดคเดฐเดฟเดชเตเดชเดฟเดšเตเดšเดฟเดฐเดฟเด•เตเด•เตเดจเตเดจเต - เด’เดฐเต เด•เตบเดธเต‹เตพ เดธเต†เดทเดจเตเดฑเต† เดฑเต†เด•เตเด•เต‹เตผเดกเดฟเด‚เด—เต เดฐเต‚เดชเดคเตเดคเดฟเตฝ. เด‡เดคเต เดฎเดจเดธเดฟเดฒเดพเด•เตเด•เดพเตป เดตเดณเดฐเต† เดฌเตเดฆเตเดงเดฟเดฎเตเดŸเตเดŸเตเดณเตเดณ เด•เดพเดฐเตเดฏเดฎเดฒเตเดฒเต†เดจเตเดจเตเด‚ เด•เต‹เดกเต เดฎเดคเดฟเดฏเดพเดฏ เดฐเต€เดคเดฟเดฏเดฟเตฝ เดฐเต‡เด–เดชเตเดชเต†เดŸเตเดคเตเดคเตเดฎเต†เดจเตเดจเตเด‚ เดชเตเดฐเดคเต€เด•เตเดทเดฟเด•เตเด•เตเดจเตเดจเต. เด…เดจเตเดคเดฐเต€เด•เตเดทเดคเตเดคเดฟเดจเต, เด‡เดต เด•เต‡เดตเดฒเด‚ เด•เต‹เดกเต เดธเตเดจเดฟเดชเตเดชเต†เดฑเตเดฑเตเด•เตพ เดฎเดพเดคเตเดฐเดฎเดฒเตเดฒ, เด’เดฐเต "เด‡เดฐเตเดฎเตเดชเต" เดŸเต†เดฒเดฟเดŸเตˆเดชเตเดชเดฟเตฝ เดจเดฟเดจเตเดจเตเดณเตเดณ เดชเต‡เดชเตเดชเตผ เด†เดฃเต†เดจเตเดจเต เดธเด™เตเด•เตฝเดชเตเดชเดฟเด•เตเด•เตเด•.

เด•เตเดฑเดžเตเดž เดตเต‡เดคเดจเดคเตเดคเดฟเตฝ เดจเต€เดฒ-เดชเดšเตเดš เดตเดฟเดจเตเดฏเดพเดธเด‚

เด•เต‹เดกเต เดตเดพเดฏเดฟเด•เตเด•เตเดจเตเดจเดคเดฟเดฒเต‚เดŸเต† Google-เดจเต เดฌเตเดฆเตเดงเดฟเดฎเตเดŸเตเดŸเตเดณเตเดณ เดฐเดธเด•เดฐเดฎเดพเดฏ เดธเดพเด™เตเด•เต‡เดคเดฟเด• เดตเดฟเดฆเตเดฏเด•เตพ เด“เดฐเต‹ เดตเดฟเดญเดพเด—เดคเตเดคเดฟเดจเตเดฑเต†เดฏเตเด‚ เดคเตเดŸเด•เตเด•เดคเตเดคเดฟเตฝ เดตเดฟเดตเดฐเดฟเดšเตเดšเดฟเดฐเดฟเด•เตเด•เตเดจเตเดจเต. เดฎเดฑเตเดฑเต†เดจเตเดคเต†เด™เตเด•เดฟเดฒเตเด‚ เดตเตเดฏเด•เตเดคเดฎเดฒเตเดฒเต†เด™เตเด•เดฟเตฝ, เด…เดคเต เด—เต‚เด—เดฟเตพ เดšเต†เดฏเตเดคเต เดชเดฐเดฟเดถเต‹เดงเดฟเด•เตเด•เตเด•. เดตเดฟเดถเดฆเต€เด•เดฐเดฟเด•เตเด•เตเดจเตเดจเต (เดญเดพเด—เตเดฏเดตเดถเดพเตฝ, เดŸเต†เดฒเดฟเด—เตเดฐเดพเด‚ เดคเดŸเดžเตเดžเดคเต เด•เดพเดฐเดฃเด‚ เด‡เดคเต เดตเต€เดฃเตเดŸเตเด‚ เดชเตเดฐเดตเตผเดคเตเดคเดฟเด•เตเด•เตเดจเตเดจเต). เดจเดฟเด™เตเด™เตพเด•เตเด•เต เด’เดจเตเดจเตเด‚ เด—เต‚เด—เดฟเตพ เดšเต†เดฏเตเดฏเดพเตป เด•เดดเดฟเดฏเตเดจเตเดจเดฟเดฒเตเดฒเต†เด™เตเด•เดฟเตฝ, เด…เดญเดฟเดชเตเดฐเดพเดฏเด™เตเด™เดณเดฟเตฝ เดšเต‹เดฆเดฟเด•เตเด•เตเด•. "เดฐเดธเด•เดฐเดฎเดพเดฏ เดธเดพเด™เตเด•เต‡เดคเดฟเด•เดคเด•เตพ" เดŽเดจเตเดจ เด…เดจเตเดฌเดจเตเดง เดตเดฟเดญเดพเด—เดคเตเดคเดฟเดฒเต‡เด•เตเด•เต เดšเต‡เตผเด•เตเด•เตเดจเตเดจเดคเดฟเตฝ เดžเดพเตป เดธเดจเตเดคเตเดทเตเดŸเดจเดพเดฃเต.

เดจเดฎเตเด•เตเด•เต เดคเตเดŸเด™เตเด™เดพเด‚.

$ mkdir blue-green-deployment && cd $_

เดธเต‡เดตเดจเด‚

เดจเดฎเตเด•เตเด•เต เด’เดฐเต เดชเดฐเต€เด•เตเดทเดฃเดพเดคเตเดฎเด• เดธเต‡เดตเดจเด‚ เด‰เดฃเตเดŸเดพเด•เตเด•เดฟ เด’เดฐเต เด•เดฃเตเดŸเต†เดฏเตเดจเดฑเดฟเตฝ เดธเตเดฅเดพเดชเดฟเด•เตเด•เดพเด‚.

เดฐเดธเด•เดฐเดฎเดพเดฏ เดŸเต†เด•เตเดจเดฟเด•เตเด•เตเด•เตพ

  • cat << EOF > file-name (เด‡เดตเดฟเดŸเต† เดกเต‹เด•เตเดฏเตเดฎเต†เดจเตเดฑเต + I/O เดฑเต€เดกเดฏเดฑเด•เตเดทเตป) เด’เดฐเต เด•เดฎเดพเตปเดกเต เด‰เดชเดฏเต‹เด—เดฟเดšเตเดšเต เด’เดฐเต เดฎเตพเดŸเตเดŸเดฟ-เดฒเตˆเตป เดซเดฏเตฝ เดธเตƒเดทเตเดŸเดฟเด•เตเด•เตเดจเตเดจเดคเดฟเดจเตเดณเตเดณ เด’เดฐเต เดฎเดพเตผเด—เดฎเดพเดฃเต. เดฌเดพเดทเต เดตเดพเดฏเดฟเด•เตเด•เตเดจเตเดจเดคเต†เดฒเตเดฒเดพเด‚ /dev/stdin เดˆ เดตเดฐเดฟเด•เตเด•เต เดถเต‡เดทเดตเตเด‚ เดตเดฐเดฟเด•เตเด•เต เดฎเตเดฎเตเดชเตเด‚ EOF เตฝ เดฐเต‡เด–เดชเตเดชเต†เดŸเตเดคเตเดคเตเด‚ file-name.
  • wget -qO- URL (เดตเดฟเดถเดฆเต€เด•เดฐเดฟเด•เตเด•เตเดจเตเดจเต) โ€” HTTP เดตเดดเดฟ เดฒเดญเดฟเดšเตเดš เด’เดฐเต เดชเตเดฐเดฎเดพเดฃเด‚ เด”เดŸเตเดŸเตเดชเตเดŸเตเดŸเต เดšเต†เดฏเตเดฏเตเด• /dev/stdout (เด…เดจเดฒเต‹เด—เต curl URL).

เดชเตเดฐเดฟเดจเตเดฑเต—เดŸเตเดŸเต

เดชเตˆเดคเตเดคเดฃเดฟเดจเดพเดฏเดฟ เดนเตˆเดฒเตˆเดฑเตเดฑเต เดšเต†เดฏเตเดฏเตเดจเตเดจเดคเต เดชเตเดฐเดตเตผเดคเตเดคเดจเด•เตเดทเดฎเดฎเดพเด•เตเด•เดพเตป เดžเดพเตป เดชเตเดฐเดคเตเดฏเต‡เด•เดฎเดพเดฏเดฟ เดธเตเดจเดฟเดชเตเดชเต†เดฑเตเดฑเต เดคเด•เตผเด•เตเด•เตเดจเตเดจเต. เด…เดตเดธเดพเดจเด‚ เด‡เดคเตเดชเต‹เดฒเต† เดฎเดฑเตเดฑเตŠเดฐเต เด•เดทเดฃเด‚ เด‰เดฃเตเดŸเดพเด•เตเด‚. เดˆ เดธเตเดฅเดฒเด™เตเด™เดณเดฟเตฝ เดนเตˆเดฒเตˆเดฑเตเดฑเดฟเด‚เด—เต เดกเดฟเดชเตเดชเดพเตผเดŸเตเดŸเตโ€Œเดฎเต†เดจเตเดฑเดฟเดฒเต‡เด•เตเด•เต เด…เดฏเดฏเตเด•เตเด•เดพเตป เดชเต‡เดชเตเดชเตผ เดฎเตเดฑเดฟเดšเตเดšเดคเดพเดฏเดฟ เดชเดฐเดฟเด—เดฃเดฟเด•เตเด•เตเด• (เด…เดตเดฟเดŸเต† เด•เต‹เดกเต เดนเตˆเดฒเตˆเดฑเตเดฑเดฑเตเด•เตพ เด‰เดชเดฏเต‹เด—เดฟเดšเตเดšเต เด•เตˆเด•เตŠเดฃเตเดŸเต เดจเดฟเดฑเดฎเตเดณเตเดณเดคเดพเดฏเดฟเดฐเตเดจเตเดจเต), เดคเตเดŸเตผเดจเตเดจเต เดˆ เด•เดทเดฃเด™เตเด™เตพ เดคเดฟเดฐเดฟเด•เต† เด’เดŸเตเดŸเดฟเดšเตเดšเต.

$ cat << EOF > uptimer.py
from http.server import BaseHTTPRequestHandler, HTTPServer
from time import monotonic

app_version = 1
app_name = f'Uptimer v{app_version}.0'
loading_seconds = 15 - app_version * 5

class Handler(BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/':
            try:
                t = monotonic() - server_start
                if t < loading_seconds:
                    self.send_error(503)
                else:
                    self.send_response(200)
                    self.send_header('Content-Type', 'text/html')
                    self.end_headers()
                    response = f'<h2>{app_name} is running for {t:3.1f} seconds.</h2>n'
                    self.wfile.write(response.encode('utf-8'))
            except Exception:
                self.send_error(500)
        else:
            self.send_error(404)

httpd = HTTPServer(('', 8080), Handler)
server_start = monotonic()
print(f'{app_name} (loads in {loading_seconds} sec.) started.')
httpd.serve_forever()
EOF

$ cat << EOF > Dockerfile
FROM python:alpine
EXPOSE 8080
COPY uptimer.py app.py
CMD [ "python", "-u", "./app.py" ]
EOF

$ docker build --tag uptimer .
Sending build context to Docker daemon  39.42kB
Step 1/4 : FROM python:alpine
 ---> 8ecf5a48c789
Step 2/4 : EXPOSE 8080
 ---> Using cache
 ---> cf92d174c9d3
Step 3/4 : COPY uptimer.py app.py
 ---> a7fbb33d6b7e
Step 4/4 : CMD [ "python", "-u", "./app.py" ]
 ---> Running in 1906b4bd9fdf
Removing intermediate container 1906b4bd9fdf
 ---> c1655b996fe8
Successfully built c1655b996fe8
Successfully tagged uptimer:latest

$ docker run --rm --detach --name uptimer --publish 8080:8080 uptimer
8f88c944b8bf78974a5727070a94c76aa0b9bb2b3ecf6324b784e782614b2fbf

$ docker ps
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS                    NAMES
8f88c944b8bf        uptimer             "python -u ./app.py"   3 seconds ago       Up 5 seconds        0.0.0.0:8080->8080/tcp   uptimer

$ docker logs uptimer
Uptimer v1.0 (loads in 10 sec.) started.

$ wget -qSO- http://localhost:8080
  HTTP/1.0 503 Service Unavailable
  Server: BaseHTTP/0.6 Python/3.8.3
  Date: Sat, 22 Aug 2020 19:52:40 GMT
  Connection: close
  Content-Type: text/html;charset=utf-8
  Content-Length: 484

$ wget -qSO- http://localhost:8080
  HTTP/1.0 200 OK
  Server: BaseHTTP/0.6 Python/3.8.3
  Date: Sat, 22 Aug 2020 19:52:45 GMT
  Content-Type: text/html
<h2>Uptimer v1.0 is running for 15.4 seconds.</h2>

$ docker rm --force uptimer
uptimer

เดฑเดฟเดตเต‡เดดเตเดธเต เดชเตเดฐเต‹เด•เตเดธเดฟ

เดžเด™เตเด™เดณเตเดŸเต† เด†เดชเตเดฒเดฟเด•เตเด•เต‡เดทเดจเต เดถเตเดฐเดฆเตเดงเดฏเดฟเตฝเดชเตเดชเต†เดŸเดพเดคเต† เดฎเดพเดฑเตเดฑเดพเตป เด•เดดเดฟเดฏเดฃเดฎเต†เด™เตเด•เดฟเตฝ, เด…เดคเดฟเดจเตเดฑเต† เดชเด•เดฐเด‚ เดตเดฏเตเด•เตเด•เตฝ เดฎเดฑเดฏเตเด•เตเด•เตเดจเตเดจ เดฎเดฑเตเดฑเต‡เดคเต†เด™เตเด•เดฟเดฒเตเด‚ เดธเตเดฅเดพเดชเดจเด‚ เด…เดคเดฟเดจเต เดฎเตเดจเตเดจเดฟเตฝ เด‰เดฃเตเดŸเดพเดฏเดฟเดฐเดฟเด•เตเด•เต‡เดฃเตเดŸเดคเต เด†เดตเดถเตเดฏเดฎเดพเดฃเต. เด…เดคเตŠเดฐเต เดตเต†เดฌเต เดธเต†เตผเดตเตผ เด†เดฏเดฟเดฐเดฟเด•เตเด•เดพเด‚ nginx ะฒ เดฑเดฟเดตเต‡เดดเตเดธเต เดชเตเดฐเต‹เด•เตเดธเดฟ เดฎเต‹เดกเต. เด•เตเดฒเดฏเดจเตเดฑเดฟเดจเตเด‚ เด†เดชเตเดฒเดฟเด•เตเด•เต‡เดทเดจเตเด‚ เด‡เดŸเดฏเดฟเตฝ เด’เดฐเต เดฑเดฟเดตเต‡เดดเตเดธเต เดชเตเดฐเต‹เด•เตเดธเดฟ เดธเตเดฅเดพเดชเดฟเดšเตเดšเต. เด‡เดคเต เด•เตเดฒเดฏเดจเตเดฑเตเด•เดณเดฟเตฝ เดจเดฟเดจเตเดจเตเดณเตเดณ เด…เดญเตเดฏเตผเดคเตเดฅเดจเด•เตพ เดธเตเดตเต€เด•เดฐเดฟเด•เตเด•เตเด•เดฏเตเด‚ เด…เดต เด†เดชเตเดฒเดฟเด•เตเด•เต‡เดทเดจเดฟเดฒเต‡เด•เตเด•เต เด•เตˆเดฎเดพเดฑเตเด•เดฏเตเด‚ เด•เตเดฒเดฏเดจเตเดฑเตเด•เตพเด•เตเด•เต เด†เดชเตเดฒเดฟเด•เตเด•เต‡เดทเดจเตเดฑเต† เดชเตเดฐเดคเดฟเด•เดฐเดฃเด™เตเด™เตพ เด•เตˆเดฎเดพเดฑเตเด•เดฏเตเด‚ เดšเต†เดฏเตเดฏเตเดจเตเดจเต.

เด†เดชเตเดฒเดฟเด•เตเด•เต‡เดทเดจเตเด‚ เดฑเดฟเดตเต‡เดดเตเดธเต เดชเตเดฐเต‹เด•เตเดธเดฟเดฏเตเด‚ เด‰เดชเดฏเต‹เด—เดฟเดšเตเดšเต เดกเต‹เด•เตเด•เดฑเดฟเดจเตเดณเตเดณเดฟเตฝ เดฒเดฟเด™เตเด•เต เดšเต†เดฏเตเดฏเดพเดจเดพเด•เตเด‚ เดกเต‹เด•เตเด•เตผ เดจเต†เดฑเตเดฑเตโ€Œเดตเตผเด•เตเด•เต. เด…เดคเดฟเดจเดพเตฝ, เด†เดชเตเดฒเดฟเด•เตเด•เต‡เดทเดจเตเดณเตเดณ เด•เดฃเตเดŸเต†เดฏเตโ€Œเดจเดฑเดฟเดจเต เดนเต‹เดธเตเดฑเตเดฑเต เดธเดฟเดธเตเดฑเตเดฑเดคเตเดคเดฟเตฝ เด’เดฐเต เดชเต‹เตผเดŸเตเดŸเต เดซเต‹เตผเดตเต‡เดกเต เดšเต†เดฏเตเดฏเต‡เดฃเตเดŸ เด†เดตเดถเตเดฏเดฎเดฟเดฒเตเดฒ; เด‡เดคเต เดฌเดพเดนเตเดฏ เดญเต€เดทเดฃเดฟเด•เดณเดฟเตฝ เดจเดฟเดจเตเดจเต เด…เดชเตเดฒเดฟเด•เตเด•เต‡เดทเดจเต† เดชเดฐเดฎเดพเดตเดงเดฟ เด’เดฑเตเดฑเดชเตเดชเต†เดŸเตเดคเตเดคเดพเตป เด…เดจเตเดตเดฆเดฟเด•เตเด•เตเดจเตเดจเต.

เดฎเดฑเตเดฑเตŠเดฐเต เดนเต‹เดธเตเดฑเตเดฑเดฟเดฒเดพเดฃเต เดฑเดฟเดตเต‡เดดเตเดธเต เดชเตเดฐเต‹เด•เตเดธเดฟ เดœเต€เดตเดฟเด•เตเด•เตเดจเตเดจเดคเต†เด™เตเด•เดฟเตฝ, เดจเดฟเด™เตเด™เตพ เดกเต‹เด•เตเด•เตผ เดจเต†เดฑเตเดฑเตโ€Œเดตเตผเด•เตเด•เต เด‰เดชเต‡เด•เตเดทเดฟเดšเตเดšเต เดชเต‹เตผเดŸเตเดŸเต เดซเต‹เตผเดตเต‡เดกเต เดšเต†เดฏเตเดคเต เดนเต‹เดธเตเดฑเตเดฑเต เดจเต†เดฑเตเดฑเตโ€Œเดตเตผเด•เตเด•เดฟเดฒเต‚เดŸเต† เด†เดชเตเดฒเดฟเด•เตเด•เต‡เดทเดจเต† เดฑเดฟเดตเต‡เดดเตเดธเต เดชเตเดฐเต‹เด•เตเดธเดฟเดฏเดฟเดฒเต‡เด•เตเด•เต เดฌเดจเตเดงเดฟเดชเตเดชเดฟเด•เตเด•เต‡เดฃเตเดŸเดคเตเดฃเตเดŸเต. เด…เดชเตเดฒเดฟเด•เตเด•เต‡เดทเดจเตเด•เตพ เดชเดฐเดพเดฎเต€เดฑเตเดฑเตผ --publish, เด†เดฆเตเดฏ เดคเตเดŸเด•เตเด•เดคเตเดคเดฟเดฒเต†เดจเตเดจเดชเต‹เดฒเต† เดฑเดฟเดตเต‡เดดเตเดธเต เดชเตเดฐเต‹เด•เตเดธเดฟ เดชเต‹เดฒเต†.

เดชเต‹เตผเดŸเตเดŸเต 80-เตฝ เดžเด™เตเด™เตพ เดฑเดฟเดตเต‡เดดเตเดธเต เดชเตเดฐเต‹เด•เตเดธเดฟ เดชเตเดฐเดตเตผเดคเตเดคเดฟเดชเตเดชเดฟเด•เตเด•เตเด‚, เด•เดพเดฐเดฃเด‚ เด‡เดคเต เด•เตƒเดคเตเดฏเดฎเดพเดฏเดฟ เดฌเดพเดนเตเดฏ เดจเต†เดฑเตเดฑเตโ€Œเดตเตผเด•เตเด•เดฟเดจเต† เดถเตเดฐเดฆเตเดงเดฟเด•เตเด•เต‡เดฃเตเดŸ เดŽเดจเตเดฑเดฟเดฑเตเดฑเดฟเดฏเดพเดฃเต. เดจเดฟเด™เตเด™เดณเตเดŸเต† เดŸเต†เดธเตเดฑเตเดฑเต เดนเต‹เดธเตเดฑเตเดฑเดฟเตฝ เดชเต‹เตผเดŸเตเดŸเต 80 เดคเดฟเดฐเด•เตเด•เดฟเดฒเดพเดฃเต†เด™เตเด•เดฟเตฝ, เดชเดฐเดพเดฎเต€เดฑเตเดฑเตผ เดฎเดพเดฑเตเดฑเตเด• --publish 80:80 เด“เตบ --publish ANY_FREE_PORT:80.

เดฐเดธเด•เดฐเดฎเดพเดฏ เดŸเต†เด•เตเดจเดฟเด•เตเด•เตเด•เตพ

เดชเตเดฐเดฟเดจเตเดฑเต—เดŸเตเดŸเต

$ docker network create web-gateway
5dba128fb3b255b02ac012ded1906b7b4970b728fb7db3dbbeccc9a77a5dd7bd

$ docker run --detach --rm --name uptimer --network web-gateway uptimer
a1105f1b583dead9415e99864718cc807cc1db1c763870f40ea38bc026e2d67f

$ docker run --rm --network web-gateway alpine wget -qO- http://uptimer:8080
<h2>Uptimer v1.0 is running for 11.5 seconds.</h2>

$ docker run --detach --publish 80:80 --network web-gateway --name reverse-proxy nginx:alpine
80695a822c19051260c66bf60605dcb4ea66802c754037704968bc42527bf120

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS                NAMES
80695a822c19        nginx:alpine        "/docker-entrypoint.โ€ฆ"   27 seconds ago       Up 25 seconds       0.0.0.0:80->80/tcp   reverse-proxy
a1105f1b583d        uptimer             "python -u ./app.py"     About a minute ago   Up About a minute   8080/tcp             uptimer

$ cat << EOF > uptimer.conf
server {
    listen 80;
    location / {
        proxy_pass http://uptimer:8080;
    }
}
EOF

$ docker cp ./uptimer.conf reverse-proxy:/etc/nginx/conf.d/default.conf

$ docker exec reverse-proxy nginx -s reload
2020/06/23 20:51:03 [notice] 31#31: signal process started

$ wget -qSO- http://localhost
  HTTP/1.1 200 OK
  Server: nginx/1.19.0
  Date: Sat, 22 Aug 2020 19:56:24 GMT
  Content-Type: text/html
  Transfer-Encoding: chunked
  Connection: keep-alive
<h2>Uptimer v1.0 is running for 104.1 seconds.</h2>

เดคเดŸเดธเตเดธเดฎเดฟเดฒเตเดฒเดพเดคเตเดค เดตเดฟเดจเตเดฏเดพเดธเด‚

เดจเดฎเตเด•เตเด•เต เด†เดชเตเดฒเดฟเด•เตเด•เต‡เดทเดจเตเดฑเต† เด’เดฐเต เดชเตเดคเดฟเดฏ เดชเดคเดฟเดชเตเดชเต เดชเตเดฑเดคเตเดคเดฟเดฑเด•เตเด•เดพเด‚ (เดฐเดฃเตเดŸเต เดฎเดŸเด™เตเด™เต เดธเตเดฑเตเดฑเดพเตผเดŸเตเดŸเดชเตเดชเต เดชเต†เตผเดซเต‹เดฎเตปเดธเต เดฌเต‚เดธเตโ€Œเดฑเตเดฑเต‹เดŸเต†) เด…เดคเต เดคเดŸเดธเตเดธเดฎเดฟเดฒเตเดฒเดพเดคเต† เดตเดฟเดจเตเดฏเดธเดฟเด•เตเด•เดพเตป เดถเตเดฐเดฎเดฟเด•เตเด•เดพเด‚.

เดฐเดธเด•เดฐเดฎเดพเดฏ เดŸเต†เด•เตเดจเดฟเด•เตเด•เตเด•เตพ

  • echo 'my text' | docker exec -i my-container sh -c 'cat > /my-file.txt' - เดตเดพเดšเด•เด‚ เดŽเดดเตเดคเตเด• my text เดซเดฏเตฝ เดšเต†เดฏเตเดฏเดพเตป /my-file.txt เด•เดฃเตเดŸเต†เดฏเตเดจเดฑเดฟเดจเตเดณเตเดณเดฟเตฝ my-container.
  • cat > /my-file.txt โ€” เด’เดฐเต เดซเดฏเดฒเดฟเดฒเต‡เด•เตเด•เต เดธเตเดฑเตเดฑเดพเตปเดกเต‡เตผเดกเต เด‡เตปเดชเตเดŸเตเดŸเดฟเดจเตเดฑเต† เด‰เดณเตเดณเดŸเด•เตเด•เด™เตเด™เตพ เดŽเดดเตเดคเตเด• /dev/stdin.

เดชเตเดฐเดฟเดจเตเดฑเต—เดŸเตเดŸเต

$ sed -i "s/app_version = 1/app_version = 2/" uptimer.py

$ docker build --tag uptimer .
Sending build context to Docker daemon  39.94kB
Step 1/4 : FROM python:alpine
 ---> 8ecf5a48c789
Step 2/4 : EXPOSE 8080
 ---> Using cache
 ---> cf92d174c9d3
Step 3/4 : COPY uptimer.py app.py
 ---> 3eca6a51cb2d
Step 4/4 : CMD [ "python", "-u", "./app.py" ]
 ---> Running in 8f13c6d3d9e7
Removing intermediate container 8f13c6d3d9e7
 ---> 1d56897841ec
Successfully built 1d56897841ec
Successfully tagged uptimer:latest

$ docker run --detach --rm --name uptimer_BLUE --network web-gateway uptimer
96932d4ca97a25b1b42d1b5f0ede993b43f95fac3c064262c5c527e16c119e02

$ docker logs uptimer_BLUE
Uptimer v2.0 (loads in 5 sec.) started.

$ docker run --rm --network web-gateway alpine wget -qO- http://uptimer_BLUE:8080
<h2>Uptimer v2.0 is running for 23.9 seconds.</h2>

$ sed s/uptimer/uptimer_BLUE/ uptimer.conf | docker exec --interactive reverse-proxy sh -c 'cat > /etc/nginx/conf.d/default.conf'

$ docker exec reverse-proxy cat /etc/nginx/conf.d/default.conf
server {
    listen 80;
    location / {
        proxy_pass http://uptimer_BLUE:8080;
    }
}

$ docker exec reverse-proxy nginx -s reload
2020/06/25 21:22:23 [notice] 68#68: signal process started

$ wget -qO- http://localhost
<h2>Uptimer v2.0 is running for 63.4 seconds.</h2>

$ docker rm -f uptimer
uptimer

$ wget -qO- http://localhost
<h2>Uptimer v2.0 is running for 84.8 seconds.</h2>

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS                NAMES
96932d4ca97a        uptimer             "python -u ./app.py"     About a minute ago   Up About a minute   8080/tcp             uptimer_BLUE
80695a822c19        nginx:alpine        "/docker-entrypoint.โ€ฆ"   8 minutes ago        Up 8 minutes        0.0.0.0:80->80/tcp   reverse-proxy

เดˆ เด˜เดŸเตเดŸเดคเตเดคเดฟเตฝ, เด‡เดฎเต‡เดœเต เดธเต†เตผเดตเดฑเดฟเตฝ เดจเต‡เดฐเดฟเดŸเตเดŸเต เดจเดฟเตผเดฎเตเดฎเดฟเดšเตเดšเดฟเดฐเดฟเด•เตเด•เตเดจเตเดจเต, เด‡เดคเดฟเดจเต เด†เดชเตเดฒเดฟเด•เตเด•เต‡เดทเตป เด‰เดฑเดตเดฟเดŸเด™เตเด™เตพ เด†เดตเดถเตเดฏเดฎเดพเดฃเต, เด•เต‚เดŸเดพเดคเต† เดธเต†เตผเดตเดฑเดฟเดจเต† เด…เดจเดพเดตเดถเตเดฏเดฎเดพเดฏเดฟ เดฒเต‹เดกเตเดšเต†เดฏเตเดฏเตเด•เดฏเตเด‚ เดšเต†เดฏเตเดฏเตเดจเตเดจเต. เด…เดŸเตเดคเตเดค เด˜เดŸเตเดŸเด‚ เด‡เดฎเต‡เดœเต เด…เดธเด‚เดฌเตเดฒเดฟ เด’เดฐเต เดชเตเดฐเดคเตเดฏเต‡เด• เดฎเต†เดทเต€เดจเดฟเดฒเต‡เด•เตเด•เต (เด‰เดฆเดพเดนเดฐเดฃเดคเตเดคเดฟเดจเต, เด’เดฐเต CI เดธเดฟเดธเตเดฑเตเดฑเดคเตเดคเดฟเดฒเต‡เด•เตเด•เต) เด…เดจเตเดตเดฆเดฟเด•เตเด•เตเด•เดฏเตเด‚ เดคเตเดŸเตผเดจเตเดจเต เด…เดคเต เดธเต†เตผเดตเดฑเดฟเดฒเต‡เด•เตเด•เต เดฎเดพเดฑเตเดฑเตเด•เดฏเตเด‚ เดšเต†เดฏเตเดฏเตเด• เดŽเดจเตเดจเดคเดพเดฃเต.

เดšเดฟเดคเตเดฐเด™เตเด™เตพ เด•เตˆเดฎเดพเดฑเตเดจเตเดจเต

เดจเดฟเตผเดญเดพเด—เตเดฏเดตเดถเดพเตฝ, เดฒเต‹เด•เตเด•เตฝเดนเต‹เดธเตเดฑเตเดฑเดฟเตฝ เดจเดฟเดจเตเดจเต เดฒเต‹เด•เตเด•เตฝเดนเต‹เดธเตเดฑเตเดฑเดฟเดฒเต‡เด•เตเด•เต เดšเดฟเดคเตเดฐเด™เตเด™เตพ เด•เตˆเดฎเดพเดฑเตเดจเตเดจเดคเดฟเตฝ เด…เตผเดคเตเดฅเดฎเดฟเดฒเตเดฒ, เด…เดคเดฟเดจเดพเตฝ เดจเดฟเด™เตเด™เตพเด•เตเด•เต เดกเต‹เด•เตเด•เดฑเตเดฎเดพเดฏเดฟ เดฐเดฃเตเดŸเต เดนเต‹เดธเตเดฑเตเดฑเตเด•เตพ เด‰เดฃเตเดŸเต†เด™เตเด•เดฟเตฝ เดฎเดพเดคเตเดฐเดฎเต‡ เดˆ เดตเดฟเดญเดพเด—เด‚ เดชเดฐเตเดฏเดตเต‡เด•เตเดทเดฃเด‚ เดšเต†เดฏเตเดฏเดพเตป เด•เดดเดฟเดฏเต‚. เด•เตเดฑเดžเตเดžเดคเต เด‡เดคเต เด‡เดคเตเดชเต‹เดฒเต† เด•เดพเดฃเดชเตเดชเต†เดŸเตเดจเตเดจเต:

$ ssh production-server docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

$ docker image save uptimer | ssh production-server 'docker image load'
Loaded image: uptimer:latest

$ ssh production-server docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
uptimer             latest              1d56897841ec        5 minutes ago       78.9MB

เดŸเต€เด‚ docker save เด‡เดฎเต‡เดœเต เดกเดพเดฑเตเดฑ เด’เดฐเต .tar เด†เตผเด•เตเด•เตˆเดตเดฟเตฝ เดธเด‚เดฐเด•เตเดทเดฟเด•เตเด•เตเดจเตเดจเต, เด…เดคเดพเดฏเดคเต เด•เด‚เดชเตเดฐเดธเต เดšเต†เดฏเตเดค เดฐเต‚เดชเดคเตเดคเดฟเตฝ เด…เดคเดฟเดจเตเดฑเต† เดญเดพเดฐเด‚ 1.5 เดฎเดŸเด™เตเด™เต เด•เต‚เดŸเตเดคเดฒเดพเดฃเต. เด…เดคเดฟเดจเดพเตฝ เดธเดฎเดฏเดตเตเด‚ เดŸเตเดฐเดพเดซเดฟเด•เตเด•เตเด‚ เดฒเดพเดญเดฟเด•เตเด•เตเดจเตเดจเดคเดฟเดจเตเดฑเต† เดชเต‡เดฐเดฟเตฝ เดจเดฎเตเด•เตเด•เต เด‡เดคเต เด‡เดณเด•เตเด•เดฟเดตเดฟเดŸเดพเด‚:

$ docker image save uptimer | gzip | ssh production-server 'zcat | docker image load'
Loaded image: uptimer:latest

เดจเดฟเด™เตเด™เตพเด•เตเด•เต เดกเต—เตบเดฒเต‹เดกเต เดชเตเดฐเด•เตเดฐเดฟเดฏ เดจเดฟเดฐเต€เด•เตเดทเดฟเด•เตเด•เดพเดจเตเด‚ เด•เดดเดฟเดฏเตเด‚ (เด‡เดคเดฟเดจเต เด’เดฐเต เดฎเต‚เดจเตเดจเดพเด‚ เด•เด•เตเดทเดฟ เดฏเต‚เดŸเตเดŸเดฟเดฒเดฟเดฑเตเดฑเดฟ เด†เดตเดถเตเดฏเดฎเดพเดฃเต†เด™เตเด•เดฟเดฒเตเด‚):

$ docker image save uptimer | gzip | pv | ssh production-server 'zcat | docker image load'
25,7MiB 0:01:01 [ 425KiB/s] [                   <=>    ]
Loaded image: uptimer:latest

เดจเตเดฑเตเด™เตเด™เต: SSH เดตเดดเดฟ เด’เดฐเต เดธเต†เตผเดตเดฑเดฟเดฒเต‡เด•เตเด•เต เด•เดฃเด•เตเดฑเตเดฑเตเดšเต†เดฏเตเดฏเดพเตป เดจเดฟเด™เตเด™เตพเด•เตเด•เต เด’เดฐเต เด•เต‚เดŸเตเดŸเด‚ เดชเดพเดฐเดพเดฎเต€เดฑเตเดฑเดฑเตเด•เตพ เด†เดตเดถเตเดฏเดฎเตเดฃเตเดŸเต†เด™เตเด•เดฟเตฝ, เดจเดฟเด™เตเด™เตพ เดซเดฏเตฝ เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เตเดจเตเดจเดฟเดฒเตเดฒเดพเดฏเดฟเดฐเดฟเด•เตเด•เดพเด‚ ~/.ssh/config.

เดตเดดเดฟ เดšเดฟเดคเตเดฐเด‚ เด•เตˆเดฎเดพเดฑเตเดจเตเดจเต docker image save/load - เด‡เดคเต เดเดฑเตเดฑเดตเตเด‚ เดšเตเดฐเตเด™เตเด™เดฟเดฏ เดฐเต€เดคเดฟเดฏเดพเดฃเต, เดชเด•เตเดทเต‡ เด’เดจเตเดจเดฒเตเดฒ. เดฎเดฑเตเดฑเตเดณเตเดณเดตเดฏเตเดฃเตเดŸเต:

  1. เด•เดฃเตเดŸเต†เดฏเตเดจเตผ เดฐเดœเดฟเดธเตเดŸเตเดฐเดฟ (เด‡เตปเดกเดธเตเดŸเตเดฐเดฟ เดธเตเดฑเตเดฑเดพเตปเดกเต‡เตผเดกเต).
  2. เดฎเดฑเตเดฑเตŠเดฐเต เดนเต‹เดธเตเดฑเตเดฑเดฟเตฝ เดจเดฟเดจเตเดจเต เดกเต‹เด•เตเด•เตผ เดกเต†เดฎเตบ เดธเต†เตผเดตเดฑเดฟเดฒเต‡เด•เตเด•เต เด•เดฃเด•เตเดฑเตเดฑเตเดšเต†เดฏเตเดฏเตเด•:
    1. เดชเดฐเดฟเดธเตเดฅเดฟเดคเดฟ เดตเต‡เดฐเดฟเดฏเดฌเดฟเตพ DOCKER_HOST.
    2. เด•เดฎเดพเตปเดกเต เดฒเตˆเตป เด“เดชเตเดทเตป -H เด…เดฅเดตเดพ --host เด‰เดชเด•เดฐเดฃเด‚ docker-compose.
    3. docker context

เดฐเดฃเตเดŸเดพเดฎเดคเตเดคเต† เดฐเต€เดคเดฟ (เด…เดคเดฟเดจเตเดฑเต† เดจเดฟเตผเดตเตเดตเดนเดฃเดคเตเดคเดฟเดจเตเดณเตเดณ เดฎเต‚เดจเตเดจเต เด“เดชเตเดทเดจเตเด•เตพ) เดฒเต‡เด–เดจเดคเตเดคเดฟเตฝ เดจเดจเตเดจเดพเดฏเดฟ เดตเดฟเดตเดฐเดฟเดšเตเดšเดฟเดฐเดฟเด•เตเด•เตเดจเตเดจเต เดกเต‹เด•เตเด•เตผ-เด•เด‚เดชเต‹เดธเต เด‰เดชเดฏเต‹เด—เดฟเดšเตเดšเต เดฑเดฟเดฎเต‹เดŸเตเดŸเต เดกเต‹เด•เตเด•เตผ เดนเต‹เดธเตเดฑเตเดฑเตเด•เดณเดฟเตฝ เดŽเด™เตเด™เดจเต† เดตเดฟเดจเตเดฏเดธเดฟเด•เตเด•เดพเด‚.

deploy.sh

เด‡เดจเดฟ เดจเดฎเตเดฎเตพ เดธเตเดตเดฎเต‡เดงเดฏเดพ เดšเต†เดฏเตเดคเดคเต†เดฒเตเดฒเดพเด‚ เด’เดฐเต เดธเตเด•เตเดฐเดฟเดชเตเดฑเตเดฑเดฟเตฝ เดถเต‡เด–เดฐเดฟเด•เตเด•เดพเด‚. เดจเดฎเตเด•เตเด•เต เดŸเต‹เดชเตเดชเต-เดฒเต†เดตเตฝ เดซเด‚เด—เตโ€Œเดทเดจเดฟเตฝ เดจเดฟเดจเตเดจเต เด†เดฐเด‚เดญเดฟเด•เตเด•เดพเด‚, เดคเตเดŸเตผเดจเตเดจเต เด…เดคเดฟเตฝ เด‰เดชเดฏเต‹เด—เดฟเดšเตเดšเดฟเดฐเดฟเด•เตเด•เตเดจเตเดจ เดฎเดฑเตเดฑเตเดณเตเดณเดต เดจเต‹เด•เตเด•เดพเด‚.

เดฐเดธเด•เดฐเดฎเดพเดฏ เดŸเต†เด•เตเดจเดฟเด•เตเด•เตเด•เตพ

  • ${parameter?err_msg} - เดฌเดพเดทเต เดฎเดพเดจเตเดคเตเดฐเดฟเด• เดฎเดจเตเดคเตเดฐเด™เตเด™เดณเดฟเดฒเตŠเดจเตเดจเต (เด…เด•เตเด• เดชเดพเดฐเดพเดฎเต€เดฑเตเดฑเตผ เดชเด•เดฐเด‚ เดตเดฏเตเด•เตเด•เตฝ). เดŽเด™เตเด•เดฟเตฝ parameter เดตเตเดฏเด•เตเดคเดฎเดพเด•เตเด•เดฟเดฏเดฟเดŸเตเดŸเดฟเดฒเตเดฒ, เด”เดŸเตเดŸเตเดชเตเดŸเตเดŸเต err_msg เด•เต‹เดกเต 1 เด‰เดชเดฏเต‹เด—เดฟเดšเตเดšเต เดชเตเดฑเดคเตเดคเตเด•เดŸเด•เตเด•เตเด•.
  • docker --log-driver journald โ€” เดธเตเดฅเดฟเดฐเดธเตเดฅเดฟเดคเดฟเดฏเดพเดฏเดฟ, เดกเต‹เด•เตเด•เตผ เดฒเต‹เด—เดฟเด‚เด—เต เดกเตเดฐเตˆเดตเตผ เด’เดฐเต เดฑเตŠเดŸเตเดŸเต‡เดทเตป เด‡เดฒเตเดฒเดพเดคเตเดค เด’เดฐเต เดŸเต†เด•เตเดธเตเดฑเตเดฑเต เดซเดฏเดฒเดพเดฃเต. เดˆ เดธเดฎเต€เดชเดจเดคเตเดคเดฟเดฒเต‚เดŸเต†, เดฒเต‹เด—เตเด•เตพ เดฎเตเดดเตเดตเตป เดกเดฟเดธเตเด•เตเด‚ เดตเต‡เด—เดคเตเดคเดฟเตฝ เดจเดฟเดฑเดฏเตเด•เตเด•เตเดจเตเดจเต, เด…เดคเดฟเดจเดพเตฝ เด’เดฐเต เดชเตเดฐเตŠเดกเด•เตเดทเตป เดชเดฐเดฟเดคเดธเตเดฅเดฟเดคเดฟเด•เตเด•เต เดกเตเดฐเตˆเดตเดฑเดฟเดจเต† เดฎเดฟเด•เดšเตเดš เด’เดจเตเดจเดฟเดฒเต‡เด•เตเด•เต เดฎเดพเดฑเตเดฑเต‡เดฃเตเดŸเดคเต เด†เดตเดถเตเดฏเดฎเดพเดฃเต.

เดตเดฟเดจเตเดฏเดพเดธ เดธเตเด•เตเดฐเดฟเดชเตเดฑเตเดฑเต

deploy() {
    local usage_msg="Usage: ${FUNCNAME[0]} image_name"
    local image_name=${1?$usage_msg}

    ensure-reverse-proxy || return 2
    if get-active-slot $image_name
    then
        local OLD=${image_name}_BLUE
        local new_slot=GREEN
    else
        local OLD=${image_name}_GREEN
        local new_slot=BLUE
    fi
    local NEW=${image_name}_${new_slot}
    echo "Deploying '$NEW' in place of '$OLD'..."
    docker run 
        --detach 
        --restart always 
        --log-driver journald 
        --name $NEW 
        --network web-gateway 
        $image_name || return 3
    echo "Container started. Checking health..."
    for i in {1..20}
    do
        sleep 1
        if get-service-status $image_name $new_slot
        then
            echo "New '$NEW' service seems OK. Switching heads..."
            sleep 2  # Ensure service is ready
            set-active-slot $image_name $new_slot || return 4
            echo "'$NEW' service is live!"
            sleep 2  # Ensure all requests were processed
            echo "Killing '$OLD'..."
            docker rm -f $OLD
            docker image prune -f
            echo "Deployment successful!"
            return 0
        fi
        echo "New '$NEW' service is not ready yet. Waiting ($i)..."
    done
    echo "New '$NEW' service did not raise, killing it. Failed to deploy T_T"
    docker rm -f $NEW
    return 5
}

เด‰เดชเดฏเต‹เด—เดฟเดšเตเดš เดธเดตเดฟเดถเต‡เดทเดคเด•เตพ:

  • ensure-reverse-proxy - เดฑเดฟเดตเต‡เดดเตเดธเต เดชเตเดฐเต‹เด•เตเดธเดฟ เดชเตเดฐเดตเตผเดคเตเดคเดฟเด•เตเด•เตเดจเตเดจเตเดฃเตเดŸเต†เดจเตเดจเต เด‰เดฑเดชเตเดชเดพเด•เตเด•เตเดจเตเดจเต (เด†เดฆเตเดฏเดคเตเดคเต† เดตเดฟเดจเตเดฏเดพเดธเดคเตเดคเดฟเดจเต เด‰เดชเดฏเต‹เด—เดชเตเดฐเดฆเดฎเดพเดฃเต)
  • get-active-slot service_name - เดจเตฝเด•เดฟเดฏเดฟเดฐเดฟเด•เตเด•เตเดจเตเดจ เดธเต‡เดตเดจเดคเตเดคเดฟเดจเดพเดฏเดฟ เดจเดฟเดฒเดตเดฟเตฝ เดเดคเต เดธเตเดฒเต‹เดŸเตเดŸเต เดธเดœเต€เดตเดฎเดพเดฃเต†เดจเตเดจเต เดจเดฟเตผเดฃเตเดฃเดฏเดฟเด•เตเด•เตเดจเตเดจเต (BLUE เด…เดฅเดตเดพ GREEN)
  • get-service-status service_name deployment_slot โ€” เด‡เตปเด•เดฎเดฟเด‚เด—เต เด…เดญเตเดฏเตผเดคเตเดฅเดจเด•เตพ เดชเตเดฐเต‹เดธเดธเตเดธเต เดšเต†เดฏเตเดฏเดพเตป เดธเต‡เดตเดจเด‚ เดคเดฏเตเดฏเดพเดฑเดพเดฃเต‹ เดŽเดจเตเดจเต เดจเดฟเตผเดฃเตเดฃเดฏเดฟเด•เตเด•เตเดจเตเดจเต
  • set-active-slot service_name deployment_slot โ€” เดฑเดฟเดตเต‡เดดเตเดธเต เดชเตเดฐเต‹เด•เตเดธเดฟ เด•เดฃเตเดŸเต†เดฏเตเดจเดฑเดฟเดฒเต† nginx เด•เต‹เตบเดซเดฟเด—เดฑเต‡เดทเตป เดฎเดพเดฑเตเดฑเตเดจเตเดจเต

เด•เตเดฐเดฎเดคเตเดคเดฟเตฝ:

ensure-reverse-proxy() {
    is-container-up reverse-proxy && return 0
    echo "Deploying reverse-proxy..."
    docker network create web-gateway
    docker run 
        --detach 
        --restart always 
        --log-driver journald 
        --name reverse-proxy 
        --network web-gateway 
        --publish 80:80 
        nginx:alpine || return 1
    docker exec --interactive reverse-proxy sh -c "> /etc/nginx/conf.d/default.conf"
    docker exec reverse-proxy nginx -s reload
}

is-container-up() {
    local container=${1?"Usage: ${FUNCNAME[0]} container_name"}

    [ -n "$(docker ps -f name=${container} -q)" ]
    return $?
}

get-active-slot() {
    local service=${1?"Usage: ${FUNCNAME[0]} service_name"}

    if is-container-up ${service}_BLUE && is-container-up ${service}_GREEN; then
        echo "Collision detected! Stopping ${service}_GREEN..."
        docker rm -f ${service}_GREEN
        return 0  # BLUE
    fi
    if is-container-up ${service}_BLUE && ! is-container-up ${service}_GREEN; then
        return 0  # BLUE
    fi
    if ! is-container-up ${service}_BLUE; then
        return 1  # GREEN
    fi
}

get-service-status() {
    local usage_msg="Usage: ${FUNCNAME[0]} service_name deployment_slot"
    local service=${1?usage_msg}
    local slot=${2?$usage_msg}

    case $service in
        # Add specific healthcheck paths for your services here
        *) local health_check_port_path=":8080/" ;;
    esac
    local health_check_address="http://${service}_${slot}${health_check_port_path}"
    echo "Requesting '$health_check_address' within the 'web-gateway' docker network:"
    docker run --rm --network web-gateway alpine 
        wget --timeout=1 --quiet --server-response $health_check_address
    return $?
}

set-active-slot() {
    local usage_msg="Usage: ${FUNCNAME[0]} service_name deployment_slot"
    local service=${1?$usage_msg}
    local slot=${2?$usage_msg}
    [ "$slot" == BLUE ] || [ "$slot" == GREEN ] || return 1

    get-nginx-config $service $slot | docker exec --interactive reverse-proxy sh -c "cat > /etc/nginx/conf.d/$service.conf"
    docker exec reverse-proxy nginx -t || return 2
    docker exec reverse-proxy nginx -s reload
}

เดซเด‚เด—เตเดทเตป get-active-slot เด’เดฐเต เดšเต†เดฑเดฟเดฏ เดตเดฟเดถเดฆเต€เด•เดฐเดฃเด‚ เด†เดตเดถเตเดฏเดฎเดพเดฃเต:

เดŽเดจเตเดคเตเด•เตŠเดฃเตเดŸเดพเดฃเต เด‡เดคเต เด’เดฐเต เดจเดฎเตเดชเตผ เดจเตฝเด•เตเด•เดฏเตเด‚ เด’เดฐเต เดธเตเดŸเตเดฐเดฟเด‚เด—เต เด”เดŸเตเดŸเตเดชเตเดŸเตเดŸเต เดšเต†เดฏเตเดฏเดพเดคเดฟเดฐเดฟเด•เตเด•เตเด•เดฏเตเด‚ เดšเต†เดฏเตเดฏเตเดจเตเดจเดคเต?

เดŽเดจเตเดคเดพเดฏเดพเดฒเตเด‚, เด•เต‹เดณเดฟเด‚เด—เต เดซเด‚เด—เตเดทเดจเดฟเตฝ เดžเด™เตเด™เตพ เด…เดคเดฟเดจเตเดฑเต† เดชเตเดฐเดตเตผเดคเตเดคเดจเดคเตเดคเดฟเดจเตเดฑเต† เดซเดฒเด‚ เดชเดฐเดฟเดถเต‹เดงเดฟเด•เตเด•เตเดจเตเดจเต, เด•เต‚เดŸเดพเดคเต† เดฌเดพเดทเต เด‰เดชเดฏเต‹เด—เดฟเดšเตเดšเต เดŽเด•เตเดธเดฟเดฑเตเดฑเต เด•เต‹เดกเต เดชเดฐเดฟเดถเต‹เดงเดฟเด•เตเด•เตเดจเตเดจเดคเต เด’เดฐเต เดธเตเดŸเตเดฐเดฟเด‚เด—เต เดชเดฐเดฟเดถเต‹เดงเดฟเด•เตเด•เตเดจเตเดจเดคเดฟเดจเต‡เด•เตเด•เดพเตพ เดตเดณเดฐเต† เดŽเดณเตเดชเตเดชเดฎเดพเดฃเต. เด•เต‚เดŸเดพเดคเต†, เด…เดคเดฟเตฝ เดจเดฟเดจเตเดจเต เด’เดฐเต เดธเตเดŸเตเดฐเดฟเด‚เด—เต เดฒเดญเดฟเด•เตเด•เตเดจเตเดจเดคเต เดตเดณเดฐเต† เดฒเดณเดฟเดคเดฎเดพเดฃเต:
get-active-slot service && echo BLUE || echo GREEN.

เดŽเดฒเตเดฒเดพ เดธเด‚เดธเตเดฅเดพเดจเด™เตเด™เดณเต†เดฏเตเด‚ เดตเต‡เตผเดคเดฟเดฐเดฟเดšเตเดšเดฑเดฟเดฏเดพเตป เดฎเต‚เดจเตเดจเต เดตเตเดฏเดตเดธเตเดฅเด•เตพ เดถเดฐเดฟเด•เตเด•เตเด‚ เดฎเดคเดฟเดฏเต‹?

เด•เตเดฑเดžเตเดž เดตเต‡เดคเดจเดคเตเดคเดฟเตฝ เดจเต€เดฒ-เดชเดšเตเดš เดตเดฟเดจเตเดฏเดพเดธเด‚

เดฐเดฃเตเดŸเต†เดฃเตเดฃเด‚ เดชเต‹เดฒเตเด‚ เดฎเดคเดฟเดฏเดพเด•เตเด‚, เด…เดตเดธเดพเดจเดคเตเดคเต‡เดคเต เดชเต‚เตผเดฃเตเดฃเดคเดฏเตเด•เตเด•เดพเดฏเดฟ เด‡เดตเดฟเดŸเต†เดฏเตเดฃเตเดŸเต, เด…เดคเดฟเดจเดพเตฝ เดŽเดดเตเดคเดฐเตเดคเต else.

nginx เด•เต‹เตบเดซเดฟเด—เดฑเต‡เดทเดจเตเด•เตพ เดจเตฝเด•เตเดจเตเดจ เดซเด‚เด—เตโ€Œเดทเตป เดฎเดพเดคเตเดฐเด‚ เดจเดฟเตผเดตเดšเดฟเด•เตเด•เดชเตเดชเต†เดŸเตเดŸเดฟเดŸเตเดŸเดฟเดฒเตเดฒ: get-nginx-config service_name deployment_slot. เด†เดฐเต‹เด—เตเดฏ เดชเดฐเดฟเดถเต‹เดงเดจเดฏเตเดฎเดพเดฏเดฟ เดธเดพเดฎเตเดฏเดฎเตเดณเตเดณเดคเดฟเดจเดพเตฝ, เด‡เดตเดฟเดŸเต† เดจเดฟเด™เตเด™เตพเด•เตเด•เต เดเดคเต เดธเต‡เดตเดจเดคเตเดคเดฟเดจเตเด‚ เดเดคเต เด•เต‹เตบเดซเดฟเด—เดฑเตเด‚ เดธเดœเตเดœเดฎเดพเด•เตเด•เดพเตป เด•เดดเดฟเดฏเตเด‚. เดฐเดธเด•เดฐเดฎเดพเดฏ เด•เดพเดฐเตเดฏเด™เตเด™เดณเดฟเตฝ - เดฎเดพเดคเตเดฐเด‚ cat <<- EOF, เดคเตเดŸเด•เตเด•เดคเตเดคเดฟเตฝ เดคเดจเตเดจเต† เดŽเดฒเตเดฒเดพ เดŸเดพเดฌเตเด•เดณเตเด‚ เดจเต€เด•เตเด•เด‚ เดšเต†เดฏเตเดฏเดพเตป เดจเดฟเด™เตเด™เดณเต† เด…เดจเตเดตเดฆเดฟเด•เตเด•เตเดจเตเดจเต. เดถเดฐเดฟเดฏเดพเดฃเต, เดจเดฒเตเดฒ เดซเต‹เตผเดฎเดพเดฑเตเดฑเดฟเด‚เด—เดฟเดจเตเดฑเต† เดตเดฟเดฒ เดธเตโ€Œเดชเต†เดฏเตโ€Œเดธเตเด•เดณเตเดณเตเดณ เดฎเดฟเด•เตเดธเดกเต เดŸเดพเดฌเตเด•เดณเดพเดฃเต, เด…เดคเต เด‡เดจเตเดจเต เดตเดณเดฐเต† เดฎเต‹เดถเดฎเดพเดฏ เดฐเต‚เดชเดฎเดพเดฏเดฟ เด•เดฃเด•เตเด•เดพเด•เตเด•เดชเตเดชเต†เดŸเตเดจเตเดจเต. เดŽเดจเตเดจเดพเตฝ เดฌเดพเดทเต เดซเต‹เดดเตโ€Œเดธเต เดŸเดพเดฌเตเด•เตพ, เด•เต‚เดŸเดพเดคเต† nginx เด•เต‹เตบเดซเดฟเด—เดฑเดฟเตฝ เดธเดพเดงเดพเดฐเดฃ เดซเต‹เตผเดฎเดพเดฑเตเดฑเดฟเด‚เด—เต เด‰เดฃเตเดŸเดพเดฏเดฟเดฐเดฟเด•เตเด•เตเดจเตเดจเดคเตเด‚ เดจเดฒเตเดฒเดคเดพเดฃเต. เดšเตเดฐเตเด•เตเด•เดคเตเดคเดฟเตฝ, เด‡เดตเดฟเดŸเต† เดธเตโ€Œเดชเต†เดฏเตโ€Œเดธเตเดฎเดพเดฏเดฟ เดŸเดพเดฌเตเด•เตพ เดฎเดฟเด•เตโ€Œเดธเต เดšเต†เดฏเตเดฏเตเดจเตเดจเดคเต เดเดฑเตเดฑเดตเตเด‚ เดฎเต‹เดถเดฎเดพเดฏเดคเดฟเตฝ เดจเดฟเดจเตเดจเต เดฎเดฟเด•เดšเตเดš เดชเดฐเดฟเดนเดพเดฐเดฎเดพเดฏเดฟ เดคเต‹เดจเตเดจเตเดจเตเดจเต. เดŽเดจเตเดจเดฟเดฐเตเดจเตเดจเดพเดฒเตเด‚, เดŽเดฒเตเดฒเดพ เดŸเดพเดฌเตเด•เดณเตเด‚ 4 เดธเตโ€Œเดชเต†เดฏเตโ€Œเดธเตเด•เดณเดพเด•เตเด•เดฟ เดฎเดพเดฑเตเดฑเตเด•เดฏเตเด‚ EOF เด…เดธเดพเดงเตเดตเดพเด•เตเด•เตเด•เดฏเตเด‚ เดšเต†เดฏเตเดคเตเด•เตŠเดฃเตเดŸเต Habr "เด‡เดคเต เดจเดจเตเดจเดพเดฏเดฟ เดšเต†เดฏเตเดฏเตเดจเตเดจเต" เดŽเดจเตเดจเดคเดฟเดจเดพเตฝ, เดšเตเดตเดŸเต†เดฏเตเดณเตเดณ เดธเตโ€Œเดจเดฟเดชเตเดชเดฑเตเดฑเดฟเตฝ เดจเดฟเด™เตเด™เตพ เด‡เดคเต เด•เดพเดฃเดฟเดฒเตเดฒ. เด‡เดตเดฟเดŸเต† เด…เดคเต เดถเตเดฐเดฆเตเดงเต‡เดฏเดฎเดพเดฃเต.

เดฐเดฃเตเดŸเต เดคเดตเดฃ เดŽเดดเตเดจเตเดจเต‡เตฝเด•เตเด•เดพเดคเดฟเดฐเดฟเด•เตเด•เดพเตป, เดžเดพเตป เด‰เดŸเตป เดคเดจเตเดจเต† เดจเดฟเด™เตเด™เดณเต‹เดŸเต เดชเดฑเดฏเตเด‚ cat << 'EOF', เด…เดคเต เดชเดฟเดจเตเดจเต€เดŸเต เดจเต‡เดฐเดฟเดŸเตเด‚. เดจเดฟเด™เตเด™เตพ เดฒเดณเดฟเดคเดฎเดพเดฏเดฟ เดŽเดดเตเดคเตเด•เดฏเดพเดฃเต†เด™เตเด•เดฟเตฝ cat << EOF, เดนเต†เดฑเต†เดกเต‹เด•เตเด•เดฟเดจเตเดณเตเดณเดฟเตฝ เดธเตเดŸเตเดฐเดฟเด‚เด—เต เด‡เดจเตเดฑเตผเดชเต‹เดณเต‡เดฑเตเดฑเต เดšเต†เดฏเตเดฏเดชเตเดชเต†เดŸเตเดจเตเดจเต (เดตเต‡เดฐเดฟเดฏเดฌเดฟเดณเตเด•เตพ เดตเดฟเด•เดธเดฟเดชเตเดชเดฟเดšเตเดšเดฟเดฐเดฟเด•เตเด•เตเดจเตเดจเต ($foo), เด•เดฎเดพเตปเดกเต เด•เต‹เดณเตเด•เตพ ($(bar)) เดฎเตเดคเดฒเดพเดฏเดต), เด•เต‚เดŸเดพเดคเต† เดจเดฟเด™เตเด™เตพ เดกเต‹เด•เตเดฏเตเดฎเต†เดจเตเดฑเดฟเดจเตเดฑเต† เด…เดตเดธเดพเดจเด‚ เด’เดฑเตเดฑ เด‰เดฆเตเดงเดฐเดฃเดฟเด•เดณเดฟเตฝ เด‰เตพเดชเตเดชเต†เดŸเตเดคเตเดคเดฟเดฏเดพเตฝ, เด‡เดจเตเดฑเตผเดชเต‹เดณเต‡เดทเตป เดชเตเดฐเดตเตผเดคเตเดคเดจเดฐเดนเดฟเดคเดฎเดพเด•เตเด•เตเด•เดฏเตเด‚ เดšเดฟเดนเตเดจเด‚ $ เด…เดคเต‡เดชเดŸเดฟ เดชเตเดฐเดฆเตผเดถเดฟเดชเตเดชเดฟเด•เตเด•เตเดจเตเดจเต. เดฎเดฑเตเดฑเตŠเดฐเต เดธเตเด•เตเดฐเดฟเดชเตเดฑเตเดฑเดฟเดจเตเดณเตเดณเดฟเตฝ เด’เดฐเต เดธเตเด•เตเดฐเดฟเดชเตเดฑเตเดฑเต เดคเดฟเดฐเตเด•เดพเตป เดจเดฟเด™เตเด™เตพ เดšเต†เดฏเตเดฏเต‡เดฃเตเดŸเดคเต.

get-nginx-config() {
    local usage_msg="Usage: ${FUNCNAME[0]} service_name deployment_slot"
    local service=${1?$usage_msg}
    local slot=${2?$usage_msg}
    [ "$slot" == BLUE ] || [ "$slot" == GREEN ] || return 1

    local container_name=${service}_${slot}
    case $service in
        # Add specific nginx configs for your services here
        *) nginx-config-simple-service $container_name:8080 ;;
    esac
}

nginx-config-simple-service() {
    local usage_msg="Usage: ${FUNCNAME[0]} proxy_pass"
    local proxy_pass=${1?$usage_msg}

cat << EOF
server {
    listen 80;
    location / {
        proxy_pass http://$proxy_pass;
    }
}
EOF
}

เด‡เดคเดพเดฃเต เดฎเตเดดเตเดตเตป เดคเดฟเดฐเด•เตเด•เดฅเดฏเตเด‚. เด…เดคเตเด•เต†เดพเดฃเตเดŸเต เดˆ เดธเตเด•เตเดฐเดฟเดชเตเดฑเตเดฑเดฟเดจเตŠเดชเตเดชเด‚ เดธเด‚เด—เตเดฐเดนเด‚ wget เด…เดฒเตเดฒเต†เด™เตเด•เดฟเตฝ curl เดตเดดเดฟ เดกเต—เตบเดฒเต‹เดกเต เดšเต†เดฏเตเดฏเตเดจเตเดจเดคเดฟเดจเต.

เด’เดฐเต เดฑเดฟเดฎเต‹เดŸเตเดŸเต เดธเต†เตผเดตเดฑเดฟเตฝ เดชเดพเดฐเดพเดฎเต€เดฑเตเดฑเตผ เดšเต†เดฏเตเดค เดธเตเด•เตเดฐเดฟเดชเตเดฑเตเดฑเตเด•เตพ เดŽเด•เตเดธเดฟเด•เตเดฏเต‚เดŸเตเดŸเต เดšเต†เดฏเตเดฏเตเดจเตเดจเต

เดŸเดพเตผเด—เต†เดฑเตเดฑเต เดธเต†เตผเดตเดฑเดฟเตฝ เดฎเตเดŸเตเดŸเดพเดจเตเดณเตเดณ เดธเดฎเดฏเดฎเดพเดฃเดฟเดคเต. เด‡เดคเตเดคเดตเดฃ localhost เดคเดฟเด•เดšเตเดšเตเด‚ เด…เดจเตเดฏเต‹เดœเตเดฏเดฎเดพเดฃเต:

$ ssh-copy-id localhost
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
himura@localhost's password: 

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'localhost'"
and check to make sure that only the key(s) you wanted were added.

เดŸเดพเตผเด—เต†เดฑเตเดฑเต เดธเต†เตผเดตเดฑเดฟเดฒเต‡เด•เตเด•เต เดฎเตเตปเด•เต‚เดŸเตเดŸเดฟ เดจเดฟเตผเดฎเตเดฎเดฟเดšเตเดš เดšเดฟเดคเตเดฐเด‚ เดกเต—เตบเดฒเต‹เดกเต เดšเต†เดฏเตเดฏเตเด•เดฏเตเด‚ เดธเต‡เดตเดจ เด•เดฃเตเดŸเต†เดฏเตโ€Œเดจเตผ เดคเดŸเดธเตเดธเดฎเดฟเดฒเตเดฒเดพเดคเต† เดฎเดพเดฑเตเดฑเดฟเดธเตเดฅเดพเดชเดฟเด•เตเด•เตเด•เดฏเตเด‚ เดšเต†เดฏเตเดฏเตเดจเตเดจ เด’เดฐเต เดตเดฟเดจเตเดฏเดพเดธ เดธเตโ€Œเด•เตเดฐเดฟเดชเตเดฑเตเดฑเต เดžเด™เตเด™เตพ เดŽเดดเตเดคเดฟเดฏเดฟเดŸเตเดŸเตเดฃเตเดŸเต, เดŽเดจเตเดจเดพเตฝ เด’เดฐเต เดฑเดฟเดฎเต‹เดŸเตเดŸเต เดฎเต†เดทเต€เดจเดฟเตฝ เด…เดคเต เดŽเด™เตเด™เดจเต† เดŽเด•เตโ€Œเดธเดฟเด•เตเดฏเต‚เดŸเตเดŸเต เดšเต†เดฏเตเดฏเดพเด‚? เดธเตโ€Œเด•เตเดฐเดฟเดชเตเดฑเตเดฑเดฟเดจเต เด†เตผเด—เตเดฏเตเดฎเต†เดจเตเดฑเตเด•เดณเตเดฃเตเดŸเต, เด•เดพเดฐเดฃเด‚ เด‡เดคเต เดธเดพเตผเดตเดคเตเดฐเดฟเด•เดตเตเด‚ เด’เดฐเต เดฑเดฟเดตเต‡เดดเตโ€Œเดธเต เดชเตเดฐเต‹เด•เตโ€Œเดธเดฟเด•เตเด•เต เด•เต€เดดเดฟเตฝ เดจเดฟเดฐเดตเดงเดฟ เดธเต‡เดตเดจเด™เตเด™เตพ เด’เดฐเต‡เดธเดฎเดฏเด‚ เดตเดฟเดจเตเดฏเดธเดฟเด•เตเด•เดพเตป เด•เดดเดฟเดฏเตเด‚ (เดเดคเต url เดเดคเดพเดฃเต†เดจเตเดจเต เดจเดฟเตผเดฃเตเดฃเดฏเดฟเด•เตเด•เดพเตป เดจเดฟเด™เตเด™เตพเด•เตเด•เต nginx เด•เต‹เตบเดซเดฟเด—เดฑเต‡เดทเดจเตเด•เตพ เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เดพเด‚). เดธเตโ€Œเด•เตเดฐเดฟเดชเตเดฑเตเดฑเต เดธเต†เตผเดตเดฑเดฟเตฝ เดธเด‚เดญเดฐเดฟเด•เตเด•เดพเตป เด•เดดเดฟเดฏเดฟเดฒเตเดฒ, เด•เดพเดฐเดฃเด‚ เดˆ เดธเดพเดนเดšเดฐเตเดฏเดคเตเดคเดฟเตฝ เดžเด™เตเด™เตพเด•เตเด•เต เด…เดคเต เดธเตเดตเดฏเดฎเต‡เดต เด…เดชเตโ€Œเดกเต‡เดฑเตเดฑเต เดšเต†เดฏเตเดฏเดพเตป เด•เดดเดฟเดฏเดฟเดฒเตเดฒ (เดฌเด—เต เดชเดฐเดฟเดนเดฐเดฟเด•เตเด•เตเดจเตเดจเดคเดฟเดจเตเด‚ เดชเตเดคเดฟเดฏ เดธเต‡เดตเดจเด™เตเด™เตพ เดšเต‡เตผเด•เตเด•เตเดจเตเดจเดคเดฟเดจเตเด‚ เดตเต‡เดฃเตเดŸเดฟ), เดชเตŠเดคเตเดตเต‡, เดธเตเดฑเตเดฑเต‡เดฑเตเดฑเต = เดคเดฟเดจเตเดฎ.

เดชเดฐเดฟเดนเดพเดฐเด‚ 1: เดธเตเด•เตเดฐเดฟเดชเตเดฑเตเดฑเต เด‡เดชเตเดชเต‹เดดเตเด‚ เดธเต†เตผเดตเดฑเดฟเตฝ เดธเด‚เดญเดฐเดฟเด•เตเด•เตเด•, เดŽเดจเตเดจเดพเตฝ เด“เดฐเต‹ เดคเดตเดฃเดฏเตเด‚ เด…เดคเต เดชเด•เตผเดคเตเดคเตเด• scp. เดคเตเดŸเตผเดจเตเดจเต เดตเดดเดฟ เดฌเดจเตเดงเดฟเดชเตเดชเดฟเด•เตเด•เตเด• ssh เด†เดตเดถเตเดฏเดฎเดพเดฏ เด†เตผเด—เตเดฏเตเดฎเต†เดจเตเดฑเตเด•เตพ เด‰เดชเดฏเต‹เด—เดฟเดšเตเดšเต เดธเตเด•เตเดฐเดฟเดชเตเดฑเตเดฑเต เดŽเด•เตเดธเดฟเด•เตเดฏเต‚เดŸเตเดŸเต เดšเต†เดฏเตเดฏเตเด•.

เดชเดฐเดฟเด—เดฃเดจ:

  • เด’เดจเตเดจเดฟเดจเต เดชเด•เดฐเด‚ เดฐเดฃเตเดŸเต เดชเตเดฐเดตเตƒเดคเตเดคเดฟเด•เตพ
  • เดจเดฟเด™เตเด™เตพ เดชเด•เตผเดคเตเดคเตเดจเตเดจ เด’เดฐเต เดธเตเดฅเดฒเดฎเดฟเดฒเตเดฒเดพเดฏเดฟเดฐเดฟเด•เตเด•เดพเด‚, เด…เดฒเตเดฒเต†เด™เตเด•เดฟเตฝ เด…เดคเดฟเดฒเต‡เด•เตเด•เต เด†เด•เตเดธเดธเต เด‡เดฒเตเดฒเดพเดฏเดฟเดฐเดฟเด•เตเด•เดพเด‚, เด…เดฒเตเดฒเต†เด™เตเด•เดฟเตฝ เดชเด•เดฐเด‚ เดตเดฏเตเด•เตเด•เตเดจเตเดจ เดธเดฎเดฏเดคเตเดคเต เดธเตเด•เตเดฐเดฟเดชเตเดฑเตเดฑเต เดŽเด•เตเดธเดฟเด•เตเดฏเต‚เดŸเตเดŸเต เดšเต†เดฏเตเดคเต‡เด•เตเด•เดพเด‚.
  • เดธเตเดตเดฏเด‚ เดตเตƒเดคเตเดคเดฟเดฏเดพเด•เตเด•เตเดจเตเดจเดคเต เด‰เดšเดฟเดคเดฎเดพเดฃเต (เดธเตเด•เตเดฐเดฟเดชเตเดฑเตเดฑเต เด‡เดฒเตเดฒเดพเดคเดพเด•เตเด•เตเด•).
  • เด‡เดคเดฟเดจเด•เด‚ เดฎเต‚เดจเตเดจเต เดชเตเดฐเดตเตผเดคเตเดคเดจเด™เตเด™เตพ.

เดชเดฐเดฟเดนเดพเดฐเด‚ 2:

  • เดธเตเด•เตเดฐเดฟเดชเตเดฑเตเดฑเดฟเตฝ เดซเด‚เด—เตเดทเตป เดจเดฟเตผเดตเดšเดจเด™เตเด™เตพ เดฎเดพเดคเตเดฐเด‚ เดธเต‚เด•เตเดทเดฟเด•เตเด•เตเด•, เด’เดจเตเดจเตเด‚ เดชเตเดฐเดตเตผเดคเตเดคเดฟเดชเตเดชเดฟเด•เตเด•เดฐเตเดคเต
  • เดธเดนเดพเดฏเดคเตเดคเต‹เดŸเต† sed เด…เดตเดธเดพเดจเด‚ เด’เดฐเต เดซเด‚เด—เตโ€Œเดทเตป เด•เต‹เตพ เดšเต‡เตผเด•เตเด•เตเด•
  • เดชเตˆเดชเตเดชเต เดตเดดเดฟ เด…เดคเต†เดฒเตเดฒเดพเด‚ เดจเต‡เดฐเดฟเดŸเตเดŸเต shh เดฒเต‡เด•เตเด•เต เด…เดฏเดฏเตเด•เตเด•เตเด• (|)

เดชเตเดฐเต‹เดธเต:

  • เดถเดฐเดฟเด•เตเด•เตเด‚ เดฐเดพเดœเตเดฏเดฐเดนเดฟเดคเตป
  • เดฌเต‹เดฏเดฟเดฒเตผ เดชเตเดฒเต‡เดฑเตเดฑเต เดŽเดจเตเดฑเดฟเดฑเตเดฑเดฟเด•เดณเตŠเดจเตเดจเตเดฎเดฟเดฒเตเดฒ
  • เดคเดฃเตเดชเตเดชเต เด…เดจเตเดญเดตเดชเตเดชเต†เดŸเตเดจเตเดจเต

เด…เตปเดธเดฟเดฌเดฟเตพ เด‡เดฒเตเดฒเดพเดคเต† เดคเดจเตเดจเต† เดšเต†เดฏเตเดฏเดพเด‚. เด…เดคเต†, เดŽเดฒเตเดฒเดพเด‚ เด‡เดคเดฟเดจเด•เด‚ เด•เดฃเตเดŸเตเดชเดฟเดŸเดฟเดšเตเดšเดคเดพเดฃเต. เด…เดคเต†, เด’เดฐเต เดธเตˆเด•เตเด•เดฟเตพ. เดฌเตˆเด•เตเด•เต เดŽเดคเตเดฐ เดฒเดณเดฟเดคเดตเตเด‚ เดฎเดจเต‹เดนเดฐเดตเตเด‚ เดฎเดฟเดจเดฟเดฎเดฒเดฟเดธเตเดฑเตเดฑเดฟเด•เต เด†เดฃเต†เดจเตเดจเตเด‚ เดจเต‹เด•เตเด•เต‚:

$ cat << 'EOF' > deploy.sh
#!/bin/bash

usage_msg="Usage: $0 ssh_address local_image_tag"
ssh_address=${1?$usage_msg}
image_name=${2?$usage_msg}

echo "Connecting to '$ssh_address' via ssh to seamlessly deploy '$image_name'..."
( sed "$a deploy $image_name" | ssh -T $ssh_address ) << 'END_OF_SCRIPT'
deploy() {
    echo "Yay! The '${FUNCNAME[0]}' function is executing on '$(hostname)' with argument '$1'"
}
END_OF_SCRIPT
EOF

$ chmod +x deploy.sh

$ ./deploy.sh localhost magic-porridge-pot
Connecting to localhost...
Yay! The 'deploy' function is executing on 'hut' with argument 'magic-porridge-pot'

เดŽเดจเตเดจเดฟเดฐเตเดจเตเดจเดพเดฒเตเด‚, เดฑเดฟเดฎเต‹เดŸเตเดŸเต เดนเต‹เดธเตเดฑเตเดฑเดฟเดจเต เดฎเดคเดฟเดฏเดพเดฏ เดฌเดพเดทเต เด‰เดฃเตเดŸเต†เดจเตเดจเต เดžเด™เตเด™เตพเด•เตเด•เต เด‰เดฑเดชเตเดชเดฟเด•เตเด•เดพเตป เด•เดดเดฟเดฏเดฟเดฒเตเดฒ, เด…เดคเดฟเดจเดพเตฝ เดžเด™เตเด™เตพ เดคเตเดŸเด•เตเด•เดคเตเดคเดฟเตฝ เด’เดฐเต เดšเต†เดฑเดฟเดฏ เดšเต†เด•เตเด•เต เดšเต‡เตผเด•เตเด•เตเด‚ (เด‡เดคเต เดชเด•เดฐเด‚ เดทเต†เตฝเดฌเดพเด‚เด—เต):

if [ "$SHELL" != "/bin/bash" ]
then
    echo "The '$SHELL' shell is not supported by 'deploy.sh'. Set a '/bin/bash' shell for '$USER@$HOSTNAME'."
    exit 1
fi

เด‡เดชเตเดชเต‹เตพ เด…เดคเต เดฏเดฅเดพเตผเดคเตเดฅเดฎเดพเดฃเต:

$ docker exec reverse-proxy rm /etc/nginx/conf.d/default.conf

$ wget -qO deploy.sh https://git.io/JUURc

$ chmod +x deploy.sh

$ ./deploy.sh localhost uptimer
Sending gzipped image 'uptimer' to 'localhost' via ssh...
Loaded image: uptimer:latest
Connecting to 'localhost' via ssh to seamlessly deploy 'uptimer'...
Deploying 'uptimer_GREEN' in place of 'uptimer_BLUE'...
06f5bc70e9c4f930e7b1f826ae2ca2f536023cc01e82c2b97b2c84d68048b18a
Container started. Checking health...
Requesting 'http://uptimer_GREEN:8080/' within the 'web-gateway' docker network:
  HTTP/1.0 503 Service Unavailable
wget: server returned error: HTTP/1.0 503 Service Unavailable
New 'uptimer_GREEN' service is not ready yet. Waiting (1)...
Requesting 'http://uptimer_GREEN:8080/' within the 'web-gateway' docker network:
  HTTP/1.0 503 Service Unavailable
wget: server returned error: HTTP/1.0 503 Service Unavailable
New 'uptimer_GREEN' service is not ready yet. Waiting (2)...
Requesting 'http://uptimer_GREEN:8080/' within the 'web-gateway' docker network:
  HTTP/1.0 200 OK
  Server: BaseHTTP/0.6 Python/3.8.3
  Date: Sat, 22 Aug 2020 20:15:50 GMT
  Content-Type: text/html

New 'uptimer_GREEN' service seems OK. Switching heads...
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
2020/08/22 20:15:54 [notice] 97#97: signal process started
The 'uptimer_GREEN' service is live!
Killing 'uptimer_BLUE'...
uptimer_BLUE
Total reclaimed space: 0B
Deployment successful!

เด‡เดชเตเดชเต‹เตพ เดจเดฟเด™เตเด™เตพเด•เตเด•เต เดคเตเดฑเด•เตเด•เดพเด‚ http://localhost/ เดฌเตเดฐเต—เดธเดฑเดฟเตฝ, เดตเดฟเดจเตเดฏเดพเดธเด‚ เดตเต€เดฃเตเดŸเตเด‚ เดชเตเดฐเดตเตผเดคเตเดคเดฟเดชเตเดชเดฟเด•เตเด•เตเด•, เดฒเต‡เด”เดŸเตเดŸเต เดธเดฎเดฏเดคเตเดคเต เดธเดฟเดกเดฟ เด…เดจเตเดธเดฐเดฟเดšเตเดšเต เดชเต‡เดœเต เด…เดชเตเดกเต‡เดฑเตเดฑเต เดšเต†เดฏเตเดคเตเด•เตŠเดฃเตเดŸเต เด…เดคเต เดคเดŸเดธเตเดธเดฎเดฟเดฒเตเดฒเดพเดคเต† เดชเตเดฐเดตเตผเดคเตเดคเดฟเด•เตเด•เตเดจเตเดจเตเดตเต†เดจเตเดจเต เด‰เดฑเดชเตเดชเดพเด•เตเด•เตเด•.

เดœเต‹เดฒเดฟ เด•เดดเดฟเดžเตเดžเต เดตเตƒเดคเตเดคเดฟเดฏเดพเด•เตเด•เดพเตป เดฎเดฑเด•เตเด•เดฐเตเดคเต :3

$ docker rm -f uptimer_GREEN reverse-proxy 
uptimer_GREEN
reverse-proxy

$ docker network rm web-gateway 
web-gateway

$ cd ..

$ rm -r blue-green-deployment

เด…เดตเดฒเด‚เดฌเด‚: www.habr.com