Å ajÄ rakstÄ mÄs izmantojam stipri iesist, ssh, dokers Šø nginx MÄs organizÄsim nevainojamu tÄ«mekļa aplikÄcijas izkÄrtojumu. Zili zaļa izvietoÅ”ana ir paÅÄmiens, kas ļauj nekavÄjoties atjauninÄt lietojumprogrammu, nenoraidot nevienu pieprasÄ«jumu. TÄ ir viena no nulles dÄ«kstÄves izvietoÅ”anas stratÄÄ£ijÄm, un tÄ ir vislabÄk piemÄrota lietojumprogrammÄm ar vienu gadÄ«jumu, bet iespÄja ielÄdÄt otru, darbam gatavu instanci tuvumÄ.
PieÅemsim, ka jums ir tÄ«mekļa lietojumprogramma, ar kuru aktÄ«vi strÄdÄ daudzi klienti, un tai nav nekÄdu iespÄju uz pÄris sekundÄm nogulties. Un jums patieÅ”Äm ir jÄizlaiž bibliotÄkas atjauninÄjums, kļūdu labojums vai jauna lieliska funkcija. ParastÄ situÄcijÄ lietojumprogramma bÅ«s jÄpÄrtrauc, jÄaizstÄj un jÄsÄk no jauna. Docker gadÄ«jumÄ jÅ«s varat to vispirms nomainÄ«t, pÄc tam restartÄt, taÄu joprojÄm bÅ«s periods, kurÄ lietojumprogrammas pieprasÄ«jumi netiks apstrÄdÄti, jo parasti lietojumprogrammas sÄkotnÄjÄ ielÄde prasa zinÄmu laiku. Ko darÄ«t, ja tas sÄkas, bet izrÄdÄs nederÄ«gs? TÄ ir problÄma, atrisinÄsim to ar minimÄliem lÄ«dzekļiem un pÄc iespÄjas elegantÄk.
ATRUNA: LielÄkÄ daļa raksta ir parÄdÄ«ta eksperimentÄlÄ formÄtÄ - konsoles sesijas ieraksta veidÄ. Cerams, ka to nebÅ«s pÄrÄk grÅ«ti saprast un kods sevi pietiekami dokumentÄs. AtmosfÄrai iedomÄjieties, ka tie nav tikai koda fragmenti, bet gan papÄ«rs no ādzelzsā teletaipa.
Katras sadaļas sÄkumÄ ir aprakstÄ«ti interesanti paÅÄmieni, kurus Google ir grÅ«ti atrast, vienkÄrÅ”i izlasot kodu. Ja vÄl kaut kas nav skaidrs, meklÄjiet to Google un pÄrbaudiet. paskaidrojiet shell (par laimi, tas atkal darbojas, pateicoties telegrammas atbloÄ·ÄÅ”anai). Ja neko nevarat Google, jautÄjiet komentÄros. Ar prieku papildinÄÅ”u atbilstoÅ”o sadaļu āInteresanti tehnikaā.
SÄksim.
$ mkdir blue-green-deployment && cd $_
ApkalpoŔana
Izveidosim eksperimentÄlu servisu un ievietosim to konteinerÄ.
Interesantas tehnikas
cat << EOF > file-name (Å eit ir dokuments + I/O novirzÄ«Å”ana) ir veids, kÄ ar vienu komandu izveidot vairÄku rindu failu. Viss bash skan no /dev/stdin aiz Ŕīs rindas un pirms rindas EOF tiks ierakstÄ«ts file-name.
wget -qO- URL (paskaidrojiet shell) ā izvada dokumentu, kas saÅemts, izmantojot HTTP, uz /dev/stdout (analogs curl URL).
IzprintÄt
Es Ä«paÅ”i pÄrtraucu fragmentu, lai iespÄjotu izcelÅ”anu Python. BeigÄs bÅ«s vÄl viens Å”Äds gabals. Å emiet vÄrÄ, ka Å”ajÄs vietÄs papÄ«rs tika izgriezts, lai nosÅ«tÄ«tu uz izcelÅ”anas nodaļu (kur kods tika iekrÄsots ar rokÄm ar marÄ·ieriem), un pÄc tam Å”ie gabali tika pielÄ«mÄti atpakaļ.
$ cat << EOF > uptimer.py
from http.server import BaseHTTPRequestHandler, HTTPServer
from 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} is running for {t:3.1f} seconds.</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} (loads in {loading_seconds} sec.) started.')
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 is running for 15.4 seconds.</h2>
$ docker rm --force uptimer
uptimer
Reversais starpniekserveris
Lai mÅ«su lietojumprogramma varÄtu nemanot mainÄ«ties, ir nepiecieÅ”ams, lai tÄs priekÅ”Ä bÅ«tu kÄda cita entÄ«tija, kas paslÄps tÄs nomaiÅu. Tas varÄtu bÅ«t tÄ«mekļa serveris nginx Š² apgrieztais starpniekservera režīms. Starp klientu un lietojumprogrammu tiek izveidots apgrieztais starpniekserveris. TÄ pieÅem klientu pieprasÄ«jumus un pÄrsÅ«ta tos uz lietojumprogrammu un pÄrsÅ«ta lietojumprogrammas atbildes klientiem.
Lietojumprogrammu un reverso starpniekserveri var saistÄ«t dokera iekÅ”pusÄ, izmantojot doku tÄ«kls. TÄdÄjÄdi konteineram ar lietojumprogrammu pat nav jÄpÄrsÅ«ta resursdatora sistÄmas ports; tas ļauj lietojumprogrammu maksimÄli izolÄt no ÄrÄjiem draudiem.
Ja reversais starpniekserveris darbojas citÄ resursdatorÄ, jums bÅ«s jÄatsakÄs no doka tÄ«kla un lietojumprogramma jÄsavieno ar reverso starpniekserveri, izmantojot resursdatora tÄ«klu, pÄrsÅ«tot portu. progr parametrs --publish, tÄpat kÄ pirmajÄ startÄ un kÄ ar apgriezto starpniekserveri.
MÄs palaidÄ«sim apgriezto starpniekserveri 80. portÄ, jo tieÅ”i Å”ai entÄ«tijai vajadzÄtu klausÄ«ties ÄrÄjo tÄ«klu. Ja testa resursdatorÄ ir aizÅemts ports 80, mainiet parametru --publish 80:80 par --publish ANY_FREE_PORT:80.
$ 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 is running for 11.5 seconds.</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 seconds ago Up 25 seconds 0.0.0.0:80->80/tcp reverse-proxy
a1105f1b583d uptimer "python -u ./app.py" About a minute ago Up About a 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: Sat, 22 Aug 2020 19:56:24 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Connection: keep-alive
<h2>Uptimer v1.0 is running for 104.1 seconds.</h2>
Nevainojama izvietoŔana
IzlaidÄ«sim jaunu lietojumprogrammas versiju (ar divkÄrÅ”u startÄÅ”anas veiktspÄjas palielinÄjumu) un mÄÄ£inÄsim to izvietot nemanÄmi.
Interesantas tehnikas
echo 'my text' | docker exec -i my-container sh -c 'cat > /my-file.txt' ā RakstÄ«t tekstu my text uz failu /my-file.txt konteinera iekÅ”pusÄ my-container.
cat > /my-file.txt ā Ierakstiet standarta ievades saturu failÄ /dev/stdin.
IzprintÄt
$ 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 is running for 23.9 seconds.</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 is running for 63.4 seconds.</h2>
$ docker rm -f uptimer
uptimer
$ wget -qO- http://localhost
<h2>Uptimer v2.0 is running for 84.8 seconds.</h2>
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
96932d4ca97a uptimer "python -u ./app.py" About a minute ago Up About a minute 8080/tcp uptimer_BLUE
80695a822c19 nginx:alpine "/docker-entrypoint.ā¦" 8 minutes ago Up 8 minutes 0.0.0.0:80->80/tcp reverse-proxy
Å ajÄ posmÄ attÄls tiek veidots tieÅ”i uz servera, kas prasa, lai lietojumprogrammu avoti bÅ«tu tur, kÄ arÄ« noslogo serveri ar nevajadzÄ«gu darbu. NÄkamais solis ir attÄla komplekta pieŔķirÅ”ana atseviŔķai maŔīnai (piemÄram, CI sistÄmai) un pÄc tam pÄrsÅ«tÄ«Å”ana uz serveri.
AttÄlu pÄrsÅ«tÄ«Å”ana
DiemžÄl nav jÄgas pÄrsÅ«tÄ«t attÄlus no localhost uz localhost, tÄpÄc Å”o sadaļu var izpÄtÄ«t tikai tad, ja jums ir divi saimniekdatori ar Docker. Vismaz tas izskatÄs apmÄram Å”Ädi:
$ 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.9MB
Komanda docker save saglabÄ attÄla datus .tar arhÄ«vÄ, kas nozÄ«mÄ, ka tie sver aptuveni 1.5 reizes vairÄk nekÄ tie sver saspiestÄ formÄ. TÄpÄc sakratÄ«sim to laika un satiksmes taupÄ«Å”anas vÄrdÄ:
Padoms. Ja jums ir nepiecieÅ”ami vairÄki parametri, lai izveidotu savienojumu ar serveri, izmantojot SSH, iespÄjams, neizmantojat failu ~/.ssh/config.
AttÄla pÄrsÅ«tÄ«Å”ana, izmantojot docker image save/load - Å Ä« ir minimÄlistiskÄkÄ metode, bet ne vienÄ«gÄ. Ir arÄ« citi:
Konteineru reģistrs (nozares standarts).
Izveidojiet savienojumu ar docker dÄmonu serveri no cita resursdatora:
vides mainīgais DOCKER_HOST.
Komandrindas opcija -H vai --host rīks docker-compose.
Tagad apkoposim visu, ko veicÄm manuÄli, vienÄ skriptÄ. SÄksim ar augstÄkÄ lÄ«meÅa funkciju un pÄc tam apskatÄ«sim pÄrÄjÄs tajÄ izmantotÄs funkcijas.
Interesantas tehnikas
${parameter?err_msg} - viena no bash burvestÄ«bÄm (aka parametru aizstÄÅ”ana). Ja parameter nav norÄdÄ«ts, izvade err_msg un izejiet ar kodu 1.
docker --log-driver journald ā pÄc noklusÄjuma docker reÄ£istrÄÅ”anas draiveris ir teksta fails bez rotÄcijas. Izmantojot Å”o pieeju, žurnÄli Ätri aizpilda visu disku, tÄpÄc ražoÅ”anas videi ir jÄmaina draiveris uz viedÄku.
IzvietoŔanas skripts
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
}
IzmantotÄs funkcijas:
ensure-reverse-proxy ā PÄrliecinÄs, vai darbojas reversais starpniekserveris (noderÄ«gs pirmajai izvietoÅ”anai)
get-active-slot service_name ā Nosaka, kurÅ” slots paÅ”laik ir aktÄ«vs konkrÄtajam pakalpojumam (BLUE vai GREEN)
get-service-status service_name deployment_slot ā Nosaka, vai pakalpojums ir gatavs apstrÄdÄt ienÄkoÅ”os pieprasÄ«jumus
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 prasa nelielu skaidrojumu:
KÄpÄc tas atgriež skaitli, nevis izvada virkni?
JebkurÄ gadÄ«jumÄ izsaukÅ”anas funkcijÄ mÄs pÄrbaudÄm tÄs darba rezultÄtu, un izejas koda pÄrbaude, izmantojot bash, ir daudz vienkÄrÅ”Äka nekÄ virknes pÄrbaude. TurklÄt virknes iegÅ«Å”ana no tÄ ir ļoti vienkÄrÅ”a: get-active-slot service && echo BLUE || echo GREEN.
Vai tieÅ”Äm pietiek ar trim nosacÄ«jumiem, lai atŔķirtu visas valstis?
Pietiks pat ar diviem, pÄdÄjais Å”eit tikai pilnÄ«bai, lai nerakstÄ«tu else.
NedefinÄta paliek tikai funkcija, kas atgriež nginx konfigurÄcijas: get-nginx-config service_name deployment_slot. PÄc analoÄ£ijas ar veselÄ«bas pÄrbaudi Å”eit varat iestatÄ«t jebkuru konfigurÄciju jebkuram pakalpojumam. No interesantajÄm lietÄm - tikai cat <<- EOF, kas ļauj noÅemt visas cilnes sÄkumÄ. Tiesa, laba formatÄjuma cena ir jauktas cilnes ar atstarpÄm, kas mÅ«sdienÄs tiek uzskatÄ«tas par ļoti sliktu formu. Bet bash piespiež cilnes, un bÅ«tu arÄ« jauki, ja nginx konfigurÄcijÄ bÅ«tu normÄls formatÄjums. ÄŖsÄk sakot, ciļÅu sajaukÅ”ana ar atstarpÄm Å”eit patieÅ”Äm Ŕķiet labÄkais risinÄjums no sliktÄkajiem. TomÄr jÅ«s to neredzÄsit tÄlÄk esoÅ”ajÄ fragmentÄ, jo Habrs āto dara labiā, mainot visas cilnes uz 4 atstarpÄm un padarot EOF nederÄ«gus. Un Å”eit tas ir pamanÄms.
Lai neceltos divreiz, es jums tÅ«lÄ«t pastÄstÄ«Å”u par cat << 'EOF', kas tiks sastapts vÄlÄk. Ja raksti vienkÄrÅ”i cat << EOF, tad heredoc iekÅ”pusÄ virkne tiek interpolÄta (mainÄ«gie tiek paplaÅ”inÄti ($foo), komandu izsaukumi ($(bar)) utt.), un, ja dokumenta beigas ievietojat atseviŔķÄs pÄdiÅÄs, interpolÄcija tiek atspÄjota un simbols $ tiek parÄdÄ«ts tÄds, kÄds ir. Kas jums nepiecieÅ”ams, lai ievietotu skriptu citÄ skriptÄ.
get-nginx-config() {
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
local container_name=${service}_${slot}
case $service in
# Add specific nginx configs for your services here
*) nginx-config-simple-service $container_name:8080 ;;
esac
}
nginx-config-simple-service() {
local usage_msg="Usage: ${FUNCNAME[0]} proxy_pass"
local proxy_pass=${1?$usage_msg}
cat << EOF
server {
listen 80;
location / {
proxy_pass http://$proxy_pass;
}
}
EOF
}
Å is ir viss skripts. LÄ«dz ar to bÅ«tÄ«ba ar Å”o skriptu lejupielÄdei, izmantojot wget vai curl.
Parametru skriptu izpilde attÄlajÄ serverÄ«
Ir pienÄcis laiks pieklauvÄt pie mÄrÄ·a servera. Å oreiz localhost diezgan piemÄrots:
$ ssh-copy-id localhost
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
himura@localhost's password:
Number of key(s) added: 1
Now try logging into the machine, with: "ssh 'localhost'"
and check to make sure that only the key(s) you wanted were added.
MÄs esam uzrakstÄ«juÅ”i izvietoÅ”anas skriptu, kas mÄrÄ·a serverÄ« lejupielÄdÄ iepriekÅ” izveidotu attÄlu un nemanÄmi aizstÄj pakalpojuma konteineru, taÄu kÄ mÄs varam to izpildÄ«t attÄlajÄ datorÄ? Skriptam ir argumenti, jo tas ir universÄls un var izvietot vairÄkus pakalpojumus vienlaikus vienÄ reversajÄ starpniekserverÄ« (varat izmantot nginx konfigurÄcijas, lai noteiktu, kurÅ” url bÅ«s kurÅ” pakalpojums). Skriptu nevar saglabÄt serverÄ«, jo Å”ajÄ gadÄ«jumÄ mÄs nevarÄsim to automÄtiski atjauninÄt (lai labotu kļūdas un pievienotu jaunus pakalpojumus), un kopumÄ stÄvoklis = ļaunums.
1. risinÄjums: joprojÄm saglabÄjiet skriptu serverÄ«, bet kopÄjiet to katru reizi scp. PÄc tam izveidojiet savienojumu, izmantojot ssh un izpildiet skriptu ar nepiecieÅ”amajiem argumentiem.
MÄ«nusi:
Divas darbÄ«bas vienas vietÄ
IespÄjams, ka nav vietas, kur jÅ«s kopÄjat, vai tai var nebÅ«t piekļuves, vai arÄ« skripts var tikt izpildÄ«ts aizstÄÅ”anas laikÄ.
VÄlams aiz sevis sakopt (izdzÄst skriptu).
Jau trīs darbības.
2. risinÄjums:
SaglabÄjiet skriptÄ tikai funkciju definÄ«cijas un nepalaidiet neko
Ar sed beigÄs pievienojiet funkcijas izsaukumu
Nosūtiet to visu tieŔi uz shh, izmantojot cauruli (|)
Plusi:
PatieÅ”Äm bezvalstnieks
Nav pamata entītiju
Jūtos forŔi
DarÄ«sim to bez Ansible. JÄ, viss jau ir izdomÄts. JÄ, velosipÄds. Paskatieties, cik vienkÄrÅ”s, elegants un minimÄlistisks ir velosipÄds:
$ cat << 'EOF' > 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_SCRIPT
EOF
$ chmod +x deploy.sh
$ ./deploy.sh localhost magic-porridge-pot
Connecting to localhost...
Yay! The 'deploy' function is executing on 'hut' with argument 'magic-porridge-pot'
TomÄr mÄs nevaram bÅ«t pÄrliecinÄti, ka attÄlajam saimniekdatoram ir pietiekams bash, tÄpÄc sÄkumÄ pievienosim nelielu pÄrbaudi (tas ir nevis shellbang):
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
fi
Un tagad tas ir Ä«sts:
$ 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!
Tagad jÅ«s varat atvÄrt http://localhost/ pÄrlÅ«kprogrammÄ vÄlreiz palaidiet izvietoÅ”anu un pÄrliecinieties, ka tÄ darbojas nevainojami, izkÄrtojuma laikÄ atjauninot lapu atbilstoÅ”i kompaktdiskam.