In dit artikel gaan we met behulp van , , en een naadloze uitrol van een webapplicatie organiseren. is een techniek waarmee je een applicatie onmiddellijk kunt updaten zonder dat een enkele aanvraag wordt afgewezen. Het is een van de strategieƫn voor zero downtime deployment en is het beste geschikt voor applicaties met ƩƩn instantie, maar met de mogelijkheid om daarnaast een tweede, werkende instantie te laden.
Stel, je hebt een webapplicatie die door veel klanten actief wordt gebruikt, en het is absoluut niet mogelijk om deze enkele seconden stil te leggen. Maar je hebt dringend een bibliotheekupdate, een bugfix of een nieuwe coole functie nodig. In een normale situatie zou je de applicatie moeten stoppen, vervangen en opnieuw opstarten. Bij Docker kun je deze eerst vervangen en dan opnieuw opstarten, maar er zal altijd een periode zijn waarin aanvragen naar de applicatie niet worden verwerkt, aangezien een applicatie meestal enige tijd nodig heeft voor de initiƫle opstart. En wat als deze opgestart wordt, maar niet werkt? Laten we deze taak oplossen met minimale middelen en maximaal elegant.
DISCLAIMER: Het grootste deel van het artikel is gepresenteerd in een experimenteel formaat - in de vorm van een console-sessie-opname. Ik hoop dat dit niet te moeilijk te volgen is en dat deze code zichzelf voldoende documenteert. Stel je voor dat dit geen eenvoudige codefragmenten zijn, maar papier van een 'ijzeren' telegraaf.
Interessante technieken die moeilijk te vinden zijn door alleen maar de code te lezen, worden aan het begin van elk hoofdstuk beschreven. Als er iets onduidelijk is, zoek dan op en controleer dit in (gelukkig werkt het weer, aangezien Telegram weer toegankelijk is). Wat niet te vinden is, vraag het in de reacties. Ik vul het betreffende gedeelte 'Interessante technieken' graag aan.
Laten we beginnen.
$ mkdir blue-green-deployment && cd $_Dienst
Laten we een testservice maken en deze in een container plaatsen.
Interessante technieken
cat < file-name( + ) - is een manier om een meerregelig bestand met ƩƩn opdracht te maken. Alles wat bash leest van/dev/stdinna deze regel en tot de regelEOFzal worden opgeslagen infile-name.wget -qO- URL() - om het ontvangen document via HTTP weer te geven in/dev/stdout(vergelijkbaar metcurl URL).
Afdrukken
Ik snijd de snippet speciaal door om de markup voor Python in te schakelen. Aan het einde komt er nog zo'n stuk. Beschouw het alsof op deze plekken het papier is gesneden om overgedragen te worden aan de highlight afdeling (waar de code met hand gemarkeerd werd met markeerstiften), en daarna zijn deze stukken weer teruggeplakt.
$ cat < uptimer.pyvan http.server import BaseHTTPRequestHandler, HTTPServer
van tijd import monotonic
app_versie = 1
app_naam = f'Uptimer v{app_versie}.0'
laden_seconden = 15 - app_versie * 5
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
if self.path == '':
try:
t = monotonic() - server_start
if t < laden_seconden:
self.send_error(503)
else:
self.send_response(200)
self.send_header('Content-Type', 'text/html')
self.end_headers()
response = f'<h2>{app_naam} draait al {t:3.1f} seconden.</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_naam} (laadt in {laden_seconden} sec.) gestart.')
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 .
Verzendt buildcontext naar de Docker-daemon 39.42kB
Stap 1/4 : FROM python:alpine
---> 8ecf5a48c789
Stap 2/4 : EXPOSE 8080
---> Gebruik cache
---> cf92d174c9d3
Stap 3/4 : COPY uptimer.py app.py
---> a7fbb33d6b7e
Stap 4/4 : CMD [ "python", "-u", ".\/app.py" ]
---> Running in 1906b4bd9fdf
Verwijdert tussenliggende container 1906b4bd9fdf
---> c1655b996fe8
Succesvol gebouwd c1655b996fe8
Succesvol getagd 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 seconden geleden Op 5 seconden 0.0.0.0:8080->8080/tcp uptimer
$ docker logs uptimer
Uptimer v1.0 (laadt in 10 sec.) gestart.
$ wget -qSO- http:\/\/localhost:8080
HTTP\/1.0 503 Service Unavailable
Server: BaseHTTP\/0.6 Python\/3.8.3
Date: za, 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: za, 22 aug 2020 19:52:45 GMT
Content-Type: text\/html
<h2>Uptimer v1.0 draait al 15,4 seconden.</h2>
$ docker rm --force uptimer
uptimerReverse proxy
Om ons applicatie eindelijk onopgemerkt te kunnen veranderen, moet er een andere entiteit voor staan die de vervangingen verbergt. Dit kan een webserver zijn. in . De reverse proxy staat tussen de client en de applicatie. Het accepteert verzoeken van clients en stuurt deze door naar de applicatie, terwijl het de antwoorden van de applicatie weer naar de clients stuurt.
De applicatie en de reverse proxy kunnen binnen Docker worden verbonden met behulp van . Op deze manier hoeft de container met de applicatie geen poort in het host-systeem door te geven, wat het mogelijk maakt om de applicatie maximaal te isoleren van bedreigingen van buitenaf.
Als de reverse proxy op een andere host draait, moet je docker network opgeven en de applicatie met de reverse proxy verbinden via het hostnetwerk door de poort door te geven. applicatie parameter --publish, net als bij de eerste opstart en zoals bij de reverse proxy.
We zullen de reverse proxy op poort 80 draaien, omdat dit precies de entiteit is die naar de buitenwereld moet luisteren. Als poort 80 op jouw testhost al bezet is, wijzig dan de parameter. --publish 80:80 en een werkende opdracht krijgen. --publish ANY_FREE_PORT:80.
Interessante technieken
- "In door de gebruiker gemaakte Docker-netwerken kunnen containers niet alleen per IP-adres met elkaar communiceren. De naam van de container wordt ook vertaald naar zijn IP-adres" (, punt 5 van de Docker-codex).
Afdrukken
$ 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 draait al 11,5 seconden.</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 seconden geleden Up 25 seconden 0.0.0.0:80->80\/tcp reverse-proxy
a1105f1b583d uptimer "python -u .\/app.py" Ongeveer een minuut geleden Up Ongeveer een minuut 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: Za, 22 Aug 2020 19:56:24 GMT
Content-Type: text\/html
Transfer-Encoding: chunked
Connection: keep-alive
<h2>Uptimer v1.0 draait al 104,1 seconden.</h2>Naadloze implementatie
We zullen een nieuwe versie van de applicatie uitrollen (met een tweevoudige boost in startup-prestaties) en proberen deze naadloos te implementeren.
Interessante technieken
echo 'my text' | docker exec -i my-container sh -c 'cat > /my-file.txt'ā Schrijf tekstmy textnaar bestand/my-file.txtbinnen de containermy-container.cat > /my-file.txtā Schrijf de inhoud van de standaardinvoer naar een bestand/dev/stdin.
Afdrukken
$ sed -i "s/app_version = 1/app_version = 2/" uptimer.py
$ docker build --tag uptimer .
Verzending bouwcontext naar Docker daemon 39.94kB
Stap 1/4 : VAN python:alpine
---> 8ecf5a48c789
Stap 2/4 : EXPOSE 8080
---> Hierbij wordt cache gebruikt
---> cf92d174c9d3
Stap 3/4 : KOPIEER uptimer.py app.py
---> 3eca6a51cb2d
Stap 4/4 : CMD [ "python", "-u", ".\/app.py" ]
---> Uitvoering in 8f13c6d3d9e7
Verwijdering van tussencontainer 8f13c6d3d9e7
---> 1d56897841ec
Met succes gebouwd 1d56897841ec
Met succes getagd uptimer:latest
$ docker run --detach --rm --name uptimer_BLUE --network web-gateway uptimer
96932d4ca97a25b1b42d1b5f0ede993b43f95fac3c064262c5c527e16c119e02
$ docker logs uptimer_BLUE
Uptimer v2.0 (laadt in 5 sec.) gestart.
$ docker run --rm --network web-gateway alpine wget -qO- http://uptimer_BLUE:8080
<h2>Uptimer v2.0 draait nu al 23,9 seconden.</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 {
luister 80;
locatie / {
proxy_pass http://uptimer_BLUE:8080;
}
}
$ docker exec reverse-proxy nginx -s reload
2020/06/25 21:22:23 [notice] 68#68: signaalproces gestart
$ wget -qO- http://localhost
<h2>Uptimer v2.0 draait nu al 63,4 seconden.</h2>
$ docker rm -f uptimer
uptimer
$ wget -qO- http://localhost
<h2>Uptimer v2.0 draait nu al 84,8 seconden.</h2>
$ docker ps
CONTAINER-ID IMAGE COMMAND AANGEMAAKT STATUS POORTEN NAAM
96932d4ca97a uptimer "python -u .\/app.py" Ongeveer een minuut geleden Actief Ongeveer een minuut 8080/tcp uptimer_BLUE
80695a822c19 nginx:alpine "\/docker-entrypoint.…" 8 minuten geleden Actief 8 minuten 0.0.0.0:80->80/tcp reverse-proxyIn deze fase wordt het image direct op de server gebouwd, wat vereist dat de bronschriften daar beschikbaar zijn, en het belast de server met onnodig werk. De volgende stap zal zijn om de constructie van het image naar een aparte machine (bijvoorbeeld in een CI-systeem) te verplaatsen en het daarna naar de server te verzenden.
Images overzetten
Helaas heeft het weinig zin om afbeeldingen van localhost naar localhost over te zetten, dus deze sectie kan alleen worden verkend als je twee hosts met Docker tot je beschikking hebt. In de minimalistische opzet ziet het er ongeveer zo uit:
$ 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.9MBOpdracht docker save slaat de gegevens van de afbeelding op in een .tar-archief, wat betekent dat het ongeveer 1,5 keer zoveel weegt als het in gecomprimeerde vorm zou wegen. Laten we het daarom comprimeren om tijd en bandbreedte te besparen:
$ docker image save uptimer | gzip | ssh production-server 'zcat | docker image load'
Loaded image: uptimer:latestDaarnaast kun je het overdrachtsproces volgen (hiervoor heb je echter een externe tool nodig):
$ docker image save uptimer | gzip | pv | ssh production-server 'zcat | docker image load'
25,7MiB 0:01:01 [ 425KiB/s] [ ]
Loaded image: uptimer:latestTip: Als je een hoop parameters nodig hebt voor de SSH-verbinding met de server, gebruik je mogelijk het bestand niet
~/.ssh/config.
Overdracht van afbeeldingen via docker image save/load is de meest minimalistische methode, maar niet de enige. Er zijn ook andere:
- Container Registry (de industrie standaard).
- Verbind met de Docker-daemon van de server vanaf een andere host:
- Omgevingsvariabele
DOCKER_HOST. - Opdrachtregelparameter
-Hof--hosttooldocker-compose. docker context
- Omgevingsvariabele
De tweede methode (met drie implementatievarianten) is goed beschreven in het artikel .
deploy.sh
Laten we alles wat we handmatig hebben gedaan samenvoegen in ƩƩn script. We beginnen met de top-level functie en kijken dan naar de andere die daarin worden gebruikt.
Interessante technieken
${parameter?err_msg}is een van de spreuken van bash-magic (aka ). Alsparameterniet is opgegeven, geef danerr_msgweer en verlaat met code 1.docker --log-driver journaldis standaard de logging driver van Docker en dat is een tekstbestand zonder enige rotatie. Met deze aanpak vullen de logs snel de schijf, dus voor een productieomgeving is het noodzakelijk om de driver te vervangen door een slimmere.
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
}Gebruikte functies:
ensure-reverse-proxyā Zorgt ervoor dat de reverse proxy werkt (handig voor de eerste deployment)get-active-slot service_nameā Bepaalt welke slot momenteel actief is voor de opgegeven service (BLAUWofGROEN)get-service-status service_name deployment_slotā Bepaalt of de service klaar is om inkomende aanvragen te verwerkenset-active-slot service_name deployment_slotā Wijzigt de nginx-configuratie in de reverse proxy container
Volgorde:
ensure-reverse-proxy() {
is-container-up reverse-proxy && return 0
echo "Reverse-proxy aan het implementeren..."
docker network create web-gateway
docker run
--detach
--restart altijd
--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?"Gebruik: ${FUNCNAME[0]} container_naam"}
[ -n "$(docker ps -f name=${container} -q)" ]
return $?
}
get-active-slot() {
local service=${1?"Gebruik: ${FUNCNAME[0]} service_naam"}
if is-container-up ${service}_BLUE && is-container-up ${service}_GREEN; then
echo "Botsing gedetecteerd! ${service}_GREEN stoppen..."
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="Gebruik: ${FUNCNAME[0]} service_naam deployment_slot"
local service=${1?usage_msg}
local slot=${2?$usage_msg}
case $service in
# Voeg specifieke healthcheck-paden voor uw services hier toe
*) local health_check_port_path=":8080/" ;;
esac
local health_check_address="http://${service}_${slot}${health_check_port_path}"
echo "Verzoek om '$health_check_address' binnen het 'web-gateway' docker netwerk:"
docker run --rm --network web-gateway alpine
wget --timeout=1 --quiet --server-response $health_check_address
return $?
}
set-active-slot() {
local usage_msg="Gebruik: ${FUNCNAME[0]} service_naam 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
}Functie get-active-slot vereist enige toelichting:
Waarom retourneert het een nummer en geeft het geen string weer?
Toch controleren we het resultaat in de aanroepende functie; het is veel eenvoudiger om de exitcode in bash te controleren dan een string. Bovendien is het heel eenvoudig om een string eruit te krijgen:
get-active-slot service && echo BLUE || echo GREEN.
Hebben we echt drie voorwaarden nodig om alle toestanden te onderscheiden?
Twee zijn zelfs voldoende; de laatste is hier gewoon voor de volledigheid, zodat we niet hoeven te schrijven. else.
De functie die de nginx-configuraties retourneert is nog onbepaald: get-nginx-config service_naam deployment_slot. Net als bij de healthcheck kan hier elke configuratie voor elke service worden ingesteld. Wat interessant is ā alleen cat <<- EOF, waardoor alle tabs aan het begin kunnen worden verwijderd. De prijs van nette opmaak is echter gemengde tabs met spaties, wat tegenwoordig als zeer onfatsoenlijk wordt beschouwd. Maar bash dwingt tabs af, en het zou ook prettig zijn om normale opmaak in de nginx-configuratie te hebben. Kortom, hier lijkt de mix van tabs en spaties echt de beste oplossing van de slechtste opties te zijn. Echter, in de onderstaande snippet zult u dit niet zien, omdat habr 'het goed doet', door alle tabs te vervangen door 4 spaties en EOF ongeldig te maken. .
Om twee keer te voorkomen dat ik dezelfde informatie geef, zal ik direct vertellen over
cat << 'EOF', dat verderop ook nog zal voorkomen. Als je gewoon schrijftcat << EOF, dan vindt er binnen de heredoc interpolatie van de string plaats (variabelen worden onthuld ($foo), opdrachtoproepen ($(bar)) enzovoort), en als je het eindteken van het document tussen enkele aanhalingstekens plaatst, dan wordt de interpolatie uitgeschakeld en het teken$wordt letterlijk weergegeven. Dat is wat je nodig hebt om een script in een ander script in te voegen.
get-nginx-config() {
local usage_msg="Gebruik: ${FUNCNAME[0]} servicenaam implementatieslot"
local service=${1?$usage_msg}
local slot=${2?$usage_msg}
[ "$slot" == BLUE ] || [ "$slot" == GREEN ] || return 1
local container_name=${service}_${slot}
case $service in
# Voeg specifieke nginx-configs voor uw diensten hier toe
*) nginx-config-simple-service $container_name:8080 ;;
esac
}
nginx-config-simple-service() {
local usage_msg="Gebruik: ${FUNCNAME[0]} proxy_pass"
local proxy_pass=${1?$usage_msg}
cat << EOF
server {
listen 80;
location / {
proxy_pass http://$proxy_pass;
}
}
EOF
}Dit is het volledige script. En hier is om te downloaden via wget of curl.
Het uitvoeren van geparameteriseerde scripts op een externe server
Het is tijd om in te loggen op de doelserver. Dit keer localhost is totaal geschikt:
$ ssh-copy-id localhost
/usr/bin/ssh-copy-id: INFO: probeert in te loggen met de nieuwe sleutel(els), om alle reeds geĆÆnstalleerde te filteren
/usr/bin/ssh-copy-id: INFO: 1 sleutel(s) blijven om geĆÆnstalleerd te worden -- als u nu wordt gevraagd, is het om de nieuwe sleutels te installeren
himura@localhost's wachtwoord:
Aantal toegevoegde sleutel(s): 1
Probeer nu in te loggen op de machine met: "ssh 'localhost'"
en controleer of alleen de sleutel(s) die je wilde, zijn toegevoegd.We wrote a deployment script that transfers a pre-compiled image to the target server and seamlessly replaces the service container, but how do we execute it on a remote machine? The script has arguments since it is versatile and can deploy multiple services under one reverse proxy (you can manage which service connects to which URL using nginx configurations). The script cannot be stored on the server because we won't be able to automatically update it (for bug fixes and adding new services), and generally, state = evil.
Solution 1: Store the script on the server but copy it each time via scp. Then connect via ssh and execute the script with the necessary arguments.
Nadelen:
- Two actions instead of one.
- The destination where you copy may not exist, or there may not be access, or the script may execute during the replacement.
- It's advisable to clean up afterwards (delete the script).
- Now three actions.
Solution 2:
- Keep only function definitions in the script and don't execute anything.
- Met
sedAppend a function call at the end. - Send all of this directly to shh through a pipe (
|)
Voordelen:
- Truly stateless.
- No boilerplate entities.
- Feeling cool.
Let's just avoid Ansible. Yes, everything has already been invented. Yes, the bicycle. Look at this simple, elegant, and minimalist bicycle:
$ 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
Connecting to localhost...
Yay! The 'deploy' function is executing on 'hut' with the argument 'magic-porridge-pot'.However, we cannot be certain that there is an adequate bash on the remote host, so let's add a small check at the beginning (this instead of ):
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
fiAnd now everything is real:
$ 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
Gezipte afbeelding 'uptimer' naar 'localhost' verzenden via ssh...
Afbeelding geladen: uptimer:latest
Verbinden met 'localhost' via ssh om 'uptimer' naadloos te implementeren...
'Uptimer_GREEN' implementeren ter vervanging van 'uptimer_BLUE'...
06f5bc70e9c4f930e7b1f826ae2ca2f536023cc01e82c2b97b2c84d68048b18a
Container gestart. Gezondheid controleren...
'http://uptimer_GREEN:8080/' aanvragen binnen het 'web-gateway' docker netwerk:
HTTP/1.0 503 Service Unavailable
wget: server gaf fout terug: HTTP/1.0 503 Service Unavailable
Nieuwe 'uptimer_GREEN' service is nog niet klaar. Wachten (1)...
'http://uptimer_GREEN:8080/' aanvragen binnen het 'web-gateway' docker netwerk:
HTTP/1.0 503 Service Unavailable
wget: server gaf fout terug: HTTP/1.0 503 Service Unavailable
Nieuwe 'uptimer_GREEN' service is nog niet klaar. Wachten (2)...
'http://uptimer_GREEN:8080/' aanvragen binnen het 'web-gateway' docker netwerk:
HTTP/1.0 200 OK
Server: BaseHTTP/0.6 Python/3.8.3
Datum: za, 22 aug 2020 20:15:50 GMT
Content-Type: text/html
Nieuwe 'uptimer_GREEN' service lijkt OK. Overstappen...
nginx: de configuratiebestanden /etc/nginx/nginx.conf syntaxis is ok
nginx: configuratiebestand /etc/nginx/nginx.conf test is succesvol
2020/08/22 20:15:54 [notice] 97#97: signaalproces gestart
De 'uptimer_GREEN' service is live!
'Uptimer_BLUE' beƫindigen...
uptimer_BLUE
Totaal teruggewonnen ruimte: 0B
Implementatie succesvol!Nu kan je openen in de browser, de implementatie nogmaals uitvoeren en controleren of deze naadloos verloopt door de pagina te verversen terwijl je aan het uitrollen bent.
Vergeet niet om op te ruimen na het werk :3
$ docker rm -f uptimer_GREEN reverse-proxy
uptimer_GREEN
reverse-proxy
$ docker network rm web-gateway
web-gateway
$ cd ..
$ rm -r blue-green-deploymentBron: habr.com
