Eng kam ish haqi bo'yicha ko'k-yashil joylashtirish
Ushbu maqolada biz foydalanamiz bosh, sSH, docker ΠΈ nginx Biz veb-ilovaning uzluksiz tartibini tashkil qilamiz. Moviy-yashil joylashtirish bitta so'rovni rad etmasdan dasturni bir zumda yangilash imkonini beruvchi texnikadir. Bu nol uzilish vaqtini tarqatish strategiyalaridan biri bo'lib, bir nusxasi bo'lgan ilovalar uchun eng mos keladi, lekin ikkinchi, ishga tayyor namunani yaqin atrofda yuklash imkoniyati.
Aytaylik, sizda ko'plab mijozlar faol ishlayotgan veb-ilovangiz bor va u bir necha soniya davomida yotishning mutlaqo imkoni yo'q. Va siz haqiqatan ham kutubxonani yangilash, xatolarni tuzatish yoki yangi ajoyib xususiyatni ishga tushirishingiz kerak. Oddiy holatda, dasturni to'xtatish, uni almashtirish va qayta ishga tushirish kerak bo'ladi. Docker bo'lsa, avval uni almashtirishingiz mumkin, keyin uni qayta ishga tushirishingiz mumkin, lekin hali ham dasturga so'rovlar ko'rib chiqilmaydigan muddat bo'ladi, chunki odatda dasturni dastlab yuklash uchun biroz vaqt ketadi. Agar u boshlansa, lekin ishlamay qolsa-chi? Bu muammo, keling, uni minimal vositalar bilan va iloji boricha oqlangan holda hal qilaylik.
Ogohlantirish: Maqolaning ko'p qismi eksperimental formatda - konsol seansini yozib olish shaklida taqdim etilgan. Umid qilamanki, buni tushunish juda qiyin bo'lmaydi va kod o'zini etarli darajada hujjatlashtiradi. Atmosfera uchun bu shunchaki kod parchalari emas, balki "temir" teletayp qog'ozi ekanligini tasavvur qiling.
Kodni o'qish orqali Google uchun qiyin bo'lgan qiziqarli texnikalar har bir bo'limning boshida tasvirlangan. Agar biror narsa tushunarsiz bo'lsa, uni Google-ga kiriting va tekshiring. tushuntirish qobig'i (xayriyatki, telegramma blokdan chiqarilganligi sababli u yana ishlaydi). Agar siz Google-da hech narsa qila olmasangiz, sharhlarda so'rang. Tegishli bo'limga "Qiziqarli texnikalar" qo'shishdan xursand bo'laman.
Keling, boshlaymiz.
$ mkdir blue-green-deployment && cd $_
xizmat
Keling, eksperimental xizmat ko'rsatamiz va uni idishga joylashtiramiz.
Qiziqarli texnikalar
cat << EOF > file-name (Mana Hujjat + I/U qayta yo'naltirish) - bitta buyruq bilan ko'p qatorli fayl yaratish usuli. Barcha bash o'qiydi /dev/stdin bu qatordan keyin va qatordan oldin EOF da qayd etiladi file-name.
wget -qO- URL (tushuntirish qobig'i) β HTTP orqali olingan hujjatni chiqarish /dev/stdout (analog curl URL).
Chop etish
Python uchun ajratib ko'rsatishni yoqish uchun men alohida parchani buzaman. Oxirida shunga o'xshash yana bir parcha bo'ladi. Tasavvur qiling-a, bu joylarda qog'oz ajratib ko'rsatish bo'limiga jo'natish uchun kesilgan (bu erda kod yoritgichlar bilan qo'lda bo'yalgan) va keyin bu qismlar orqaga yopishtirilgan.
$ 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
Teskari proksi
Ilovamiz sezilmasdan o'zgarishi uchun uning oldida uning o'rnini yashiradigan boshqa ob'ekt bo'lishi kerak. Bu veb-server bo'lishi mumkin nginx Π² teskari proksi rejimi. Mijoz va dastur o'rtasida teskari proksi-server o'rnatiladi. U mijozlarning so'rovlarini qabul qiladi va ularni ilovaga yuboradi va arizaning javoblarini mijozlarga yuboradi.
Ilova va teskari proksi-server yordamida docker ichida bog'lanishi mumkin docker tarmog'i. Shunday qilib, ilova bilan konteyner host tizimidagi portni yo'naltirishga hojat yo'q, bu ilovani tashqi tahdidlardan maksimal darajada ajratish imkonini beradi.
Agar teskari proksi boshqa xostda yashasa, siz docker tarmog'idan voz kechishingiz va dasturni portni yo'naltirish orqali xost tarmog'i orqali teskari proksi-serverga ulashingiz kerak bo'ladi. ilovalar parametr --publish, birinchi boshlang'ichda va teskari proksi-serverda bo'lgani kabi.
Biz teskari proksi-serverni 80-portda ishga tushiramiz, chunki bu tashqi tarmoqni tinglashi kerak bo'lgan ob'ekt. Sinov xostingizda 80 port band bo'lsa, parametrni o'zgartiring --publish 80:80 haqida --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>
Uzluksiz joylashtirish
Keling, ilovaning yangi versiyasini chiqaraylik (boshlash unumdorligini ikki baravar oshirish bilan) va uni muammosiz joylashtirishga harakat qilaylik.
Qiziqarli texnikalar
echo 'my text' | docker exec -i my-container sh -c 'cat > /my-file.txt' - Matn yozing my text faylga /my-file.txt konteyner ichida my-container.
cat > /my-file.txt β Faylga standart kiritish mazmunini yozing /dev/stdin.
Chop etish
$ 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
Ushbu bosqichda tasvir to'g'ridan-to'g'ri serverda quriladi, bu dastur manbalarining u erda bo'lishini talab qiladi, shuningdek serverni keraksiz ish bilan yuklaydi. Keyingi qadam, tasvirni yig'ishni alohida mashinaga (masalan, CI tizimiga) ajratish va keyin uni serverga o'tkazishdir.
Tasvirlarni uzatish
Afsuski, tasvirlarni localhost-dan localhost-ga o'tkazish mantiqqa to'g'ri kelmaydi, shuning uchun bu bo'lim faqat sizning qo'lingizda Docker-ga ega ikkita xostingiz bo'lsa, o'rganilishi mumkin. Hech bo'lmaganda u shunday ko'rinadi:
$ 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 tasvir ma'lumotlarini .tar arxivida saqlaydi, ya'ni u siqilgan shakldagi og'irlikdan taxminan 1.5 baravar ko'proq og'irlik qiladi. Keling, vaqt va trafikni tejash uchun uni silkitamiz:
Maslahat: Agar serverga SSH orqali ulanish uchun bir qator parametrlar kerak boΚ»lsa, siz fayldan foydalanmayotgan boΚ»lishingiz mumkin. ~/.ssh/config.
Tasvirni uzatish orqali docker image save/load - Bu eng minimalist usul, ammo yagona emas. Boshqalar ham bor:
Konteynerlar reestri (sanoat standarti).
Boshqa xostdan docker demon serveriga ulaning:
atrof-muhit o'zgaruvchisi DOCKER_HOST.
Buyruqlar qatori opsiyasi -H yoki --host asbob docker-compose.
Keling, qo'lda qilgan hamma narsani bitta skriptga to'playmiz. Keling, yuqori darajadagi funksiyadan boshlaylik, keyin esa unda ishlatiladigan boshqa funksiyalarni ko'rib chiqamiz.
Qiziqarli texnikalar
${parameter?err_msg} - bash sehrli afsunlardan biri (aka parametrlarni almashtirish). Agar parameter belgilanmagan, chiqish err_msg va 1-kod bilan chiqing.
docker --log-driver journald β sukut bo'yicha, docker jurnali drayveri hech qanday aylanishsiz matn faylidir. Ushbu yondashuv bilan jurnallar tezda butun diskni to'ldiradi, shuning uchun ishlab chiqarish muhiti uchun drayverni aqlliroqqa o'zgartirish kerak.
O'rnatish skripti
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
}
Foydalanilgan xususiyatlar:
ensure-reverse-proxy β Teskari proksi-server ishlayotganiga ishonch hosil qiladi (birinchi joylashtirish uchun foydali)
get-active-slot service_name β Berilgan xizmat uchun hozirda qaysi slot faol ekanligini aniqlaydi (BLUE yoki GREEN)
get-service-status service_name deployment_slot β Xizmat kiruvchi soβrovlarni koβrib chiqishga tayyormi yoki yoβqligini aniqlaydi
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
}
vazifa get-active-slot bir oz tushuntirishni talab qiladi:
Nima uchun u raqamni qaytaradi va satrni chiqarmaydi?
Qanday bo'lmasin, chaqiruv funktsiyasida biz uning ishining natijasini tekshiramiz va bash yordamida chiqish kodini tekshirish satrni tekshirishdan ko'ra osonroqdir. Bundan tashqari, undan satr olish juda oddiy: get-active-slot service && echo BLUE || echo GREEN.
Barcha davlatlarni farqlash uchun uchta shart haqiqatan ham etarlimi?
Hatto ikkitasi etarli bo'ladi, oxirgisi yozmaslik uchun faqat to'liqlik uchun else.
Faqat nginx konfiguratsiyasini qaytaruvchi funksiya aniqlanmagan: get-nginx-config service_name deployment_slot. Sog'liqni saqlash tekshiruviga o'xshab, bu erda istalgan xizmat uchun istalgan konfiguratsiyani o'rnatishingiz mumkin. Qiziqarli narsalardan - faqat cat <<- EOF, bu sizga boshida barcha yorliqlarni olib tashlash imkonini beradi. To'g'ri, yaxshi formatlash narxi bugungi kunda juda yomon shakl deb hisoblanadigan bo'shliqlar bilan aralash tablardir. Lekin bash tablarni majburlaydi va nginx konfiguratsiyasida normal formatlash ham yaxshi bo'lardi. Muxtasar qilib aytganda, bu erda bo'shliqlar bilan yorliqlarni aralashtirish, albatta, eng yomonidan eng yaxshi yechim kabi ko'rinadi. Biroq, siz buni quyidagi parchada ko'rmaysiz, chunki Habr barcha yorliqlarni 4 bo'sh joyga o'zgartirib, EOFni yaroqsiz qilib "yaxshi qiladi". Va bu erda u sezilarli.
Ikki marta turmaslik uchun men sizga darhol aytib beraman cat << 'EOF', bu keyinroq duch keladi. Agar oddiygina yozsangiz cat << EOF, keyin heredoc ichida satr interpolyatsiya qilinadi (o'zgaruvchilar kengaytiriladi ($foo), buyruq chaqiruvlari ($(bar)) va hokazo) va agar siz hujjatning oxirini bitta tirnoq ichiga qo'ysangiz, interpolyatsiya o'chiriladi va belgi $ kabi ko'rsatiladi. Boshqa skript ichiga skript kiritish uchun nima kerak.
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
}
Maqsadli serverni taqillatish vaqti keldi. Bu safar localhost juda mos:
$ 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.
Biz maqsadli serverga oldindan yaratilgan tasvirni yuklaydigan va xizmat ko'rsatish konteynerini muammosiz almashtiradigan joylashtirish skriptini yozdik, ammo uni masofaviy kompyuterda qanday bajarishimiz mumkin? Skriptda argumentlar mavjud, chunki u universal va bir vaqtning o'zida bir nechta xizmatlarni bitta teskari proksi-server ostida joylashtirishi mumkin (qaysi url qaysi xizmat bo'lishini aniqlash uchun nginx konfiguratsiyasidan foydalanishingiz mumkin). Skriptni serverda saqlab bo'lmaydi, chunki bu holda biz uni avtomatik ravishda yangilay olmaymiz (xatolarni tuzatish va yangi xizmatlarni qo'shish uchun) va umuman, davlat = yomon.
Yechim 1: Skriptni hali ham serverda saqlang, lekin uni har safar nusxalang scp. Keyin orqali ulaning ssh va skriptni kerakli argumentlar bilan bajaring.
Kamchiliklari:
Bitta o'rniga ikkita harakat
Siz nusxa ko'chiradigan joy bo'lmasligi yoki unga kirish imkoni bo'lmasligi yoki almashtirish vaqtida skript bajarilgan bo'lishi mumkin.
O'zingizdan keyin tozalash tavsiya etiladi (skriptni o'chirish).
Allaqachon uchta harakat.
Yechim 2:
Skriptda faqat funksiya ta'riflarini saqlang va hech narsani ishga tushirmang
Yordamida sed oxirigacha funktsiya chaqiruvini qo'shing
Hammasini quvur orqali to'g'ridan-to'g'ri shhga yuboring (|)
Taroziga soling:
Haqiqatan ham vatansiz
Boilerplate ob'ektlari yo'q
Salqin his
Keling, buni Ansiblesiz qilaylik. Ha, hamma narsa allaqachon ixtiro qilingan. Ha, velosiped. Velosiped qanchalik sodda, oqlangan va minimalist ekanligini ko'ring:
$ 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'
Biroq, biz masofaviy xostda etarli bash borligiga ishonchimiz komil emas, shuning uchun biz boshida kichik chek qo'shamiz (bu o'rniga 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
Va endi bu haqiqiy:
$ 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!
Endi siz ochishingiz mumkin http://localhost/ brauzerda joylashtirishni qayta ishga tushiring va tartib davomida sahifani CD ga muvofiq yangilash orqali uning muammosiz ishlashiga ishonch hosil qiling.