Рекомендации по обновлению задач службы 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