V tomto článku pomocí , , a uspořádáme bezproblémové nasazení webové aplikace. je technika, která umožňuje okamžitou aktualizaci aplikace bez přerušení jakékoli žádosti. Je to jedna ze strategií nasazení bez výpadku a nejlépe se hodí pro aplikace s jedním instance, ale s možností vedle toho spustit druhou, připravenou instance.
Představte si, že máte webovou aplikaci, na které aktivně pracuje mnoho klientů, a ta se ani na pár sekund nesmí zastavit. A vy velmi potřebujete vydat aktualizaci knihovny, opravit chybu nebo přidat novou skvělou funkci. V běžné situaci by bylo nutné aplikaci zastavit, vyměnit ji a znovu spustit. V případě Dockeru můžete nejprve vyměnit, pak restartovat, ale i tak dojde k období, kdy žádosti k aplikaci nebudou zpracovány, neboť aplikaci obvykle nějaký čas trvá, než se inicializuje. A co když se spustí, ale nebude funkční? Takový úkol, pojďme to vyřešit s minimálními prostředky a co nejvíce elegantně.
DISCLAIMER: Většina článku je prezentována v experimentálním formátu — jako záznam konzolové relace. Doufám, že to nebude moc obtížné vnímat a tento kód se dostatečně dokumentuje sám. Pro atmosféru si představte, že to nejsou jen kódové ukázky, ale papír z "železného" teletype.
Zajímavé techniky, které se těžko hledají jen čtením kódu, jsou popsány na začátku každé části. Pokud něco nebude jasné — hledejte a kontrolujte v (naštěstí opět funguje, díky odblokování Telegramu). Co se nedá najít — ptejte se v komentářích. Rád doplním odpovídající část "Zajímavé techniky".
Začněme.
$ mkdir blue-green-deployment && cd $_SA-Frontend
Vytvoříme zkušební službu a umístíme ji do kontejneru.
Zajímavé techniky
cat < file-name( + ) — způsob, jak vytvořit vícerozměrný soubor jedním příkazem. Všechno, co bash přečte z/dev/stdinpo této řádce a do řádkuEOFbude zapsáno dofile-name.wget -qO- URL() — zobrazí přijatý dokument přes HTTP v/dev/stdout(analogcurl URL).
Tisk
Speciálně rozděluji snippet, abych zahrnul zvýraznění pro Python. Na konci bude ještě jeden takový kus. Považujte to za místa, kde byla papír rozříznut, aby se předal do oddělení zvýrazňování (kde byl kód ručně zbarven zvýrazňovači), a poté byly tyto kusy znovu vloženy.
$ cat < uptimer.pyz http.server import BaseHTTPRequestHandler, HTTPServer
z time import monotonic
verze_aplikace = 1
název_aplikace = f'Uptimer v{verze_aplikace}.0'
čekací_sekundy = 15 - verze_aplikace * 5
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
if self.path == '\/':
try:
t = monotonic() - server_start
if t < čekací_sekundy:
self.send_error(503)
else:
self.send_response(200)
self.send_header('Content-Type', 'text\/html')
self.end_headers()
response = f'<h2>{název_aplikace} běží po {t:3.1f} sekundách.</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'{název_aplikace} (načítá se za {čekací_sekundy} sek.) spuštěno.')
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 (nahrává se za 10 sekund) už běží.
$ wget -qSO- http:\/\/localhost:8080
HTTP\/1.0 503 Služba nedostupná
Server: BaseHTTP\/0.6 Python\/3.8.3
Date: So, 22 Srp 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: So, 22 Srp 2020 19:52:45 GMT
Content-Type: text\/html
<h2>Uptimer v1.0 běží po 15,4 sekundách.</h2>
$ docker rm --force uptimer
uptimerReverse proxy
Aby naše aplikace měla možnost nepozorovaně změnit, je potřeba, aby před ní byla ještě nějaká entita, která skryje její výměnu. Může to být webový server. v . Reverse proxy je umístěna mezi klientem a aplikací. Přebírá požadavky od klientů a přesměrovává je k aplikaci, zatímco odpovědi aplikace posílá klientům.
Aplikaci a reverse proxy můžeme propojit uvnitř Dockeru pomocí . Takto není nutné ani přeposílat port kontejneru s aplikací do hostitelského systému, což umožňuje maximálně izolovat aplikaci od hrozeb zvenčí.
Pokud bude reverse proxy žít na jiném hostiteli, budeme muset opustit docker network a propojit aplikaci s reverse proxy přes síť hostitele, přeposílat port aplikace parametrem --publish, stejně jako při prvním spuštění a jako u reverse proxy.
Reverse proxy spustíme na portu 80, protože to je ta entita, která by měla poslouchat z vnějšku. Pokud je port 80 na vašem testovacím hostiteli obsazen, změňte parametr --publish 80:80 na --publish ANY_FREE_PORT:80.
Zajímavé techniky
- "V uživatelských dockerových sítích je možné komunikovat s kontejnery nejen podle IP adresy. Jméno kontejneru se také převádí na jeho IP adresu" (, bod 5 dokerské kodexu).
Tisk
$ 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 běží po dobu 11,5 sekundy.</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.…" před 27 sekundami Běží 25 sekund 0.0.0.0:80->80\/tcp reverse-proxy
a1105f1b583d uptimer "python -u .\/app.py" před asi minutou Běží asi minutu 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: So, 22 Srp 2020 19:56:24 GMT
Content-Type: text\/html
Transfer-Encoding: chunked
Connection: keep-alive
<h2>Uptimer v1.0 běží po dobu 104,1 sekundy.</h2>Bezešvé nasazení
Nasadíme novou verzi aplikace (s dvojnásobným výkonem při spouštění) a pokusíme se ji nasadit bezproblémově.
Zajímavé techniky
echo 'my text' | docker exec -i my-container sh -c 'cat > /my-file.txt'— Zapsat textmy textdo souboru/my-file.txtuvnitř kontejnerumy-container.cat > /my-file.txt— Zapsat do souboru obsah standardního vstupu./dev/stdin.
Tisk
$ 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 (načítá se za 5 sekund) spuštěn.
$ docker run --rm --network web-gateway alpine wget -qO- http://uptimer_BLUE:8080
<h2>Uptimer v2.0 běží po dobu 23,9 sekund.</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: signál procesu spuštěn
$ wget -qO- http://localhost
<h2>Uptimer v2.0 běží po dobu 63,4 sekund.</h2>
$ docker rm -f uptimer
uptimer
$ wget -qO- http://localhost
<h2>Uptimer v2.0 běží po dobu 84,8 sekund.</h2>
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
96932d4ca97a uptimer "python -u .\/app.py" Přibližně před minutou Běží přibližně minutu 8080/tcp uptimer_BLUE
80695a822c19 nginx:alpine "\/docker-entrypoint.…" před 8 minutami Běží 8 minut 0.0.0.0:80->80/tcp reverse-proxyV této fázi se obraz vytváří přímo na serveru, což vyžaduje, aby tam byly zdrojové kódy aplikace a zároveň zatěžuje server zbytečnou prací. Dalším krokem bude segregace sestavení obrazu na jiný stroj (například v CI systému) s následným jeho přenesením na server.
Přenášení obrazů
Bohužel, přesun obrazů z localhostu na localhost nemá smysl, takže tuto část může vyzkoušet pouze ten, kdo má po ruce dva hostitele s dockerem. Na minimalizaci to vypadá přibližně takto:
$ 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.9MBTým docker save ukládá data obrazu do archivu .tar, což znamená, že bude vážit přibližně 1,5krát více, než by mohl vážit v komprimované podobě. Tak ho zkomprimujme ve jménu úspory času a dat:
$ docker image save uptimer | gzip | ssh production-server 'zcat | docker image load'
Loaded image: uptimer:latestA navíc, můžete sledovat proces přenosu (i když k tomu potřebujete externí nástroj):
$ docker image save uptimer | gzip | pv | ssh production-server 'zcat | docker image load'
25,7MiB 0:01:01 [ 425KiB/s] [ ]
Loaded image: uptimer:latestTip: Pokud potřebujete k připojení k serveru přes SSH spoustu parametrů, možná nepoužíváte soubor
~/.ssh/config.
Přenášení obrazu přes docker image save/load — to je nejvíce minimalistická metoda, ale ne jediná. Existují i jiné:
- Container Registry (standard odvětví).
- Připojte se k docker daemonu serveru z jiného hostitele:
- Proměnná prostředí
DOCKER_HOST. - Parametr příkazového řádku
-Hnebo--hostnástrojedocker-compose. docker context
- Proměnná prostředí
Druhý způsob (se třemi variantami jeho provedení) je dobře popsán v článku .
deploy.sh
Nyní spojme vše, co jsme dělali ručně, do jednoho skriptu. Začneme s funkce na nejvyšší úrovni a pak se podíváme na další, které v ní byly použity.
Zajímavé techniky
${parameter?err_msg}— jedno z kouzel bash-magie (aka ). Pokudparameternení nastaven, vypíšemeerr_msga odejdeme s kódem 1.docker --log-driver journald— ve výchozím nastavení je ovladačem logů dockera textový soubor bez nějaké rotace. S tímto přístupem logy rychle zaplní celý disk, takže pro produkční prostředí je nutné změnit ovladač na inteligentnější.
Skript nasazení
deploy() {
local usage_msg="Použití: ${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 "Nasazení '$NEW' místo '$OLD'..."
docker run
--detach
--restart always
--log-driver journald
--name $NEW
--network web-gateway
$image_name || return 3
echo "Kontejner spuštěn. Kontrola zdraví..."
for i in {1..20}
do
sleep 1
if get-service-status $image_name $new_slot
then
echo "Nová služba '$NEW' se zdá být v pořádku. Přepínání slotů..."
sleep 2 # Zajištění, že je služba připravena
set-active-slot $image_name $new_slot || return 4
echo "Služba '$NEW' je živá!"
sleep 2 # Zajištění, že všechny požadavky byly zpracovány
echo "Zabíjení '$OLD'..."
docker rm -f $OLD
docker image prune -f
echo "Nasazení bylo úspěšné!"
return 0
fi
echo "Nová služba '$NEW' ještě není připravena. Čekám ($i)..."
done
echo "Nová služba '$NEW' se nezprovoznila, zabíjím ji. Nasazení selhalo T_T"
docker rm -f $NEW
return 5
}Použité funkce:
ensure-reverse-proxy— Zajišťuje, že reverzní proxy funguje (užitečné při prvním nasazení)get-active-slot service_name— Určuje, který slot je nyní aktivní pro danou službu (BLUEneboGREEN)get-service-status service_name deployment_slot— Určuje, zda je služba připravena zpracovávat příchozí požadavkyset-active-slot service_name deployment_slot— Mění konfiguraci nginx v kontejneru reverzní proxy
V pořadí:
ensure-reverse-proxy() {
is-container-up reverse-proxy && return 0
echo "Nasazení 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?"Použití: ${FUNCNAME[0]} jméno_kontejneru"}
[ -n "$(docker ps -f name=${container} -q)" ]
return $?
}
get-active-slot() {
local service=${1?"Použití: ${FUNCNAME[0]} jméno_slサービス"}
if is-container-up ${service}_BLUE && is-container-up ${service}_GREEN; then
echo "Detekován konflikt! Zastavuji ${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="Použití: ${FUNCNAME[0]} jméno_slサービス deploje_slot"
local service=${1?usage_msg}
local slot=${2?$usage_msg}
case $service in
# Přidejte specifické cesty pro healthcheck pro vaše služby zde
*) local health_check_port_path=":8080/" ;;
esac
local health_check_address="http://${service}_${slot}${health_check_port_path}"
echo "Žádám o '$health_check_address' v rámci docker sítě 'web-gateway':"
docker run --rm --network web-gateway alpine
wget --timeout=1 --quiet --server-response $health_check_address
return $?
}
set-active-slot() {
local usage_msg="Použití: ${FUNCNAME[0]} jméno_sl服务 deploje_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
}Funkce get-active-slot vyžaduje drobná vysvětlení:
Proč vrací číslo a ne vypisuje řetězec?
I tak v volající funkci kontrolujeme výsledek její práce, a kontrolovat exit code pomocí bash je mnohem jednodušší než řetězec. Navíc, získat z ní řetězec je velmi jednoduché:
get-active-slot service && echo BLUE || echo GREEN.
A třech podmínek je opravdu dost k rozlišení všech stavů?
Dokonce stačí i dvě, to poslední je zde jen pro úplnost, abychom nemuseli psát else.
Zůstala nejasná pouze funkce, která vrací konfigurace nginx: get-nginx-config service_name deployment_slot. Podobně jako u healthchecku lze zde nastavit jakoukoliv konfiguraci pro jakoukoli službu. Z zajímavého — pouze cat <<- EOF, což umožňuje odstranit všechny tabulátory na začátku. Pravda, cena důstojného formátování — smíšené tabulátory s mezerami, což je dnes považováno za velmi špatný vkus. Ale bash nutí tabulátory a v konfiguraci nginx by také bylo dobré mít normální formátování. Takže zde se smíšení tabulátorů s mezerami zdá opravdu nejlepší volbou z nejhorších. Nicméně, ve snippetě níže to nevidíte, protože habr "dělá dobře", mění všechny tabulátory na 4 mezery a dělá EOF neplatným. .
Abych se dvakrát neptal, hned vám povím o
cat << 'EOF', který se dále ještě objeví. Pokud napíšete jednodušecat << EOF, tak uvnitř heredocu probíhá interpolace řetězce (rozkrývají se proměnné ($foo), volání příkazů ($(bar)) atd.), a pokud uzavřete znak konce dokumentu do jednoduchých uvozovek, interpolace se vypne a znak$se zobrazí, jak je. To je to, co potřebujete pro vložení skriptu dovnitř jiného skriptu.
get-nginx-config() {
local usage_msg="Použití: ${FUNCNAME[0]} služba název slotu nasazení"
local service=${1?$usage_msg}
local slot=${2?$usage_msg}
[ "$slot" == BLUE ] || [ "$slot" == GREEN ] || return 1
local container_name=${service}_${slot}
case $service in
# Přidejte specifické nginx konfigurace pro své služby zde
*) nginx-config-simple-service $container_name:8080 ;;
esac
}
nginx-config-simple-service() {
local usage_msg="Použití: ${FUNCNAME[0]} proxy_pass"
local proxy_pass=${1?$usage_msg}
cat << EOF
server {
listen 80;
location / {
proxy_pass http://$proxy_pass;
}
}
EOF
}To je celý skript. A tady je ke stažení přes wget nebo curl.
Provádění parametrizovaných skriptů na vzdáleném serveru
Nastal čas se ozvat cílovému serveru. Tentokrát localhost se hodí:
$ ssh-copy-id localhost
/usr/bin/ssh-copy-id: INFO: pokouší se přihlásit s novým klíčem(y), aby filtroval jakékoli, které jsou již nainstalovány
/usr/bin/ssh-copy-id: INFO: 1 klíč(e) zbývá nainstalovat -- pokud jste nyní vyzváni, je to k instalaci nových klíčů
himura@localhost's password:
Počet přidaných klíčů: 1
Nyní zkuste přihlásit se do stroje s: "ssh 'localhost'"
a zkontrolujte, zda byly přidány pouze požadované klíče.Napsali jsme skript pro nasazení, který přenáší předem sestavený obraz na cílový server a bezproblémově nahrazuje kontejner služby, ale jak ho spustit na vzdáleném stroji? Skript má argumenty, protože je univerzální a může nasazovat rovnou několik služeb pod jeden reverzní proxy (konfigurace nginx může vyřešit, na jaké URL bude která služba). Skript nelze uchovávat na serveru, protože v takovém případě ho nebudeme moci automaticky aktualizovat (kvůli opravám chyb a přidávání nových služeb), a vůbec, stav = zlo.
Řešení 1: Takže uchovávat skript na serveru, ale každou chvíli ho kopírovat přes scp. Pak se připojit přes ssh a spustit skript s potřebnými argumenty.
Nevýhody:
- Dvě akce místo jedné
- Místo, kam kopírujete, nemusí existovat, nebo k němu nemusí být přístup, nebo může být skript spuštěn v okamžiku, kdy se nahrazuje.
- Je dobré po sobě uklidit (smazat skript).
- Už tři akce.
Řešení 2:
- Skriptu uchovávat pouze definice funkcí a vůbec nic nespouštět,
- Pomocí
sedpřidávat na konec volání funkce. - Posílat to všechno přímo do shh přes pipe (
|)
Plusy:
- Opravdu bezstavový
- Žádné boilerplate entity
- Cítím se skvěle
Ale pojďme na to bez Ansible. Ano, už bylo všechno vymyšleno. Ano, kolo. Podívejte se, jak jednoduché, elegantní a minimalistické kolo:
$ cat < 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_SCRIPTEOF
$ chmod +x deploy.sh
$ ./deploy.sh localhost magic-porridge-pot
Připojuji se k localhost...
Hurá! Funkce 'deploy' se spouští na 'hut' s argumentem 'magic-porridge-pot'Nicméně, nemůžeme si být jisti, že na vzdáleném hostiteli je adekvátní bash, takže na začátek přidáme malé ověření (to místo ):
if [ "$SHELL" != "/bin/bash" ]
then
echo "Shell '$SHELL' není podporován skriptem 'deploy.sh'. Nastavte shell '/bin/bash' pro '$USER@$HOSTNAME'."
exit 1
fiA teď už všechno opravdu:
$ 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
Odesílání gzipped obrazu 'uptimer' na 'localhost' prostřednictvím ssh...
Načtený obraz: uptimer:latest
Připojení k 'localhost' prostřednictvím ssh pro bezproblémové nasazení 'uptimer'...
Nasazení 'uptimer_GREEN' místo 'uptimer_BLUE'...
06f5bc70e9c4f930e7b1f826ae2ca2f536023cc01e82c2b97b2c84d68048b18a
Kontejner spuštěn. Kontrola zdraví...
Žádost o 'http://uptimer_GREEN:8080/' v rámci docker sítě 'web-gateway':
HTTP/1.0 503 Služba není k dispozici
wget: server vrátil chybu: HTTP/1.0 503 Služba není k dispozici
Nová služba 'uptimer_GREEN' ještě není připravena. Čekám (1)...
Žádost o 'http://uptimer_GREEN:8080/' v rámci docker sítě 'web-gateway':
HTTP/1.0 503 Služba není k dispozici
wget: server vrátil chybu: HTTP/1.0 503 Služba není k dispozici
Nová služba 'uptimer_GREEN' ještě není připravena. Čekám (2)...
Žádost o 'http://uptimer_GREEN:8080/' v rámci docker sítě 'web-gateway':
HTTP/1.0 200 OK
Server: BaseHTTP/0.6 Python/3.8.3
Datum: So, 22. srpna 2020 20:15:50 GMT
Content-Type: text/html
Nová služba 'uptimer_GREEN' vypadá v pořádku. Přepínám hlavy...
nginx: konfigurační soubor /etc/nginx/nginx.conf má syntaxi v pořádku
nginx: test konfiguračního souboru /etc/nginx/nginx.conf byl úspěšný
2020/08/22 20:15:54 [notice] 97#97: proces signálu byl spuštěn
Služba 'uptimer_GREEN' je v provozu!
Zabíjení 'uptimer_BLUE'...
uptimer_BLUE
Celkový uvolněný prostor: 0B
Nasazení úspěšné!Nyní můžete otevřít v prohlížeči, spustit nasazení znovu a ujistit se, že probíhá bezproblémově tím, že aktualizujete stránku při nasazení.
Nezapomeňte po práci uklidit :3
$ docker rm -f uptimer_GREEN reverse-proxy
uptimer_GREEN
reverse-proxy
$ docker network rm web-gateway
web-gateway
$ cd ..
$ rm -r blue-green-deploymentZdroj: habr.com
