繁体   English   中英

AWS ECS 使用相同的任务定义和图像重新启动服务,无需停机

[英]AWS ECS restart Service with the same task definition and image with no downtime

我试图在不对任务定义进行任何更改的情况下重新启动 AWS 服务(基本上是停止和启动服务中的所有任务)。

这样做的原因是因为图像在每个构建中都附加了latest的标签。

我已尝试停止所有任务并让服务重新创建它们,但这意味着在我的实例 (2) 中重新启动服务时出现一些temporarily unavailable的错误。

处理这个问题的最佳方法是什么? 比方说,没有停机时间的蓝绿部署策略?

这就是我目前所拥有的。 它的缺点是我的应用程序将关闭几秒钟,因为服务的任务在删除后正在重建。

configure_aws_cli(){
    aws --version
    aws configure set default.region us-east-1
    aws configure set default.output json
}

start_tasks() {
    start_task=$(aws ecs start-task --cluster $CLUSTER --task-definition $DEFINITION --container-instances $EC2_INSTANCE --group $SERVICE_GROUP --started-by $SERVICE_ID)
    echo "$start_task"
}

stop_running_tasks() {
    tasks=$(aws ecs list-tasks --cluster $CLUSTER --service $SERVICE | $JQ ".taskArns | . []");
    tasks=( $tasks )
    for task in "${tasks[@]}"
    do
        [[ ! -z "$task" ]] && stop_task=$(aws ecs stop-task --cluster $CLUSTER --task "$task")
    done
}

push_ecr_image(){
    echo "Push built image to ECR"
    eval $(aws ecr get-login --region us-east-1)
    docker push $AWS_ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com/repository:$TAG
}

configure_aws_cli
push_ecr_image
stop_running_tasks
start_tasks

使用update-service--force-new-deployment标志:

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

等一下。 如果我正确理解了你的用例,这在官方文档中得到了解决:

如果更新后的 Docker 映像使用与服务的现有任务定义中相同的标签(例如,my_image:latest),则无需创建任务定义的新修订版。 您可以使用以下过程更新服务,保留服务的当前设置,然后选择强制新部署...。

为避免停机,您应该操纵 2 个参数:最小健康百分比最大百分比

例如,如果您的服务有四个任务的期望数量和最大百分比值为 200%,则调度程序可能会在停止四个旧任务之前启动四个新任务(前提是执行此操作所需的集群资源可用)。 最大百分比的默认值为 200%。

这基本上意味着,无论您的任务定义是否发生变化以及变化的程度如何,新旧任务之间都可能存在“重叠”,这就是实现弹性和可靠性的方式。

更新: Amazon 刚刚为 ECS(EC2 和 Fargate) 引入了外部部署控制器。 它包括一个新的抽象级别,称为 TaskSet。 我自己还没有尝试过,但是对服务和任务管理的这种细粒度控制(支持两种 API)可能会解决与此类似的问题。

将新映像推送到 Docker 存储库后,您可以创建任务定义的新修订版(它可以与现有任务定义相同)并更新您的服务以使用新的任务定义修订版。 这将触发服务部署,您的服务将从您的存储库中拉取新图像。

这样您的任务定义保持不变(尽管需要将服务更新到新的任务定义修订版才能触发图像拉取),并且仍然使用图像的“最新”标签,但您可以利用 ECS 服务部署避免停机的功能。

事实上,即使任务定义本身没有变化,我也必须每次都对我的任务定义创建一个新的修订版,这是不对的。

这上面有一堆粗略的 bash 实现,这意味着 AWS 应该让 ECS 服务调度程序监听图像中的更改/更新,尤其是对于自动构建过程。

crude的解决方法是有两个相同的任务定义,并在每次构建时在它们之间切换。 这样我就没有多余的修改。

这是执行此操作的特定脚本片段。

update_service() {
    echo "change task definition and update service"
    taskDefinition=$(aws ecs describe-services --cluster $CLUSTER --services $SERVICE | $JQ ".services | . [].taskDefinition")
    if [ "$taskDefinition" = "$TASK_DEF_1" ]; then
        newDefinition="$TASK_DEF_2"
    else
        newDefinition="$TASK_DEF_1"
    fi
    rollUpdate=$(aws ecs update-service --cluster $CLUSTER --service $SERVICE --task-definition $newDefinition)
}

我正在尝试重新启动 AWS 服务(基本上停止和启动服务中的所有任务)而不对任务定义进行任何更改。

这样做的原因是因为图像在每个构建中都附加了latest标签。

我已尝试停止所有任务并让服务重新创建它们,但这意味着在我的实例中重新启动服务时会出现一些temporarily unavailable错误 (2)。

处理这个问题的最佳方法是什么? 比如说,一个没有停机的蓝绿部署策略?

这就是我目前所拥有的。 它的缺点是我的应用程序将关闭几秒钟,因为服务的任务在删除它们后正在重建。

configure_aws_cli(){
    aws --version
    aws configure set default.region us-east-1
    aws configure set default.output json
}

start_tasks() {
    start_task=$(aws ecs start-task --cluster $CLUSTER --task-definition $DEFINITION --container-instances $EC2_INSTANCE --group $SERVICE_GROUP --started-by $SERVICE_ID)
    echo "$start_task"
}

stop_running_tasks() {
    tasks=$(aws ecs list-tasks --cluster $CLUSTER --service $SERVICE | $JQ ".taskArns | . []");
    tasks=( $tasks )
    for task in "${tasks[@]}"
    do
        [[ ! -z "$task" ]] && stop_task=$(aws ecs stop-task --cluster $CLUSTER --task "$task")
    done
}

push_ecr_image(){
    echo "Push built image to ECR"
    eval $(aws ecr get-login --region us-east-1)
    docker push $AWS_ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com/repository:$TAG
}

configure_aws_cli
push_ecr_image
stop_running_tasks
start_tasks

你有没有解决这个问题? 也许这对你有用。

将带有版本标签(即v1.05latest标签)的新版本映像推送到 ECR 后,我的任务定义中的image定位器需要显式更新,以便将此版本标签作为后缀,如:v1.05

使用:latest ,这个新图像在aws ecs update-service --force-new-deployment --service my-service之后没有被新容器拉取。

我正在做这样的标记和推送:

docker tag ${imageId} ${ecrRepoUri}:v1.05
docker tag ${imageId} ${ecrRepoUri}:latest
docker push ${ecrRepoUri}

...这是推送多个标签的正确方法:

docker tag ${imageId} ${ecrRepoUri}
docker push ${ecrRepoUri}:v1.05
docker push ${ecrRepoUri}:latest

官方文档中简要提到了这一点,但没有适当的示例。

效果很好https://github.com/fdfk/ecsServiceRestart

python ecsServiceRestart.py 重启 --services="app app2" --cluster=test

快速而肮脏的方式:

  • 登录到运行任务的 EC2 实例
  • 使用docker container list找到你的容器
  • 使用docker restart [container]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM