NĂ« kĂ«tĂ« artikull ne do tĂ« , , dhe organizojmĂ« njĂ« shpĂ«rndarje pa ndĂ«rprerje tĂ« aplikacionit web. Ă«shtĂ« njĂ« teknikĂ« qĂ« lejon tĂ« pĂ«rditĂ«soni menjĂ«herĂ« aplikacionin, pa devijuar as njĂ« kĂ«rkesĂ«. Ajo Ă«shtĂ« njĂ« nga strategjitĂ« e shpĂ«rndarjes me mungesĂ« kohe (zero downtime deployment) dhe Ă«shtĂ« mĂ« e pĂ«rshtatshme pĂ«r aplikacione me njĂ« instancĂ«, por me mundĂ«sinĂ« pĂ«r tĂ« ngarkuar njĂ« instancĂ« tĂ« dytĂ«, gati pĂ«r tâu pĂ«rdorur, afĂ«r.
Supozoni se keni një aplikacion web që ka shumë klientë duke u përdorur aktivisht, dhe nuk mund ta ndaloni as për disa sekonda. Ju nevojitet me urgjencë të publikoni një përditësim të bibliotekës, një rregullim të një gabimi ose një funksionalitet të ri. Në situatën e zakonshme, do të kërkonte të ndalonit aplikacionin, ta zëvendësonit dhe pastaj ta rinisnit. Në rastin e Dockers, mund të zëvendësoni së pari, pastaj ta rinisni, por prapë do të ketë një periudhë, në të cilën kërkesat për aplikacionin nuk do të përpunohen, sepse zakonisht aplikacionit i nevojitet një kohë për ngarkimin e parë. Dhe nëse ai fillon, por rezulton jo funksional? Kjo është një sfidë, le të mundohemi ta zgjidhim me mjete minimale dhe në një mënyrë sa më elegante.
DISCLAMER: Pjesa mĂ« e madhe e artikullit Ă«shtĂ« paraqitur nĂ« njĂ« format eksperimental â si njĂ« regjistrim i njĂ« seance konsolĂ«. Shpresoj se kjo nuk do tĂ« jetĂ« shumĂ« e vĂ«shtirĂ« pĂ«r t'u perceptuar, dhe ky kod e dokumenton veten nĂ« njĂ« masĂ« tĂ« mjaftueshme. PĂ«r atmosferĂ«, imagjinoni se kĂ«to nuk janĂ« thjesht kod snippete, por njĂ« letĂ«r nga njĂ« telegrame "metalike".
Teknikat interesante, tĂ« cilat janĂ« tĂ« vĂ«shtira pĂ«r t'u gjetur vetĂ«m duke lexuar kodin, janĂ« pĂ«rshkruar nĂ« fillim tĂ« çdo seksioni. NĂ«se keni ndonjĂ« paqartĂ«si tjetĂ«r â kĂ«rkoni nĂ« (me fat, ai po punon pĂ«rsĂ«ri, pĂ«r shkak tĂ« zhbllokimit tĂ« Telegramit). ĂfarĂ« nuk gjen dot â pyesni nĂ« komentet. Me kĂ«naqĂ«si do ta shtoj seksionin pĂ«rkatĂ«s "Teknika interesante".
Le të fillojmë.
$ mkdir blue-green-deployment && cd $_Shërbimi
Do të krijojmë një shërbim provë dhe do ta vendosim në një kontejner.
Teknika interesante
cat < emri-i-fajllit( + ) â njĂ« mĂ«nyrĂ« pĂ«r tĂ« krijuar njĂ« skedar shumĂ«str kinda nĂ« njĂ« komandĂ«. Ădo gjĂ« qĂ« bash do tĂ« lexojĂ« nga/dev/stdinpas kĂ«saj rresht dhe deri nĂ« rreshtinEOFdo tĂ« shkruhet nĂ«emri-i-fajllit.wget -qO- URL() â pĂ«r tĂ« shfaqur dokumentin e marrĂ« pĂ«rmes HTTP nĂ«/dev/stdout(analog tijcurl URL).
Printimi
Unë qëllimisht e ndava snippet-in për të përfshirë ndriçimin për Python. Në fund do të ketë një copë të tillë. Mendoni se në këto vende letra është prerë për t'u kaluar në departamentin e ndriçimit (ku kodi u ngjyros manualisht me highlighter), dhe pastaj këto copa janë ngjitur përsëri.
$ cat < uptimer.pynga http.server importo BaseHTTPRequestHandler, HTTPServer
nga kohë importo monotonic
versioni_i_aplikacionit = 1
emri_i_aplikacionit = f'Uptimer v{versioni_i_aplikacionit}.0'
sekondat_e_ngarkimit = 15 - versioni_i_aplikacionit * 5
klasa Handler(BaseHTTPRequestHandler):
def do_GET(self):
nëse self.path == ' / ':
përpiquni:
t = monotonic() - server_start
nëse t < sekondat_e_ngarkimit:
self.send_error(503)
përndryshe:
self.send_response(200)
self.send_header('Content-Type', 'text/html')
self.end_headers()
përgjigja = f'<h2>{emri_i_aplikacionit} po funksionon për {t:3.1f} sekonda.</h2>n'
self.wfile.write(përgjigja.encode('utf-8'))
përjashtim Tjetër:
self.send_error(500)
përndryshe:
self.send_error(404)
httpd = HTTPServer(('', 8080), Handler)
server_start = monotonic()
print(f'{emri_i_aplikacionit} (ngarkohet në {sekondat_e_ngarkimit} sek.) nisi.')
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 është duke funksionuar për 15.4 sekonda.</h2>
$ docker rm --force uptimer
uptimerReverse proxy
Për të patur mundësinë që aplikacioni ynë të ndryshojë në mënyrë të padukshme, duhet që para tij të ketë një entitet tjetër që do ta fshehë ndërrimin. Kjo mund të jetë një server web në . Reverse proxy vendoset midis klientit dhe aplikacionit. Ai merr kërkesat nga klientët dhe i redirekton ato në aplikacion, ndërsa përgjigjet e aplikacionit i drejton te klientët.
Aplikacioni dhe reverse proxy mund të lidhën brenda docker-it me anë të . Kështu, kontejneri me aplikacionin nuk ka nevojë të kalojë portin në sistemin host, duke e bërë kështu aplikacionin sa më të izoluar nga kërcënimet e jashtme.
Nëse reverse proxy do të jetojë në një host tjetër, do të duhet të heqim dorë nga docker network dhe të lidhim aplikacionin me reverse proxy përmes rrjetit të host-it, duke kaluar portin aplikacione parametrin --publish, si në fillimin origjinal dhe si për reverse proxy.
Reverse proxy do ta nisim në portin 80, sepse kjo është saktësisht ajo entitet që duhet të dëgjojë nga jasht. Nëse porti 80 është i zënë në hostin tuaj testues, ndryshoni parametrin --publish 80:80 në --publish ANY_FREE_PORT:80.
Teknika interesante
- «Në rrjetet docker, të krijuara nga përdoruesi, mund të lidhen kontejnerët jo vetëm përmes adresës IP. Emri i kontejnerit gjithashtu rezolvohet në adresën e tij IP» (, pika 5 e kodit docker).
Printimi
$ 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 po punon për 11.5 sekonda.</h2>
$ docker run --detach --publish 80:80 --network web-gateway --name reverse-proxy nginx:alpine
80695a822c19051260c66bf60605dcb4ea66802c754037704968bc42527bf120
$ docker ps
KODI I KONTEINERIT IMAZHI KOMANDA KRIJUAR STATUS PORTET EMRAT
80695a822c19 nginx:alpine "/docker-entrypoint.…" 27 sekonda më parë Up 25 sekonda 0.0.0.0:80->80/tcp reverse-proxy
a1105f1b583d uptimer "python -u ./app.py" Rreth një minut më parë Up Rreth një 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: procesi i sinjalit filloi
$ 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 po punon për 104.1 sekonda.</h2>Deploy i pandĂ«rprerĂ«
Do ta nxjerrim versionin e ri të aplikacionit (me një rritje dyfish në performancën e startup) dhe do të përpiqemi ta vendosim atë pa ndërprerje.
Teknika interesante
echo 'my text' | docker exec -i my-container sh -c 'cat > /my-file.txt'â Shkruaj tekstinmy textnĂ« skedarin/my-file.txtbrenda kontejneritmy-container.cat > /my-file.txtâ Shkruaj nĂ« skedarin pĂ«rmbajtjen e hyrjes standarde/dev/stdin.
Printimi
$ sed -i "s/app_version = 1/app_version = 2/" uptimer.py
$ docker build --tag uptimer .
Dërgimi i kontekstit të ndërtimit në daemonin Docker 39.94kB
Hapi 1/4 : FROM python:alpine
---> 8ecf5a48c789
Hapi 2/4 : EXPOSE 8080
---> Përdorimi i cache
---> cf92d174c9d3
Hapi 3/4 : COPY uptimer.py app.py
---> 3eca6a51cb2d
Hapi 4/4 : CMD [ "python", "-u", "./app.py" ]
---> Po ekzekutohet në 8f13c6d3d9e7
Duke hequr kontejnerin e përkohshëm 8f13c6d3d9e7
---> 1d56897841ec
Ndërtimi përfundoi me sukses 1d56897841ec
Me etiketë të suksesshme uptimer:latest
$ docker run --detach --rm --name uptimer_BLUE --network web-gateway uptimer
96932d4ca97a25b1b42d1b5f0ede993b43f95fac3c064262c5c527e16c119e02
$ docker logs uptimer_BLUE
Uptimer v2.0 (ngarkohet në 5 sekonda) filloi.
$ docker run --rm --network web-gateway alpine wget -qO- http://uptimer_BLUE:8080
<h2>Uptimer v2.0 është duke funksionuar për 23.9 sekonda.</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: sinjali i procesit filloi
$ wget -qO- http://localhost
<h2>Uptimer v2.0 është duke funksionuar për 63.4 sekonda.</h2>
$ docker rm -f uptimer
uptimer
$ wget -qO- http://localhost
<h2>Uptimer v2.0 është duke funksionuar për 84.8 sekonda.</h2>
$ docker ps
ID KONTEJNERI IMAZHI KOMANDA KRIJUAR STATUS PORTAT EMRAT
96932d4ca97a uptimer "python -u ./app.py" Rreth një minutë më parë Up Rreth një minutë 8080/tcp uptimer_BLUE
80695a822c19 nginx:alpine "docker-entrypoint.…" 8 minuta më parë Up 8 minuta 0.0.0.0:80->80/tcp reverse-proxyNĂ« kĂ«tĂ« fazĂ«, imazhi ndĂ«rtohet direkt nĂ« server, gjĂ« qĂ« kĂ«rkon qĂ« aty tĂ« ketĂ« origjinalet e aplikacionit, si dhe e ngarkon serverin me punĂ« tĂ« panevojshme. Hapi tjetĂ«r do tĂ« jetĂ« ndarja e ndĂ«rtimit tĂ« imazhit nĂ« njĂ« makinĂ« tĂ« veçantĂ« (pĂ«r shembull, nĂ« sistemin CI) me transmetimin e mĂ«passhĂ«m nĂ« server.
Rifreskimi i imazheve
Më vjen keq, por nuk ka kuptim të transferosh imazhet nga localhost në localhost, kështu që ky seksion mund të provohet vetëm duke pasur dy host-e me Docker. Në minimum, kjo duket kështu:
$ 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.9MBEkipa docker save ruan të dhënat e imazhit në një arkiv .tar, që do të thotë se pesha e tij është përafërsisht 1.5 herë më shumë se sa mund të ishte në versionin e kompresuar. Pra, le ta kompresojmë për shkak të kursimit të kohës dhe trafikut:
$ docker image save uptimer | gzip | ssh production-server 'zcat | docker image load'
Loaded image: uptimer:latestPo ashtu, mund të monitoroni procesin e transferimit (në të vërtetë, për këtë nevojitet një utilitar i jashtëm):
$ docker image save uptimer | gzip | pv | ssh production-server 'zcat | docker image load'
25,7MiB 0:01:01 [ 425KiB/s] [ ]
Loaded image: uptimer:latestKëshillë: Nëse ju duhen shumë parametra për t'u lidhur me serverin përmes SSH, ndoshta nuk po përdorni skedarin
~/.ssh/config.
Transferimi i imazhit pĂ«rmes docker image save/load â kjo Ă«shtĂ« metoda mĂ« minimaliste, por jo e vetmja. Ka edhe tĂ« tjera:
- Container Registry (standard i industrisë).
- Këtu lidhuni me docker daemon-n e serverit nga një host tjetër:
- Variabla
DOCKER_HOST. - Parametri i komandës së linjës
-Hose--hostinstrumentidocker-compose. docker context
- Variabla
Mënyra e dytë (me tri variante të realizimit të saj) është përshkruar mirë në artikullin .
deploy.sh
Tani do të grumbullojmë gjithçka që bëmë manualisht në një skenar. Le të fillojmë me funksionin e nivelit të lartë dhe pastaj do të shohim të tjerët që e përdorin atë.
Teknika interesante
${parameter?err_msg}â njĂ« nga magjitĂ« e bash-it (aka ). NĂ«separameternuk Ă«shtĂ« caktuar, shfaqnierr_msgdhe dilni me kodin 1.docker --log-driver journaldâ me default, shkalla e regjistrimit tĂ« docker-it Ă«shtĂ« njĂ« skedar tekstual pa ndonjĂ« rotacion. Me kĂ«tĂ« qasje, regjistrat shpejt mbushin gjithĂ« diskun, prandaj pĂ«r ambientet production Ă«shtĂ« e nevojshme tĂ« ndryshoni shkallĂ«n nĂ« njĂ« mĂ« tĂ« mençur.
Skenari i zbarkimit
deploy() {
local usage_msg="Përdorimi: ${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 "Duke vendosur '$NEW' në vend të '$OLD'..."
docker run
--detach
--restart always
--log-driver journald
--name $NEW
--network web-gateway
$image_name || return 3
echo "Kontejneri nisi. Po kontrolloj shëndetin..."
for i in {1..20}
do
sleep 1
if get-service-status $image_name $new_slot
then
echo "Shërbimi i ri '$NEW' duket OK. Duke kaluar në krye..."
sleep 2 # Sigurohuni që shërbimi është gati
set-active-slot $image_name $new_slot || return 4
echo "Shërbimi '$NEW' është në linjë!"
sleep 2 # Sigurohuni që të gjitha kërkesat janë përpunuar
echo "Duke mbyllur '$OLD'..."
docker rm -f $OLD
docker image prune -f
echo "Vendosja e suksesshme!"
return 0
fi
echo "Shërbimi i ri '$NEW' nuk është gati ende. Po pres ($i)..."
done
echo "Shërbimi i ri '$NEW' nuk u ndez, duke e mbyllur. Dështim në vendosje T_T"
docker rm -f $NEW
return 5
}Funksionet e përdorura:
ensure-reverse-proxyâ Siguron qĂ« rasti i anĂ«s tjetĂ«r po punon (e dobishme pĂ«r vendosjen e parĂ«)get-active-slot service_nameâ PĂ«rcakton se cili slot Ă«shtĂ« aktiv tani pĂ«r shĂ«rbimin e dhĂ«nĂ« (BLUEoseGREEN)get-service-status service_name deployment_slotâ PĂ«rcakton nĂ«se shĂ«rbimi Ă«shtĂ« i gatshĂ«m pĂ«r tĂ« pĂ«rpunuar kĂ«rkesat e ardhshmeset-active-slot service_name deployment_slotâ Ndryshon konfigurimin e nginx nĂ« konteinerin e rreth-rjetit
NĂ« rend:
ensure-reverse-proxy() {
is-container-up reverse-proxy && return 0
echo "Duke 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
}Funksioni get-active-slot kërkon disa shpjegime:
Përse ajo kthen një numër dhe jo një varg?
Megjithatë, në funksionin e thirrjes ne kontrollojmë rezultatin e punës së saj, dhe është shumë më e lehtë të kontrollojmë kodin e daljes me bash sesa vargun. Për më tepër, është shumë e lehtë ta marrësh atë në formën e një vargu:
get-active-slot service && echo BLUE || echo GREEN.
A janë të mjaftueshme këto tri kushte për të diferencuar të gjitha gjendjet?
Madje, dy mjaftojnë, e fundit këtu është vetëm për plotësi, që të mos shkruajmë else.
Mbetej e paqartë vetëm funksioni që kthen konfigurimet nginx: get-nginx-config service_name deployment_slot. Në përputhje me healthcheck, këtu mund të caktosh çdo konfigurim për çdo shërbim. Nga interesante, vetëm cat <<- EOF, që lejon të heqni të gjitha tabulaturat në fillim. Megjithatë, çmimi i formatimit të duhur është përzierja e tabulaturave me hapësira, që sot konsiderohet një sjellje shumë e keqe. Por bash forcon tabulat, dhe në konfigurimin e nginx do ishte gjithashtu e dobishme të kishit një formatim normal. Pra, këtu përzierja e tabulaturave me hapësira duket vërtet si zgjidhja më e mirë nga të keqijat. Megjithatë, në snippetin më poshtë, këtë nuk do ta shihni, pasi habr .
Që të mos bëj dy herë përpjekje, do të flas menjëherë për
cat << 'EOF', i cili do të shfaqet më vonë. Nëse shkruani thjeshtcat << EOF, atëherë brenda heredoc bëhet interpolimi i vargjeve (shkopen variablet ($foo), thirrjet e komandave ($(bar)), etj.), dhe nëse e mbyllni shenjën e fundit të dokumentit me thonjza të vetme, atëherë interpolimi ndalet dhe simboli$printohet siç është. Kjo është pikërisht e nevojshmja për të futur një skenar brenda një skenari tjetër.
get-nginx-config() {
local usage_msg="Përdorimi: ${FUNCNAME[0]} emri_shërbimi slot_investimi"
local service=${1?$usage_msg}
local slot=${2?$usage_msg}
[ "$slot" == BLUE ] || [ "$slot" == GREEN ] || return 1
local container_name=${service}_${slot}
case $service in
# Shtoni konfigurimet specifike të nginx për shërbimet tuaja këtu
*) nginx-config-simple-service $container_name:8080 ;;
esac
}
nginx-config-simple-service() {
local usage_msg="Përdorimi: ${FUNCNAME[0]} proxy_pass"
local proxy_pass=${1?$usage_msg}
cat << EOF
server {
listen 80;
location / {
proxy_pass http://$proxy_pass;
}
}
EOF
}Kjo është e gjithë skripti. Dhe ja për ta shkarkuar përmes wget ose curl.
Ekzekutimi i skenarëve të parametrizuar në një server të largët
Ka ardhur koha për të trokitur në serverin e synuar. Këtë herë localhost do të ishte plotësisht i përshtatshëm:
$ ssh-copy-id localhost
/usr/bin/ssh-copy-id: INFO: po përpiqet të regjistrohet me çelësi të rinj, për të filtruar çdo çelës që tashmë është instaluar
/usr/bin/ssh-copy-id: INFO: 1 çelës/çelësa mbeten për t'u instaluar -- nëse ju kërkohet tani është për të instaluar çelësat e rinj
fjalëkalimi për himura@localhost:
Numri i çelësave të shtuar: 1
Tani provoni të regjistroheni në makinë, me: "ssh 'localhost'"
dhe kontroloni për t'u siguruar që vetëm çelësa/të që dëshironi u shtuan.Ne kemi shkruar një skenar shpërndarjeje që ngarkon një pamje të paracaktuar në serverin përkatës dhe zëvendëson pa ndërprerje kontejnerin e shërbimit, por si ta ekzekutojmë atë në një makinë të largët? Skripti ka argumente, pasi është universale dhe mund të bëjë shpërndarje të disa shërbimeve nën një rreth-ndihmës (konfigurimet e nginx-it mund ta zgjidhin se për cilin URL do të jetë shërbimi). Skripti nuk mund të ruhet në server, pasi në këtë rast ne nuk do të mund ta azhurnojmë automatikisht (për qëllime rregullimi të gabimeve dhe shtesave të shërbimeve të reja), dhe gjithashtu, qëndrueshmëria = e keqe.
Zgjidhja 1: Të mbani skriptin në server, por ta kopjoni çdo herë përmes scp. Pastaj lidheni përmes ssh dhe ekzekutoni skriptin me argumentet e nevojshme.
Disavantazhet:
- Dy veprime në vend të njërit
- Vendi ku po e kopjoni mund të mos ekzistojë, ose të ketë qasje të pamjaftueshme, ose skripti mund të ekzekutohet gjatë zëvendësimit.
- Preferohet të largohet pas (fshihet skripti).
- Tashmë tre veprime.
Zgjidhja 2:
- Në skript të mbani vetëm definicionet e funksioneve dhe në përgjithësi të mos ekzekutoni asgjë,
- Me ndihmën e
sedshtoni në fund thirrjen e funksionit - Dërgoni gjithçka direkt në shh përmes pipe (
|)
Avantazhet:
- E vërtetë pa gjendje
- Nuk ka entitete boilerplate
- Duke u ndjerë i ftohtë
Por le t'i mbajmë gjërat pa Ansible. Po, gjithçka është tashmë e menduar. Po, bicikleta. Shikoni, sa e lehtë, elegante dhe minimaliste është kjo bicikletë:
$ 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
Duke u lidhur me localhost...
Yay! Funksioni 'deploy' po ekzekutohet në 'hut' me argumentin 'magic-porridge-pot'Megjithatë, ne nuk mund të jemi të sigurt se në hostin e largët ka një bash të përshtatshëm, kështu që do të shtojmë një verifikim të vogël në fillim (kjo në vend të ):
if [ "$SHELL" != "/bin/bash" ]
then
echo "Shelli '$SHELL' nuk përkrah 'deploy.sh'. Vendos një shell 'bash' për '$USER@$HOSTNAME'."
exit 1
fiTani gjithçka në të vërtetë:
$ 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
Dërgimi i imazhit gzipped 'uptimer' në 'localhost' përmes ssh...
Imazhi i ngarkuar: uptimer:latest
Po lidhet me 'localhost' përmes ssh për të vendosur pa probleme 'uptimer'...
Duke vendosur 'uptimer_GREEN' në vend të 'uptimer_BLUE'...
06f5bc70e9c4f930e7b1f826ae2ca2f536023cc01e82c2b97b2c84d68048b18a
Konteineri u nis. Po kontrollojmë shëndetin...
Duke kërkuar 'http://uptimer_GREEN:8080/' brenda rrjetit docker 'web-gateway':
HTTP/1.0 503 Shërbimi Nuk është i Disponueshëm
wget: serveri ktheu gabim: HTTP/1.0 503 Shërbimi Nuk është i Disponueshëm
Shërbimi i ri 'uptimer_GREEN' nuk është gati akoma. Po presim (1)...
Duke kërkuar 'http://uptimer_GREEN:8080/' brenda rrjetit docker 'web-gateway':
HTTP/1.0 503 Shërbimi Nuk është i Disponueshëm
wget: serveri ktheu gabim: HTTP/1.0 503 Shërbimi Nuk është i Disponueshëm
Shërbimi i ri 'uptimer_GREEN' nuk është gati akoma. Po presim (2)...
Duke kërkuar 'http://uptimer_GREEN:8080/' brenda rrjetit docker 'web-gateway':
HTTP/1.0 200 OK
Server: BaseHTTP/0.6 Python/3.8.3
Data: Sat, 22 Aug 2020 20:15:50 GMT
Content-Type: text/html
Shërbimi i ri 'uptimer_GREEN' duket OK. Po kalojmë ndërrimin...
nginx: skedari i konfigurimit /etc/nginx/nginx.conf ka sintaksë të rregullt
nginx: testi i skedarit të konfigurimit /etc/nginx/nginx.conf është i suksesshëm
2020/08/22 20:15:54 [njoftim] 97#97: procesi i sinjalit nisi
Shërbimi 'uptimer_GREEN' është në jetë!
Po vrasim 'uptimer_BLUE'...
uptimer_BLUE
Hapësira totale e rikuperuar: 0B
Vendosja e suksesshme!Tani mund të hapni në shfletues, të nisni përsëri vendosjen dhe të siguroheni që ajo kalon pa probleme duke rifreskuar faqen në mënyrë të vazhdueshme gjatë vendosjes.
Mos haroni të pastroni pas punës :3
$ docker rm -f uptimer_GREEN reverse-proxy
uptimer_GREEN
reverse-proxy
$ docker network rm web-gateway
web-gateway
$ cd ..
$ rm -r blue-green-deploymentBurimi: habr.com
