ECS部署ECR镜像时为何使用首个而非最新Task Definition?
ECS服务持续使用旧Task Definition,CodeDeploy部署停滞问题排查
问题描述
我使用CircleCI结合aws/ecr、aws/ecs orb上传新Docker镜像,预期更新ECS服务,但遇到以下问题:
- CircleCI部署日志显示已使用最新的Task Definition(可在部署版本及appspec中查看),但ECS服务始终使用最初创建的错误Task Definition(曾错误设置镜像为SHA ID导致无法拉取)。
- 错误Task Definition导致任务持续启动失败,CodeDeploy部署陷入停滞,无法完成版本更新。
核心配置信息
Terraform基础设施配置(关键片段)
# ECS任务定义 resource "aws_ecs_task_definition" "task_def" { family = "${var.app_name}-task-def-${var.env}" network_mode = "awsvpc" task_role_arn = aws_iam_role.ecs_task_role.arn execution_role_arn = aws_iam_role.ecs_exec_role.arn requires_compatibilities = ["FARGATE"] cpu = "256" memory = "512" container_definitions = jsonencode([ { name = "${var.app_name}-container-${var.env}" image = "${data.aws_ecr_repository.ecr_repository.repository_url}:latest" essential = true portMappings = [ { containerPort = var.port hostPort = var.port }, ] # 其他配置省略 }, ]) } # ECS服务 resource "aws_ecs_service" "service" { lifecycle { ignore_changes = [ task_definition, load_balancer, ] } cluster = aws_ecs_cluster.cluster.arn name = "${var.app_name}-service-${var.env}" task_definition = aws_ecs_task_definition.task_def.arn deployment_controller { type = "CODE_DEPLOY" } # 其他配置省略 } # CodeDeploy部署组 resource "aws_codedeploy_deployment_group" "deployment_group" { app_name = aws_codedeploy_app.codedeploy_app.name deployment_config_name = "CodeDeployDefault.ECSAllAtOnce" auto_rollback_configuration { enabled = true events = ["DEPLOYMENT_FAILURE"] } blue_green_deployment_config { terminate_blue_instances_on_deployment_success { action = "TERMINATE" termination_wait_time_in_minutes = 5 } } # 其他配置省略 }
CircleCI部署配置
deploy: executor: aws-ecr/default working_directory: ~/code parameters: env: type: string steps: - attach_workspace: at: ~/ - aws-ecr/build-and-push-image: repo: "test-<< parameters.env >>" tag: "latest,${CIRCLE_BUILD_NUM}" - aws-ecs/update-service: family: "test-task-def-<< parameters.env >>" service-name: "test-service-<< parameters.env >>" cluster: "test-cluster-<< parameters.env >>" container-image-name-updates: "container=test-container-<< parameters.env >>,tag=${CIRCLE_BUILD_NUM}" deployment-controller: "CODE_DEPLOY" codedeploy-application-name: "test-application-<< parameters.env >>" codedeploy-deployment-group-name: "test-deployment-group-<< parameters.env >>" codedeploy-load-balanced-container-name: "test-container-<< parameters.env >>" codedeploy-load-balanced-container-port: 3000
问题原因分析
- CodeDeploy蓝绿部署未完成切换:初始错误的Task Definition导致蓝环境任务启动失败,后续CircleCI触发的部署中,绿色环境的新任务可能因权限、镜像地址等问题仍无法启动,CodeDeploy无法完成流量切换,服务活跃任务定义停留在旧版本。
- 停滞部署阻塞更新流程:CodeDeploy存在未完成的失败部署时,新部署可能无法正常触发,或服务会持续尝试用旧任务定义恢复失败任务。
- ECS执行角色权限缺失:当前Terraform配置中,ECS执行角色未添加ECR镜像拉取权限(
AmazonEC2ContainerRegistryReadOnly),可能导致新Task Definition无法拉取镜像,任务启动失败。 - Terraform生命周期规则:ECS Service配置的
lifecycle.ignore_changes = [task_definition]会阻止Terraform更新服务的任务定义,但不影响AWS API调用(如CircleCI orb),不过初始部署的旧任务定义可能成为服务默认状态,若后续部署未正确覆盖则持续保留。
解决方案
1. 清理停滞的CodeDeploy部署
- 登录AWS CodeDeploy控制台,找到对应应用和部署组下的失败/进行中部署,手动停止或回滚。
- 确保部署组中无阻塞状态的部署。
2. 手动验证并激活正确Task Definition
- 登录AWS ECS控制台,创建任务定义新版本,指定正确的ECR镜像地址(如
xxx.dkr.ecr.region.amazonaws.com/repo:${CIRCLE_BUILD_NUM})。 - 手动更新ECS服务,切换到新版本任务定义,验证任务是否能正常启动。
3. 修复ECS执行角色权限
在Terraform中为ECS执行角色添加ECR只读权限:
resource "aws_iam_role_policy_attachment" "attach_ecr_readonly_to_exec_role" { role = aws_iam_role.ecs_exec_role.name policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly" }
执行terraform apply更新权限配置。
4. 重新触发CircleCI部署
- 确认
container-image-name-updates中的容器名称与Task Definition完全匹配,tag使用正确的构建号。 - 重新运行部署流水线,观察CodeDeploy部署流程是否正常完成,绿色环境任务是否启动成功。
5. 排查任务启动失败细节
- 查看ECS任务的CloudWatch日志,定位任务启动失败的具体原因(如镜像拉取错误、网络配置问题、环境变量缺失等)。
- 验证ECR镜像是否存在,权限是否正确配置。
内容的提问来源于stack exchange,提问作者Gergő Horváth
相关产品推荐
相关产品推荐

