更新AWS ECS服务任务的最佳实践

时间:2017-09-02 22:49:10

标签: amazon-web-services docker amazon-ec2

我目前正在尝试设置一个简单的CI,它将重建我的项目,创建一个新的docker镜像,将新图像推送到amazon ecr repo,使用最新版本创建现有任务定义的新版本docker image,使用新版本的任务定义更新正在运行的服务,最后停止运行旧版本的现有任务,并启动运行新版本的任务。

除了启动任务的新修订版外,一切正常。

从bash脚本中,我调用的最后一个命令是:

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命令会停止现有任务,并启动新任务,但看起来它首先启动新任务,如果成功则停止旧任务。

处理此问题的最佳做法是什么?我应该先停止旧任务吗?我应该先删除我脚本中的服务,然后在每次更新时重新创建整个服务吗?

目前我只需要运行一个任务实例,但如果我需要这个实例可以自动扩展到多个实例,我不想自我填充。有关解决这个问题的最佳方法的任何建议吗?

5 个答案:

答案 0 :(得分:23)

您收到的消息是因为ECS正在尝试进行蓝绿色部署。这意味着它正在尝试分配您的新任务修订版而不停止当前任务以避免服务停机。一旦最新任务准备就绪(稳定状态),旧的任务将最终被移除。

此类部署的问题在于,您需要在群集中拥有足够的免费资源,以便在一段时间内维护并运行2个任务(新旧任务)。例如,如果要部署具有2GB内存和2个CPU的任务,则群集将需要具有该数量的可用资源,以便使用新任务修订更新服务。

您有两个选择:

  1. 通过添加新的EC2实例来扩展您的群集,以便您拥有足够的可用资源并执行部署。
  2. 更改您的服务配置,以便不执行蓝绿色部署(在群集中同时只允许1个任务)。
  3. 要执行选项编号2,您只需设置以下值:

    • Minimun健康百分比:0
    • 最高百分比:100

    实施例

    Example

    这意味着您只希望100%的所需任务正在运行(并且不再需要!),并且您愿意在部署新版本时(0%的健康服务)停机。

    在示例中,我假设您只需要1个所需任务,但 Minimun健康百分比 Maximun%值适用于任何需要的量你想要的任务。

    希望它有所帮助!如果您有任何其他疑问,请告诉我。

答案 1 :(得分:3)

您可以使用构建环境中的shell脚本,通过以下步骤启动新版本的任务。

  1. 将构建环境中的tasks definition json template存储在文件中(例如,模板文件为web-server.json,任务定义系列为web-server)。

  2. 将文件目录用作当前目录并执行注册任务定义(如果不存在则首次运行发生)

    aws ecs register-task-definition --cli-input-json file://web-server.json

  3. 将运行任务ID(TASK_ID)获取到shell脚本中的变量。

    TASK_ID=`aws ecs list-tasks --cluster default --desired-status RUNNING --family web-server | egrep "task" | tr "/" " " | tr "[" " " | awk '{print $2}' | sed 's/"$//'`

  4. 获取shell脚本中变量的任务修订版(TASK_REVISION)。

    TASK_REVISION=`aws ecs describe-task-definition --task-definition web-server | egrep "revision" | tr "/" " " | awk '{print $2}' | sed 's/"$//'`

  5. 停止当前正在运行的任务

    aws ecs stop-task --cluster default --task ${TASK_ID}

  6. 立即开始新任务

    aws ecs update-service --cluster default --service web-server --task-definition web-server:${TASK_REVISION} --desired-count 1

  7. 作为最佳实践,您可以使用以下脚本保持2个任务(在服务内运行的两个任务)的最小期望值并进行滚动更新(一次更新一个任务)(多个容器的上述步骤的扩展) )零停机时间(确保在第一次容器更新后保持足够的时间,例如睡眠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
    

    注意:您需要相应地配置任务定义系列,期望实例数和任务定义模板。

答案 2 :(得分:1)

更新服务中运行的“任务”中的任务定义您需要删除任务并开始新任务。

通过这种方式,我解决了在任务中更新任务定义的问题

我写了以下代码:

    # 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

答案 3 :(得分:1)

使用-> AWS CLI

获取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

答案 4 :(得分:0)

所以我现在确实有这个工作。

在使用新任务定义调用aws ecs update service之后,我调用aws ecs list-tasks,然后对服务的每个正在运行的任务运行'aws stop task`。由于服务的所需计数为1,因此它会立即尝试备份任务并使用新的服务定义。

这不是很漂亮,但它现在似乎运作良好。