เบ™เบณเปƒเบŠเป‰เบชเบตเบŸเป‰เบฒ-เบชเบตเบ‚เบฝเบงเปƒเบ™เบ„เปˆเบฒเบˆเป‰เบฒเบ‡เบ‚เบฑเป‰เบ™เบ•เปˆเบณ

เปƒเบ™เบšเบปเบ”เบ„เบงเบฒเบกเบ™เบตเป‰เบžเบงเบเป€เบฎเบปเบฒเปƒเบŠเป‰ bash, ssh, docker ะธ nginx เบžเบงเบโ€‹เป€เบฎเบปเบฒโ€‹เบˆเบฐโ€‹เบˆเบฑเบ”โ€‹เบ•เบฑเป‰เบ‡โ€‹เบฎเบนเบšโ€‹เปเบšเบš seamless เบ‚เบญเบ‡โ€‹เบ„เปเบฒโ€‹เบฎเป‰เบญเบ‡โ€‹เบชเบฐโ€‹เบซเบกเบฑเบโ€‹เป€เบงเบฑเบšโ€‹เป„เบŠโ€‹เบ•โ€‹เปŒโ€‹. เบเบฒเบ™โ€‹เบ™เปเบฒโ€‹เปƒเบŠเป‰โ€‹เบชเบตโ€‹เบŸเป‰เบฒโ€‹, เบชเบตโ€‹เบ‚เบฝเบงโ€‹ เปเบกเปˆเบ™เป€เบ•เบฑเบเบ™เบดเบเบ—เบตเปˆเบŠเปˆเบงเบเปƒเบซเป‰เบ—เปˆเบฒเบ™เบชเบฒเบกเบฒเบ”เบ›เบฑเบšเบ›เบธเบ‡เปเบญเบฑเบšเบžเบฅเบดเป€เบ„เบŠเบฑเบ™เป„เบ”เป‰เบ—เบฑเบ™เบ—เบตเป‚เบ”เบเบšเปเปˆเบ•เป‰เบญเบ‡เบ›เบฐเบ•เบดเป€เบชเบ”เบ„เปเบฒเบฎเป‰เบญเบ‡เบ‚เปเบ”เบฝเบง. เบกเบฑเบ™เปเบกเปˆเบ™เปœเบถเปˆเบ‡เปƒเบ™เบเบธเบ”เบ—เบฐเบชเบฒเบ”เบเบฒเบ™เบ™เบณเปƒเบŠเป‰เบชเบนเบ™เบเบฒเบ™เบขเบธเบ”เป€เบฎเบฑเบ”เบงเบฝเบ เปเบฅเบฐ เป€เปเบฒเบฐเบชเบปเบกเบ—เบตเปˆเบชเบธเบ”เบชเบณเบฅเบฑเบšเปเบญเบฑเบšเบžเบฅเบดเป€เบ„เบŠเบฑเบ™เบ—เบตเปˆเบกเบตเบ•เบปเบงเบขเปˆเบฒเบ‡เปœเบถเปˆเบ‡, เปเบ•เปˆเบ„เบงเบฒเบกเบชเบฒเบกเบฒเบ”เปƒเบ™เบเบฒเบ™เป‚เบซเบผเบ”เบ•เบปเบงเบขเปˆเบฒเบ‡เบ—เบตเบชเบญเบ‡, เบžเป‰เบญเบกเบ—เบตเปˆเบˆเบฐเปเบฅเปˆเบ™เบขเบนเปˆเปƒเบเป‰เป†.

เปƒเบซเป‰เป€เบงเบปเป‰เบฒเบงเปˆเบฒเบ—เปˆเบฒเบ™เบกเบตเบ„เปเบฒเบฎเป‰เบญเบ‡เบชเบฐเบซเบกเบฑเบเป€เบงเบฑเบšเป„เบŠเบ•เปŒเบ—เบตเปˆเบฅเบนเบเบ„เป‰เบฒเบˆเปเบฒเบ™เบงเบ™เบซเบผเบฒเบเบเปเบฒเบฅเบฑเบ‡เป€เบฎเบฑเบ”เบงเบฝเบเบขเปˆเบฒเบ‡เบซเป‰เบฒเบงเบซเบฑเบ™, เปเบฅเบฐเบšเปเปˆเบกเบตเบ—เบฒเบ‡เปเบ—เป‰เป†เบ—เบตเปˆเบกเบฑเบ™เบˆเบฐเบ™เบญเบ™เบขเบนเปˆเบชเบญเบ‡เบชเบฒเบกเบงเบดเบ™เบฒเบ—เบต. เปเบฅเบฐเบ—เปˆเบฒเบ™เบเปเปˆเบˆเปเบฒเป€เบ›เบฑเบ™เบ•เป‰เบญเบ‡เป„เบ”เป‰เป€เบ›เบตเบ”เบ•เบปเบงเบเบฒเบ™เบ›เบฑเบšเบ›เบธเบ‡เบซเป‰เบญเบ‡เบชเบฐเบซเบกเบธเบ”, เบเบฒเบ™เปเบเป‰เป„เบ‚เบ‚เปเป‰เบšเบปเบเบžเปˆเบญเบ‡, เบซเบผเบทเบ„เบธเบ™เบชเบปเบกเบšเบฑเบ”เป€เบขเบฑเบ™เปƒเบซเบกเปˆ. เปƒเบ™เบชเบฐเบ–เบฒเบ™เบฐเบเบฒเบ™เบ›เบปเบเบเบฐเบ•เบด, เบ—เปˆเบฒเบ™เบˆเบฐเบ•เป‰เบญเบ‡เบขเบธเบ”เบ„เปเบฒเบฎเป‰เบญเบ‡เบชเบฐเบซเบกเบฑเบ, เบ—เบปเบ”เปเบ—เบ™เบกเบฑเบ™เปเบฅเบฐเป€เบฅเบตเปˆเบกเบ•เบปเป‰เบ™เบญเบตเบเป€เบ—เบทเปˆเบญเบซเบ™เบถเปˆเบ‡. เปƒเบ™เบเปเบฅเบฐเบ™เบตเบ‚เบญเบ‡ docker, เบ—เปเบฒเบญเบดเบ”เบ—เปˆเบฒเบ™เบชเบฒเบกเบฒเบ”เบ›เปˆเบฝเบ™เบกเบฑเบ™, เบซเบผเบฑเบ‡เบˆเบฒเบเบ™เบฑเป‰เบ™ restart เบกเบฑเบ™, เปเบ•เปˆเบกเบฑเบ™เบˆเบฐเบเบฑเบ‡เบกเบตเป„เบฅเบเบฐเป€เบงเบฅเบฒเบ—เบตเปˆเบ„เปเบฒเบฎเป‰เบญเบ‡เบ‚เปเบเบฑเบšเบ„เปเบฒเบฎเป‰เบญเบ‡เบชเบฐเบซเบกเบฑเบเบˆเบฐเบšเปเปˆเบ–เบทเบเบ”เปเบฒเป€เบ™เบตเบ™เบเบฒเบ™, เป€เบžเบฒเบฐเบงเปˆเบฒเบ›เบปเบเบเบฐเบ•เบดเปเบฅเป‰เบงเบ„เปเบฒเบฎเป‰เบญเบ‡เบชเบฐเบซเบกเบฑเบเปƒเบŠเป‰เป€เบงเบฅเบฒเบšเบฒเบ‡เป€เบงเบฅเบฒเปƒเบ™เบเบฒเบ™เป‚เบซเบผเบ”เปƒเบ™เป€เบšเบทเป‰เบญเบ‡เบ•เบปเป‰เบ™. เบˆเบฐเป€เบ›เบฑเบ™เปเบ™เบงเปƒเบ”เบ–เป‰เบฒเบกเบฑเบ™เป€เบฅเบตเปˆเบกเบ•เบปเป‰เบ™, เปเบ•เปˆเบเบฒเบเป€เบ›เบฑเบ™เบšเปเปˆเบชเบฒเบกเบฒเบ”เบ›เบฐเบ•เบดเบšเบฑเบ”เป„เบ”เป‰? เบ™เบตเป‰โ€‹เปเบกเปˆเบ™โ€‹เบšเบฑเบ™โ€‹เบซเบฒโ€‹, เบ‚เปโ€‹เปƒเบซเป‰โ€‹เปเบเป‰โ€‹เป„เบ‚โ€‹เบกเบฑเบ™โ€‹เบ”เป‰เบงเบโ€‹เบงเบดโ€‹เบ—เบตโ€‹เบเบฒเบ™โ€‹เบซเบ™เป‰เบญเบโ€‹เปเบฅเบฐ elegantly เป€เบ—เบปเปˆเบฒโ€‹เบ—เบตเปˆโ€‹เป€เบ›เบฑเบ™โ€‹เป„เบ›โ€‹เป„เบ”เป‰โ€‹.

เบเบฒเบ™เบ›เบฐเบ•เบดเป€เบชเบ”: เบšเบปเบ”เบ„เบงเบฒเบกเบชเปˆเบงเบ™เปƒเบซเบเปˆเบ–เบทเบเบ™เปเบฒเบชเบฐเป€เบซเบ™เบตเปƒเบ™เบฎเบนเบšเปเบšเบšเบ—เบปเบ”เบฅเบญเบ‡ - เปƒเบ™เบฎเบนเบšเปเบšเบšเบ‚เบญเบ‡เบเบฒเบ™เบšเบฑเบ™เบ—เบถเบเบเบญเบ‡เบ›เบฐเบŠเบธเบก console. เบซเบงเบฑเบ‡เบงเปˆเบฒเบ™เบตเป‰เบˆเบฐเบšเปเปˆเบเบฒเบเป€เบเบตเบ™เป„เบ›เบ—เบตเปˆเบˆเบฐเป€เบ‚เบปเป‰เบฒเปƒเบˆเปเบฅเบฐเบฅเบฐเบซเบฑเบ”เบˆเบฐเบšเบฑเบ™เบ—เบถเบเบ•เบปเบงเป€เบญเบ‡เบžเบฝเบ‡เบžเป. เบชเปเบฒเบฅเบฑเบšเบšเบฑเบ™เบเบฒเบเบฒเบ”, เบˆเบดเบ™เบ•เบฐเบ™เบฒเบเบฒเบ™เบงเปˆเบฒเบชเบดเปˆเบ‡เป€เบซเบผเบปเปˆเบฒเบ™เบตเป‰เปเบกเปˆเบ™เบšเปเปˆเบžเบฝเบ‡เปเบ•เปˆเบฅเบฐเบซเบฑเบ”, เปเบ•เปˆเป€เบˆเป‰เบเบˆเบฒเบ teletype "เบ—เบฒเบ”เป€เบซเบผเบฑเบ".

เบ™เบณเปƒเบŠเป‰เบชเบตเบŸเป‰เบฒ-เบชเบตเบ‚เบฝเบงเปƒเบ™เบ„เปˆเบฒเบˆเป‰เบฒเบ‡เบ‚เบฑเป‰เบ™เบ•เปˆเบณ

เป€เบ•เบฑเบเบ™เบดเบเบ—เบตเปˆเบซเบ™เป‰เบฒเบชเบปเบ™เปƒเบˆเบ—เบตเปˆเบกเบตเบ„เบงเบฒเบกเบซเบเบธเป‰เบ‡เบเบฒเบเปƒเบ™ Google เบžเบฝเบ‡เปเบ•เปˆเบญเปˆเบฒเบ™เบฅเบฐเบซเบฑเบ”เป„เบ”เป‰เบ–เบทเบเบญเบฐเบ—เบดเบšเบฒเบเปƒเบ™เบ•เบญเบ™เบ•เบปเป‰เบ™เบ‚เบญเบ‡เปเบ•เปˆเบฅเบฐเบžเบฒเบ. เบ–เป‰เบฒเบชเบดเปˆเบ‡เบญเบทเปˆเบ™เปƒเบ”เบ—เบตเปˆเบšเปเปˆเบŠเบฑเบ”เป€เบˆเบ™, google เบกเบฑเบ™เปเบฅเบฐเบเบงเบ”เป€เบšเบดเปˆเบ‡เบกเบฑเบ™. เบญเบฐโ€‹เบ—เบดโ€‹เบšเบฒเบ (เป‚เบŠเบเบ”เบต, เบกเบฑเบ™เป€เบฎเบฑเบ”เบงเบฝเบเบญเบตเบเป€เบ—เบทเปˆเบญเบซเบ™เบถเปˆเบ‡, เป€เบ™เบทเปˆเบญเบ‡เบˆเบฒเบ unblocking เบ‚เบญเบ‡ telegram). เบ–เป‰เบฒเบ—เปˆเบฒเบ™เบšเปเปˆเบชเบฒเบกเบฒเบ” Google เบซเบเบฑเบ‡เป„เบ”เป‰, เบ–เบฒเบกเปƒเบ™เบ„เปเบฒเป€เบซเบฑเบ™. เบ‚เป‰เบญเบเบˆเบฐเบเบดเบ™เบ”เบตเบ—เบตเปˆเบˆเบฐเป€เบžเบตเปˆเบกเปƒเบชเปˆเบžเบฒเบเบชเปˆเบงเบ™เบ—เบตเปˆเบชเบญเบ”เบ„เป‰เบญเบ‡เบเบฑเบ™ "เป€เบ•เบฑเบเบ™เบดเบเบ—เบตเปˆเบซเบ™เป‰เบฒเบชเบปเบ™เปƒเบˆ".

เปƒเบซเป‰เป€เบฅเบตเปˆเบกเบ•เบปเป‰เบ™.

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

เบเบฒเบ™เบšเปเบฅเบดเบเบฒเบ™

เปƒเบซเป‰เป€เบฎเบฑเบ”เบเบฒเบ™เบšเปเบฅเบดเบเบฒเบ™เบ—เบปเบ”เบฅเบญเบ‡เปเบฅเบฐเบงเบฒเบ‡เป„เบงเป‰เปƒเบ™เบ–เบฑเบ‡.

เป€เบ•เบฑเบเบ™เบดเบเบ—เบตเปˆเบซเบ™เป‰เบฒเบชเบปเบ™เปƒเบˆ

  • cat << EOF > file-name (เบ—เบตเปˆเบ™เบตเป‰เป€เบญเบเบฐเบชเบฒเบ™ + เบเบฒเบ™เบ›เปˆเบฝเบ™เป€เบชเบฑเป‰เบ™เบ—เบฒเบ‡ I/O) เปเบกเปˆเบ™เบงเบดเบ—เบตเบเบฒเบ™เบชเป‰เบฒเบ‡เป„เบŸเบฅเปŒเบซเบผเบฒเบเปเบ–เบงเบ”เป‰เบงเบเบ„เปเบฒเบชเบฑเปˆเบ‡เบ”เบฝเบง. เบ—เบธเบเบชเบดเปˆเบ‡เบ—เบธเบเบขเปˆเบฒเบ‡ bash เบญเปˆเบฒเบ™เบˆเบฒเบ /dev/stdin เบซเบผเบฑเบ‡เบˆเบฒเบเป€เบชเบฑเป‰เบ™เบ™เบตเป‰เปเบฅเบฐเบเปˆเบญเบ™เป€เบชเบฑเป‰เบ™ EOF เบˆเบฐเบ–เบทเบเบšเบฑเบ™เบ—เบถเบเป„เบงเป‰เปƒเบ™ file-name.
  • wget -qO- URL (เบญเบฐโ€‹เบ—เบดโ€‹เบšเบฒเบ) โ€” เบชเบปเปˆเบ‡เบญเบญเบเป€เบญเบเบฐเบชเบฒเบ™เบ—เบตเปˆเป„เบ”เป‰เบฎเบฑเบšเบœเปˆเบฒเบ™ HTTP เป„เบ› /dev/stdout (เบญเบฐเบ™เบฒเบฅเบฑเบญเบ curl URL).

เบžเบดเบกโ€‹เบญเบญเบโ€‹เบกเบฒ

เบ‚เป‰เบฒเบžเบฐเป€เบˆเบปเป‰เบฒเป‚เบ”เบเบชเบฐเป€เบžเบฒเบฐเบ—เปเบฒเบฅเบฒเบ snippet เป€เบžเบทเปˆเบญเป€เบ›เบตเบ”เปƒเบŠเป‰เบเบฒเบ™เป€เบ™เบฑเป‰เบ™เบชเปเบฒเบฅเบฑเบš Python. เปƒเบ™โ€‹เบ—เบตเปˆโ€‹เบชเบธเบ”โ€‹เบˆเบฐโ€‹เบกเบตโ€‹เบญเบตเบโ€‹เบ›เบฐโ€‹เบเบฒเบ™โ€‹เบซเบ™เบถเปˆเบ‡โ€‹เป€เบŠเบฑเปˆเบ™โ€‹เบ™เบตเป‰โ€‹. เบžเบดเบˆเบฒเบฅเบฐเบ™เบฒเบงเปˆเบฒเบขเบนเปˆเปƒเบ™เบšเปˆเบญเบ™เป€เบซเบผเบปเปˆเบฒเบ™เบตเป‰, เบเบฐเบ”เบฒเบ”เบ–เบทเบเบ•เบฑเบ”เป€เบžเบทเปˆเบญเบชเบปเปˆเบ‡เป„เบ›เบซเบฒเบžเบฐเปเบ™เบเบเบฒเบ™เป€เบ™เบฑเป‰เบ™ (เบšเปˆเบญเบ™เบ—เบตเปˆเบฅเบฐเบซเบฑเบ”เปเบกเปˆเบ™เบชเบตเบ”เป‰เบงเบเบกเบทเบ—เบตเปˆเบกเบตเป€เบ„เบทเปˆเบญเบ‡เป€เบ™เบฑเป‰เบ™), เปเบฅเบฐเบซเบผเบฑเบ‡เบˆเบฒเบเบ™เบฑเป‰เบ™เบ•เปˆเบญเบ™เป€เบซเบผเบปเปˆเบฒเบ™เบตเป‰เบ–เบทเบเบเบฒเบงเบ„เบทเบ™.

$ 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

Reverse proxy

เป€เบžเบทเปˆเบญเปƒเบซเป‰เบ„เปเบฒเบฎเป‰เบญเบ‡เบชเบฐเบซเบกเบฑเบเบ‚เบญเบ‡เบžเบงเบเป€เบฎเบปเบฒเบชเบฒเบกเบฒเบ”เบ›เปˆเบฝเบ™เปเบ›เบ‡เป„เบ”เป‰เป‚เบ”เบเบšเปเปˆเป„เบ”เป‰เบชเบฑเบ‡เป€เบเบ”เป€เบซเบฑเบ™, เบกเบฑเบ™เบˆเปเบฒเป€เบ›เบฑเบ™เบ•เป‰เบญเบ‡เบกเบตเบšเบฒเบ‡เบซเบ™เปˆเบงเบเบ‡เบฒเบ™เบญเบทเปˆเบ™เบขเบนเปˆเบ—เบฒเบ‡เบซเบ™เป‰เบฒเบ—เบตเปˆเบˆเบฐเป€เบŠเบทเปˆเบญเบ‡เบเบฒเบ™เบ—เบปเบ”เปเบ—เบ™เบ‚เบญเบ‡เบกเบฑเบ™. เบกเบฑเบ™เบญเบฒเบ”เบˆเบฐเป€เบ›เบฑเบ™เป€เบ„เบทเปˆเบญเบ‡เปเบกเปˆเบ‚เปˆเบฒเบเป€เบงเบฑเบšเป„เบŠเบ•เปŒ nginx ะฒ เป‚เปเบ”เบžเบฃเบฑเบญเบเบŠเบตเบ›เบตเป‰เบ™เบเบฑเบšเบเบฑเบ™. เบ•เบปเบงเปเบ—เบ™ reverse เปเบกเปˆเบ™เบชเป‰เบฒเบ‡เบ•เบฑเป‰เบ‡เบ‚เบถเป‰เบ™เบฅเบฐเบซเบงเปˆเบฒเบ‡เบฅเบนเบเบ„เป‰เบฒเปเบฅเบฐเบ„เปเบฒเบฎเป‰เบญเบ‡เบชเบฐเบซเบกเบฑเบ. เบกเบฑเบ™เบเบญเบกเบฎเบฑเบšเบ„เปเบฒเบฎเป‰เบญเบ‡เบ‚เปเบˆเบฒเบเบฅเบนเบเบ„เป‰เบฒเปเบฅเบฐเบชเบปเปˆเบ‡เบ•เปเปˆเป„เบ›เบซเบฒเบ„เปเบฒเบฎเป‰เบญเบ‡เบชเบฐเบซเบกเบฑเบเปเบฅเบฐเบชเบปเปˆเบ‡เบ•เปเปˆเบ„เปเบฒเบ•เบญเบšเบ‚เบญเบ‡เปเบญเบฑเบšเบžเบฅเบดเป€เบ„เบŠเบฑเบ™เปƒเบซเป‰เบเบฑเบšเบฅเบนเบเบ„เป‰เบฒ.

เปเบญเบฑเบšเบžเบฅเบดเป€เบ„เบŠเบฑเบ™เปเบฅเบฐเบ•เบปเบงเปเบ—เบ™ reverse เบชเบฒเบกเบฒเบ”เป€เบŠเบทเปˆเบญเบกเบ•เปเปˆเบžเบฒเบเปƒเบ™ docker เป‚เบ”เบเปƒเบŠเป‰ เป€เบ„เบทเบญเบ‚เปˆเบฒเบ docker. เบ”เบฑเปˆเบ‡เบ™เบฑเป‰เบ™, เบ•เบนเป‰เบ„เบญเบ™เป€เบ—เบ™เป€เบ™เบตเบ—เบตเปˆเบกเบตเปเบญเบฑเบšเบžเบฅเบดเป€เบ„เบŠเบฑเบ™เบšเปเปˆเบˆเปเบฒเป€เบ›เบฑเบ™เบ•เป‰เบญเบ‡เบชเบปเปˆเบ‡เบ•เปเปˆเบžเบญเบ”เปƒเบ™เบฅเบฐเบšเบปเบšเป€เบˆเบปเป‰เบฒเบžเบฒเบš;

เบ–เป‰เบฒ proxy reverse เบญเบฒเป„เบชเบขเบนเปˆเปƒเบ™ host เบญเบทเปˆเบ™, เบ—เปˆเบฒเบ™เบˆเบฐเบ•เป‰เบญเบ‡เบ›เบฐเบ–เบดเป‰เบกเป€เบ„เบทเบญเบ‚เปˆเบฒเบ docker เปเบฅเบฐเป€เบŠเบทเปˆเบญเบกเบ•เปเปˆเปเบญเบฑเบšเบžเบฅเบดเป€เบ„เบŠเบฑเบ™เบเบฑเบš proxy reverse เบœเปˆเบฒเบ™เป€เบ„เบทเบญเบ‚เปˆเบฒเบ host, เบชเบปเปˆเบ‡เบ•เปเปˆเบžเบญเบ”. apps เบžเบฒเบฅเบฒเบกเบดเป€เบ•เบต --publish, เปƒเบ™เบ•เบญเบ™เป€เบฅเบตเปˆเบกเบ•เบปเป‰เบ™เบ—เปเบฒเบญเบดเบ”เปเบฅเบฐเป€เบŠเบฑเปˆเบ™เบ”เบฝเบงเบเบฑเบ™เบเบฑเบš proxy เบ›เบตเป‰เบ™เบเบฑเบšเบเบฑเบ™.

เบžเบงเบเป€เบฎเบปเบฒเบˆเบฐเบ”เปเบฒเป€เบ™เบตเบ™เบเบฒเบ™ proxy reverse เปƒเบ™ port 80, เป€เบ™เบทเปˆเบญเบ‡เบˆเบฒเบเบงเปˆเบฒเบ™เบตเป‰เปเบกเปˆเบ™เปเบ—เป‰ entity เบ—เบตเปˆเบ„เบงเบ™เบŸเบฑเบ‡เป€เบ„เบทเบญเบ‚เปˆเบฒเบเบžเบฒเบเบ™เบญเบ. เบ–เป‰เบฒเบžเบญเบ” 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) เปเบฅเบฐเบซเบผเบฑเบ‡เบˆเบฒเบเบ™เบฑเป‰เบ™เป‚เบญเบ™เบกเบฑเบ™เป„เบ›เบซเบฒเป€เบ„เบทเปˆเบญเบ‡เปเบกเปˆเบ‚เปˆเบฒเบ.

เบเบฒเบ™โ€‹เบ–เปˆเบฒเบโ€‹เป‚เบญเบ™โ€‹เบฎเบนเบšโ€‹เบžเบฒเบšโ€‹

เปเบ•เปˆเบซเบ™เป‰เบฒเป€เบชเบเบ”เบฒเบ, เบกเบฑเบ™เบšเปเปˆเบกเบตเบ„เบงเบฒเบกเบซเบกเบฒเบเบ—เบตเปˆเบˆเบฐเป‚เบญเบ™เบฎเบนเบšเบžเบฒเบšเบˆเบฒเบ localhost เป„เบ›เบซเบฒ localhost, เบ”เบฑเปˆเบ‡เบ™เบฑเป‰เบ™เบžเบฒเบเบชเปˆเบงเบ™เบ™เบตเป‰เบชเบฒเบกเบฒเบ”เบ„เบปเป‰เบ™เบซเบฒเป„เบ”เป‰เบ–เป‰เบฒเบ—เปˆเบฒเบ™เบกเบตเบชเบญเบ‡เป‚เบฎเบ”เบเบฑเบš Docker เบขเบนเปˆเปƒเบ™เบกเบท. เบขเปˆเบฒเบ‡โ€‹เบซเบ™เป‰เบญเบโ€‹เบกเบฑเบ™โ€‹เป€เบšเบดเปˆเบ‡โ€‹เบšเบฒเบ‡โ€‹เบขเปˆเบฒเบ‡โ€‹เป€เบŠเบฑเปˆเบ™โ€‹เบ™เบตเป‰โ€‹:

$ 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 archive, เบŠเบถเปˆเบ‡เบซเบกเบฒเบเบ„เบงเบฒเบกเบงเปˆเบฒเบกเบฑเบ™เบกเบตเบ™เปเป‰เบฒเบซเบ™เบฑเบเบ›เบฐเบกเบฒเบ™ 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. เป€เบŠเบทเปˆเบญเบกเบ•เปเปˆเบเบฑเบšเป€เบ„เบทเปˆเบญเบ‡เปเบกเปˆเบ‚เปˆเบฒเบ daemon docker เบˆเบฒเบเป‚เบฎเบ”เบญเบทเปˆเบ™:
    1. เบชเบฐเบžเบฒเบšเปเบงเบ”เบฅเป‰เบญเบกเบ›เปˆเบฝเบ™เปเบ›เบ‡ DOCKER_HOST.
    2. เบ—เบฒเบ‡เป€เบฅเบทเบญเบเปเบ–เบงเบ„เปเบฒเบชเบฑเปˆเบ‡ -H เบซเบผเบท --host เป€เบ„เบทเปˆเบญเบ‡เบกเบท docker-compose.
    3. docker context

เบงเบดเบ—เบตเบเบฒเบ™เบ—เบตเบชเบญเบ‡ (เบกเบตเบชเบฒเบกเบ—เบฒเบ‡เป€เบฅเบทเบญเบเบชเปเบฒเบฅเบฑเบšเบเบฒเบ™เบ›เบฐเบ•เบดเบšเบฑเบ”เบ‚เบญเบ‡เบกเบฑเบ™) เปเบกเปˆเบ™เบญเบฐเบ—เบดเบšเบฒเบเป„เบ”เป‰เบ”เบตเปƒเบ™เบšเบปเบ”เบ„เบงเบฒเบก เบงเบดเบ—เบตเบเบฒเบ™เบ•เบดเบ”เบ•เบฑเป‰เบ‡ Docker hosts เป„เบฅเบเบฐเป„เบเบ”เป‰เบงเบ docker-compose.

deploy.sh

เบ•เบญเบ™เบ™เบตเป‰เปƒเบซเป‰เป€เบฎเบปเบฒเป€เบเบฑเบšเบเบณเบ—เบธเบเบขเปˆเบฒเบ‡เบ—เบตเปˆเบžเบงเบเป€เบฎเบปเบฒเป„เบ”เป‰เป€เบฎเบฑเบ”เบ”เป‰เบงเบเบ•เบปเบ™เป€เบญเบ‡เป€เบ›เบฑเบ™เบชเบฐเบ„เบฃเบดเบšเบ”เบฝเบง. เปƒเบซเป‰เป€เบฅเบตเปˆเบกเบ•เบปเป‰เบ™เบ”เป‰เบงเบเบŸเบฑเบ‡เบŠเบฑเบ™เบฅเบฐเบ”เบฑเบšเป€เบ—เบดเบ‡, เปเบฅเบฐเบซเบผเบฑเบ‡เบˆเบฒเบเบ™เบฑเป‰เบ™เป€เบšเบดเปˆเบ‡เบ•เบปเบงเบญเบทเปˆเบ™เป†เบ—เบตเปˆเปƒเบŠเป‰เปƒเบ™เบกเบฑเบ™.

เป€เบ•เบฑเบเบ™เบดเบเบ—เบตเปˆเบซเบ™เป‰เบฒเบชเบปเบ™เปƒเบˆ

  • ${parameter?err_msg} - เบซเบ™เบถเปˆเบ‡เปƒเบ™เบเบฒเบ™เบชเบฐเบเบปเบ”เบ„เปเบฒ magic bash (aka เบเบฒเบ™เบ—เบปเบ”เปเบ—เบ™เบžเบฒเบฅเบฒเบกเบดเป€เบ•เบต). เบ–เป‰เบฒ parameter เบšเปเปˆเป„เบ”เป‰เบฅเบฐเบšเบธ, เบœเบปเบ™เบœเบฐเบฅเบดเบ” err_msg เปเบฅเบฐเบญเบญเบเบ”เป‰เบงเบเบฅเบฐเบซเบฑเบ” 1.
  • docker --log-driver journald โ€” เป‚เบ”เบเบ„เปˆเบฒเป€เบฅเบตเปˆเบกเบ•เบปเป‰เบ™, เบ•เบปเบงเบ‚เบฑเบšเบšเบฑเบ™เบ—เบถเบ docker เปเบกเปˆเบ™เป„เบŸเบฅเปŒเบ‚เปเป‰เบ„เบงเบฒเบกเป‚เบ”เบเบšเปเปˆเบกเบตเบเบฒเบ™เบซเบกเบธเบ™เปƒเบ”เป†. เบ”เป‰เบงเบเบงเบดเบ—เบตเบเบฒเบ™เบ™เบตเป‰, เบšเบฑเบ™เบ—เบถเบเป„เบ”เป‰เป„เบงเป€เบ•เบฑเบกเปเบœเปˆเบ™เบ—เบฑเบ‡เบซเบกเบปเบ”, เบ”เบฑเปˆเบ‡เบ™เบฑเป‰เบ™เป€เบžเบทเปˆเบญเบชเบฐเบžเบฒเบšเปเบงเบ”เบฅเป‰เบญเบกเบเบฒเบ™เบœเบฐเบฅเบดเบ”เบกเบฑเบ™เบˆเปเบฒเป€เบ›เบฑเบ™เบ•เป‰เบญเบ‡เบ›เปˆเบฝเบ™เป„เบ”เป€เบงเบตเปƒเบซเป‰เบชเบฐเบซเบฅเบฒเบ”เบเบงเปˆเบฒ.

เบชเบฐเบ„เบฃเบดเบšเบเบฒเบ™เบ™เบณเปƒเบŠเป‰

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 โ€” เป€เบฎเบฑเบ”โ€‹เปƒเบซเป‰โ€‹เปเบ™เปˆโ€‹เปƒเบˆเบงเปˆโ€‹เบฒ proxy reverse เปเบกเปˆเบ™โ€‹เป€เบฎเบฑเบ”โ€‹เบงเบฝเบ (เป€เบ›เบฑเบ™โ€‹เบ›เบฐโ€‹เป‚เบซเบเบ”โ€‹เบชเปเบฒโ€‹เบฅเบฑเบšโ€‹เบเบฒเบ™โ€‹เบ™เปเบฒโ€‹เปƒเบŠเป‰โ€‹เบ„เบฑเป‰เบ‡โ€‹เบ—เปเบฒโ€‹เบญเบดเบ”โ€‹)
  • 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 เบ•เป‰เบญเบ‡เบเบฒเบ™เบ„เปเบฒเบญเบฐเบ—เบดเบšเบฒเบเป€เบฅเบฑเบเบ™เป‰เบญเบ:

เป€เบ›เบฑเบ™เบซเบเบฑเบ‡เบกเบฑเบ™เบˆเบถเปˆเบ‡เบชเบปเปˆเบ‡เบ„เบทเบ™เบ•เบปเบงเป€เบฅเบ เปเบฅเบฐเบšเปเปˆเบญเบญเบเบชเบฐเบ•เบฃเบดเบ‡?

เบขเปˆเบฒเบ‡เปƒเบ”เบเปเปˆเบ•เบฒเบก, เปƒเบ™เบซเบ™เป‰เบฒเบ—เบตเปˆเป‚เบ—เบซเบฒเบžเบงเบเป€เบฎเบปเบฒเบเบงเบ”เป€เบšเบดเปˆเบ‡เบœเบปเบ™เป„เบ”เป‰เบฎเบฑเบšเบ‚เบญเบ‡เบเบฒเบ™เป€เบฎเบฑเบ”เบงเบฝเบเบ‚เบญเบ‡เบกเบฑเบ™, เปเบฅเบฐเบเบฒเบ™เบเบงเบ”เบชเบญเบšเบฅเบฐเบซเบฑเบ”เบญเบญเบเป‚เบ”เบเปƒเบŠเป‰ bash เปเบกเปˆเบ™เบ‡เปˆเบฒเบเบเบงเปˆเบฒเบเบฒเบ™เบเบงเบ”เบชเบญเบšเบชเบฒเบ. เบ™เบญเบเบˆเบฒเบเบ™เบฑเป‰เบ™, เบเบฒเบ™เป„เบ”เป‰เบฎเบฑเบšเบชเบฒเบเบˆเบฒเบเบกเบฑเบ™เปเบกเปˆเบ™เบ‡เปˆเบฒเบเบ”เบฒเบเบซเบผเบฒเบ:
get-active-slot service && echo BLUE || echo GREEN.

เป€เบ‡เบทเปˆเบญเบ™เป„เบ‚เบชเบฒเบกเบขเปˆเบฒเบ‡เปเบกเปˆเบ™เบžเบฝเบ‡เบžเปเบ—เบตเปˆเบˆเบฐเบˆเปเบฒเปเบ™เบเบฅเบฑเบ”เบ—เบฑเบ‡เบซเบกเบปเบ”เบšเป?

เบ™เบณเปƒเบŠเป‰เบชเบตเบŸเป‰เบฒ-เบชเบตเบ‚เบฝเบงเปƒเบ™เบ„เปˆเบฒเบˆเป‰เบฒเบ‡เบ‚เบฑเป‰เบ™เบ•เปˆเบณ

เป€เบ–เบดเบ‡เปเบกเปˆเบ™เบงเปˆเบฒเบชเบญเบ‡เบˆเบฐเบžเบฝเบ‡เบžเป, เบชเบธเบ”เบ—เป‰เบฒเบเปเบกเปˆเบ™เบขเบนเปˆเบ—เบตเปˆเบ™เบตเป‰เป€เบžเบทเปˆเบญเบ„เบงเบฒเบกเบชเบปเบกเบšเบนเบ™, เป€เบžเบทเปˆเบญเบšเปเปˆเปƒเบซเป‰เบ‚เบฝเบ™ else.

เบžเบฝเบ‡เปเบ•เปˆเบŸเบฑเบ‡เบŠเบฑเบ™เบ—เบตเปˆเบชเบปเปˆเบ‡เบ„เบทเบ™เบเบฒเบ™เบ•เบฑเป‰เบ‡เบ„เปˆเบฒ nginx เบเบฑเบ‡เบšเปเปˆเบ–เบทเบเบเปเบฒเบ™เบปเบ”: get-nginx-config service_name deployment_slot. เป‚เบ”เบเบเบฒเบ™เบ›เบฝเบšเบ—เบฝเบšเบเบฑเบšเบเบฒเบ™เบเบงเบ”เบชเบธเบ‚เบฐเบžเบฒเบš, เปƒเบ™เบ—เบตเปˆเบ™เบตเป‰เบ—เปˆเบฒเบ™เบชเบฒเบกเบฒเบ”เบเปเบฒเบ™เบปเบ”เบเบฒเบ™เบ•เบฑเป‰เบ‡เบ„เปˆเบฒเปƒเบ”เป†เบชเปเบฒเบฅเบฑเบšเบเบฒเบ™เบšเปเบฅเบดเบเบฒเบ™เปƒเบ”เป†. เบ‚เบญเบ‡เบชเบดเปˆเบ‡เบ—เบตเปˆเบซเบ™เป‰เบฒเบชเบปเบ™เปƒเบˆ - เป€เบ—เบปเปˆเบฒเบ™เบฑเป‰เบ™ cat <<- EOF, เป€เบŠเบดเปˆเบ‡เบญเบฐเบ™เบธเบเบฒเบ”เปƒเบซเป‰เบ—เปˆเบฒเบ™เป€เบญเบปเบฒเปเบ–เบšเบ—เบฑเบ‡เบซเบกเบปเบ”เปƒเบ™เบ•เบญเบ™เป€เบฅเบตเปˆเบกเบ•เบปเป‰เบ™. เบ„เบงเบฒเบกเบˆเบดเบ‡, เบฅเบฒเบ„เบฒเบ‚เบญเบ‡เบเบฒเบ™เบˆเบฑเบ”เบฎเบนเบšเปเบšเบšเบ—เบตเปˆเบ”เบตเปเบกเปˆเบ™เปเบ–เบšเบ›เบฐเบชเบปเบกเบ—เบตเปˆเบกเบตเบŠเปˆเบญเบ‡เบซเบงเปˆเบฒเบ‡, เป€เบŠเบดเปˆเบ‡เบกเบทเป‰เบ™เบตเป‰เบ–เบทเบงเปˆเบฒเป€เบ›เบฑเบ™เบฎเบนเบšเปเบšเบšเบ—เบตเปˆเบšเปเปˆเบ”เบตเบซเบผเบฒเบ. เปเบ•เปˆเปเบ–เบšเบšเบฑเบ‡เบ„เบฑเบš bash, เปเบฅเบฐเบกเบฑเบ™เบเปเปˆเบˆเบฐเป€เบ›เบฑเบ™เบเบฒเบ™เบ”เบตเบ—เบตเปˆเบˆเบฐเบกเบตเบเบฒเบ™เบˆเบฑเบ”เบฎเบนเบšเปเบšเบšเบ›เบปเบเบเบฐเบ•เบดเปƒเบ™เบเบฒเบ™เบ•เบฑเป‰เบ‡เบ„เปˆเบฒ nginx. เปƒเบ™เบชเบฑเป‰เบ™, เบเบฒเบ™เบ›เบฐเบชเบปเบกเปเบ–เบšเบ—เบตเปˆเบกเบตเบŠเปˆเบญเบ‡เบซเบงเปˆเบฒเบ‡เบขเบนเปˆเบ™เบตเป‰เบเปเปˆเป€เบšเบดเปˆเบ‡เบ„เบทเบงเปˆเบฒเป€เบ›เบฑเบ™เบเบฒเบ™เปเบเป‰เป„เบ‚เบ—เบตเปˆเบ”เบตเบ—เบตเปˆเบชเบธเบ”เบˆเบฒเบเบชเบดเปˆเบ‡เบ—เบตเปˆเบฎเป‰เบฒเบเปเบฎเบ‡เบ—เบตเปˆเบชเบธเบ”. เบขเปˆเบฒเบ‡เปƒเบ”เบเปเบ•เบฒเบก, เบ—เปˆเบฒเบ™เบˆเบฐเบšเปเปˆเป€เบซเบฑเบ™เบ™เบตเป‰เบขเบนเปˆเปƒเบ™ snippet เบ‚เป‰เบฒเบ‡เบฅเบธเปˆเบกเบ™เบตเป‰, เป€เบ™เบทเปˆเบญเบ‡เบˆเบฒเบเบงเปˆเบฒ Habr "เป€เบฎเบฑเบ”เป„เบ”เป‰เบ”เบต" เป‚เบ”เบเบเบฒเบ™เบ›เปˆเบฝเบ™เปเบ›เบ‡เปเบ–เบšเบ—เบฑเบ‡เบซเบกเบปเบ”เป€เบ›เบฑเบ™ 4 เบŠเปˆเบญเบ‡เปเบฅเบฐเป€เบฎเบฑเบ”เปƒเบซเป‰ EOF เบšเปเปˆเบ–เบทเบเบ•เป‰เบญเบ‡. เปเบฅเบฐเปƒเบ™เบ—เบตเปˆเบ™เบตเป‰เบกเบฑเบ™เบชเบฑเบ‡เป€เบเบ”เป€เบซเบฑเบ™.

เป€เบžเบทเปˆเบญเบšเปเปˆเปƒเบซเป‰เบฅเบธเบเบ‚เบถเป‰เบ™เบชเบญเบ‡เป€เบ—เบทเปˆเบญ, เบ‚เป‰เบญเบเบˆเบฐเบšเบญเบเป€เบˆเบปเป‰เบฒเบ—เบฑเบ™เบ—เบต cat << 'EOF', เป€เบŠเบดเปˆเบ‡เบˆเบฐเป„เบ”เป‰เบžเบปเบšเบเบฑเบšเบ•เปเปˆเบกเบฒ. เบ–เป‰เบฒเบ—เปˆเบฒเบ™เบ‚เบฝเบ™เบ‡เปˆเบฒเบเป† cat << EOF, เบซเบผเบฑเบ‡เบˆเบฒเบเบ™เบฑเป‰เบ™เบžเบฒเบเปƒเบ™ heredoc เบชเบฐเบ•เบดเบ‡เป„เบ”เป‰เบ–เบทเบ interpolated (เบ•เบปเบงเปเบ›เป„เบ”เป‰เบ–เบทเบเบ‚เบฐเบซเบเบฒเบ (.$foo), เป‚เบ—เบชเบฑเปˆเบ‡ ($(bar)) เปเบฅเบฐเบญเบทเปˆเบ™เป†), เปเบฅเบฐเบ–เป‰เบฒเบซเบฒเบเบงเปˆเบฒเบ—เปˆเบฒเบ™เบ›เบดเบ”เบ—เป‰เบฒเบเบ‚เบญเบ‡เป€เบญเบเบฐเบชเบฒเบ™เปƒเบ™เบงเบปเบ‡เบขเบทเบกเบ”เบฝเบง, เบซเบผเบฑเบ‡เบˆเบฒเบเบ™เบฑเป‰เบ™ interpolation เปเบกเปˆเบ™เบžเบดเบเบฒเบ™เปเบฅเบฐเบชเบฑเบ™เบเบฒเบฅเบฑเบ. $ เบ–เบทเบเบชเบฐเปเบ”เบ‡เป€เบ›เบฑเบ™. เบชเบดเปˆเบ‡เบ—เบตเปˆเบ—เปˆเบฒเบ™เบˆเปเบฒเป€เบ›เบฑเบ™เบ•เป‰เบญเบ‡เปƒเบชเปˆเบชเบฐเบ„เบดเบšเบžเบฒเบเปƒเบ™เบชเบฐเบ„เบดเบšเบญเบทเปˆเบ™.

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
}

เบ™เบตเป‰เปเบกเปˆเบ™ script เบ—เบฑเบ‡เบซเบกเบปเบ”. เปเบฅเบฐเบ”เบฑเปˆเบ‡เบ™เบฑเป‰เบ™ gist เบเบฑเบš script เบ™เบตเป‰ เบชเปเบฒเบฅเบฑเบšเบเบฒเบ™เบ”เบฒเบงเป‚เบซเบผเบ”เบœเปˆเบฒเบ™ wget เบซเบผเบท curl.

เบ”เปเบฒเป€เบ™เบตเบ™เบเบฒเบ™ scripts parameterized เปƒเบ™เป€เบ„เบทเปˆเบญเบ‡เปเบกเปˆเบ‚เปˆเบฒเบเบซเปˆเบฒเบ‡เป„เบเบชเบญเบเบซเบผเบตเบ

เบกเบฑเบ™เป€เบ›เบฑเบ™เป€เบงเบฅเบฒเบ—เบตเปˆเบˆเบฐเป€เบ„เบฒเบฐเป€เบ„เบทเปˆเบญเบ‡เปเบกเปˆเบ‚เปˆเบฒเบเป€เบ›เบปเป‰เบฒเบซเบกเบฒเบ. เบ„เบฑเป‰เบ‡โ€‹เบ™เบตเป‰ 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.

เบžเบงเบเป€เบฎเบปเบฒเป„เบ”เป‰เบ‚เบฝเบ™เบชเบฐเบ„เบฃเบดเบšเบเบฒเบ™เบ™เบณเปƒเบŠเป‰เบ—เบตเปˆเบ”เบฒเบงเป‚เบซเบฅเบ”เบฎเบนเบšเบžเบฒเบšเบ—เบตเปˆเบชเป‰เบฒเบ‡เบ‚เบถเป‰เบ™เบเปˆเบญเบ™เปƒเบชเปˆเป€เบŠเบตเบšเป€เบงเบตเป€เบ›เบปเป‰เบฒเปเบฒเบ เปเบฅเบฐเบ›เปˆเบฝเบ™เปเบ—เบ™เบ—เบตเปˆเบšเบฑเบ™เบˆเบธเบšเปเบฅเบดเบเบฒเบ™เป„เบ”เป‰เบขเปˆเบฒเบ‡เบšเปเปˆเบขเบธเบ”เบขเบฑเป‰เบ‡, เปเบ•เปˆเบžเบงเบเป€เบฎเบปเบฒเบˆเบฐเบ”เบณเป€เบ™เบตเบ™เบเบฒเบ™เบเบฑเบšเป€เบ„เบทเปˆเบญเบ‡เบˆเบฑเบเบ—เบฒเบ‡เป„เบเป„เบ”เป‰เปเบ™เบงเปƒเบ”? เบชเบฐเบ„เบฃเบดเบšเบกเบตเบ‚เปเป‰เป‚เบ•เป‰เปเบเป‰เบ‡, เป€เบžเบฒเบฐเบงเปˆเบฒเบกเบฑเบ™เป€เบ›เบฑเบ™เปเบšเบšเบ—เบปเปˆเบงเป†เป„เบ›เปเบฅเบฐเบชเบฒเบกเบฒเบ”เบ™เปเบฒเป„เบ›เปƒเบŠเป‰เบซเบผเบฒเบเบเบฒเบ™เบšเปเบฅเบดเบเบฒเบ™เปƒเบ™เป€เบงเบฅเบฒเบ”เบฝเบงเบเบฑเบ™เบžเบฒเบเปƒเบ•เป‰เบซเบ™เบถเปˆเบ‡ reverse proxy (เบ—เปˆเบฒเบ™เบชเบฒเบกเบฒเบ”เบ™เปเบฒเปƒเบŠเป‰ nginx configs เป€เบžเบทเปˆเบญเบเปเบฒเบ™เบปเบ”เบงเปˆเบฒ url เบˆเบฐเป€เบ›เบฑเบ™เบšเปเบฅเบดเบเบฒเบ™เปƒเบ”). script เบšเปเปˆเบชเบฒเบกเบฒเบ”เบ–เบทเบเป€เบเบฑเบšเป„เบงเป‰เปƒเบ™เป€เบ„เบทเปˆเบญเบ‡เปเบกเปˆเบ‚เปˆเบฒเบ, เป€เบ™เบทเปˆเบญเบ‡เบˆเบฒเบเบงเปˆเบฒเปƒเบ™เบเปเบฅเบฐเบ™เบตเบ™เบตเป‰เบžเบงเบเป€เบฎเบปเบฒเบˆเบฐเบšเปเปˆเบชเบฒเบกเบฒเบ”เบ›เบฑเบšเบ›เบธเบ‡เบกเบฑเบ™เป‚เบ”เบเบญเบฑเบ”เบ•เบฐเป‚เบ™เบกเบฑเบ” (เบชเปเบฒเบฅเบฑเบšเบˆเบธเบ”เบ›เบฐเบชเบปเบ‡เบ‚เบญเบ‡เบเบฒเบ™เปเบเป‰เป„เบ‚ bug เปเบฅเบฐเป€เบžเบตเปˆเบกเบเบฒเบ™เบšเปเบฅเบดเบเบฒเบ™เปƒเบซเบกเปˆ), เปเบฅเบฐเป‚เบ”เบเบ—เบปเปˆเบงเป„เบ›, state = evil.

เบเบฒเบ™เปเบเป‰เป„เบ‚ 1: เบเบฑเบ‡เป€เบเบฑเบšเบฎเบฑเบเบชเบฒ script เปƒเบ™เป€เบ„เบทเปˆเบญเบ‡เปเบกเปˆเบ‚เปˆเบฒเบ, เปเบ•เปˆเบ„เบฑเบ”เบฅเบญเบเบกเบฑเบ™เบ—เบธเบเบ„เบฑเป‰เบ‡เบœเปˆเบฒเบ™ scp. เบซเบผเบฑเบ‡เบˆเบฒเบเบ™เบฑเป‰เบ™เป€เบŠเบทเปˆเบญเบกเบ•เปเปˆเบœเปˆเบฒเบ™ ssh เปเบฅเบฐเบ›เบฐเบ•เบดเบšเบฑเบ” script เบ”เป‰เบงเบเบเบฒเบ™เป‚เบ•เป‰เบ–เบฝเบ‡เบ—เบตเปˆเบˆเปเบฒเป€เบ›เบฑเบ™.

Cons:

  • เบชเบญเบ‡เบเบฒเบ™เบเบฐเบ—เปเบฒเปเบ—เบ™เบ—เบตเปˆเบˆเบฐเป€เบ›เบฑเบ™เบซเบ™เบถเปˆเบ‡
  • เบญเบฒเบ”เบˆเบฐเบšเปเปˆเบกเบตเบชเบฐเบ–เบฒเบ™เบ—เบตเปˆเบ—เบตเปˆเบ—เปˆเบฒเบ™เบ„เบฑเบ”เบฅเบญเบ, เบซเบผเบทเบญเบฒเบ”เบˆเบฐเบšเปเปˆเป€เบ‚เบปเป‰เบฒเป€เบ–เบดเบ‡เบกเบฑเบ™, เบซเบผเบทเบชเบฐเบ„เบดเบšเบญเบฒเบ”เบˆเบฐเบ–เบทเบเบ›เบฐเบ•เบดเบšเบฑเบ”เปƒเบ™เป€เบงเบฅเบฒเบ—เบตเปˆเบ›เปˆเบฝเบ™เปเบ—เบ™.
  • เบกเบฑเบ™เปเบกเปˆเบ™เปเบ™เบฐเบ™เปเบฒเปƒเบซเป‰เป€เบฎเบฑเบ”เบ„เบงเบฒเบกเบชเบฐเบญเบฒเบ”เบซเบผเบฑเบ‡เบˆเบฒเบเบ•เบปเบงเบ—เปˆเบฒเบ™เป€เบญเบ‡ (เบฅเบถเบšเบชเบฐเบ„เบดเบš).
  • เปเบฅเป‰เบงเบชเบฒเบกเบ›เบฐเบ•เบดเบšเบฑเบ”.

เบเบฒเบ™เปเบเป‰เป„เบ‚ 2:

  • เบฎเบฑเบเบชเบฒเบžเบฝเบ‡เปเบ•เปˆเบ„เปเบฒเบ™เบดเบเบฒเบกเบซเบ™เป‰เบฒเบ—เบตเปˆเบขเบนเปˆเปƒเบ™เบชเบฐเบ„เบดเบšเปเบฅเบฐเบ”เปเบฒเป€เบ™เบตเบ™เบเบฒเบ™เบšเปเปˆเบกเบตเบซเบเบฑเบ‡เป€เบฅเบตเบ
  • เบ”เป‰เบงเบเบ„เบงเบฒเบกเบŠเปˆเบงเบเป€เบซเบผเบทเบญเบ‚เบญเบ‡ sed เป€เบžเบตเปˆเบกเบเบฒเบ™เป€เบญเบตเป‰เบ™เบŸเบฑเบ‡เบŠเบฑเบ™เปƒเบ™เบ—เป‰เบฒเบ
  • เบชเบปเปˆเบ‡เบ—เบฑเบ‡เบซเบกเบปเบ”เป‚เบ”เบเบเบปเบ‡เบเบฑเบš shh เบœเปˆเบฒเบ™เบ—เปเปˆ (|)

Pros:

  • เบšเปเปˆเบกเบตเบชเบฑเบ™เบŠเบฒเบ”เบขเปˆเบฒเบ‡เปเบ—เป‰เบˆเบดเบ‡
  • เบšเปเปˆเบกเบตเบซเบ™เปˆเบงเบเบ‡เบฒเบ™ boilerplate
  • เบฎเบนเป‰เบชเบถเบเป€เบขเบฑเบ™

เปƒเบซเป‰เบ‚เบญเบ‡เบžเบฝเบ‡เปเบ•เปˆเป€เบฎเบฑเบ”เบกเบฑเบ™เป‚เบ”เบเบšเปเปˆเบกเบตเบเบฒเบ™ Ansible. เปเบกเปˆเบ™เปเบฅเป‰เบง, เบ—เบธเบเบชเบดเปˆเบ‡เบ—เบธเบเบขเปˆเบฒเบ‡เป„เบ”เป‰เบ–เบทเบ invented เปเบฅเป‰เบง. เปเบกเปˆเบ™เปเบฅเป‰เบง, เบฅเบปเบ”เบ–เบตเบš. เป€เบšเบดเปˆเบ‡เบงเบดเบ—เบตเบเบฒเบ™เบ‡เปˆเบฒเบเบ”เบฒเบ, elegant เปเบฅเบฐ minimalistic เบฅเบปเบ”เบ–เบตเบšเปเบกเปˆเบ™:

$ 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'

เบขเปˆเบฒเบ‡เปƒเบ”เบเปเบ•เบฒเบก, เบžเบงเบเป€เบฎเบปเบฒเบšเปเปˆเบชเบฒเบกเบฒเบ”เปเบ™เปˆเปƒเบˆเบงเปˆเบฒเป€เบˆเบปเป‰เบฒเบžเบฒเบšเบซเปˆเบฒเบ‡เป„เบเบชเบญเบเบซเบผเบตเบเบกเบต bash เบžเบฝเบ‡เบžเป, เบ”เบฑเปˆเบ‡เบ™เบฑเป‰เบ™เบžเบงเบเป€เบฎเบปเบฒเบˆเบฐเป€เบžเบตเปˆเบกเบเบฒเบ™เบเบงเบ”เบชเบญเบšเบ‚เบฐเบซเบ™เบฒเบ”เบ™เป‰เบญเบเปƒเบ™เบ•เบญเบ™เป€เบฅเบตเปˆเบกเบ•เบปเป‰เบ™ (เบ™เบตเป‰เปเบกเปˆเบ™เปเบ—เบ™เบ—เบตเปˆเบˆเบฐเป€เบ›เบฑเบ™. shellbang):

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/ เปƒเบ™เบ•เบปเบงเบ—เปˆเบญเบ‡เป€เบงเบฑเบš, เบ”เปเบฒเป€เบ™เบตเบ™เบเบฒเบ™ deployment เบญเบตเบเป€เบ—เบทเปˆเบญเบซเบ™เบถเปˆเบ‡เปเบฅเบฐเปƒเบซเป‰เปเบ™เปˆเปƒเบˆเบงเปˆเบฒเบกเบฑเบ™เบ”เปเบฒเป€เบ™เบตเบ™เบเบฒเบ™ seamlessly เป‚เบ”เบเบเบฒเบ™เบ›เบฑเบšเบ›เบธเบ‡เบซเบ™เป‰เบฒเบ•เบฒเบก CD เปƒเบ™เบฅเบฐเบซเบงเปˆเบฒเบ‡เบเบฒเบ™เบˆเบฑเบ”เบงเบฒเบ‡.

เบขเปˆเบฒโ€‹เบฅเบทเบกโ€‹เป€เบฎเบฑเบ”โ€‹เบ„เบงเบฒเบกโ€‹เบชเบฐโ€‹เบญเบฒเบ”โ€‹เบซเบผเบฑเบ‡โ€‹เบˆเบฒเบโ€‹เบเบฒเบ™โ€‹เป€เบฎเบฑเบ”โ€‹เบงเบฝเบโ€‹: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

เบŠเบทเป‰เป‚เบฎเบ”เบ•เบดเป‰เบ‡เบ—เบตเปˆเป€เบŠเบทเปˆเบญเบ–เบทเป„เบ”เป‰เบชเปเบฒเบฅเบฑเบšเป€เบงเบฑเบšเป„เบŠเบ—เปŒเบ—เบตเปˆเบกเบตเบเบฒเบ™เบ›เบปเบเบ›เป‰เบญเบ‡ DDoS, เป€เบ„เบทเปˆเบญเบ‡เปเบกเปˆเบ‚เปˆเบฒเบ VPS VDS ๐Ÿ”ฅ เบŠเบทเป‰เป€เบงเบฑเบšเป„เบŠเบ—เปŒเป‚เบฎเบ”เบ•เบดเป‰เบ‡เบ—เบตเปˆเป€เบŠเบทเปˆเบญเบ–เบทเป„เบ”เป‰เบ”เป‰เบงเบเบเบฒเบ™เบ›เป‰เบญเบ‡เบเบฑเบ™ DDoS, เป€เบŠเบตเบšเป€เบงเบต VPS VDS | ProHoster