请求在AWS EC2启动ECS任务前执行docker system prune解决磁盘满问题
嘿,这个问题我之前帮好几个开发者处理过,确实是ECS+EC2自动关机场景里很容易踩的坑——任务刚结束就触发关机,Docker的自动清理(比如定时垃圾回收或者默认的资源清理逻辑)根本没机会跑,日积月累磁盘自然就被占满了。给你几个靠谱的解决方案,按优先级排序:
方案1:在关机流程里主动触发Docker清理(最可靠)
核心思路是不要直接关机,先让EC2执行完彻底的Docker清理操作,确认完成后再关机。你可以修改CloudWatch规则触发的Lambda函数来实现这个流程:
- 原来的Lambda可能是直接调用
ec2.stop_instances(),现在改成三步:- 用EC2 Run Command给目标实例发送清理命令
- 等待清理命令执行完成
- 再调用关机接口
示例Lambda代码片段(Python):
import boto3 import time ec2 = boto3.client('ec2') ssm = boto3.client('ssm') def lambda_handler(event, context): # 从CloudWatch事件中获取目标EC2实例ID instance_id = event['detail']['instance-id'] # 发送Docker全量清理命令:清理未使用的容器、镜像、卷 response = ssm.send_command( InstanceIds=[instance_id], DocumentName='AWS-RunShellScript', Parameters={'commands': ['docker system prune -af --volumes']} ) command_id = response['Command']['CommandId'] # 轮询等待命令执行完成(最多等待5分钟) wait_time = 0 while wait_time < 300: invocation_status = ssm.get_command_invocation( CommandId=command_id, InstanceId=instance_id )['Status'] if invocation_status in ['Success', 'Failed']: break time.sleep(10) wait_time += 10 # 无论清理成功与否,最终执行关机(也可根据状态调整逻辑) ec2.stop_instances(InstanceIds=[instance_id]) return {'status': 'shutdown initiated after cleanup attempt'}
注意事项:
- 给Lambda角色添加
ssm:SendCommand、ssm:GetCommandInvocation、ec2:StopInstances的权限(最小权限原则,别直接给全量权限) - EC2实例需要安装SSM Agent(Amazon Linux 2默认自带,其他系统需手动安装)
方案2:给EC2添加本地关机钩子
如果不想改动Lambda,也可以在EC2实例的操作系统层面设置关机前的自动清理脚本:
以Amazon Linux 2为例,创建一个systemd服务:
# 新建服务文件 sudo tee /etc/systemd/system/shutdown-docker-cleanup.service <<EOF [Unit] Description=Cleanup Docker resources on shutdown DefaultDependencies=no Before=shutdown.target reboot.target halt.target [Service] Type=oneshot ExecStart=/usr/bin/docker system prune -af --volumes TimeoutStartSec=300 # 最多等待5分钟完成清理 [Install] WantedBy=shutdown.target reboot.target halt.target EOF
然后启用这个服务:
sudo systemctl daemon-reload sudo systemctl enable shutdown-docker-cleanup.service
这样实例收到关机信号时,会先执行Docker清理,完成后再继续关机流程。
方案3:延迟关机,给自动清理留时间
这是最简单的临时方案,可靠性稍差:修改CloudWatch规则的触发逻辑,不是任务一停止就关机,而是延迟15-30分钟再触发。
比如在CloudWatch事件规则里,把触发动作设置为“延迟15分钟”,或者用Lambda的异步调用+SQS延迟队列实现。这个方法的缺点是清理时间不确定,但大多数场景下15分钟足够Docker默认的垃圾回收跑完。
额外优化:从源头减少磁盘占用
除了事后清理,还可以从任务层面降低磁盘消耗:
- 在ECS任务定义中配置
awslogs日志驱动,把容器日志传到CloudWatch,避免日志占用本地磁盘 - 尽量使用轻量级基础镜像(比如Alpine代替Ubuntu),减少镜像体积
- 在容器启动脚本的末尾,主动清理临时文件(比如
rm -rf /tmp/*)
内容的提问来源于stack exchange,提问作者user2043723
相关产品推荐
相关产品推荐

