Имеется достаточно интересная ифраструктура одного проекта (UPD: описана в посте AWS: билд Java + Maven + Docker + Packer + Terraform), в котором деплой API-приложения выполняется скриптом, описанным ниже.
Его задача – запустить EC2 инстансы, объединённые в blue AutoScale группу, подключить её к Elastic Load Balancer-у (ELB), отключить от ELB green-группу, перезапустить в ней инстансы, подключить её обратно к ELB и отключить blue-группу.
Сам скрипт, как решение задачи, является скорее антипаттерном того, как надо делать – куда логичнее тут смотрелся бы Terraform, который используется во время деплоя для обновления launch-configuration AutoScale группы, с новыми AMI ID, которые являются результатом билда с новой версией приложения. Инстансы, запускаемые скриптом используют этот новый launch-configuration, и запускаются с новым приложением. Скрипт запускается groovy-скриптом из docker-контейнера в Jenkins, который сам работает в docker-контейнере.
Ещё лучше было бы мигрировать весь проект на AWS ECS, но выбор между Groovy, Terraform или bash
+ AWS CLI обуславливался временем, а ECS отложен на будущие фазы проекта, т.к. его (пока) нет в Китае, с которым предстоит работать.
Вообще про blue/green деплой AutoScale групп можно почитать интересные документы вот тут>>> и тут>>>.
UPD: сам скрипт (спустя почти год после написания поста) доступен в Github тут>>>.
Основной недостаток скрипта и вообще подхода к деплою тут – это не “чистый” blue-green деплой, т.к. инстансы в Blue группе после деплоя уничтожаются, и окружение остаётся только с одной версией приложения, и второй момент – вместо запуска и удаления инстансов в Bleu группе – можно было бы подключать Blue группу к ELB, и оставлять её работать, а Green – отключить, уменьшив таким образом кол-во выполняемые операций и ускорив деплой.
Тем не менее – сам по себе скрипт выглядит любопытно и содержит много реальных примеров работы с AWS CLI.
В скрипте используются 10 основных глобальных переменных, из которых 5 в “боевой” версии передаются в докер-контейнер Jenkins-ом опциями командной строки, заданных в билде:
#!/usr/bin/env bash #set -xe ################################################### ### See comments in main() block at the bottom. ### ################################################### # $1 - for getopts() option AWS_ACCESS_KEY_ID=$2 AWS_SECRET_ACCESS_KEY=$3 AWS_REGION=$4 ENVIRONMENT=$5 MIN_SIZE_GREEN=$6 #export AWS_DEFAULT_PROFILE=PROJECTNAME #export AWS_DEFAULT_REGION=eu-west-1 #AWS_ACCESS_KEY_ID= #AWS_SECRET_ACCESS_KEY= #AWS_REGION=eu-west-1 BLUE_ASG="$ENVIRONMENT-api-blue-asg" GREEN_ASG="$ENVIRONMENT-api-green-asg" ELB="$ENVIRONMENT-api-elb" SCALE_UP_RULE="$ENVIRONMENT-api-scale-up" SCALE_DOWN_RULE="$ENVIRONMENT-api-scale-down" export PATH=$PATH:"/home/aws/aws/env/bin/" export AWS_DEFAULT_REGION=$AWS_REGION ...
Скрипт умеет принимать 3 опции, которые обрабатываются с помощью getopts()
:
... HELP="Specify one of the following options: -d - simple deploy, -b - Production Blue deploy, -g - Production Green deploy" get_params () { if [[ -z $* ]];then echo -e "\n$HELP\n" exit 1 fi deploy= deploy_blue= deploy_green= while getopts "dbgh" opt; do case $opt in d) deploy=1 ;; b) deploy_blue=1 ;; g) deploy_green=1 ;; h) echo "$HELP" ;; esac done } ...
-d
– simple deploy: выполняет Production Blue deploy и Production Green deploy, один за другим. Используется для Dev-деплоя, где не требуется подтверждение между переключениями в ELB blue и green групп.-b
– Production Blue deploy: устанавливает переменнуюdeploy_blue
== 1, в результате чего вызывается функцияdeploy_blue()
.-g
– Production Green deploy: аналогично – устанавливает переменнуюdeploy_green
== 1, в результате чего вызывается функцияdeploy_green()
.
Далее в скрипте описываются различные вспомогательные функции, которые вызывают AWS CLI для выполнения действий, а замыкающими описываются три основных функции – deploy_blue()
, deploy_green(),
и последняя – main()
, которые последовательно вызывают все функции, описанные в скрипте выше.
Выполнение скрипта начинается в самом его низу, с вызова функций get_params()
и main()
:
... # check for -d (simple deploy), -b (deploy_blue()) or -g (deploy_green()) option first get_params $@ # execute main() which will call appropriate function depending on variables specified by get_params() main && echo -e "\nDeployment finished successfully.\n" ...
get_params()
принимает переданные Jenkins-ом опцию ($@
– все аргументы, переданные скрипту), и глобально задаёт одну из трёх переменных (надо было сделать через аргумент в main()), в зависимости от чего в main()
выполняется одна из трёх последовательностей:
... [[ $deploy ]] && { deploy_blue && deploy_green; echo -e "Result code: $?\n"; } [[ $deploy_blue ]] && { deploy_blue; echo -e "Result code: $?\n"; } [[ $deploy_green ]] && { deploy_green; echo -e "Result code: $?\n"; } ...
Содержание
Деплой blue-группы
main()
Полностью функция main()
с кратким описанием процесса всего процесса билда и деплоя приложения выглядит так:
... main () { # Build and deploy workflow # # 1 Maven # 1.1 Maven build jar archives with an application. # 1.2 Maven builds Docker images 1 per service with those jar-files included. # 1.3 Maven push those images to the Artifactory Private Docker registry. # 2 Packer # 2.1 Packer takes $base_ami ID and creates new EC2 instance. # 2.2 Installs Docker there and pulls Docker images with the latest code built by Maven. # 2.3 Builds new AMI with those images included. # 3 Terraform # 3.1 Terraform checks all its configs and current infrastructure state plus TF's state-files. # 3.2 Regarding to "most_recent = true" in api.tf - TF will see differences between current EC2 instances AMI ID # and ones found as "latest" in AWS account's AMIs list, as there are new AMIs created by Packer. # 3.4 Terraform updates Launch Configs (LC) for AutoScaling groups (ASG) with new AMI IDs. # 4 Deploy # 4.1 Add new EC2 instance to Blue AutoScale group. # 4.2 Attach Blue ASG to the Elastic Load Balancer (ELB). # 4.3 Detach Green ASG - traffic will be served by the Blue Group's EC2 instance, started with latest AMI ID. # 4.4 Terminate Green ASG instances. # 4.5 AutoScale will create an appropriate number of new instances. # 4.6 Attach Green ASG to the ELB. # 4.7 Detach Blue ASG. # 4.8 Terminate Blue ASG instances. [[ $deploy ]] && { deploy_blue && deploy_green; echo -e "Result code: $?\n"; } [[ $deploy_blue ]] && { deploy_blue; echo -e "Result code: $?\n"; } [[ $deploy_green ]] && { deploy_green; echo -e "Result code: $?\n"; } } ...
После чего вызывается сначала функция deploy_blue()
, которая обновляет EC2-инстансы в AutoScale blue-группе, а за ней deploy_green()
, которая обновляет инстансы в green-группе.
Собственно функция deploy_blue()
выглядит так:
... deploy_blue () { if blue_asg_status $BLUE_ASG; then # add 1 instance in Blue group wich will start with latest builded AMI echo -e "\n[BLUE] Blue ASG is empty, executing ScaleUp policy...\n" asg_scale_up $BLUE_ASG && echo -e "Scaled up to 1 instance.\n" || exit 1 # to prevent new instances creation during deployment echo -e "[BLUE] Blue ASG updating MAX value to 1...\n" asg_set_max_size $BLUE_ASG 1 && echo -e "Done.\n" || exit 1 # wait when Blue EC2 will start echo -e "[BLUE] Checking Blue ASG health...\n" asg_health $BLUE_ASG || exit 1 # to prevent new instances creation during deployment echo -e "[GREEN] Green ASG updating MIN value to 1...\n" asg_set_min_size $GREEN_ASG 1 && echo -e "Done.\n" || exit 1 # to prevent new instances creation during deployment echo -e "[GREEN] Green ASG updating MAX value to 1...\n" asg_set_max_size $GREEN_ASG 1 && echo -e "Done.\n" || exit 1 # add Blue EC2 under ELB's traffic control echo -e "[BLUE] Attaching Blue to ELB...\n" asg_attach $BLUE_ASG && echo -e "Blue ASG attached.\n" || exit 1 # to avoid instance termitation during it's "Green" role echo -e "[BLUE] Setting ScaleIn protection...\n" asg_set_protect $BLUE_ASG && echo -e "Done\n" || exit 1 # sleep before check ELB - intanse will be added not immediately echo -e "[BLUE] Checking ELB intastances health for Blue instance Up...\n" sleep 30 # ELB health checks :8080/health # Thus - it will check untill Gateway service will not start elb_health $BLUE_ASG || exit 1 echo -e "\n[GREEN] Detaching Green from ELB.\n" asg_detach $GREEN_ASG && echo -e "Done.\n" || exit 1 # sleep before check ELB - Green intanse will be removed from ELB not immediately # ask Verify after ## sleep 30 echo -e "Blue ASG deploy finished successfully.\n" else echo -e "ERROR - all instances in Blue ASG must be terminated and Desired value == 0. Exit.\n" exit 1 fi } ...
blue_asg_status()
Ход выполнения deploy_blue()
достаточно простой, и начинается с проверки результата выполнения функции blue_asg_status()
, которой аргументом передаётся имя AutoScale группы со значением dev, stage или prod, в зависимости от переменой $ENVIRONMENT
, заданной из аргументов Jenkins-а:
... BLUE_ASG="$ENVIRONMENT-api-blue-asg" ...
Вызов blue_asg_status()
:
... if blue_asg_status $BLUE_ASG; then ...
Задача функции blue_asg_status()
– проверить, не имеется ли запущенных инстансов в blue-группе (которая после деплоя остаётся пустой).
Выглядит она так:
... blue_asg_status () { local asg_name=$1 local instances_running=$(get_instances_running $asg_name) if [[ ! -z $instances_running ]]; then echo -e "\nThere is running instances in the Blue ASG: $instances_running\n" return 1 fi } ...
Если переменная $instances_running
не равна нулю – то билд останавливается с ненулевым результатом выполнения. Значение $instances_running
зависит от результата выполнения функции $get_instances_running()
, которая вызывает AWS CLI, подключется к AWS-аккаунту, и проверяет количество запущенных инстансов, а результат передаёт обратно в blue_asg_status()
:
... get_instances_running () { local asg_name=$1 local instances_running=$(aws autoscaling describe-auto-scaling-groups --auto-scaling-group-names $asg_name --query '[AutoScalingGroups[*].Instances[*].InstanceId]' --output text) echo $instances_running } ...
Если же $instances_running
== 0, то deploy_blue()
продолжает выполнение, и вызывает следующую функцию – asg_scale_up()
:
... # add 1 instance in Blue group wich will start with latest builded AMI echo -e "\n[BLUE] Blue ASG is empty, executing ScaleUp policy...\n" asg_scale_up $BLUE_ASG && echo -e "Scaled up to 1 instance.\n" || exit 1 ...
Собственно ход выполнения main()
и deploy_blue()
в output Jenkins-а выглядит так:
... [EU-api-staging-build] Running shell script + ./scripts/api_eu_deploy.sh -b **** **** eu-west-1 staging 2 [BLUE] Blue ASG is empty, executing ScaleUp policy... ...
Функция asg_scale_up()
применяет к blue AutoScale группе политику масштабирования из переменной $SCALE_UP_RULE
:
... SCALE_UP_RULE="$ENVIRONMENT-api-scale-up" ...
Правило с именем $ENVIRONMENT-api-scale-up
создаётся, обновляется или не изменяется Terraform-ом во время деплоя.
Политика $ENVIRONMENT-api-scale-up
увеличивает количество инстансов в blue-группе (которая “приходит” в деплой пустой) на число, зависящее от окружения (dev – 1, staging, prod – 2):
... asg_scale_up () { local asg_name=$1 aws autoscaling execute-policy --auto-scaling-group-name $asg_name --policy-name $SCALE_UP_RULE } ...
asg_set_max_size()
Следующей вызывается asg_set_max_size()
:
... # to prevent new instances creation during deployment echo -e "[BLUE] Blue ASG updating MAX value to 1...\n" asg_set_max_size $BLUE_ASG 1 && echo -e "Done.\n" || exit 1 ...
Сама функция:
... asg_set_max_size () { local asg_name=$1 local max_size=$2 aws autoscaling update-auto-scaling-group --auto-scaling-group-name $asg_name --max-size $max_size } ...
Она задаёт масксимальное количество EC2-инстансов в blue группе равным единице, после чего AWS AutoScale запускает новую машину из последнего AMI с приложением. Так как это blue-группа – то для экономии времени в ней достаточно одной машины.
asg_health()
После этого – deploy_blue()
вызывает функцию asg_health()
:
... # wait when Blue EC2 will start echo -e "[BLUE] Checking Blue ASG health...\n" asg_health $BLUE_ASG || exit 1 ...
Задача её – дождаться запуска машины (статус == InService) за $max
* $timeout
секунд, после чего выполнение цикла прерывается оператором break
, и управление выполнения возвращается к deploy_blue()
с кодом 0:
... asg_health () { local at=0 local max=10 local timeout=10 local asg_name=$1 while [ $at -lt $max ]; do local health=$(aws autoscaling describe-auto-scaling-groups --auto-scaling-group-names $asg_name --query [AutoScalingGroups[*].Instances[*].LifecycleState] --output text) if [[ $health == "InService" ]]; then echo -e "\n\n$asg_name instance(s) OK, ready to attach to ELB: $health\n" break else echo "($at/$max $timeout sec) $asg_name instance(s) not ready yet: $health" fi ((at++)) sleep $timeout done } ...
Выполнение asg_scale_up()
, asg_set_max_size()
и asg_health()
выглядит так:
…
Scaled up to 1 instance.[BLUE] Blue ASG updating MAX value to 1…
Done.
[BLUE] Checking Blue ASG health…
(0/10 10 sec) staging-api-blue-asg instance(s) not ready yet:
(1/10 10 sec) staging-api-blue-asg instance(s) not ready yet:
(2/10 10 sec) staging-api-blue-asg instance(s) not ready yet: Pending
(3/10 10 sec) staging-api-blue-asg instance(s) not ready yet: Pending
(4/10 10 sec) staging-api-blue-asg instance(s) not ready yet: Pendingstaging-api-blue-asg instance(s) OK, ready to attach to ELB: InService
…
asg_set_min_size()
Далее вызывается asg_set_min_size()
:
... # to prevent new instances creation during deployment echo -e "[GREEN] Green ASG updating MIN value to 1...\n" asg_set_min_size $GREEN_ASG 1 && echo -e "Done.\n" || exit 1 ...
Она уменьшает текущее количество инстасов в green-группе до 1 (во избежаение проблем с таймаутами в циклах далее):
... asg_set_min_size () { local asg_name=$1 local min_size=$2 aws autoscaling update-auto-scaling-group --auto-scaling-group-name $asg_name --min-size $min_size } ...
asg_set_max_size()
Аналогично вызывается функция asg_set_max_size()
, но для значения Max instances number для green-группы:
... asg_set_max_size () { local asg_name=$1 local max_size=$2 aws autoscaling update-auto-scaling-group --auto-scaling-group-name $asg_name --max-size $max_size } ...
asg_attach()
Вызов:
... # add Blue EC2 under ELB's traffic control echo -e "[BLUE] Attaching Blue to ELB...\n" asg_attach $BLUE_ASG && echo -e "Blue ASG attached.\n" || exit 1 ...
asg_attach()
подключает blue-группу с инстансом к Elastic Load Balancer-у, который начинает перенаправлять трафик на новую машину:
... asg_attach () { local asg_name=$1 aws autoscaling attach-load-balancers --auto-scaling-group-name $asg_name --load-balancer-names $ELB } ...
asg_set_protect()
После подключения blue-группы – можно отключать green, но сначала – лучше установить Scale in Protection для инстанса в blue-группе, что выполняется с помощью asg_set_protect()
:
... # to avoid instance termitation during it's "Green" role echo -e "[BLUE] Setting ScaleIn protection...\n" asg_set_protect $BLUE_ASG && echo -e "Done\n" || exit 1 ...
Тело функции:
... asg_set_protect () { local asg_name=$1 local instance_to_protect=$(get_instances_running $asg_name) aws autoscaling set-instance-protection --instance-ids $instance_to_protect --protected-from-scale-in --auto-scaling-group-name $asg_name } ...
Она получает Instance ID из функции get_instances_running()
... get_instances_running () { local asg_name=$1 local instances_running=$(aws autoscaling describe-auto-scaling-groups --auto-scaling-group-names $asg_name --query '[AutoScalingGroups[*].Instances[*].InstanceId]' --output text) echo $instances_running } ...
elb_health()
Вызов:
... # sleep before check ELB - intanse will be added not immediately echo -e "[BLUE] Checking ELB intastances health for Blue instance Up...\n" sleep 30 # ELB health checks :8080/health # Thus - it will check untill Gateway service will not start elb_health $BLUE_ASG || exit 1 ...
Упоминал о циклах и таймаутах чуть выше, пример такой функции (зачем два раза [ $at -lt $max ]
? только сейчас заметил):
... elb_health () { local out_state="OutOfService" local at=0 local max=30 local timeout=30 while [ $at -lt $max ]; do local elb_health=$(aws elb describe-instance-health --load-balancer-name $ELB --query '[InstanceStates[*].State]' --output text) if [[ $elb_health =~ $out_state ]]; then echo "($at/$max $timeout sec) Some intances still $elb_health" else echo -e "\n\nIntance up and running: $elb_health" break fi ((at++)) sleep $timeout if [ $at == $max ]; then echo "\nERROR: max attempts reached.\n" exit 1 fi done } ...
Так как только для иницилизации приложения на Java Spring Framework уходит порядка двух минут – то билд замирает в ожидании, пока в ELB не посчитает, что только что подключенный blue-инстанс уже готов обрабатывать запросы. Такое решение ELB принимает на основании результатов health-проверок к инстансу на порт 8080, после чего статус инстанса сменится с OutOfService на InService.
asg_detach()
Теперь ELB готов к отключению green-группы, что бы начать перенаправлять весь трафик на машину из blue-группы.
Отключение выполняется вызовом asg_detach()
:
... echo -e "\n[GREEN] Detaching Green from ELB.\n" asg_detach $GREEN_ASG && echo -e "Done.\n" || exit 1 ...
В результатах билда asg_set_min_size()
, asg_set_max_size()
, asg_attach()
, asg_set_protect()
, elb_health()
и asg_detach()
выглядят так:
…
[GREEN] Green ASG updating MIN value to 1…Done.
[GREEN] Green ASG updating MAX value to 1…
Done.
[BLUE] Attaching Blue to ELB…
Blue ASG attached.
[BLUE] Setting ScaleIn protection…
Done
[BLUE] Checking ELB intastances health for Blue instance Up…
(0/30 30 sec) Some intances still InService OutOfService
…
(14/30 30 sec) Some intances still InService OutOfServiceIntance up and running: InService InService
[GREEN] Detaching Green from ELB.
Done.
Blue ASG deploy finished successfully.
Result code: 0
…
Следующим шагом main()
после подтверждения вызывает deploy_green()
.
Vefiry step для Jenkins реализован в groovy-скрипте:
... def deploy_prod_verify() { stage 'Verify' input id: 'Deploy', message: 'Is Blue node fine? Proceed with Green node deployment?', ok: 'Deploy!' } ...
И выглядит так:
Деплой green-группы
deploy_green()
deploy_green()
аналогична debloy_blue()
и использует те же функции плюс 2 дополнительных:
... deploy_green () { # terminate Gren's instance echo -e "[GREEN] Updating Green ASG instances.\n" green_asg_terminate $GREEN_ASG echo -e "\n[GREEN] Waiting for Green ASG instance termination...\n" slee?p 30 # new instances must be started here by ASG echo -e "[GREEN] Checking Green ASG health.\n" asg_health $GREEN_ASG || exit 1 # add Green to ELB echo -e "[GREEN] Attaching Green to ELB.\n" asg_attach $GREEN_ASG && echo -e "Green ASG attached\n" || exit 1 # wait for the Gateway service UP state (/health) echo -e "[GREEN] Checking ELB intastances health for Green instance Up...\n" sleep 30 elb_health $GREEN_ASG || exit 1 # detach Blue - Green now is Green echo -e "\n[BLUE] Detaching Blue...\n" asg_detach $BLUE_ASG && echo -e "Done.\n" || exit 1 # remove protection before ScaleIn rule will be executed echo -e "[BLUE] Removing ScaleIn protection...\n" asg_remove_protect $BLUE_ASG && echo -e "Done\n" || exit 1 # ScaleIn rule will be executed :-) echo -e "[BLUE] Scaling Blue in...\n" asg_scale_down $BLUE_ASG && echo -e "Scale in to 0 instance - done.\n" || { echo "ERROR: can't execute ScaleDown policy. Exit."; exit 1; } # set Green ASG Max instances back to 8 echo -e "[GREEN] Green ASG restoring MAX value to 8...\n" asg_set_max_size $GREEN_ASG 8 && echo -e "Done.\n" || exit 1 # set Green ASG Min instances back to ${MIN_SIZE_GREEN} from eu-west-ENV.groovy echo -e "[GREEN] Green ASG restoring MIN value to $MIN_SIZE_GREEN...\n" asg_set_min_size $GREEN_ASG $MIN_SIZE_GREEN && echo -e "Done.\n" || exit 1 echo -e "Green ASG deploy finished successfully.\n" } ...
green_asg_terminate()
Вызов:
... deploy_green () { # terminate Gren's instance echo -e "[GREEN] Updating Green ASG instances.\n" green_asg_terminate $GREEN_ASG ...
Она начинает своё выполнение с вызова green_asg_terminate()
, задача которой – остановить инстансы green-группы со старым кодом, на место которых потом будут добавлены новые, из свежесобранных AMI:
... green_asg_terminate () { local asg_name=$1 local instances_running=$(get_instances_running $asg_name) instance_terminate "$instances_running" echo -e "\nChecking $instances_running state...\n" # be sure instance already terminated before proceed instance_state "$instances_running" } ...
get_instances_running()
уже упоминалась в deploy_blue()
, а instance_terminate()
выглядит так:
... instance_terminate () { local instances_running=$1 echo -e "Terminating instances $instances_running..." for instance in $instances_running; do echo -e "\nStopping instance $instance...\n" aws ec2 terminate-instances --instance-ids $instance || exit 1 done } ...
После того как старые инстансы были остановлены – AWS AutoScale увеличиет их количество, с новым кодом приложения.
Следующие функции уже упоминались:
... echo -e "\n[GREEN] Waiting for Green ASG instance termination...\n" sleep 30 # new instances must be started here by ASG echo -e "[GREEN] Checking Green ASG health.\n" asg_health $GREEN_ASG || exit 1 # add Green to ELB echo -e "[GREEN] Attaching Green to ELB.\n" asg_attach $GREEN_ASG && echo -e "Green ASG attached\n" || exit 1 # wait for the Gateway service UP state (/health) echo -e "[GREEN] Checking ELB intastances health for Green instance Up...\n" sleep 30 elb_health $GREEN_ASG || exit 1 # detach Blue - Green now is Green echo -e "\n[BLUE] Detaching Blue...\n" asg_detach $BLUE_ASG && echo -e "Done.\n" || exit 1 ...
asg_health()
ожидает состояния всех инстансов в green-группе == InService, asg_attach()
подключает её к ELB, elb_health()
ожидает ответа от всех инстансов в ELB на запросы к порту 8080 а asg_detach()
отключает blue-группу.
Результат в Jenkins:
…
[GREEN] Updating Green ASG instances.Terminating instances i-064dbc31791a0ad2c…
Stopping instance i-064dbc31791a0ad2c…
{
“TerminatingInstances”: [
{
“InstanceId”: “i-064dbc31791a0ad2c”,
“CurrentState”: {
“Code”: 32,
“Name”: “shutting-down”
},
“PreviousState”: {
“Code”: 16,
“Name”: “running”
}
}
]
}Checking i-064dbc31791a0ad2c state…
(0/10 20 sec) Instance i-064dbc31791a0ad2c still running…
(1/10 20 sec) Instance i-064dbc31791a0ad2c still running…
(2/10 20 sec) Instance i-064dbc31791a0ad2c still running…Instance i-064dbc31791a0ad2c stopped.
[GREEN] Waiting for Green ASG instance termination…
[GREEN] Checking Green ASG health.
(0/10 10 sec) staging-api-green-asg instance(s) not ready yet: Pending
(1/10 10 sec) staging-api-green-asg instance(s) not ready yet: Pending
(2/10 10 sec) staging-api-green-asg instance(s) not ready yet: Pendingstaging-api-green-asg instance(s) OK, ready to attach to ELB: InService
[GREEN] Attaching Green to ELB.
Green ASG attached
[GREEN] Checking ELB intastances health for Green instance Up…
(0/30 30 sec) Some intances still OutOfService InService
…
(15/30 30 sec) Some intances still OutOfService InServiceIntance up and running: InService InService
[BLUE] Detaching Blue…
Done.
…
asg_remove_protect()
... # remove protection before ScaleIn rule will be executed echo -e "[BLUE] Removing ScaleIn protection...\n" asg_remove_protect $BLUE_ASG && echo -e "Done\n" || exit 1 ...
asg_remove_protect()
снимает ScaleIn защиту с инстанса в blue-группе для её “зачистки” перед завершением деплоя:
... asg_remove_protect () { local asg_name=$1 local instance_to_protect=$(get_instances_running $asg_name) aws autoscaling set-instance-protection --instance-ids $instance_to_protect --no-protected-from-scale-in --auto-scaling-group-name $asg_name } ...
asg_scale_down()
Далее blue-группа уменьшается до 0 машин:
... # ScaleIn rule will be executed echo -e "[BLUE] Scaling Blue in...\n" asg_scale_down $BLUE_ASG && echo -e "Scale in to 0 instance - done.\n" || { echo "ERROR: can't execute ScaleDown policy. Exit."; exit 1; } ...
asg_set_max_size()
и asg_set_min_size() у
же были – восстанавливаются исходные данные green-группы для Max intances до 8, а Min – до 2:
... # set Green ASG Max instances back to 8 echo -e "[GREEN] Green ASG restoring MAX value to 8...\n" asg_set_max_size $GREEN_ASG 8 && echo -e "Done.\n" || exit 1 # set Green ASG Min instances back to ${MIN_SIZE_GREEN} from eu-west-ENV.groovy echo -e "[GREEN] Green ASG restoring MIN value to $MIN_SIZE_GREEN...\n" asg_set_min_size $GREEN_ASG $MIN_SIZE_GREEN && echo -e "Done.\n" || exit 1 echo -e "Green ASG deploy finished successfully.\n" } ...
В Jenkins это выглядит так:
…
[BLUE] Removing ScaleIn protection…Done
[BLUE] Scaling Blue in…
Scale in to 0 instance – done.
[GREEN] Green ASG restoring MAX value to 8…
Done.
[GREEN] Green ASG restoring MIN value to 2…
Done.
Green ASG deploy finished successfully.
Result code: 0
[Pipeline] }
[Pipeline] // withCredentials
[Pipeline] }
$ docker stop –time=1 e59c0fac136f8222e9b83da116931a4956cb9f4a80428b5844fdb271557de179
$ docker rm -f e59c0fac136f8222e9b83da116931a4956cb9f4a80428b5844fdb271557de179
[Pipeline] // withDockerContainer
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
Как-то так…