Назад | Перейти на главную страницу

Обновить контейнер сервиса в Amazon ECS

Какой подход рекомендуется для обновления контейнера службы, работающей в Amazon ECS?

В Документация AWS говорит: «Если вы обновили Docker-образ вашего приложения, вы можете создать новое определение задачи с этим образом и развернуть его в своей службе, по одной задаче за раз». Это почти все, что в настоящее время доступно в документации (13 апреля 2015 г.).

Правильно ли я понял, что единственный способ обновить контейнер моего приложения в Amazon ECS - это создать новую задачу, затем остановить старую и запустить новую?

Я успешно использую тег "последний" с Core OS и Fleetctl. Преимущество этого заключается в том, что нет необходимости изменять тег образа Docker для новых обновлений, поскольку при перезагрузке службы будут обнаружены новые изменения и обновлен контейнер (с использованием того же тега «latest»).

Какие подходы вы использовали для обновления своего сервиса с помощью обновленного образа докера в Amazon ECS?

Не уверен, что это считается заброшенным вопросом - наткнулся на это при устранении моей проблемы и теперь добавляю свое решение, когда оно решено.

Чтобы обновить сервис новым контейнером, вам необходимо:

  1. загрузить новый контейнер в репозиторий;
  2. запускать обновление определения задачи;
  3. запускать обновление контейнера;
  4. важно: убедитесь, что правила сервиса позволяют запускать новую версию задачи.

Если служебная задача не обновлена ​​до последней версии, проверьте вкладку «События» на наличие ошибок. Например, возможно, ECS не удалось запустить новую версию вашего сервиса: у вас есть только один экземпляр ec2 в кластере, а порт приложения уже используется на хосте. В этом случае установите ограничения «минимальное / максимальное здоровье» на «0%, 100%» - таким образом, ECS выберет уничтожение старого контейнера перед развертыванием нового. Это также происходит в течение нескольких минут - не торопитесь, если вы не видите немедленной обратной связи.

Ниже приведен пример сценария развертывания для обновления контейнера в предварительно настроенном кластере и службе. Обратите внимание, что нет необходимости указывать версии, если вы просто имеете в виду «использовать последнюю из семейства».

awsRegion=us-east-1
containerName=..
containerRepository=..
taskDefinitionFile=...
taskDefinitionName=...
serviceName=...


echo 'build docker image...'
docker build -t $containerName .

echo 'upload docker image...'
docker tag $containerName:latest $containerRepository:$containerName
docker push $containerRepository:$containerName

echo 'update task definition...'
aws ecs register-task-definition --cli-input-json file://$taskDefinitionFile --region $awsRegion > /dev/null

echo 'update our service with that last task..'
aws ecs update-service --service $serviceName --task-definition $taskDefinitionName --region $awsRegion  > /dev/null

Чтобы обновить приложение, обновите определение задачи, а затем обновите службу. Видеть http://docs.aws.amazon.com/AmazonECS/latest/developerguide/update-service.html

Я знаю, что это старый поток, но решение намного проще, чем большинство ответов здесь.

Как обновить работающий контейнер за два шага:

Ниже предполагается, что у вас есть служба, выполняющая задачу, которая ссылается на контейнер с тегами latest (или любой другой статический тег, который не изменяется при обновлении контейнера).

  1. Загрузите ваш новый контейнер в репозиторий
  2. Вручную убей свои задачи

Если наша цель - выпустить новую сборку на волю, нам не нужно полагаться в этом на наш сервис (и я бы сказал, что мы не должен положитесь на это). Если вы завершите свою задачу, служба обнаружит, что у нее нет Desired Count запущенных задач и просто раскрутите новую. Это вызовет повторное извлечение вашего контейнера на основе того же тега.

Услуги ECS - это сеть безопасности HA, не замена вашего конвейера CD / CI.


Бонус: Если цель состоит в том, чтобы служба распознала, что новый контейнер был отправлен (независимо от тегов), нам нужно учитывать последствия этого. Неужели мы действительно хотим, чтобы базовый сервис управлял нашим конвейером развертывания? Скорее всего, нет. В идеале вы будете использовать свои контейнеры с разными тегами (в зависимости от версии выпуска или чего-то еще). В этом случае препятствием для развертывания является то, что служба должна быть уведомлена о чем-то новом - опять же, это подстраховка для службы и не более того.


Как развернуть новые теги за три шага:

  1. Загрузите свой новый container:tag в репозиторий
  2. Создайте новое определение задачи, ссылаясь на новое tag
  3. Обновите свою службу, чтобы ссылаться на новое определение задачи
    • Осторожно! Если у вас есть minimum healthy установлен в 0% как предполагают некоторые другие ответы, вы даете AWS полное право уничтожить весь ваш сервис, чтобы развернуть новое определение задачи. Если вы предпочитаете скользящее / постепенное развертывание, установите для минимума что-нибудь >0%.
    • Или установите свой minimum healthy к 100% и ваш maximum healthy к чему-то >100% чтобы позволить вашему сервису развернуть новый задачи, прежде чем убивать старые (минимизация воздействия на ваших пользователей).

С этого момента ваша служба автоматически распознает, что вы указали новую задачу, и будет работать над ее развертыванием на основе minimum/maximum здоровые пороги, которые вы настроили.

Я использую часть из сценарий ecs-deploy с моими улучшениями (он берет изображения из каждого описания контейнера и заменяет его часть тега на $ TAG_PURE): https://gist.github.com/Forever-Young/e939d9cc41bc7a105cdcf8cd7ab9d714

# based on ecs-deploy script
TASK_DEFINITION_NAME=$(aws ecs describe-services --services $SERVICE --cluster $CLUSTER | jq -r .services[0].taskDefinition)
TASK_DEFINITION=$(aws ecs describe-task-definition --task-def "$TASK_DEFINITION_NAME" | jq '.taskDefinition')
NEW_CONTAINER_DEFINITIONS=$(echo "$TASK_DEFINITION" | jq --arg NEW_TAG $TAG_PURE 'def replace_tag: if . | test("[a-zA-Z0-9.]+/[a-zA-Z0-9]+:[a-zA-Z0-9]+") then sub("(?<s>[a-zA-Z0-9.]+/[a-zA-Z0-9]+:)[a-zA-Z0-9]+"; "\(.s)" + $NEW_TAG) else . end ; .containerDefinitions | [.[] | .+{image: .image | replace_tag}]')
TASK_DEFINITION=$(echo "$TASK_DEFINITION" | jq ".+{containerDefinitions: $NEW_CONTAINER_DEFINITIONS}")
# Default JQ filter for new task definition
NEW_DEF_JQ_FILTER="family: .family, volumes: .volumes, containerDefinitions: .containerDefinitions"
# Some options in task definition should only be included in new definition if present in
# current definition. If found in current definition, append to JQ filter.
CONDITIONAL_OPTIONS=(networkMode taskRoleArn)
for i in "${CONDITIONAL_OPTIONS[@]}"; do
  re=".*${i}.*"
  if [[ "$TASK_DEFINITION" =~ $re ]]; then
    NEW_DEF_JQ_FILTER="${NEW_DEF_JQ_FILTER}, ${i}: .${i}"
  fi
done

# Build new DEF with jq filter
NEW_DEF=$(echo $TASK_DEFINITION | jq "{${NEW_DEF_JQ_FILTER}}")
NEW_TASKDEF=`aws ecs register-task-definition --cli-input-json "$NEW_DEF" | jq -r .taskDefinition.taskDefinitionArn`

echo "New task definition registered, $NEW_TASKDEF"

aws ecs update-service --cluster $CLUSTER --service $SERVICE --task-definition "$NEW_TASKDEF" > /dev/null

echo "Service updated"

После загрузки нового образа Docker, даже если он имеет тот же тег, что и используемый задачей, необходимо скопировать последнюю задачу, а затем настроить Службу для использования этой новой задачи. При желании можно просто создать 2 повторяющиеся задачи и настроить Службу для переключения между ними при каждом обновлении образа Docker.

По сути, для того, чтобы создать новый контейнер Docker с помощью ECS, обновление Службы должно запускать его, и единственный способ сделать триггер службы - обновить его каким-либо образом - например, указав ему использовать другой номер задачи.

Обратите внимание, что существующие работающие Контейнеры могут не останавливаться автоматически только потому, что Служба была обновлена ​​- вам может потребоваться просмотреть список задач и остановить их вручную.

Подход, который мне подходит, аналогичен приведенному выше. После создания службы и задачи и начала работы отредактируйте Группа автоматического масштабирования и обеспечить мин, Максимум и желанный установлены на 1.

Группа может быть по умолчанию; если вы не уверены, вы можете перейти к нему, выбрав Экземпляры ECS вкладка в кластере, затем из Действия раскрывающийся список выберите Ресурсы кластера и щелкните ссылку в нижней части открывшегося диалогового окна.

Когда все на месте, каждый раз, когда вы хотите развернуть обновленный образ контейнера, перейдите в Задача площадь кластера и Стоп задание. Вы получите предупреждение, но при условии, что автоматическое масштабирование настроено, служба снова запустит его при последнем нажатии.

Не нужно создавать новые версии ни сервиса, ни задачи.

Обратите внимание, что служба / задача обновляются в любом месте мгновенно с точностью до минуты или около того. Если вы отчаянно ждете, вы можете просто запустить новую задачу вручную. Сервис не будет владеть им, поэтому он не идеален, но он все равно запустит новый, если он умрет.

Ты можешь использовать --force-new-deployment вариант на ecs update-service вызов api. Само обслуживание не требует обновления. Из документы:

Следует ли форсировать новое развертывание службы. По умолчанию развертывания не выполняются принудительно. Вы можете использовать этот параметр, чтобы запустить новое развертывание без изменений определения службы. Например, вы можете обновить задачи службы, чтобы использовать более новый образ Docker с той же комбинацией изображения и тега (my_image: latest) или перенести задачи Fargate на более новую версию платформы.

Это так же просто, как с aws-cli:

aws ecs update-service --cluster my-cluster --service my-service --force-new-deployment