V tem članku bomo s pomočjo , , in organizirali brezšivno nameščanje spletne aplikacije. je tehnika, ki omogoča takojšnje posodobitve aplikacije brez zavračanja nobene zahteve. Je ena od strategij zero downtime deployment in najbolje deluje za aplikacije z enim instancom, a s sposobnostjo nalaganja drugega, pripravljenga za delo, poleg.
Recimo, da imate spletno aplikacijo, s katero aktivno dela veliko strank, in je nikakor ne morete ustaviti niti za nekaj sekund. Potrebujete pa nujno posodobiti knjižnico, odpraviti napako ali dodati novo funkcionalnost. V običajnem scenariju bi bilo treba ustaviti aplikacijo, jo zamenjati in znova zagnati. V primeru Dockerja lahko najprej zamenjate, nato pa ponovo zaženete, vendar bo vseeno prišlo do obdobja, ko zahteve za aplikacijo ne bodo obdelane, saj običajno aplikaciji traja nekaj časa, da se sprva naloži. Kaj pa, če se ponovno zažene, a se izkaže za neoperativno? Takšno nalogo bomo rešili z minimalnimi sredstvi in maksimalno eleganco.
ZGODBA O ODLAGANJU: Večina članka je predstavljena v eksperimentalnem formatu — kot zapis konzolne seje. Upam, da to ne bo preveč težko za razumevanje, in da se ta koda sama dokumentira v zadostni meri. Za vzdušje si predstavljajte, da to niso le kosi kode, temveč papir iz „železnega“ teleprinterja.
Zanimive tehnike, ki jih je težko najti zgolj z branjem kode, so opisane na začetku vsakega razdelka. Če še kaj ni jasno, iščite in preverite v (na srečo zdaj spet deluje, ker je Telegram odklenjen). Tisto, kar se ne da najti, vprašajte v komentarjih. Z veseljem bom dopolnil ustrezen razdelek „Zanimive tehnike“.
Začnimo.
$ mkdir blue-green-deployment && cd $_Storitev
Ustvarili bomo poskusno storitev in jo postavili v kontejner.
Zanimive tehnike
cat < file-name( + ) — način za ustvarjanje večvrstičnega dokumenta z eno samo ukazom. Vse, kar bash prebere iz/dev/stdinpo tej vrstici in do vrsticeEOFbo zapisano vfile-name.wget -qO- URL() — za izpis pridobljenega dokumenta preko HTTP v/dev/stdout(podobnocurl URL).
Izpis
Namerno prekinjam snipet da uključim označavanje za Python. Na kraju će biti još jedan takav deo. Smatrajte da su u tim mestima papiri isečeni radi prenosa u odeljenje za obeležavanje (gde je kod ručno obeležen markerima), a zatim su ti delovi ponovo zalepili.
$ cat < uptimer.pyz http.server import BaseHTTPRequestHandler, HTTPServer
z 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} deluje že {t:3.1f} sekunde.</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} (naloži v {loading_seconds} sek.) začel.)
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 работает в течение 15.4 секунд.</h2>
$ docker rm --force uptimer
uptimerReverzni proksi
Da bi naša aplikacija mogla tiho da se zameni, potrebno je da ispred nje postoji neka entitet koji će sakriti njenu zamenu. To može biti veb server u . Reverzni proksi se postavlja između klijenta i aplikacije. Prihvata zahteve od klijenata i preusmerava ih na aplikaciju, a odgovore aplikacije šalje klijentima.
Aplikaciju i reverzni proksi možemo povezati unutar dokera pomoću . Tako da kontejneru s aplikacijom čak i ne treba preusmeriti port na host sistemu, što omogućava maksimalnu izolaciju aplikacije od spoljašnjih pretnji.
Ako će reverzni proksi biti na drugom hostu, moraćemo da se odrekne docker mreže i povežemo aplikaciju s reverznim proksijem putem mreže hosta, preusmerivši port aplikacije parametrom --publish, kao pri prvom pokretanju i kao kod reverznog proksija.
Reverzni proksi pokrećemo na portu 80, jer je to entitet koji treba da sluša spolja. Ako je port 80 na vašem test hostu zauzet, promenite parametar --publish 80:80 na --publish ANY_FREE_PORT:80.
Zanimive tehnike
- „U docker mrežama, koje kreira korisnik, sa kontejnerima se može povezivati ne samo putem IP adrese. Ime kontejnera se takođe prevodi u njegovu IP adresu“ (, stavka 5 docker kodeksa).
Izpis
$ 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 стругает уже 11.5 секунд.</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 секунд назад В работе 25 секунд 0.0.0.0:80->80/tcp reverse-proxy
a1105f1b583d uptimer "python -u ./app.py" Минуту назад В работе около минуты 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: сигнал процесса начат
$ wget -qSO- http://localhost
HTTP/1.1 200 OK
Server: nginx/1.19.0
Date: Сб, 22 Авг 2020 19:56:24 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Connection: keep-alive
<h2>Uptimer v1.0 стругает уже 104.1 секунды.</h2>Nepristrasni deploy
Izdavaćemo novu verziju aplikacije (sa dvostrukim povećanjem performansi pri pokretanju) i pokušaćemo da je neometano implementiramo.
Zanimive tehnike
echo 'my text' | docker exec -i my-container sh -c 'cat > /my-file.txt'— Upisati tekstmy textu datoteku/my-file.txtunutar kontejneramy-container.cat > /my-file.txt— Upisati u datoteku sadržaj standardnog ulaza/dev/stdin.
Izpis
$ 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 je aktivan već 23.9 sekundi.</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 je aktivan već 63.4 sekundi.</h2>
$ docker rm -f uptimer
uptimer
$ wget -qO- http://localhost
<h2>Uptimer v2.0 je aktivan već 84.8 sekundi.</h2>
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
96932d4ca97a uptimer "python -u ./app.py" Prije otprilike jedne minute Up prije jedne minute 8080/tcp uptimer_BLUE
80695a822c19 nginx:alpine "docker-entrypoint.…" Prije 8 minuta Up 8 minuta 0.0.0.0:80->80/tcp reverse-proxyU ovoj fazi, slika se gradi direktno na serveru, što zahteva prisutnost izvora aplikacije, kao i dodatno opterećuje server. Sledeći korak biće odvajanje izrade slike na poseban mašinu (na primer, u CI sistemu) uz kasniju distribuciju na server.
Prenos slika
Žal, prenos slike z localhost na localhost nima smisla, zato lahko ta razdelek preizkusite le, če imate na voljo dva gostitelja z Dockerjem. Na minimalni ravni to izgleda približno tako:
$ ssh production-server docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
$ docker image save uptimer | ssh production-server 'docker image load'
Naložena slika: uptimer:latest
$ ssh production-server docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
uptimer latest 1d56897841ec 5 minutes ago 78.9MBKomanda docker save shranjuje podatke slike v .tar arhiv, kar pomeni, da je približno 1.5-krat večji, kot bi bil v stisnjeni obliki. Torej ga stisnimo v imenu varčevanja s časom in prometom:
$ docker image save uptimer | gzip | ssh production-server 'zcat | docker image load'
Naložena slika: uptimer:latestPrav tako lahko spremljate potek prenosa (seveda potrebujete zunanje orodje):
$ docker image save uptimer | gzip | pv | ssh production-server 'zcat | docker image load'
25,7MiB 0:01:01 [ 425KiB/s] [ ]
Naložena slika: uptimer:latestNasvet: Če potrebujete veliko parametrov za povezavo s strežnikom prek SSH, morda ne uporabljate datoteke
~/.ssh/config.
Prenos slike preko docker image save/load je najbolj minimalistična metoda, vendar ni edina. Obstajajo tudi druge:
- Container Registry (standard industrije).
- Povezovanje z docker daemon strežnika iz drugega gostitelja:
- Spremenljivka okolja
DOCKER_HOST. - Parameter ukazne vrstice
-Hili--hostorodjadocker-compose. docker context
- Spremenljivka okolja
Drugi način (s tremi različicami njegove izvedbe) je dobro opisan v članku .
deploy.sh
Zdaj bomo vse, kar smo počeli ročno, združili v en skript. Začnimo z vrhnjo funkcijo, nato pa si bomo ogledali ostale funkcije, ki jih uporablja.
Zanimive tehnike
${parameter?err_msg}je ena od čarovnij bash magije (aka ). Čeparameterni določen, izpišierr_msgin izstopi s kodo 1.docker --log-driver journaldje privzeto gonilo beleženja Dockerja besedilna datoteka brez kakršnekoli rotacije. Takšen pristop hitro napolni vse diske z logi, zato je za produkcijska okolja nujno spremeniti gonilo v pametnejše.
Skripta za namestitev
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
}Uporabljene funkcije:
ensure-reverse-proxy— Preveri, ali deluje reverzni proxy (koristno za prvo namestitev)get-active-slot service_name— Ugotovi, kateri slot je trenutno aktiven za dane storitve (BLUEiliGREEN)get-service-status service_name deployment_slot— Ugotovi, ali je storitev pripravljena za obdelavo vhodnih zahtevset-active-slot service_name deployment_slot— Spremeni konfiguracijo nginx v kontejnerju reverznega proxyja
Po vrsti:
ensure-reverse-proxy() {
is-container-up reverse-proxy && return 0
echo "Развёртывание обратного прокси..."
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?"Использование: ${FUNCNAME[0]} имя контейнера"}
[ -n "$(docker ps -f name=${container} -q)" ]
return $?
}
get-active-slot() {
local service=${1?"Использование: ${FUNCNAME[0]} имя сервиса"}
if is-container-up ${service}_BLUE && is-container-up ${service}_GREEN; then
echo "Обнаружено столкновение! Останавливаем ${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="Использование: ${FUNCNAME[0]} имя сервиса слот развертывания"
local service=${1?usage_msg}
local slot=${2?$usage_msg}
case $service in
# Добавьте специфические пути для проверки состояния ваших сервисов здесь
*) local health_check_port_path=":8080/" ;;
esac
local health_check_address="http://${service}_${slot}${health_check_port_path}"
echo "Запрос к '$health_check_address' в сети '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="Использование: ${FUNCNAME[0]} имя сервиса слот развертывания"
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
}Funkcija get-active-slot требует небольших пояснений:
Почему она возвращает число, а не выводит строку?
Всё равно в вызывающей функции мы проверяем результат её работы, а проверять exit code средствами bash намного проще, чем строку. К тому же, получить из неё строку очень просто:
get-active-slot service && echo BLUE || echo GREEN.
А трёх условий точно хватает, чтобы различить все состояния?
Даже двух хватит, последнее тут просто для полноты, чтобы не писать else.
Осталась неопределённой только функция, возвращающая конфиги nginx: get-nginx-config service_name deployment_slot. По аналогии с хелсчеком, тут можно задать любой конфиг для любого сервиса. Из интересного — только cat <<- EOF, ki omogoča odstranitev vseh tabulatorjev na začetku. Res je, da cena lepega oblikovanja — mešani tabulatorji s presledki, kar danes velja za zelo slabo noto. Vendar bash prisili tabulatorje, v nginx konfiguraciji pa bi bilo prav tako dobro imeti normalno oblikovanje. Skratka, tukaj se mešanje tabulatorjev s presledki zdi res najboljša rešitev med najslabšimi. Vendar pa tega v spodnjem odlomku ne boste videli, saj Habr 'naredi dobro', tako da vse tabulatorje spremeni v 4 presledke in naredi EOF neveljavnega. .
Da se ne bi dvakrat vračali, takoj povem o
cat << 'EOF', ki se bo še pojavil naprej. Če preprosto napišetecat << EOF, se v heredoc izvaja interpolacija nizov (odprte so spremenljivke ($foo), klici ukazov ($(bar)) itd.), če pa oznako konca dokumenta obdajate z enojnimi narekovaji, se interpolacija izklopi in znak$se izpiše, kot je. Kar potrebujete za vstavljanje skripta v drug skript.
get-nginx-config() {
local usage_msg="Uporaba: ${FUNCNAME[0]} ime_storitve delovna_mesta"
local service=${1?$usage_msg}
local slot=${2?$usage_msg}
[ "$slot" == BLUE ] || [ "$slot" == GREEN ] || return 1
local container_name=${service}_${slot}
case $service in
# Dodajte specifične nginx nastavitve za vaše storitve tukaj
*) nginx-config-simple-service $container_name:8080 ;;
esac
}
nginx-config-simple-service() {
local usage_msg="Uporaba: ${FUNCNAME[0]} proxy_pass"
local proxy_pass=${1?$usage_msg}
cat << EOF
server {
listen 80;
location / {
proxy_pass http://$proxy_pass;
}
}
EOF
}To je celoten skript. In tu za prenos preko wget ali curl.
Izvajanje parameteriziranih skriptov na oddaljenem strežniku
Prišel je čas, da potrkamo na ciljni strežnik. Tokrat localhost kulturno ustreza:
$ ssh-copy-id localhost
/usr/bin/ssh-copy-id: INFO: poskus prijave z novim ključem, da filtrirate vse, ki so že nameščeni
/usr/bin/ssh-copy-id: INFO: 1 ključ(ov) ostane za namestitev -- če vas zdaj pozove, je to za namestitev novih ključev
himura@localhostova geslo:
Število dodanih ključev: 1
Zdaj poskusite prijavo v napravo z: "ssh 'localhost'"
in preverite, da so bili dodani samo želeni ključi.Napisali smo skript za implementaciju koji prenosi prethodno sastavljenu sliku na ciljni server i bespravno zamenjuje kontejner usluge, ali kako ga izvršiti na udaljenoj mašini? Skript ima argumente jer je univerzalan i može implementirati više usluga pod jednim reverz-proksijem (konfiguracije nginx mogu rešiti koji će servis biti na kojem url-u). Skript ne može biti sačuvan na serveru, jer u tom slučaju ne možemo automatski ažurirati (radi ispravki grešaka i dodavanja novih usluga), a uopšte, stanje = zlo.
Rešenje 1: Držite skript na serveru, ali svaki put ga kopirajte preko scp. Zatim se povezati preko ssh i izvršiti skript sa neophodnim argumentima.
Mane:
- Dve akcije umesto jedne
- Mesto gde kopirate možda ne postoji, ili nemate pristup njemu, ili se skript može izvršavati u trenutku zamene.
- Poželjno je ukloniti (izbrisati skript) nakon sebe.
- Već tri akcije.
Rešenje 2:
- U skriptu držati samo definicije funkcija i uopšte ništa ne pokretati
- S pomočjo
seddodavati na kraj poziv funkcije - Sve to direktno slati u shh preko pipe-a (
|)
Prednosti:
- Zaista bez stanja
- Bez standardnih entiteta
- Zabavno je
Samo da to bude bez Ansibla. Da, sve je već izmišljeno. Da, bicikl. Pogledajte, kakav jednostavan, elegantan i minimalistički bicikl:
$ 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
Povezivanje na localhost...
Ura! Funkcija 'deploy' se izvršava na 'hut' sa argumentom 'magic-porridge-pot'Međutim, ne možemo biti sigurni da na udaljenom hostu postoji adekvatan bash, tako da ćemo dodati malu proveru na početak (to umesto ):
if [ "$SHELL" != "/bin/bash" ]
then
echo "Skripta '$SHELL' nije podržana od strane 'deploy.sh'. Postavite 'bash' na '$USER@$HOSTNAME'."
exit 1
fiA sada sve zaista:
$ 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
Pos sending gzipped image 'uptimer' to 'localhost' via ssh...
Loaded image: uptimer:latest
Connecting to 'localhost' via ssh to seamlessly deploy 'uptimer'...
Deploying 'uptimer_GREEN' instead 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!Т الآن можно открыть в браузере, запустить деплоймент ещё раз и убедиться, что он проходит без перебоев, обновляя страницу по КД во время выкладки.
Не забывайте убираться после работы :3
$ docker rm -f uptimer_GREEN reverse-proxy
uptimer_GREEN
reverse-proxy
$ docker network rm web-gateway
web-gateway
$ cd ..
$ rm -r blue-green-deploymentIzvor: habr.com
