I den hÀr artikeln kommer vi att , , och organisera en sömlös distribusion av webbapplikationen. Àr en teknik som gör det möjligt att omedelbart uppdatera en applikation utan att avvisa nÄgra begÀrningar. Det Àr en av strategierna för zero downtime deployment och passar bÀst för applikationer med en instans, men med möjligheten att ladda en andra, redo att anvÀnda instans bredvid.
Anta att du har en webbapplikation som mÄnga anvÀndare aktivt anvÀnder, och den kan inte stanna i nÄgra sekunder. Du mÄste verkligen rulla ut en uppdatering, fixa en bugg eller introducera en ny spÀnnande funktion. I vanliga fall skulle du behöva stoppa applikationen, byta ut den och starta om den. Med Docker kan du först byta ut den och sedan starta om, men det kommer fortfarande att finnas en period dÄ begÀrningar till applikationen inte kommer att behandlas, eftersom applikationen vanligtvis behöver lite tid för att initialt ladda. Men vad om den startas, men Àr oanvÀndbar? SÄdana uppgifter, lÄt oss lösa dem med minimala medel och sÄ elegant som möjligt.
DISCLAIMER: Största delen av artikeln presenteras i ett experimentellt format â som en inspelning av en konsolsession. Jag hoppas att detta inte blir för svĂ„rt att ta till sig, och att denna kod dokumenterar sig sjĂ€lv tillrĂ€ckligt. För stĂ€mningens skull, förestĂ€ll dig att det inte bara Ă€r kodsnuttar, utan papper frĂ„n en "jĂ€rnhĂ„rd" teletype.
Intressanta tekniker som Ă€r svĂ„ra att googla bara genom att lĂ€sa koden beskrivs i början av varje avsnitt. Om nĂ„got fortfarande Ă€r oklart â googla och kolla i (lyckligtvis fungerar den igen pĂ„ grund av att Telegram har avblockerats). Det som inte kan googlas â frĂ„ga i kommentarerna. Jag fyller gĂ€rna pĂ„ den relevanta sektionen "Intressanta tekniker".
LÄt oss börja.
$ mkdir blue-green-deployment && cd $_TjÀnsten
LÄt oss skapa en försöksservice och placera den i en container.
Intressanta tekniker
cat < file-name( + ) â ett sĂ€tt att skapa en flerradig fil med ett kommando. Allt som bash lĂ€ser frĂ„n/dev/stdinefter denna rad och fram till radenEOFkommer att skrivas tillfile-name.wget -qO- URL() â skriver ut det mottagna dokumentet via HTTP till/dev/stdout(motsvarandecurl URL).
Utskrift
Jag delar medvetet upp snippeten för att inkludera syntaxmarkering för Python. I slutet kommer det att finnas en sÄdan bit till. TÀnk pÄ det som att papperet har klippts vid dessa stÀllen för att överlÀmnas till avdelningen för highlightning (dÀr koden fÀrgades manuellt med highlighters), och sedan klipptes dessa bitar tillbaka.
$ cat < uptimer.pyfrån http.server importera BaseHTTPRequestHandler, HTTPServer
från time importera 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} körs i {t:3.1f} sekunder.</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} (laddas på {loading_seconds} sek.) startad.')
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 (laddar på 10 sek.) startad.
$ wget -qSO- http:\/\/localhost:8080
HTTP\/1.0 503 Tjänsten är inte tillgänglig
Server: BaseHTTP\/0.6 Python\/3.8.3
Date: Lör, 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: Lör, 22 Aug 2020 19:52:45 GMT
Content-Type: text\/html
<h2>Uptimer v1.0 har kört i 15.4 sekunder.</h2>
$ docker rm --force uptimer
uptimerReverse proxy
För att vÄr applikation ska kunna bytas ut osynligt, mÄste det finnas en annan enhet framför den som döljer dess byte. Det kan vara en webbserver. pÄ . Reverse proxy installeras mellan klienten och applikationen. Den tar emot förfrÄgningar frÄn klienterna och vidarebefordrar dem till applikationen, och svaren frÄn applikationen skickas till klienterna.
Applikationen och reverse proxy kan kopplas samman inom Docker med hjÀlp av . PÄ sÄ sÀtt behöver inte applikationscontainern ens ha en port exponerad i vÀrdsystemet, vilket gör det möjligt att isolera applikationen maximalt frÄn externa hot.
Om reverse proxy kommer att bo pÄ en annan vÀrd mÄste vi avstÄ frÄn docker network och koppla applikationen till reverse proxy via vÀrdets nÀtverk genom att vidarebefordra en port. applikationen parametern --publish, precis som vid första starten och som hos reverse proxy.
Reverse proxy kommer att köras pÄ port 80, eftersom det Àr just denna enhet som bör lyssna pÄ det externa. Om port 80 Àr upptagen pÄ din testvÀrd, Àndra parametern. --publish 80:80 till --publish ANY_FREE_PORT:80.
Intressanta tekniker
- «I anvÀndardefinierade Docker-nÀtverk kan containrar kopplas inte bara via IP-adress. Namnet pÄ containern löses ocksÄ till dess IP-adress» (, punkt 5 i Docker-koden).
Utskrift
$ 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 har kört i 11,5 sekunder.</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 sekunder sedan Up 25 sekunder 0.0.0.0:80->80\/tcp reverse-proxy
a1105f1b583d uptimer "python -u .\/app.py" För ungefär en minut sedan Up För ungefär en minut 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 har kört i 104,1 sekunder.</h2>Sömlös deployment
Vi kommer att lansera en ny version av applikationen (med dubbelt sÄ hög startup-prestanda) och försöka deploya den sömlöst.
Intressanta tekniker
echo 'my text' | docker exec -i my-container sh -c 'cat > /my-file.txt'â Spara textmy texttill filen/my-file.txtinuti containernmy-container.cat > /my-file.txtâ Skriv till filen innehĂ„llet frĂ„n standardingĂ„ngen/dev/stdin.
Utskrift
$ sed -i "s/app_version = 1/app_version = 2/" uptimer.py
$ docker build --tag uptimer .
Skickar byggkontext till Docker-damon 39.94kB
Steg 1/4 : FRÅN python:alpine
---> 8ecf5a48c789
Steg 2/4 : EXPOSE 8080
---> Använder cache
---> cf92d174c9d3
Steg 3/4 : COPY uptimer.py app.py
---> 3eca6a51cb2d
Steg 4/4 : CMD [ "python", "-u", ".\/app.py" ]
---> Körs i 8f13c6d3d9e7
Tar bort mellanliggande container 8f13c6d3d9e7
---> 1d56897841ec
Framgångsrikt byggd 1d56897841ec
Framgångsrikt märkt uptimer:latest
$ docker run --detach --rm --name uptimer_BLUE --network web-gateway uptimer
96932d4ca97a25b1b42d1b5f0ede993b43f95fac3c064262c5c527e16c119e02
$ docker logs uptimer_BLUE
Uptimer v2.0 (laddar på 5 sek.) startad.
$ docker run --rm --network web-gateway alpine wget -qO- http://uptimer_BLUE:8080
<h2>Uptimer v2.0 har varit igång i 23.9 sekunder.</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 {
lyssna 80;
location / {
proxy_pass http://uptimer_BLUE:8080;
}
}
$ docker exec reverse-proxy nginx -s reload
2020/06/25 21:22:23 [notis] 68#68: signalprocessen startad
$ wget -qO- http://localhost
<h2>Uptimer v2.0 har varit igång i 63.4 sekunder.</h2>
$ docker rm -f uptimer
uptimer
$ wget -qO- http://localhost
<h2>Uptimer v2.0 har varit igång i 84.8 sekunder.</h2>
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
96932d4ca97a uptimer "python -u .\/app.py" För cirka en minut sedan Aktiv För cirka en minut 8080/tcp uptimer_BLUE
80695a822c19 nginx:alpine "\/docker-entrypoint.…" 8 minuter sedan Aktiv 8 minuter 0.0.0.0:80->80/tcp reverse-proxyI detta skede byggs bilden direkt pĂ„ servern, vilket krĂ€ver att applikationens kĂ€llkod finns dĂ€r samt belastar servern med extra arbete. NĂ€sta steg kommer att vara att dedikera byggandet av bilden till en separat maskin (t.ex. i CI-systemet) med efterföljande överföring till servern.
Ăverföring av bilder
TyvÀrr har det ingen mening att överföra bilder frÄn localhost till localhost, sÄ den hÀr sektionen kan endast utforskas om man har tvÄ vÀrdar med Docker tillgÀngliga. PÄ en minimal nivÄ ser det ut ungefÀr sÄ hÀr:
$ 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.9MBTeam docker save sparar bilddata i en .tar-arkiv, vilket betyder att den vÀger ungefÀr 1,5 gÄnger mer Àn den skulle göra i komprimerad form. SÄ lÄt oss komprimera den för att spara tid och trafik:
$ docker image save uptimer | gzip | ssh production-server 'zcat | docker image load'
Loaded image: uptimer:latestOch dessutom kan man övervaka överföringsprocessen (dock krÀvs en extern nyttjandeprogram för detta):
$ docker image save uptimer | gzip | pv | ssh production-server 'zcat | docker image load'
25,7MiB 0:01:01 [ 425KiB/s] [ ]
Loaded image: uptimer:latestTips: Om du behöver massor av parametrar för att ansluta till servern via SSH, kanske du inte anvÀnder filen
~/.ssh/config.
Ăverföring av en bild genom docker image save/load Ă€r den mest minimalistiska metoden, men inte den enda. Det finns andra:
- Container Registry (branschstandard).
- Anslut till Docker-daemonen pÄ servern frÄn en annan vÀrd:
- Miljövariabel
DOCKER_HOST. - Kommandoradparameter
-Heller--hostverktygetdocker-compose. docker context
- Miljövariabel
Ett andra sÀtt (med tre varianter av dess implementering) beskrivs vÀl i artikeln .
deploy.sh
Nu ska vi samla allt vi har gjort manuellt i ett skript. Vi börjar med toppnivÄfunktionen och ser sedan pÄ de andra som anvÀnds inom den.
Intressanta tekniker
${parameter?err_msg}â en av bash-magi (aka ). Omparameterinte Ă€r angiven, skriv uterr_msgoch avsluta med kod 1.docker --log-driver journaldâ som standard Ă€r Docker-loggdrivaren en textfil utan nĂ„gon rotation. Med detta tillvĂ€gagĂ„ngssĂ€tt fylls loggarna snabbt pĂ„ hela disken, sĂ„ för produktionsmiljöer mĂ„ste man byta loggdrivare till nĂ„got mer intelligent.
Deploymentskript
deploy() {
local usage_msg="AnvÀndning: ${FUNCNAME[0]} bild_namn"
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 "Installerar '$NEW' istÀllet för '$OLD'..."
docker run
--detach
--restart always
--log-driver journald
--name $NEW
--network web-gateway
$image_name || return 3
echo "BehÄllare startad. Kontrollerar hÀlsa..."
for i in {1..20}
do
sleep 1
if get-service-status $image_name $new_slot
then
echo "Ny '$NEW' tjÀnst verkar vara okej. VÀxlar huvud..."
sleep 2 # SÀkerstÀll att tjÀnsten Àr redo
set-active-slot $image_name $new_slot || return 4
echo "'$NEW' tjÀnst Àr live!"
sleep 2 # SÀkerstÀll att alla förfrÄgningar har behandlats
echo "Dödar '$OLD'..."
docker rm -f $OLD
docker image prune -f
echo "UppstÀllning lyckad!"
return 0
fi
echo "Ny '$NEW' tjÀnst Àr inte redo Ànnu. VÀntar ($i)..."
done
echo "Ny '$NEW' tjÀnst kunde inte startas, dödar den. Misslyckades med att installera T_T"
docker rm -f $NEW
return 5
}AnvÀnda funktioner:
ensure-reverse-proxyâ SĂ€kerstĂ€ller att reversproxy fungerar (nyttigt för första installationen)get-active-slot service_nameâ BestĂ€mmer vilken slot som för nĂ€rvarande Ă€r aktiv för den angivna tjĂ€nsten (BLUEellerGREEN)get-service-status service_name deployment_slotâ BestĂ€mmer om tjĂ€nsten Ă€r redo att ta emot inkommande förfrĂ„gningarset-active-slot service_name deployment_slotâ Ăndrar nginx-konfigurationen i reversproxycontainern
I ordning:
ensure-reverse-proxy() {
is-container-up reverse-proxy && return 0
echo "Implementerar 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?"AnvÀndning: ${FUNCNAME[0]} container_name"}
[ -n "$(docker ps -f name=${container} -q)" ]
return $?
}
get-active-slot() {
local service=${1?"AnvÀndning: ${FUNCNAME[0]} service_name"}
if is-container-up ${service}_BLUE && is-container-up ${service}_GREEN; then
echo "Kollision upptÀckt! Stoppar ${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="AnvÀndning: ${FUNCNAME[0]} service_name deployment_slot"
local service=${1?usage_msg}
local slot=${2?$usage_msg}
case $service in
# LÀgg till specifika hÀlsokontrollvÀgar för dina tjÀnster hÀr
*) local health_check_port_path=":8080/" ;;
esac
local health_check_address="http://${service}_${slot}${health_check_port_path}"
echo "BegÀr '$health_check_address' inom 'web-gateway' docker-nÀtverket:"
docker run --rm --network web-gateway alpine
wget --timeout=1 --quiet --server-response $health_check_address
return $?
}
set-active-slot() {
local usage_msg="AnvÀndning: ${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
}Funktionen get-active-slot krÀver nÄgra förtydliganden:
Varför returnerar den ett nummer istÀllet för att skriva ut en strÀng?
I alla fall kontrollerar vi resultatet av dess körning i den anropande funktionen, och det Àr mycket enklare att kontrollera exit-koden med hjÀlp av bash Àn en strÀng. Dessutom Àr det mycket enkelt att fÄ en strÀng frÄn den:
get-active-slot service && echo BLUE || echo GREEN.
Ăr tre villkor verkligen tillrĂ€ckligt för att sĂ€rskilja alla tillstĂ„nd?
TvÄ rÀcker, det sista hÀr Àr bara för fullstÀndighetens skull, för att slippa skriva. else.
Den Ă„terstĂ„ende odefinierade funktionen Ă€r den som returnerar nginx-konfigurationer: get-nginx-config service_name deployment_slot. PĂ„ liknande sĂ€tt som hĂ€lsokontrollen kan vilken konfiguration som helst för vilken tjĂ€nst som helst anges. Intressant nog â bara cat <<- EOF, vilket gör att man kan ta bort alla tabbkaraktĂ€rer i början. Men priset för fin formatering Ă€r blandade tabbkaraktĂ€rer med mellanslag, vilket idag anses vara vĂ€ldigt dĂ„ligt. Men bash tvingar fram tabbar, och i nginx-konfigurationen skulle det ocksĂ„ vara bra att ha en korrekt formatering. Kort sagt, hĂ€r verkar blandningen av tabbar och mellanslag vara den bĂ€sta lösningen av de dĂ„liga alternativen. Men i snippeten nedan kommer du inte att se detta, eftersom Habr "gör det bra" genom att byta ut alla tabbar mot fyra mellanslag och gör EOF ogiltigt. .
SÄ att jag slipper upprepa mig, lÄt mig berÀtta om
cat << 'EOF', som kommer att dyka upp senare. Om man bara skrivercat << EOF, sÄ görs interpolation av strÀngen (variablerna öppnas ($foo), kommandon anropas ($(bar)) osv.), men om man omger slutmarkeringen av dokumentet med enkla citattecken, dÄ stÀngs interpolation av och tecknet$skrivs ut som det Àr. Detta Àr precis vad som behövs för att infoga ett skript i ett annat skript.
get-nginx-config() {
lokal usage_msg="AnvÀndning: ${FUNCNAME[0]} service_name deployment_slot"
lokal service=${1?$usage_msg}
lokal slot=${2?$usage_msg}
[ "$slot" == BLUE ] || [ "$slot" == GREEN ] || return 1
lokal container_name=${service}_${slot}
case $service in
# LÀgg till specifika nginx-konfigurationer för dina tjÀnster hÀr
*) nginx-config-simple-service $container_name:8080 ;;
esac
}
nginx-config-simple-service() {
lokal usage_msg="AnvÀndning: ${FUNCNAME[0]} proxy_pass"
lokal proxy_pass=${1?$usage_msg}
cat << EOF
server {
lyssna 80;
plats / {
proxy_pass http://$proxy_pass;
}
}
EOF
}Detta Àr hela skriptet. Och hÀr Àr för nedladdning via wget eller curl.
Exekvering av parametriserade skript pÄ en fjÀrrserver
Det Àr dags att knacka pÄ mÄlservern. Den hÀr gÄngen localhost funkar det bra:
$ ssh-copy-id localhost
/usr/bin/ssh-copy-id: INFO: försöker logga in med de nya nycklarna, för att filtrera bort de som redan Àr installerade
/usr/bin/ssh-copy-id: INFO: 1 nyckel ÄterstÄr att installera -- om du nu blir tillfrÄgad Àr det för att installera de nya nycklarna
himura@localhost's lösenord:
Antal nycklar tillagda: 1
Försök nu att logga in pÄ maskinen med: "ssh 'localhost'"
och kontrollera att endast de nycklar du ville ha lades till.Vi har skrivit ett deploymentskript som överför en förberedd bild till den valda servern och sömlöst byter ut tjÀnstens container, men hur utför man det pÄ en fjÀrrdator? Skriptet har argument eftersom det Àr universellt och kan distribuera flera tjÀnster under en omvÀnd proxy (genom nginx-konfigurationerna kan man stÀlla in vilken URL som korrelerar med vilken tjÀnst). Skriptet kan inte lagras pÄ servern, eftersom vi annars inte skulle kunna uppdatera det automatiskt (i syfte att fixa buggar och lÀgga till nya tjÀnster), och dessutom, state = ont.
Lösning 1: För att lagra skriptet pÄ servern, men kopiera det varje gÄng via scp. Anslut sedan via ssh och kör skriptet med nödvÀndiga argument.
Nackdelar:
- TvÄ ÄtgÀrder istÀllet för en.
- Det kan hÀnda att det stÀlle dit du kopierar inte finns, eller att det inte gÄr att nÄ, eller att skriptet kan köras vid tidpunkten för bytet.
- Det Àr fördelaktigt att stÀda upp efter sig (ta bort skriptet).
- Redan tre ÄtgÀrder.
Lösning 2:
- HÄlla endast funktionsdefinitioner i skriptet och inte köra nÄgot.
- Med hjÀlp av
sedLĂ€gga till anrop till funktionen i slutet. - Skicka allt detta direkt till shh via pipe (
|)
Fördelar:
- Egentligen stateless.
- Inga boilerplate-enheter.
- KĂ€nns coolt.
Men lÄt oss bara undvika Ansible. Ja, allt Àr redan uppfunnet. Ja, cykeln. Titta pÄ vilken enkel, elegant och minimalistisk cykel:
$ 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
Ansluter till localhost...
Yay! Funktionen 'deploy' körs pÄ 'hut' med argumentet 'magic-porridge-pot'.Men vi kan inte vara sÀkra pÄ att det finns en adekvat bash pÄ den fjÀrran vÀrden, sÄ vi lÀgger till en liten kontroll i början (detta istÀllet för ):
if [ "$SHELL" != "/bin/bash" ]
then
echo "SkrÀddarsydd '$SHELL' skal stöds inte av 'deploy.sh'. StÀll in en '/bin/bash' skal för '$USER@$HOSTNAME'."
exit 1
fiOch nu Àr allt pÄ riktigt:
$ 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!Nu kan vi öppna i webblÀsaren, köra deployment igen och sÀkerstÀlla att det gÄr sömlöst genom att uppdatera sidan med F5 under deployment-processen.
Glöm inte att stÀda upp efter dig :3
$ docker rm -f uptimer_GREEN reverse-proxy
uptimer_GREEN
reverse-proxy
$ docker network rm web-gateway
web-gateway
$ cd ..
$ rm -r blue-green-deploymentKĂ€lla: habr.com
