Бул макалада биз колдонобуз Баш, SSH, ютуб и жөргөмүш Биз веб-тиркеменин кемчиликсиз макетін уюштурабыз. Көк-жашыл жайылтуу бир эле өтүнүчтү четке какпастан, тиркемени заматта жаңыртууга мүмкүндүк берген техника. Бул нөлдүк токтоп калуу стратегияларынын бири жана бир нускасы бар тиркемелер үчүн эң ылайыктуу, бирок жакын жерде экинчи, иштетүүгө даяр инстанцияны жүктөө мүмкүнчүлүгү.
Сизде көптөгөн кардарлар жигердүү иштеп жаткан веб-тиркеме бар дейли, жана анын бир-эки секунд жатып калышына таптакыр жол жок. Сиз чындап эле китепкана жаңыртуу, мүчүлүштүктөрдү оңдоо же жаңы сонун функцияны чыгарышыңыз керек. Кадимки кырдаалда, сиз колдонмону токтотуп, аны алмаштырып, кайра башташыңыз керек болот. Докердин шартында, сиз адегенде аны алмаштырып, анан кайра иштетсеңиз болот, бирок тиркемеге болгон суроо-талаптар иштелбей турган мезгил болот, анткени, эреже катары, тиркемени жүктөө үчүн бир аз убакыт талап кылынат. Ал башталса, бирок иштебей калсачы? Бул көйгөй, келгиле, аны минималдуу каражаттар менен жана мүмкүн болушунча жарашыктуу чечели.
ЭСКЕРТҮҮ: Макаланын көбү эксперименталдык форматта - консолдук сессиянын жазуусу түрүндө берилген. Муну түшүнүү өтө кыйын болбойт жана код өзүн жетиштүү түрдө документтештирет деп үмүттөнөбүз. Атмосфера үчүн бул жөн гана код үзүндүлөрү эмес, “темир” телетайптын кагазы деп элестетиңиз.
Кодду окуп эле Google үчүн кыйын болгон кызыктуу ыкмалар ар бир бөлүмдүн башында баяндалат. Эгер дагы бир нерсе түшүнүксүз болсо, аны гуглдан таап, текшериңиз. түшүндүрүү (Бактыга жараша, ал телеграмманын бөгөттөн чыгарылгандыгына байланыштуу кайра иштейт). Эгер Google эч нерсе кыла албасаңыз, комментарийлерде сураңыз. Тиешелүү бөлүмгө "Кызыктуу техникалар" кошууга кубанычта болом.
Улантуу.
$ mkdir blue-green-deployment && cd $_
кызмат
Эксперименталдык кызмат жасап, аны контейнерге салалы.
Кызыктуу техникалар
cat << EOF > file-name (Бул жерде документ + I/O кайра багыттоо) бир команда менен көп саптуу файлды түзүү ыкмасы. Бардык bash окуйт /dev/stdin бул саптан кийин жана саптын алдында EOF жылы жазылат file-name.
wget -qO- URL (түшүндүрүү) — HTTP аркылуу алынган документти чыгаруу /dev/stdout (аналог curl URL).
Басып чыгаруу
Мен өзгөчө Python үчүн бөлүп көрсөтүүнү иштетүү үчүн үзүндүнү сындырдым. Аягында ушул сыяктуу дагы бир чыгарма болот. Бул жерлерде кагазды бөлүп көрсөтүү бөлүмүнө жөнөтүү үчүн кесилгенин (ал жерде кодду кол менен боёгучтар менен боёп коюшкан), андан кийин бул бөлүктөр кайра чапталганын карап көрөлү.
$ 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
Тескери прокси
Биздин тиркеме байкалбастан өзгөрө алышы үчүн, анын алдында анын алмаштырууну жашыра турган башка объект болушу керек. Бул веб-сервер болушу мүмкүн жөргөмүш в тескери прокси режими. Кардар менен тиркеменин ортосунда тескери прокси орнотулат. Ал кардарлардын суроо-талаптарын кабыл алат жана аларды колдонмого жөнөтөт жана өтүнмөнүн жоопторун кардарларга жөнөтөт.
Тиркеме жана тескери прокси аркылуу докердин ичинде байланыштырса болот докер тармагы. Ошентип, колдонмосу бар контейнерге хост тутумундагы портту башка жакка жөнөтүүнүн кереги жок; бул колдонмону тышкы коркунучтардан максималдуу түрдө обочолонтууга мүмкүндүк берет.
Эгерде тескери прокси башка хостто жашаса, сиз докер тармагынан баш тартып, портту багыттоо менен тиркемени хост тармагы аркылуу тескери проксиге туташтырыңыз. колдонмолор параметр --publish, биринчи башталгычтагыдай жана тескери проксидегидей.
Биз 80-портто тескери проксиди иштетебиз, анткени дал ушул нерсе тышкы тармакты угушу керек. Эгерде 80 порту сыноо хостуңузда бош эмес болсо, параметрди өзгөртүңүз --publish 80:80 боюнча --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>
Бир калыпта жайгаштыруу
Келгиле, тиркеменин жаңы версиясын чыгаралы (эки эсе баштоонун натыйжалуулугун жогорулатуу менен) жана аны бир калыпта жайгаштырууга аракет кылалы.
Кызыктуу техникалар
echo 'my text' | docker exec -i my-container sh -c 'cat > /my-file.txt' — Текст жаз my text файлга /my-file.txt контейнердин ичинде my-container.
cat > /my-file.txt — Стандарттык киргизүүнүн мазмунун файлга жазыңыз /dev/stdin.
Басып чыгаруу
$ 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
Бул этапта, сүрөт түздөн-түз серверде курулат, ал тиркеме булактарынын ошол жерде болушун талап кылат, ошондой эле серверди керексиз жумуш менен жүктөйт. Кийинки кадам сүрөт жыйындысын өзүнчө машинага (мисалы, CI системасына) бөлүп, андан кийин серверге өткөрүп берүү.
Сүрөттөрдү өткөрүү
Тилекке каршы, сүрөттөрдү localhost'тан localhostко которуунун мааниси жок, андыктан бул бөлүмдү Docker менен эки хостуңуз болгондо гана изилдөөгө болот. Жок дегенде, ал төмөнкүдөй көрүнөт:
$ 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
команда docker save сүрөттөлүштүн берилиштерин .tar архивинде сактайт, башкача айтканда, ал кысылган түрдө таразага караганда болжол менен 1.5 эсеге көп. Келгиле, убакытты жана трафикти үнөмдөө максатында аны чайкап көрөлү:
Эми кол менен жасаган нерселердин баарын бир сценарийге чогулталы. Келгиле, жогорку деңгээлдеги функциядан баштайлы, андан кийин анда колдонулган башка функцияларды карап көрөлү.
Кызыктуу техникалар
${parameter?err_msg} - баш сыйкырлардын бири (ака параметр алмаштыруу). Эгерде parameter көрсөтүлгөн эмес, чыгаруу err_msg жана коду 1 менен чыгуу.
docker --log-driver journald — демейки боюнча, докер журналынын драйвери эч кандай айлануусуз текст файлы. Бул ыкма менен журналдар бүт дискти тез толтурат, андыктан өндүрүш чөйрөсү үчүн драйверди акылдууга алмаштыруу керек.
Жайгаштыруу скрипти
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
}
Колдонулган өзгөчөлүктөр:
ensure-reverse-proxy — Тескери прокси иштеп жатканын текшерет (биринчи жайылтуу үчүн пайдалуу)
get-active-slot service_name — Берилген кызмат үчүн учурда кайсы слот активдүү экенин аныктайт (BLUE же GREEN)
get-service-status service_name deployment_slot — Кызмат түшкөн суроо-талаптарды иштетүүгө даярбы же жокпу аныктайт
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
}
милдети get-active-slot бир аз түшүндүрмө талап кылат:
Эмне үчүн ал санды кайтарып, сапты чыгарбайт?
Баары бир, чакыруу функциясында биз анын ишинин жыйынтыгын текшеребиз, ал эми bash аркылуу чыгуу кодун текшерүү сапты текшерүүгө караганда алда канча жеңил. Мындан тышкары, андан сап алуу абдан жөнөкөй: get-active-slot service && echo BLUE || echo GREEN.
Чынында эле бардык мамлекеттерди айырмалоо үчүн үч шарт жетиштүүбү?
Жада калса экөө жетиштүү болот, акыркысы толуктук үчүн бул жерде, жазбаш үчүн else.
Nginx конфигурациясын кайтарган функция гана аныкталбаган бойдон калат: get-nginx-config service_name deployment_slot. Ден соолук текшерүүсүнө окшошуп, бул жерде сиз каалаган кызмат үчүн каалаган конфигурацияны орното аласыз. Кызыктуу нерселерден - бир гана cat <<- EOF, бул сиз башында бардык өтмөктөрдү алып салууга мүмкүндүк берет. Ырас, жакшы форматтоо баасы бүгүнкү күндө абдан жаман түрү болуп эсептелет боштуктар менен аралаш өтмөктөр болуп саналат. Бирок bash өтмөктөрдү күчтөндүрөт жана nginx конфигурациясында кадимки форматтоо болсо жакшы болмок. Кыскача айтканда, бул жерде боштуктар менен өтмөктөрдү аралаштыруу, чынында эле, эң начар чечим катары көрүнөт. Бирок, сиз муну төмөндөгү фрагментте көрбөйсүз, анткени Хабр бардык өтмөктөрдү 4 боштукка өзгөртүп, EOF жараксыз кылып "жакшы кылат". Жана бул жерде байкалып турат.
Эки жолу туруп калбаш үчүн, мен сага дароо айтып берем cat << 'EOF', бул кийинчерээк кездешет. Жөнөкөй жазсаңыз cat << EOF, анда heredoc ичинде сап интерполяцияланат (өзгөрмөлөр кеңейтилет ($foo), командалык чакыруулар ($(bar)) ж.б.) жана эгерде сиз документтин соңун жалгыз тырмакчага кошсоңуз, анда интерполяция өчүрүлөт жана символ $ болуп көрсөтүлөт. Башка скрипттин ичине скрипт киргизүү үчүн эмне керек.
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
}
Бул бүт сценарий. Жана ошентип бул скрипт менен wget же curl аркылуу жүктөө үчүн.
Алыскы серверде параметрленген скрипттерди аткаруу
Бул максаттуу серверди тыкылдатууга убакыт келди. Бул убакыт localhost абдан ылайыктуу:
$ 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.
Биз алдын ала түзүлгөн сүрөттү максаттуу серверге жүктөөчү жана тейлөө контейнерин кемчиликсиз алмаштыра турган жайылтуу сценарийин жаздык, бирок аны алыскы машинада кантип аткара алабыз? Скрипттин аргументтери бар, анткени ал универсалдуу жана бир эле тескери прокси астында бир нече кызматтарды орното алат (кайсы url кайсы кызмат болорун аныктоо үчүн nginx конфигурацияларын колдонсоңуз болот). Скриптти серверде сактоо мүмкүн эмес, анткени бул учурда биз аны автоматтык түрдө жаңырта албайбыз (каталарды оңдоо жана жаңы кызматтарды кошуу үчүн) жана жалпысынан абал = жамандык.
Чечим 1: Скриптти дагы эле серверде сактаңыз, бирок аны ар дайым көчүрүңүз scp. Андан кийин аркылуу байланыш ssh жана сценарийди керектүү аргументтер менен аткарыңыз.
жактары:
Бир эмес, эки аракет
Сиз көчүргөн жер жок болушу мүмкүн, же ага жетүү мүмкүн эмес, же скрипт алмаштыруу учурунда аткарылышы мүмкүн.
Өзүңүздөн кийин тазалоо сунушталат (скриптти жок кылуу).
Буга чейин үч иш-аракет.
Чечим 2:
Скриптте функциянын аныктамаларын гана сактап, эч нерсени иштетпеңиз
Жардамы менен sed аягына чейин функция чалуу кошуу
Баарын труба аркылуу түз эле шшга жөнөтүңүз (|)
артыкчылыктары:
Чынында жарандыгы жок
Эч кандай объектилер жок
Сезим салкын
Келгиле, Ansible жок эле кылалы. Ооба, баары мурунтан эле ойлоп табылган. Ооба, велосипед. Велосипед канчалык жөнөкөй, жарашыктуу жана минималисттик экенин караңыз:
$ 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'
Бирок, биз алыскы хосттун адекваттуу башына ээ экенине ишене албайбыз, андыктан башында кичинекей чекти кошобуз (бул анын ордуна 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
Ал эми азыр реалдуу:
$ 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!
Эми сиз ача аласыз http://localhost/ браузерде жайгаштырууну кайра иштетиңиз жана макет учурунда CDге ылайык баракчаны жаңыртуу менен анын үзгүлтүксүз иштешине ынаныңыз.