1. 为什么需要自动化Docker清理脚本
在长期使用Docker进行开发和部署的过程中,我发现镜像和容器就像房间里的杂物一样会不断堆积。每次构建新镜像时,旧版本并不会自动清除;停止的容器如果不手动删除,也会一直占用磁盘空间。这个问题在持续集成环境中尤为严重——我们团队的Jenkins服务器曾因为未清理的Docker对象导致磁盘爆满,最终引发构建失败。
通过docker system df命令可以看到,这些"垃圾"主要分为三类:
- 悬空镜像(dangling images):构建新镜像时产生的中间层
- 未被使用的镜像:没有被任何容器引用的镜像
- 停止的容器:已经exit但未被删除的容器实例
一个典型的案例是我们的微服务项目,每次代码提交都会触发镜像构建。一个月后,仅这一个项目就产生了47个历史镜像版本,占用空间超过30GB。而实际上我们只需要保留最近3个版本即可。
2. 手动清理的局限性
虽然Docker提供了原生清理命令,但实际使用中存在诸多不便:
bash复制# 基础清理命令示例
docker image prune # 删除悬空镜像
docker container prune # 删除停止的容器
docker system prune # 综合清理
主要问题包括:
- 无法选择性保留特定镜像(如按时间或标签过滤)
- 批量操作时缺乏预览机制,容易误删
- 需要人工定期执行,无法实现自动化
- 无法处理镜像间的依赖关系
3. 智能清理脚本设计
3.1 核心清理逻辑
基于实际需求,我设计了一个分层次的清理策略:
bash复制#!/bin/bash
# 参数定义
KEEP_LAST=3 # 保留最近N个镜像
IMAGE_PATTERN="*your-image-prefix*" # 镜像名称模式
# 1. 清理停止的容器
docker container prune -f
# 2. 清理悬空镜像
docker image prune -f
# 3. 清理未被使用的镜像(保留最近KEEP_LAST个)
docker images --filter reference="$IMAGE_PATTERN" --format "{{.ID}} {{.CreatedAt}}" \
| sort -rk2 | awk -v keep="$KEEP_LAST" 'NR>keep {print $1}' \
| xargs -r docker rmi -f
3.2 关键实现细节
-
镜像筛选:
- 使用
--filter reference=实现精准匹配,避免grep解析表格的不稳定性 - 支持通配符模式匹配(如
*dev-*)
- 使用
-
排序保留机制:
- 按创建时间倒序排序(
sort -rk2) - 通过awk跳过前N条记录实现保留最新版本
- 按创建时间倒序排序(
-
安全防护:
xargs -r防止空参数报错- 删除前可添加确认提示(开发阶段建议启用)
4. 进阶功能实现
4.1 多维度保留策略
实际项目中我们可能需要更复杂的保留逻辑:
bash复制# 保留最近7天+最近3个版本
docker images --filter reference="$IMAGE_PATTERN" --format "{{.ID}} {{.CreatedAt}}" \
| awk -v keep="$KEEP_LAST" -v cutoff="$(date -d '7 days ago' +%s)" '
{
gsub(/-|:/," ",$2);
ts=mktime($2" "$3" "$4" "$5" "$6);
if(ts > cutoff) { print $1" keep_by_date"; next }
if(++count <= keep) { print $1" keep_by_count"; next }
print $1
}' \
| grep -v "keep_" | xargs -r docker rmi -f
4.2 容器关联检查
避免删除被隐藏依赖的镜像:
bash复制# 检查镜像是否被任何容器(包括停止的)使用
is_used() {
local image_id=$1
docker ps -a --filter ancestor="$image_id" --format "{{.ID}}" | wc -l
}
# 在删除前添加检查
if [ $(is_used "$image_id") -eq 0 ]; then
docker rmi "$image_id"
fi
5. 生产环境部署方案
5.1 定时任务配置
建议通过systemd或cron实现自动化:
bash复制# 每日凌晨3点执行清理
0 3 * * * /usr/local/bin/docker-cleanup >> /var/log/docker-cleanup.log 2>&1
5.2 监控与告警
添加清理结果通知:
bash复制# 发送清理报告
cleanup_report=$(docker system prune -a --force --filter "until=168h" 2>&1)
echo "$cleanup_report" | mail -s "Docker Weekly Cleanup Report" admin@example.com
6. 避坑指南
在实际使用中遇到的典型问题:
-
共享层删除:
- 现象:删除A镜像导致B镜像损坏
- 解决方案:先检查镜像依赖关系(
docker image inspect --format='{{.RootFS.Layers}}')
-
时间格式问题:
- 现象:不同Docker版本时间格式不一致
- 解决方案:统一转换为时间戳处理
-
CI/CD集成:
- 建议:在流水线最后添加清理步骤,但保留最近2次构建的镜像
-
磁盘空间监控:
bash复制# 添加磁盘检查逻辑 THRESHOLD=90 usage=$(df /var/lib/docker --output=pcent | tail -1 | tr -d '% ') [ $usage -ge $THRESHOLD ] && trigger_cleanup
7. 性能优化技巧
-
并行删除:
bash复制echo "$image_list" | xargs -P 4 -n 10 docker rmi -f -
构建时清理:
在Dockerfile中添加构建后清理指令:dockerfile复制RUN apt-get update && \ apt-get install -y package && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* -
registry垃圾回收:
对于私有仓库,定期执行:bash复制docker exec registry bin/registry garbage-collect /etc/docker/registry/config.yml
这个脚本在我们生产环境运行半年后,Docker磁盘占用从平均85%降至35%以下,再没有出现过因磁盘空间导致的运维事故。最重要的是,它把我们从繁琐的手动维护中彻底解放了出来。
