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

32

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

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

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

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

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

Петрус Репо
источник
Также пытаемся это выяснить, поскольку мы надеемся использовать ECS для развертывания различных демонов, которые должны непрерывно работать в производстве.
parent5446
1
Просто чтобы подтвердить, вы сказали, что перезапуск службы ecs приведет к сбою последней версии образа? Я искал документацию об этом и нигде не могу ее найти.
ммиллерува
1
Есть подтверждение на этот?
Лиор Оана
@LiorOhana К сожалению, это правда. Смотрите мой ответ для деталей.
hamx0r
Я разместил новый подробный ответ ниже, но поясню: ваш сервис всегда будет пытаться получить свежую копию вашего контейнера из репозитория на основе установленного вами тега. Если задача будет убита, когда служба разворачивает его снова, он не помнит , что было в репо, только то , что есть в репо.
MrDuk

Ответы:

18

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

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

  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
uiron
источник
2
Это заставляет меня иметь определение задачи в виде файла локально, и, если я правильно понимаю, это единственное место, где я могу определять переменные среды. Есть ли способ сделать это без локальных переменных окружения? В идеале я хотел бы выдать команду, указывающую на новый тег изображения докера, без отправки какой-либо другой информации о задаче / услуге / контейнере / и т. Д.
rmac
1
Комментарии на set "min health/max health" limits to "0%, 100%"это золотой. Спасибо большое!
Сивабуд
1
Здесь следует предостеречь, если вы установите minзначение 0%, при изменении определения задачи, которую развертывает ваша служба, вы, по сути, даете ей полное право одновременно завершать выполнение всех задач для этого развертывания.
MrDuk
1

Я использую некоторую часть из скрипта 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"
Вечно молодой
источник
Рекомендуется указывать полезную информацию по ссылкам в вашем ответе, чтобы предоставить ссылку-гниль. Не могли бы вы сделать это, пожалуйста?
BE77Y
1
Обновил
1

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

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

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

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

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

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

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

Нет необходимости создавать новые версии службы или задачи.

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

К Картлидж
источник
1

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

Как обновить работающий контейнер в два этапа:

Ниже предполагается, что у вас есть служба, выполняющая задачу, которая ссылается на контейнер с тегом 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/ maximumhealthy.

MrDuk
источник
хорошо, спасибо, лучше, чем другие ответы
Олегзандр Денман