U ovom članku ćemo uz pomoć , , i organizirati nevidljivo implementiranje web aplikacije. je tehnika koja omogućava trenutno ažuriranje aplikacije bez odbijanja nijednog zahteva. To je jedna od strategija zero downtime deployment i najbolje se uklapa u aplikacije sa jednim instancom, ali mogućnošću učitavanja pored njega drugog, spremnog za rad.
Recimo da imate web aplikaciju s kojom aktivno radi mnogo klijenata i ne može jednostavno stati na nekoliko sekundi. A potrebno vam je da implementirate ažuriranje biblioteke, ispravku greške ili novu sjajnu funkcionalnost. U normalnim okolnostima, trebalo bi da zaustavite aplikaciju, zamenite je i ponovo pokrenete. U slučaju dockera, možete prvo zameniti, a zatim ponovo pokrenuti, ali i dalje će postojati period tokom kojeg zahtevi za aplikaciju neće biti obrađeni, jer obično aplikaciji treba neko vreme za prvobitno učitavanje. A šta ako se pokrene, ali ispostavi se da nije funkcionalno? Ova situacija, hajde da je rešimo minimalnim sredstvima i maksimalno elegantno.
DISCLAIMER: Veći deo članka predstavljen je u eksperimentalnom formatu — u obliku snimka konzolne sesije. Nadam se da to neće biti previše teško za razumevanje i da će ovaj kod sam sebe dokumentovati u dovoljnoj meri. Za atmosferu, zamislite da ovo nisu samo kod snimci, već papir iz 'čeličnog' teletajpa.
Zanimljive tehnike koje je teško pronaći jednostavnim čitanjem koda opisane su na početku svake sekcije. Ako nešto još bude nejasno — guglajte i proverite u (srećom, ponovo funkcioniše, zbog ponovnog otvaranja Telegrama). Ono što se ne može guglati — pitajte u komentarima. Rado ću dopuniti odgovarajući deo 'Zanimljive tehnike'.
Krenimo.
$ mkdir blue-green-deployment && cd $_Servis
Napravimo eksperimentalni servis i stavimo ga u kontejner.
Zanimljive tehnike
cat < file-name( + ) — način da se stvori višelinijski fajl jednim komandama. Sve što bash pročita od/dev/stdinposle ove linije i do linijeEOFbiće zapisano ufile-name.wget -qO- URL() — da se izvede dobijeni HTTP dokument u/dev/stdout(analogcurl URL).
Štampanje
Namjerno prekinem snipet kako bih uključio naglašavanje za Python. Na kraju će biti još jedan takav dio. Smatrajte da su na tim mjestima papir razrezali za prijenos u odjel za naglašavanje (gdje su kod ručno bojili markerima), a zatim su te komade ponovno zalijepili.
$ cat < uptimer.pyiz http.server import BaseHTTPRequestHandler, HTTPServer
iz vremena 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} radi već {t:3.1f} sekundi.</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} (učitava se u {loading_seconds} sek.) pokrenut.')
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 radi već 15.4 sekundi.</h2>
$ docker rm --force uptimer
uptimerObrnuti proxy
Da bi naša aplikacija mogla neprimjetno promijeniti, potrebno je da ispred nje bude još neka entitet koji će sakriti njezinu promjenu. To može biti web server. u . Obrnuti proxy postavlja se između klijenta i aplikacije. Prima zahtjeve od klijenata i preusmjerava ih na aplikaciju, a odgovore aplikacije šalje klijentima.
Aplikaciju i obrnuti proxy možemo povezati unutar dockera pomoću . Na taj način, kontejneru s aplikacijom čak nije potrebno proslijediti port u host sustavu, što omogućuje maksimalnu izolaciju aplikacije od vanjskih prijetnji.
Ako obrnuti proxy bude na drugom hostu, morat ćemo odustati od docker network i povezati aplikaciju s obrnuti proxy preko host mreže, proslijedivši port. aplikacije parametrom --publish, kao pri prvom pokretanju i kao kod obrnuti proxy.
Obrnuti proxy ćemo pokrenuti na portu 80, jer je to zapravo ta entitet koja bi trebala slušati vanjske zahtjeve. Ako je 80. port zauzet na vašem testnom hostu, promijenite parametar. --publish 80:80 na --publish ANY_FREE_PORT:80.
Zanimljive tehnike
- „U docker mrežama koje je stvorio korisnik, kontejneri se mogu povezivati ne samo putem IP adrese. Ime kontejnera se također razrješava u njegovu IP adresu“ (, točka 5 docker kodeksa).
Štampanje
$ 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 radi 11.5 sekundi.</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 sekundi prije Up 25 sekundi 0.0.0.0:80->80\/tcp reverse-proxy
a1105f1b583d uptimer "python -u .\/app.py" Prije otprilike minute Up Prije otprilike 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: Sub, 22 Kol 2020 19:56:24 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Connection: keep-alive
<h2>Uptimer v1.0 radi 104.1 sekundi.</h2>Besprijekorno uvođenje
Izbacit ćemo novu verziju aplikacije (s dvostrukim poboljšanjem startup performansi) i pokušati je besprijekorno implementirati.
Zanimljive tehnike
echo 'my text' | docker exec -i my-container sh -c 'cat > /my-file.txt'— Zapisati tekstmy textu datoteku/my-file.txtunutar kontejneramy-container.cat > /my-file.txt— Zapisati u datoteku sadržaj standardnog ulaza/dev/stdin.
Štampanje
$ sed -i "s/app_version = 1/app_version = 2/" uptimer.py
$ docker build --tag uptimer .
Slanje konteksta build-a Docker demon-u 39.94kB
Korak 1/4 : FROM python:alpine
---> 8ecf5a48c789
Korak 2/4 : EXPOSE 8080
---> Korištenje keša
---> cf92d174c9d3
Korak 3/4 : COPY uptimer.py app.py
---> 3eca6a51cb2d
Korak 4/4 : CMD [ "python", "-u", "../app.py" ]
---> Izvodi se u 8f13c6d3d9e7
Uklanjanje međukontejnera 8f13c6d3d9e7
---> 1d56897841ec
Uspješno je izgrađen 1d56897841ec
Uspješno označeno uptimer:latest
$ docker run --detach --rm --name uptimer_BLUE --network web-gateway uptimer
96932d4ca97a25b1b42d1b5f0ede993b43f95fac3c064262c5c527e16c119e02
$ docker logs uptimer_BLUE
Uptimer v2.0 (uvođenje u 5 sekundi) je pokrenut.
$ docker run --rm --network web-gateway alpine wget -qO- http://uptimer_BLUE:8080
<h2>Uptimer v2.0 radi 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 [obavijest] 68#68: signal proces počeo
$ wget -qO- http://localhost
<h2>Uptimer v2.0 radi već 63.4 sekundi.</h2>
$ docker rm -f uptimer
uptimer
$ wget -qO- http://localhost
<h2>Uptimer v2.0 radi već 84.8 sekundi.</h2>
$ docker ps
ID KONTEJNERA SLIKA KOMANDA STVORENO STATUS PORTOVI IMENA
96932d4ca97a uptimer "python -u ./app.py" Prije oko minute Up Prije oko 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 izravno na serveru, što zahtijeva prisutnost izvora aplikacije, a također opterećuje server dodatnim radom. Sljedeći korak bit će izdvajanje gradnje slike na zasebnom stroju (npr. u CI sustavu) s naknadnim prijenosom na server.
Preuzimanje slika
Nažalost, prijenos slika s localhosta na localhost nema smisla, stoga ovaj odjeljak možete istražiti samo s dva hosta sa Dockerom. U minimalnom obliku to izgleda otprilike ovako:
$ 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.9MBKomanda docker save sprema podatke slike u .tar arhiv, tj. abit će otprilike 1.5 puta veći nego što bi mogao biti u komprimiranom formatu. Zbog toga ćemo ga komprimirati u ime uštede vremena i prometa:
$ docker image save uptimer | gzip | ssh production-server 'zcat | docker image load'
Loaded image: uptimer:latestOsim toga, možete pratiti proces prijenosa (iako za to treba treći alat):
$ docker image save uptimer | gzip | pv | ssh production-server 'zcat | docker image load'
25,7MiB 0:01:01 [ 425KiB/s] [ ]
Loaded image: uptimer:latestSavjet: Ako vam za povezivanje sa serverom putem SSH treba mnogo parametara, možda ne koristite datoteku
~/.ssh/config.
Prijenos slike putem docker image save/load je najminimalističnija metoda, ali ne i jedina. Ima i drugih:
- Container Registry (standard u industriji).
- Povežite se na Docker daemon servera s drugog hosta:
- Varijabla okruženja
DOCKER_HOST. - Parametar naredbenog retka
-Hili--hostalatdocker-compose. docker context
- Varijabla okruženja
Drugi način (s tri mogućnosti njegove implementacije) dobro je opisan u članku .
deploy.sh
Sada ćemo sve što smo radili ručno okupiti u jedan skript. Počnimo s top-level funkcijom, a zatim ćemo pogledati ostale koje se koriste u njoj.
Zanimljive tehnike
${parameter?err_msg}je jedan od čarobnjaka bash-magije (aka ). Akoparameternije postavljen, ispisatierr_msgi izaći s kodom 1.docker --log-driver journaldje osnovni vozač za evidentiranje koji se koristi u Dockeru, a koji koristi tekstualnu datoteku bez rotacije. Takav pristup brzo popunjava cijeli disk s logovima, stoga je za produkcijsko okruženje potrebno promijeniti vozača na pametniji.
Skript za postavljanje
deploy() {
local usage_msg="Korištenje: ${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 "Implementiram '$NEW' umjesto '$OLD'..."
docker run
--detach
--restart always
--log-driver journald
--name $NEW
--network web-gateway
$image_name || return 3
echo "Kontejner je započeo. Provjeravam stanje..."
for i in {1..20}
do
sleep 1
if get-service-status $image_name $new_slot
then
echo "Nova '$NEW' usluga izgleda u redu. Prebacujem glave..."
sleep 2 # Osigurajte da je usluga spremna
set-active-slot $image_name $new_slot || return 4
echo "'$NEW' usluga je aktivna!"
sleep 2 # Osigurajte da su svi zahtjevi obrađeni
echo "Ubijam '$OLD'..."
docker rm -f $OLD
docker image prune -f
echo "Implementacija uspješna!"
return 0
fi
echo "Nova '$NEW' usluga još nije spremna. Čekam ($i)..."
done
echo "Nova '$NEW' usluga se nije pokrenula, ubijam je. Neuspješna implementacija T_T"
docker rm -f $NEW
return 5
}Korištene funkcije:
ensure-reverse-proxy— Provjerava da li reverzni proxy radi (korisno za prvu implementaciju)get-active-slot service_name— Određuje koji je trenutni slot aktivan za zadanu uslugu (BLUEiliGREEN)get-service-status service_name deployment_slot— Utvrđuje je li usluga spremna za obradu ulaznih zahtjevaset-active-slot service_name deployment_slot— Mijenja konfiguraciju nginx u kontejneru reverznog proxyja
Redom:
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
}Funkcija get-active-slot potrebno malo pojašnjenja:
Zašto vraća broj, a ne ispisuje string?
I dalje u pozivnoj funkciji provjeravamo rezultat njenog rada, a provjeravati exit code putem basha mnogo je jednostavnije nego string. Osim toga, dobiti string iz toga je vrlo lako:
get-active-slot service && echo BLUE || echo GREEN.
Da li tri uvjeta zaista dovoljno da razlikuju sve stanje?
Dovoljna su i dva, zadnje je ovde samo za potpunost, da ne pišem else.
Neodređena je samo funkcija koja vraća nginx konfiguracije: get-nginx-config service_name deployment_slot. Po analogiji sa healthcheckom, ovde se može postaviti bilo koja konfiguracija za bilo koju uslugu. Zanimljivo je samo cat <<- EOF, što omogućuje uklanjanje svih tabova na početku. Istina, cijena pristojnog oblikovanja su miješani tabovi s razmacima, što se danas smatra vrlo lošim stilom. No, bash forsira tabove, a u nginx konfiguraciji također bi bilo dobro imati normalno oblikovanje. Ukratko, ovdje se čini da je miješanje tabova s razmacima zapravo najbolja opcija među lošim. Međutim, u isječku dolje to nećete vidjeti, jer Habr „radi dobro“, mijenjajući sve tabove u 4 razmaka i čineći EOF nevažećim. .
Da ne bismo dvaput govorili, odmah ću pričati o
cat << 'EOF', koji će se opet susresti. Ako samo napišetecat << EOF, unutar heredoca se vrši interpolacija stringa (otvaraju se varijable ($foo), pozivi naredbi ($(bar)) itd.), a ako se znak kraja dokumenta stavi u jednostruke navodnike, interpolacija se onemogućava i znak$se ispisuje onako kako jest. To je potrebno za umetanje skripte unutar druge skripte.
get-nginx-config() {
local usage_msg="Upotreba: ${FUNCNAME[0]} naziv_usluge slot_deploymana"
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 konfiguracije za vaše usluge ovdje
*) nginx-config-simple-service $container_name:8080 ;;
esac
}
nginx-config-simple-service() {
local usage_msg="Upotreba: ${FUNCNAME[0]} proxy_pass"
local proxy_pass=${1?$usage_msg}
cat << EOF
server {
listen 80;
location / {
proxy_pass http://$proxy_pass;
}
}
EOF
}To je cijela skripta. I evo za preuzimanje putem wget ili curl.
Izvršavanje parametriziranih skripti na udaljenom poslužitelju
Došlo je vrijeme za povezivanje s ciljnim poslužiteljem. Ovaj put localhost savršeno odgovara:
$ ssh-copy-id localhost
/usr/bin/ssh-copy-id: INFO: pokušaj prijave s novim ključem(ima), da filtrira sve koji su već instalirani
/usr/bin/ssh-copy-id: INFO: 1 ključ(ova) ostaje za instalaciju -- ako se sada zatraži, to je za instalaciju novih ključeva
himura@localhostova lozinka:
Broj dodanih ključeva: 1
Sada pokušajte prijaviti se na računalo s: "ssh 'localhost'"
i provjerite jesu li dodani samo ključevi koje ste željeli.Napisali smo skriptu za implementaciju koja prebacuje prethodno sastavljenu sliku na ciljni server i neprimjetno zamjenjuje kontejner usluge, ali kako je izvršiti na udaljenoj mašini? Skripta ima argumente, budući da je univerzalna i može implementirati više usluga za jedan reverzni proxy (konfiguracije nginx-a mogu se preusmjeriti po kojoj URL-u će koja usluga biti). Skriptu nije moguće pohraniti na serveru jer tu ne bismo mogli automatski ažurirati (u svrhu ispravki grešaka i dodavanja novih usluga), a uostalom, stanje = zlo.
Rješenje 1: Čuvati skriptu na serveru, ali je svaki put kopirati putem scp. Zatim se priključiti putem ssh i izvršiti skriptu s potrebnim argumentima.
Mane:
- Dva koraka umjesto jednog
- Mjesta na koja kopirate možda nema, ili nemate pristup, ili se skripta može izvršavati tijekom zamjene.
- Preporučljivo je ukloniti nakon upotrebe (izbrisati skriptu).
- Sada imamo tri koraka.
Rješenje 2:
- Skriptu treba držati samo s definicijama funkcija i uopće ne pokretati ništa
- Pomoću
seddodati na kraj poziv funkcije - Sve ovo slati direktno u shh putem cijevi (
|)
Prednosti:
- Zaista bez stanja
- Bez suvišnih entiteta
- Super osjećaj
Samo da ne idemo na Ansible. Da, sve je već izmišljeno. Da, bicikl. Poglejte, 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
Spajanje na localhost...
Ura! Funkcija 'deploy' se izvršava na 'hut' s argumentom 'magic-porridge-pot'Međutim, ne možemo biti sigurni da na udaljenom hostu postoji adekvatan bash, pa ćemo dodati malu provjeru na početak (to umjesto ):
if [ "$SHELL" != "/bin/bash" ]
then
echo "Šell '$SHELL' nije podržan od strane 'deploy.sh'. Postavite ' /bin/bash' šell za '$USER@$HOSTNAME'."
exit 1
fiA sada sve pošteno:
$ 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
Slanje gzipane slike 'uptimer' na 'localhost' putem ssh...
Učitana slika: uptimer:latest
Povezivanje s 'localhost' putem ssh za neometano postavljanje 'uptimer'...
Postavljanje 'uptimer_GREEN' umjesto 'uptimer_BLUE'...
06f5bc70e9c4f930e7b1f826ae2ca2f536023cc01e82c2b97b2c84d68048b18a
Kontejner pokrenut. Provjera zdravlja...
Zahtjev za 'http://uptimer_GREEN:8080/' unutar docker mreže 'web-gateway':
HTTP/1.0 503 Usluga nedostupna
wget: server je vratio grešku: HTTP/1.0 503 Usluga nedostupna
Nova služba 'uptimer_GREEN' još nije spremna. Čekam (1)...
Zahtjev za 'http://uptimer_GREEN:8080/' unutar docker mreže 'web-gateway':
HTTP/1.0 503 Usluga nedostupna
wget: server je vratio grešku: HTTP/1.0 503 Usluga nedostupna
Nova služba 'uptimer_GREEN' još nije spremna. Čekam (2)...
Zahtjev za 'http://uptimer_GREEN:8080/' unutar docker mreže 'web-gateway':
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
Nova služba 'uptimer_GREEN' izgleda u redu. Prebacivanje glava...
nginx: konfiguracijska datoteka /etc/nginx/nginx.conf sintaksa je u redu
nginx: test konfiguracijske datoteke /etc/nginx/nginx.conf je uspješan
2020/08/22 20:15:54 [notice] 97#97: signal process started
Služba 'uptimer_GREEN' je aktivna!
Gasenje 'uptimer_BLUE'...
uptimer_BLUE
Ukupno oslobođen prostor: 0B
Implementacija uspješna!Sada možete otvoriti u pregledniku, ponovno pokrenuti implementaciju i osigurati da prolazi neometano tako da osvježite stranicu tijekom postavljanja.
Ne zaboravite očistiti nakon rada :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
