Рекомендации по обновлению задач службы AWS ECS
В настоящее время я пытаюсь создать простой CI, который перестроит мой проект, создаст новое изображение докеров, подтолкнет новое изображение к репозиторию amazon ecr, создаст новую ревизию существующего определения задачи с последним изображением докеров, обновить запущенную службу с новой ревизией определения задачи и, наконец, остановить существующую задачу, выполняющую старую ревизию, и запустить запуск новой версии.
Все работает отлично, за исключением начала новой ревизии задачи.
От bash script заключительная команда, которую я вызываю:
aws ecs update-service --cluster "$CLUSTER" --service "$SERVICE" --task-definition "$TASK_DEFINITION":"$REVISION"
Это приводит к ошибке события:
(service rj-api-service) was unable to place a task because no container instance met all of its requirements. The closest matching (container-instance bbbc23d5-1a09-45e7-b344-e68cc408e683) is already using a port required by your task.
И это имеет смысл, потому что контейнер, который я заменяю, точно такой же, как новый, и будет работать на одном и том же порту, он просто содержит самую последнюю версию моего приложения.
У меня было впечатление, что команда update-service
остановит существующую задачу и запустит новую, но похоже, что она сначала запускает новую, и если она преуспевает, она останавливает старую.
Какова наилучшая практика для этого? Должен ли я сначала остановить старую задачу? Должен ли я просто удалить службу в моем script и обновить всю услугу каждое обновление?
В настоящее время мне нужен только один экземпляр запускаемой задачи, но я не хочу вставлять себя, если мне это нужно, чтобы иметь возможность автоматического масштабирования для нескольких экземпляров. Любые предложения по наилучшему способу решения этой проблемы?
Ответы
Ответ 1
Сообщение, которое вы получаете, связано с тем, что ECS пытается выполнить сине-зеленое развертывание. Это означает, что он пытается распределить вашу новую ревизию задачи, не останавливая текущую задачу, чтобы избежать простоев в вашей службе. Когда новая задача будет готова (устойчивое состояние), старый будет удален.
Проблема с этим типом развертывания заключается в том, что вам нужно иметь достаточно свободных ресурсов в вашем кластере, чтобы поддерживать и запускать 2 задачи (старые и новые) в течение определенного периода времени. Например, если вы развертываете задачу с 2 ГБ оперативной памяти и 2 ЦП, ваш кластер должен будет иметь такое количество свободных ресурсов, чтобы обновить службу с новой ревизией задачи.
У вас есть 2 варианта:
- Увеличьте свой кластер, добавив новый экземпляр EC2, чтобы иметь достаточно свободных ресурсов и выполнить развертывание.
- Измените конфигурацию своей службы, чтобы не выполнять сине-зеленое развертывание (одновременно разрешите только одно задание в вашем кластере).
Для выполнения опции номер 2 вам нужно установить только следующие значения:
- Minimun health percent: 0
- Максимум%: 100
Пример
![Пример]()
Это означает, что вы хотите, чтобы у вас было 100% ваших желаемых задач (и не более!), и вы готовы иметь простой при развертывании новой версии (0% полезной службы).
В примере я предполагаю, что вы хотите только 1 желаемую задачу, но значения Minimun healthy percent и Maximun percent будут работать для любого количества желаемых задач, которые вы хотите.
Надеюсь, это поможет! Дайте мне знать, если у вас есть другие сомнения.
Ответ 2
Вы можете запустить новую ревизию задач со следующими шагами, используя оболочку script в своей среде сборки.
-
Храните определение json-шаблона задач в вашей среде сборки в файле (например, файл шаблона web-server.json
и задача определение web-server
).
-
Используйте каталог файлов в качестве текущего каталога и выполните определение задачи регистрации (происходит для первого запуска, если не существует)
aws ecs register-task-definition --cli-input-json file://web-server.json
-
Получить идентификатор текущей задачи (TASK_ID) в переменной в оболочке script.
TASK_ID=`aws ecs list-tasks --cluster default --desired-status RUNNING --family web-server | egrep "task" | tr "/" " " | tr "[" " " | awk '{print $2}' | sed 's/"$//'`
-
Получить ревизию задачи (TASK_REVISION) для переменных в оболочке script.
TASK_REVISION=`aws ecs describe-task-definition --task-definition web-server | egrep "revision" | tr "/" " " | awk '{print $2}' | sed 's/"$//'`
-
Остановить выполнение текущей задачи
aws ecs stop-task --cluster default --task ${TASK_ID}
-
Немедленно запустите новую задачу
aws ecs update-service --cluster default --service web-server --task-definition web-server:${TASK_REVISION} --desired-count 1
Как наилучшая практика, вы можете сохранить минимальный минимум для двух задач (две задачи, выполняемые внутри службы), и выполнять скользящие обновления (одновременно обновлять одну задачу), используя следующий script (расширение вышеуказанных шагов для несколько контейнеров) с нулевым временем простоя (убедитесь, что у вас осталось достаточно времени после первого обновления контейнера, например, sleep 30, чтобы он был готов принимать новые запросы).
cd /<directory-containing-web-server.json>
aws ecs register-task-definition --cli-input-json file://web-server.json
OLD_TASK_ID=`aws ecs list-tasks --cluster default --desired-status RUNNING --family web-server | egrep "task" | tr "/" " " | tr "[" " " | awk '{print $2}' | sed 's/"$//'`
TASK_REVISION=`aws ecs describe-task-definition --task-definition web-server | egrep "revision" | tr "/" " " | awk '{print $2}' | sed 's/"$//'`
aws ecs stop-task --cluster default --task ${OLD_TASK_ID}
OLD_TASK_ID=`aws ecs list-tasks --cluster default --desired-status RUNNING --family web-server | egrep "task" | tr "/" " " | tr "[" " " | awk '{print $2}' | sed 's/"$//'`
aws ecs update-service --cluster default --service web-server --task-definition web-server:${TASK_REVISION} --desired-count 1
sleep 30
aws ecs stop-task --task ${OLD_TASK_ID}
aws ecs update-service --cluster default --service web-server --task-definition web-server:${TASK_REVISION} --desired-count 2
Примечание. Необходимо соответствующим образом настроить семейство определения задачи, желаемое количество экземпляров и шаблон определения задачи.
Ответ 3
Чтобы обновить определение задачи в "задачах", запущенных в сервисе, необходимо удалить задачи и запустить новую задачу.
Таким образом, я решаю проблему обновления определения задач в задачах.
Я написал следующий код:
# Register a new Task definition
aws ecs register-task-definition --family testing-cluster --cli-input-json file://scripts/taskdefinition/testingtaskdef.json --region $AWS_REGION
# Update Service in the Cluster
aws ecs update-service --cluster $CLUSTER_NAME --service $SERVICE --task-definition testing-cluster --desired-count 1 --region $AWS_REGION
DECRIBED_SERVICE=$(aws ecs describe-services --region $AWS_REGION --cluster $CLUSTER_NAME --services $SERVICE);
CURRENT_DESIRED_COUNT=$(echo $DECRIBED_SERVICE | jq --raw-output ".services[0].desiredCount")
# - echo $CURRENT_DESIRED_COUNT
CURRENT_TASK_REVISION=$(echo $DECRIBED_SERVICE | jq -r ".services[0].taskDefinition")
echo "Current Task definition in Service" + $CURRENT_TASK_REVISION
CURRENT_RUNNING_TASK=$(echo $DECRIBED_SERVICE | jq -r ".services[0].runningCount")
echo $CURRENT_RUNNING_TASK
CURRENT_STALE_TASK=$(echo $DECRIBED_SERVICE | jq -r ".services[0].deployments | .[] | select(.taskDefinition != \"$CURRENT_TASK_REVISION\") | .taskDefinition")
echo "Task defn apart from current service Taskdefn" + $CURRENT_STALE_TASK
# - echo $CURRENT_STALE_TASK
tasks=$(aws ecs --region $AWS_REGION list-tasks --cluster $CLUSTER_NAME | jq -r '.taskArns | map(.[40:]) | reduce .[] as $item (""; . + $item + " ")')
echo "Tasks are as follows"
echo $tasks
TASKS=$(aws ecs --region $AWS_REGION describe-tasks --cluster $CLUSTER_NAME --task $tasks);
# - echo $TASKS
OLDER_TASK=$(echo $TASKS | jq -r ".tasks[] | select(.taskDefinitionArn!= \"$CURRENT_TASK_REVISION\") | .taskArn | split(\"/\") | .[1] ")
echo "Older Task running " + $OLDER_TASK
for old_task in $OLDER_TASK; do
aws ecs --region us-east-1 stop-task --cluster $CLUSTER_NAME --task $old_task
done
# Run new tasks with the updated new Task-definition
aws ecs --region $AWS_REGION run-task --cluster $CLUSTER_NAME --task-definition $CURRENT_TASK_REVISION
Ответ 4
Итак, теперь у меня есть эта работа.
После вызова aws ecs update service
с новым определением задачи я вызываю aws ecs list-tasks
, а затем запускаю "aws stop task" для каждой запущенной задачи для службы. Поскольку требуемый счетчик для службы равен 1, он сразу же пытается запустить резервное копирование задач и использует новое определение службы.
Это не очень красиво, но, похоже, сейчас он достаточно хорошо работает.
Ответ 5
Получить OLD_TASK_ID
aws ecs list-tasks --cluster ${ecsClusterName} --desired-status RUNNING --family ${nameTaskDefinition} | egrep "task/" | sed -E "s/.*task\/(.*)\"/\1/"
Стоп ЗАДАЧА
aws ecs stop-task --cluster ${ecsClusterName} --task ${OLD_TASK_ID}
Обновление службы ECS
aws ecs update-service --cluster ${ecsClusterName} --service ${nameService} --task-definition ${nameTaskDefinition}:${version} --desired-count 1 --force-new-deployment