Мне нравится использовать Docker, везде, а также, особенно докер-составляющую и его магию.
В настоящее время я работаю над приложением, я буду развертывать приложение так скоро, ранее я использовал докку, но, честно говоря, мне это не понравилось, я искал интернет, как развернуть приложение, используя только мой файл составляющей докера, но Я нашел только докер Рой, Nginx-porxy и другие вещи, которые не свободны.
В этой статье я объясню, как вы можете развернуть ваше приложение с нулевым временем, используя только ваш файл Compose Docker.
Установка Docker-Compose
Это файл Docker-Compose, который я объясню, что будет добавлено, что будет добавлено, чтобы сделать работу нулевого простоя.
Приложение/Docker-Compose.yml
version: "3.6"
services:
app_db:
image: postgres
restart: always
ports:
- 5432:5432
container_name: pqdb
networks:
- db_nw
app_server:
build:
dockerfile: Dockerfile.server
ports:
- "8989"
networks:
- db_nw
- web_nw
restart: always
volumes:
- ../:/apps/go-app
depends_on:
- app_db
app_nginx:
image: nginx:latest
container_name: nginx
restart: always
volumes:
- ./cfg/nginx.conf:/etc/nginx/nginx.conf
ports:
- 8888:80
networks:
- web_nw
depends_on:
- app_server
networks:
db_nw:
driver: bridge
web_nw:
driver: bridge
У меня есть 3 службы, app_db, app_server и app_nginx. Здесь ничего не хочет. Самое важное Piece Здесь не устанавливает имя контейнера, ни отображения порта («1234: 0987») в службе App_server, я скажу вам, почему позже.
Но вы, возможно, задаетесь вопросом — это пользовательские сети, необходимые для создания этой работы? короткий ответ
Позвольте мне объяснить докерные сети первым, потому что она имеет большую роль в создании этих работ.
Docker Networks
Когда вы запустите файл Docker-Compose, Docker подключает ваши услуги к той же сети, которая является сетью по умолчанию называется Bridge, и я думаю, что имя самоуверенно, оно создает мост между услугами, чтобы они могли общаться друг с другом, И забавная часть — это вам не нужно знать каждый IP-адрес контейнера, просто используйте имя сервиса, а Docker будет обрабатывать остальные.
Но я создаю пользовательские сети, чтобы я мог убедиться, что каждая услуга разговаривает с обслуживанием, с которым она должна поговорить.
Если вы хотите узнать больше о Docker Networks, и вы должны делать, читать Эта статья
Nginx.
Nginx также является важным обслуживанием здесь, я покажу вам файл конфигурации, а затем объясните.
Приложение/cfg/nginx.conf
http {
server {
listen 80;
location / {
proxy_pass "http://app_server:8989";
}
}
}
events {}
Это самая базовая конфигурация NGINX на Земле, мы создаем веб-сервер, который слушает в порту 80 и пропускать запросы на наш сервер приложений. Как вы можете видеть, я использую имя сервиса здесь, Docker переведет это на соответствующий IP-адрес контейнера.
Теперь, если вы запустите файл Pocker Compose, вы должны быть в состоянии сделать запросы на веб-сервер, который мы сопоставляем его в порт 8888 попробуйте Curl http://localhost: 8888
Но ждать…
Да, вы хотите знать, почему я не поместил имя контейнера и не отображает порт в службу App_server. Правильно ? Ну, просто не настраивая их, позволит Docker принять решение, он создаст имя, которое идентично именному имени сервиса, но суффиксировано с номером/индексом контейнера. Пример, если вы запустите свой Docker Compose файл и введите докер PS. Вы увидите, что имя контейнера App_Server на самом деле App_server_1. ОК, как насчет порта? Также не отображение порта к сервису позволит Docker выбрать динамический порт и сопоставьте его в порт, который мы устанавливаем на службу, каждый раз, когда вы запускаете Docker Compose File, порт изменится.
Веселая часть
Теперь мы сделаем развертывание нулевого простоя. Мы напишем простой и небольшой скрипт Bash, который сделает следующее:
1) Создайте новый экземпляр App_server (С новым изменениям кода) 2) Проверьте, если он работает и работает 3) Перезагрузить nginx (Так что он может распознать новый экземпляр) 4) Удалить старый экземпляр (со старым кодом)
Позвольте мне показать вам сценарий, а потом я объясню, как и почему?
service_name=app_server
nginx_container_name=nginx
reload_nginx() {
docker exec $nginx_container_name /usr/sbin/nginx -s reload
}
# server health check
server_status() {
# $1 = first func arg
local port=$1
local status=$(curl -is --connect-timeout 5 --show-error http://localhost:$port | head -n 1 | cut -d " " -f2)
# if status is not a status code (123), means we got an error not an http header
# this could be a timeout message, connection refused error msg, and so on...
if [[ $(echo ${#status}) != 3 ]]; then
echo "503"
fi
echo $status
}
update_server() {
old_container_id=$(docker ps -f name=$service_name -q | tail -n1)
# create a new instance of the server
docker-compose up --build -d --no-deps --scale $service_name=2 --no-recreate $service_name
new_container_id=$(docker ps -f name=$service_name -q | head -n1)
if [[ -z $new_container_id ]]; then
echo "ID NOT FOUND, QUIT !"
exit
fi
new_container_port=$(docker port $new_container_id | cut -d " " -f3 | cut -d ":" -f2)
if [[ -z $new_container_port ]]; then
echo "PORT NOT FOUND, QUIT !"
exit
fi
# sleep until server is up
while [[ $(server_status $new_container_port) > "404" ]]; do
echo "New instance is getting ready..."
sleep 3
done
# ---- server is up ---
# reload nginx, so it can recognize the new instance
reload_nginx
# remove old instance
docker rm $old_container_id -f
# reload ngnix, so it stops routing requests to the old instance
reload_nginx
echo "DONE !"
}
# call func
update_server
У нас есть 3 функции: 1) Перезагрузка Nginx На самом деле перезагрузка Nginx не вызывает простоя
3) Проверка здоровья сервера
curl -is --connect-timeout 5 --show-error http://localhost:$port
Это вернет заголовки ответа, так как мы можем видеть, что первая строка — это код состояния HTTP
HTTP/1.1 200 OK Age: ... Cache-Control: ... Content-Type: ... ...
Мы хотим первую строку
head -n1
Разделите текст на основе пробелов и получите второе поле, которое 200 в нашем примере
cut -d " " -f2
3) Обновить сервер В этой функции мы получаем текущий или старый идентификатор контейнера сервера, то мы создаем новый экземпляр службы App_server, не касаясь других связанных служб,
docker-compose up -d --no-deps --scale $service_name=2 --no-recreate $service_name
Затем мы получаем этот новый контейнер идентификатор и порт, чтобы мы могли проверить его состояние, если он он, поэтому мы можем остановить старый контейнер и начать отправлять запросы на новый контейнер.
Окончательно
Так как это будет работать? Как я буду развернуть мой сервер и обновить его? Если вы запустите скрипт на своей машине, он должен работать на вашем сервере, причина, это как работает Docker, верно?
Вы можете использовать SCP (Безопасная копия) Чтобы скопировать код с локальной машины на сервер, и вы можете использовать одну и ту же команду для обновления кода на сервере
scp USER@IP:~/apps ./local/app
Вы должны использовать Docker-Poompout прежде всего, если ваш первый раз ваш развертывающий код. А затем запустите скрипт update_server, чтобы обновить изменения без простоя.
Вы также можете использовать Git, который я предпочитаю развернуть и обновлять свой сервер и использовать Git крючки, поэтому всякий раз, когда есть Git Push на ваш сервер, вы запускаете скрипт update_server
Читать дальше Как вы можете использовать Git для развертывания вашего кода, так как прост в виде Git Push.
Ресурсы
Bash Cheat лист Docker Cheat лист
Оригинал: «https://dev.to/wassimbj/deploy-your-docker-containers-with-zero-downtime-o3f»