Прим. перев. — Этой статьёй мы начинаем цикл переводов, посвященных теме Zero Downtime Deployment. Следующие публикации осветят вопросы деплоя новых версий приложения с БД и деплой в Kubernetes.
Несмотря на то, что техническое решение, описываемое ниже достаточно спорно, целью данной статьи является знакомство читателя непосредственно с подходом Blue-Green деплоя, который, кстати, применим не только к приложениям Spring.
Целью Blue-Green деплоя является устранение простоев во время развертывания новой версии приложения.
Простой связан с недоступностью серверов, когда новая версия приложения устанавливается для замены старой. Идея Blue / Green deployment заключается в развертывании новой версии приложения в некоем отдельном месте, где можно проводить тестирование, вплоть до момента принятия окончательного решения о переключении на неё как на основную.
В этой статье мы рассмотрим, как настроить Blue-Green деплой Spring boot приложения. Мы будем использовать Nginx в качестве основного веб-сервера для перенаправления входящих запросов в наши приложения.
Настройка сервера
В этом руководстве предполагается, что у вас есть сервер и работающее Spring boot приложение, которое можно на нём развернуть.
На сервере зайдите в домашнюю директорию и создайте две папки: blue
и green
. Затем нам понадобятся две символические ссылки available
и testing
. Эти ссылки будут указывать либо на синюю, либо на зеленую папку. Например, если available
указывает на green
, тогда testing
указывает на blue
.
mkdir blue
mkdir green
ln -s ./green ./available
ln -s ./blue ./testing
Каждая папка будет содержать свое собственное приложение Spring и конфигурацию Nginx. В какой-то момент во время деплоя оба приложения будут работать одновременно (хотя и на разных портах), и для переключения с синего приложения на зеленое нам потребуется только изменить конфигурацию Nginx либо на green, либо на blue.
Конфигурации Nginx
Допустим, у нас есть домен springsite.com. “Зеленая” конфигурация Nginx перенаправит все вызовы springsite.com/api/ в приложение green
на порт 8080, а все вызовы springsite.com/api-test/ — в приложение blue
на порт 8090.
Давайте создадим эти конфигурационные файлы. Откройте ваш любимый редактор и добавьте следующее содержимое.
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name mysite.com;
location /api {
proxy_pass http://localhost:8090/api;
}
location /api-test {
proxy_pass http://localhost:8080/api;
}
}
include servers/*;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name mysite.com;
location /api {
proxy_pass http://localhost:8080/api;
}
location /api-test {
proxy_pass http://localhost:8090/api;
}
}
include servers/*;
}
Структура файлов должна выглядеть примерно так:
--root
|--- blue
|--- nginx.conf.blue
|--- app-V2.jar
|--- green
|--- nginx.conf.green
|--- app-V1.jar
|--- available -> ./green
|--- testing -> ./blue
Допустим, мы хотим развернуть новую версию в blue
контейнере. Мы можем протестировать ее, пока предыдущая версия еще доступна. Как только все довольны новой версией, нам нужно будет всего лишь поменять ссылки!
Создайте файл swap.sh
в папке, содержащей как blue
, так и green
папки:
touch swap.sh
chmod +x swap.sh
Добавьте следующее содержимое в файл swap.sh
:
#!/bin/bash
testing_now=$(ls -l ./ | grep testing)
if [[ "$testing_now" == *blue ]]
then
testing="blue"
active="green"
else
testing="green"
active="blue"
fi
#remove current links
rm ./available
rm ./testing
rm -f /etc/nginx/nginx.conf
#create new links with the active/inactive reversed
ln -s ./$inactive ./available
ln -s ./$active ./testing
ln -s /home/ubuntu/spring/$active/nginx.conf /etc/nginx/nginx.conf
#reload the http server
service nginx reload
echo swap completed $active is now available
На этом этапе мы можем запустить 2 приложения Spring на портах 8090 и 8080 и менять их, запуская sudo ./swap.sh
.
Деплой
Благодаря символическим ссылкам мы знаем, что на основное приложение всегда указывает available
, а на тестируемое — testing
. Следовательно, мы всегда должны деплоить новую версию приложения в папке testing
, используя символическую ссылку. Предполагается, что мы только что упаковали приложение, и теперь мы можем загрузить его с помощью scp
.
scp -r -i ~/.ssh/MyKeyPair.pem <package name.jar> <user>@<ip>:spring/testing
Идем дальше
Настройка Blue-Green деплоя на вашем сервере позволит значительно сократить время простоя. В этом руководстве объясняется, как деплоить новые версии вашего приложения, которые находятся на одном физическом сервере. Оно может быть адаптировано к ситуациям с несколькими физическими серверами и балансировщику нагрузки. Однако, для этого потребуется иметь вдвое больше производственных сред, чем необходимо. Для очень большой инфраструктуры это либо невозможно, либо чрезвычайно дорого.
Это приводит к вопросу: Как крупным компаниям удается выпускать новые версии своих приложений без простоев? Подумайте о Google или Facebook, которые всегда доступны!
Использование Blue-Green деплоя тут нереально из-за огромного количества необходимых серверов. Обновления приложений выполняются постепенно: серверы поочередно выводятся из работы, а после обновления возвращаются обратно. Более того, новые версии также выпускаются постепенно: в начале только небольшая часть серверов будет работать с новой версией. Затем, если проблем или багов не обнаружено, всё больше и больше серверов будут запускаться с новым кодом. На этом этапе оцениваются важные метрики производительности, такие как CPU, память и производительность запросов. Если все прошло успешно, то релиз завершен, и на каждом сервере по всему миру будет запущена новая версия приложения.
Заключение
Я надеюсь, теперь вы понимаете, как решить проблему простоя благодаря Blue-Green деплою. Теперь вы сможете настроить базовый Blue-Green деплой вашего Spring приложения с NGINX.
Как вы, возможно, заметили, когда мы используем это решение, старые и текущие версии ваших приложений работают одновременно и оба подключены к базе данных. Это может привести к неожиданным проблемам при изменении структуры базы данных. Эта замечательная статья https://spring.io/blog/2016/05/31/zero-downtime-deployment-with-a-database описывает, как справиться с подобными ситуациями.
И, наконец, вас может заинтересовать то, что и AWS, и Google Cloud Compute предлагают услуги по Blue-Green Deployment из коробки:
https://aws.amazon.com/quickstart/architecture/blue-green-deployment/
https://cloud.google.com/solutions/continuous-delivery/
Также читайте другие статьи в нашем блоге:
- Как запустить несколько пайплайнов с помощью GitLab CI/CD
- /etc/resolv.conf для Kubernetes pods, опция ndots:5, как это может негативно сказаться на производительности приложения
- Разбираемся с пакетом Context в Golang
- Три простых приема для уменьшения Docker-образов
- Бэкапы Stateful в Kubernetes
- Резервное копирование большого количества разнородных web-проектов
- Telegram-бот для Redmine. Как упростить жизнь себе и людям
jashcka
спасибо интересно, но думаю это просто
а как быть с базой / миграциями
где почитать про это?
AlexeyTokar
liquibase решает. А с недавних версий MySQL, например, поддерживает online ddl. А мейнтененс СУБД — это вопрос вашей архитектуры. Для Mongo — это, например, mongos. А для того же MySQL — mysql proxy… Масса вариантов. Исходить надо из задачи
fori1ton
Liquibase так себе решает в ряде случаев. Пока апдейтается база, с ней работает активные инстансы приложения, и важно их не сломать. Мы не можем просто так переименовать или дропнуть колонку, существенно поменять формат данных, пока с ней работают не обновлённые инстансы приложения. Если мы не хотим даунтайма, нужно поддерживать обратную соовместимость на время миграции, и несовместимые изменения накатывать только после обновления последнего инстанса приложения. Например, данные в новом формате писать в новую колонку, при этом транслируя в старую данные в старом формате, а после обновления всех инстансов отключить обновление старой колонки и выкосить её. Вот о менеджменте таких процессов и было бы интересно почитать.
AlexeyTokar
ну вот же — вы все правильно расписали :) менеджится в две-три стадии в зависимости от комплексности изменения. автоматизированных средств я пока не встречал да и сложно себе их представляю.
borisershov Автор
Здравствуйте!
Скоро от нас будут ещё переводы статей, продолжающие тему Zero Downtime, в которых как раз будет рассказываться про миграции БД )