Sa artikulong ito ginagamit namin malakas na palo, SSH, docker ΠΈ nginx Aayusin namin ang isang tuluy-tuloy na layout ng web application. Asul-berde na deployment ay isang pamamaraan na nagbibigay-daan sa iyo upang agad na i-update ang isang application nang hindi tinatanggihan ang isang kahilingan. Isa ito sa mga diskarte sa pag-deploy ng zero downtime at pinakaangkop para sa mga application na may isang instance, ngunit ang kakayahang mag-load ng pangalawang, ready-to-run na instance sa malapit.
Sabihin nating mayroon kang web application kung saan aktibong nagtatrabaho ang maraming kliyente, at talagang walang paraan para mahiga ito sa loob ng ilang segundo. At kailangan mo talagang maglunsad ng update sa library, pag-aayos ng bug, o bagong cool na feature. Sa isang normal na sitwasyon, kakailanganin mong ihinto ang application, palitan ito at simulan itong muli. Sa kaso ng docker, maaari mo munang palitan ito, pagkatapos ay i-restart ito, ngunit magkakaroon pa rin ng isang panahon kung saan ang mga kahilingan sa application ay hindi mapoproseso, dahil kadalasan ang application ay tumatagal ng ilang oras upang unang mag-load. Paano kung nagsimula ito, ngunit lumabas na hindi maoperahan? Ito ang problema, lutasin natin ito sa kaunting paraan at kasing elegante hangga't maaari.
DISCLAIMER: Karamihan sa artikulo ay ipinakita sa isang pang-eksperimentong format - sa anyo ng isang pag-record ng isang console session. Sana ay hindi ito masyadong mahirap maunawaan at ang code ay magdodokumento ng sarili nitong sapat. Para sa kapaligiran, isipin na ang mga ito ay hindi lamang mga snippet ng code, ngunit papel mula sa isang "bakal" na teletype.
Ang mga kagiliw-giliw na diskarte na mahirap sa Google sa pamamagitan lamang ng pagbabasa ng code ay inilarawan sa simula ng bawat seksyon. Kung mayroon pang hindi malinaw, i-google ito at tingnan ito. explainshell (sa kabutihang palad, ito ay gumagana muli, dahil sa pag-unblock ng telegrama). Kung wala kang magawa sa Google, magtanong sa mga komento. Ikalulugod kong idagdag sa kaukulang seksyon na "Mga kawili-wiling diskarte".
Magsimula tayo.
$ mkdir blue-green-deployment && cd $_
Tools
Gumawa tayo ng pang-eksperimentong serbisyo at ilagay ito sa isang lalagyan.
Mga kawili-wiling pamamaraan
cat << EOF > file-name (Narito ang Dokumento + I/O Redirection) ay isang paraan upang lumikha ng isang multi-line na file na may isang command. Lahat ng bash nagbabasa mula sa /dev/stdin pagkatapos ng linyang ito at bago ang linya EOF ay itatala sa file-name.
wget -qO- URL (explainshell) β maglabas ng dokumentong natanggap sa pamamagitan ng HTTP sa /dev/stdout (analogue curl URL).
Printout
Partikular kong sinira ang snippet upang paganahin ang pag-highlight para sa Python. Sa dulo magkakaroon ng isa pang piraso na tulad nito. Isaalang-alang na sa mga lugar na ito ang papel ay pinutol upang ipadala sa departamento ng pag-highlight (kung saan ang code ay kinulayan ng kamay na may mga highlighter), at pagkatapos ay ang mga piraso ay idinikit pabalik.
$ 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
Baliktarin ang proxy
Upang ang aming aplikasyon ay makapagbago nang hindi napapansin, kinakailangan na mayroong ibang entity sa harap nito na magtatago ng kapalit nito. Maaaring ito ay isang web server nginx Π² reverse proxy mode. Ang isang reverse proxy ay itinatag sa pagitan ng kliyente at ng application. Tumatanggap ito ng mga kahilingan mula sa mga kliyente at ipinapasa ang mga ito sa aplikasyon at ipinapasa ang mga tugon ng aplikasyon sa mga kliyente.
Ang application at reverse proxy ay maaaring maiugnay sa loob ng docker gamit network ng docker. Kaya, ang lalagyan na may application ay hindi na kailangang mag-forward ng isang port sa host system; ito ay nagpapahintulot sa application na lubos na ihiwalay mula sa mga panlabas na banta.
Kung ang reverse proxy ay nakatira sa isa pang host, kailangan mong iwanan ang docker network at ikonekta ang application sa reverse proxy sa pamamagitan ng host network, na ipapasa ang port apps parameter --publish, tulad ng sa unang pagsisimula at tulad ng sa reverse proxy.
Tatakbo kami ng reverse proxy sa port 80, dahil ito mismo ang entity na dapat makinig sa panlabas na network. Kung abala ang port 80 sa iyong test host, baguhin ang parameter --publish 80:80 sa --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>
Walang putol na deployment
Maglunsad tayo ng bagong bersyon ng application (na may dalawang beses na pagpapalakas ng pagganap ng startup) at subukang i-deploy ito nang walang putol.
Mga kawili-wiling pamamaraan
echo 'my text' | docker exec -i my-container sh -c 'cat > /my-file.txt' β Sumulat ng teksto my text mag-file /my-file.txt sa loob ng lalagyan my-container.
cat > /my-file.txt β Isulat ang mga nilalaman ng karaniwang input sa isang file /dev/stdin.
Printout
$ 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
Sa yugtong ito, ang imahe ay binuo nang direkta sa server, na nangangailangan ng mga mapagkukunan ng application na naroroon, at naglo-load din sa server ng hindi kinakailangang trabaho. Ang susunod na hakbang ay ang paglalaan ng image assembly sa isang hiwalay na makina (halimbawa, sa isang CI system) at pagkatapos ay ilipat ito sa server.
Paglilipat ng mga larawan
Sa kasamaang palad, hindi makatuwirang ilipat ang mga larawan mula sa localhost patungo sa localhost, kaya't maaari lamang tuklasin ang seksyong ito kung mayroon kang dalawang host na may Docker sa kamay. Sa pinakamababa, ganito ang hitsura nito:
$ 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
Koponan docker save sine-save ang data ng imahe sa isang .tar archive, ibig sabihin, tumitimbang ito ng humigit-kumulang 1.5 beses na mas mataas kaysa sa tinitimbang nito sa naka-compress na anyo. Kaya't ipagpatuloy natin ito sa ngalan ng pagtitipid ng oras at trapiko:
Tip: Kung kailangan mo ng isang grupo ng mga parameter upang kumonekta sa isang server sa pamamagitan ng SSH, maaaring hindi mo ginagamit ang file ~/.ssh/config.
Paglilipat ng larawan sa pamamagitan ng docker image save/load - Ito ang pinaka minimalistic na paraan, ngunit hindi ang isa lamang. May iba pa:
Container Registry (pamantayan sa industriya).
Kumonekta sa docker daemon server mula sa isa pang host:
variable ng kapaligiran DOCKER_HOST.
Opsyon ng command line -H o --host tool docker-compose.
Ngayon, kolektahin natin ang lahat ng ginawa natin nang manu-mano sa isang script. Magsimula tayo sa top-level na function, at pagkatapos ay tingnan ang iba pang ginamit dito.
Mga kawili-wiling pamamaraan
${parameter?err_msg} - isa sa mga bash magic spells (aka pagpapalit ng parameter). Kung parameter hindi tinukoy, output err_msg at lumabas gamit ang code 1.
docker --log-driver journald β bilang default, ang driver ng pag-log ng docker ay isang text file na walang anumang pag-ikot. Sa diskarteng ito, mabilis na pinupuno ng mga log ang buong disk, kaya para sa isang kapaligiran ng produksyon kinakailangan na baguhin ang driver sa isang mas matalinong isa.
deployment script
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
}
Mga tampok na ginamit:
ensure-reverse-proxy β Tinitiyak na gumagana ang reverse proxy (kapaki-pakinabang para sa unang pag-deploy)
get-active-slot service_name β Tinutukoy kung aling slot ang kasalukuyang aktibo para sa isang ibinigay na serbisyo (BLUE o GREEN)
get-service-status service_name deployment_slot β Tinutukoy kung handa na ang serbisyo na iproseso ang mga papasok na kahilingan
set-active-slot service_name deployment_slot β Binabago ang nginx config sa reverse proxy container
Upang:
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
}
Tungkulin get-active-slot nangangailangan ng kaunting paliwanag:
Bakit ito nagbabalik ng isang numero at hindi naglalabas ng isang string?
Anyway, sa calling function, sinusuri namin ang resulta ng trabaho nito, at ang pagsuri sa exit code gamit ang bash ay mas madali kaysa sa pagsuri ng string. Bilang karagdagan, ang pagkuha ng isang string mula dito ay napaka-simple: get-active-slot service && echo BLUE || echo GREEN.
Sapat ba talaga ang tatlong kundisyon para makilala ang lahat ng estado?
Kahit dalawa ay sapat na, ang huli ay narito lamang para sa pagkakumpleto, upang hindi magsulat else.
Tanging ang function na nagbabalik ng nginx configs ay nananatiling hindi natukoy: get-nginx-config service_name deployment_slot. Sa pamamagitan ng pagkakatulad sa pagsusuri sa kalusugan, dito maaari kang magtakda ng anumang config para sa anumang serbisyo. Sa mga kawili-wiling bagay - lamang cat <<- EOF, na nagbibigay-daan sa iyong alisin ang lahat ng tab sa simula. Totoo, ang presyo ng mahusay na pag-format ay halo-halong mga tab na may mga puwang, na ngayon ay itinuturing na napakasamang anyo. Ngunit pinipilit ng bash ang mga tab, at maganda rin na magkaroon ng normal na pag-format sa nginx config. Sa madaling salita, ang paghahalo ng mga tab na may mga puwang dito ay tila ang pinakamahusay na solusyon sa pinakamasama. Gayunpaman, hindi mo ito makikita sa snippet sa ibaba, dahil "mahusay ang ginagawa" ni Habr sa pamamagitan ng pagpapalit ng lahat ng tab sa 4 na espasyo at paggawang hindi wasto ang EOF. At dito kapansin-pansin.
Para hindi makabangon ng dalawang beses, sasabihin ko kaagad sa iyo cat << 'EOF', na makakatagpo sa ibang pagkakataon. Kung magsusulat ka ng simple cat << EOF, pagkatapos ay sa loob ng heredoc ang string ay interpolated (mga variable ay pinalawak ($foo), command calls ($(bar)) atbp.), at kung isasama mo ang dulo ng dokumento sa mga solong panipi, hindi pinagana ang interpolation at ang simbolo $ ay ipinapakita bilang ay. Ano ang kailangan mong magpasok ng isang script sa loob ng isa pang script.
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
}
Ito ang buong script. At kaya buod sa script na ito para sa pag-download sa pamamagitan ng wget o curl.
Pagpapatupad ng mga parameterized na script sa isang malayuang server
Oras na para kumatok sa target na server. Sa pagkakataong ito localhost medyo angkop:
$ 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.
Nagsulat kami ng deployment script na nagda-download ng pre-built na imahe sa target na server at walang putol na pinapalitan ang service container, ngunit paano namin ito maipapatupad sa isang remote na makina? Ang script ay may mga argumento, dahil ito ay pangkalahatan at maaaring mag-deploy ng ilang mga serbisyo nang sabay-sabay sa ilalim ng isang reverse proxy (maaari kang gumamit ng nginx configs upang matukoy kung aling url ang magiging serbisyo). Ang script ay hindi maiimbak sa server, dahil sa kasong ito, hindi namin ito maa-update nang awtomatiko (para sa layunin ng pag-aayos ng bug at pagdaragdag ng mga bagong serbisyo), at sa pangkalahatan, state = evil.
Solusyon 1: Iimbak pa rin ang script sa server, ngunit kopyahin ito sa bawat oras scp. Pagkatapos ay kumonekta sa pamamagitan ng ssh at isagawa ang script gamit ang mga kinakailangang argumento.
Cons:
Dalawang aksyon sa halip na isa
Maaaring walang lugar kung saan mo kinokopya, o maaaring walang access dito, o maaaring isagawa ang script sa oras ng pagpapalit.
Maipapayo na maglinis pagkatapos ng iyong sarili (tanggalin ang script).
Tatlong aksyon na.
Solusyon 2:
Panatilihin lamang ang mga kahulugan ng function sa script at wala man lang pinapatakbo
May sed magdagdag ng isang function na tawag sa dulo
Direktang ipadala ang lahat sa shh sa pamamagitan ng pipe (|)
Pros:
Tunay na walang estado
Walang boilerplate entity
Feeling cool
Gawin na lang natin ng walang Ansible. Oo, lahat ay naimbento na. Oo, isang bisikleta. Tingnan kung gaano kasimple, elegante at minimalistic ang bike:
$ 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'
Gayunpaman, hindi namin matiyak na ang malayong host ay may sapat na bash, kaya magdadagdag kami ng maliit na tseke sa simula (ito ay sa halip na 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
At ngayon ito ay totoo:
$ 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!
Ngayon ay maaari mong buksan http://localhost/ sa browser, patakbuhin muli ang deployment at tiyaking tumatakbo ito nang walang putol sa pamamagitan ng pag-update ng page ayon sa CD sa panahon ng layout.
Huwag kalimutang maglinis pagkatapos ng trabaho :3