ECS部署新容器后旧容器未自动删除的技术求助
问题分析与解决方案
从你提供的docker ps输出能看到核心问题:旧容器sad_shannon是手动启动的(名字不带ECS前缀),ECS只会自动清理由自身服务/任务创建的容器(名字以ecs-开头),不会处理手动运行的容器。另外还有几处配置问题导致自动部署流程异常,以下是具体修复步骤:
1. 彻底清理手动容器,统一由ECS管理部署
首先删除所有手动启动的Web容器,之后禁止直接在EC2实例上手动运行docker run启动应用容器,所有部署操作通过ECS服务完成:
# 停止并删除手动容器 docker stop 1a70ab03320c docker rm 1a70ab03320c
2. 修正任务定义的端口映射配置
当前任务定义中hostPort: 4173是固定宿主机端口,在EC2模式下会导致:
- 同一EC2实例上无法同时运行多个任务(端口冲突)
- 部署时旧任务未完全终止前,新任务无法绑定端口(你当前的新ECS容器没有端口映射,说明启动时端口被占用,ECS自动跳过了端口绑定)
修复方案:
将任务定义中的hostPort改为0,使用动态端口映射,配合AWS Application Load Balancer(ALB)转发流量:
"portMappings": [ { "name": "aguacero-frontend-4173-tcp", "containerPort": 4173, "hostPort": 0, // 改为0,让ECS自动分配宿主机端口 "protocol": "tcp", "appProtocol": "http" } ]
之后配置ALB监听4173端口,将流量转发到ECS服务的目标组,由ALB自动处理容器的端口映射和流量切换。
3. 为任务添加健康检查配置
ECS需要通过健康检查确认新容器就绪后,才会终止旧任务。在任务定义的容器配置中添加健康检查:
"healthCheck": { "command": ["CMD-SHELL", "curl -f http://localhost:4173 || exit 1"], "interval": 30, "timeout": 5, "retries": 3, "startPeriod": 60 }
这样ECS会等待新容器健康后,再逐步终止旧任务,避免服务中断。
4. 修正任务定义中的环境变量拼写错误
你任务定义里的环境变量存在拼写错误,导致ECS代理的镜像拉取和清理功能失效:
- 将
ECS_IMAGE_PULL_BEHAVIORL改为ECS_IMAGE_PULL_BEHAVIOR,值设为always(确保每次部署拉取最新镜像) - 保留
ECS_IMAGE_CLEANUP_INTERVAL(用于自动清理旧镜像,不影响容器删除)
修正后的环境变量:
"environment": [ { "name": "VITE_HOST_URL", "value": "http://0.0.0.0:8081" }, { "name": "ECS_IMAGE_CLEANUP_INTERVAL", "value": "3600" }, { "name": "ECS_IMAGE_PULL_BEHAVIOR", "value": "always" } ]
5. 验证ECS服务的部署配置
确保ECS服务的以下配置正确:
- 部署类型:滚动更新(默认)
- 最小健康百分比:0%(你已设置)
- 最大健康百分比:100%(你已设置)
- 期望任务数:1(确保每次部署只运行一个任务实例)
6. 验证GitHub Actions的服务更新命令
你的update-service命令已包含--force-new-deployment,这会强制ECS启动新任务并终止旧任务,无需额外修改。
完成以上配置后,重新推送代码触发部署,ECS会自动:
- 启动新任务(使用动态端口)
- 等待新任务健康检查通过
- 终止旧任务并自动删除对应的容器
- ALB自动将流量切换到新容器
内容的提问来源于stack exchange,提问作者Wx_Trader
相关产品推荐
相关产品推荐

