本文目录导读:

- 方法一:清理“悬空镜像”(最安全,最常用)
- 方法二:清理“所有未使用”的镜像(包括悬空 + 未关联容器的镜像)
- 方法三:保留最近 N 个镜像(适用于频繁构建的场景)
- 方法四:清理特定日期之前的镜像(基于创建时间)
- 方法五:组合清理(推荐用于定时任务)
- 如何自动化执行这些脚本?
- 最终建议
清理无用的 Docker 镜像(通常指悬空镜像或未被任何容器使用的镜像)是保持磁盘空间整洁的重要操作,以下是几种常见的自动化脚本方法,你可以根据场景选择使用。
⚠️ 重要提示:
- 以下命令会永久删除镜像,请确保你不再需要它们。
- 建议先将脚本放在测试环境中运行,确认无误后再用于生产环境。
清理“悬空镜像”(最安全,最常用)
悬空镜像是指 ID 和标签都为 <none> 的镜像,它们通常是由于使用相同标签构建新镜像后产生的,删除它们最安全,不会影响任何正在运行或已停止的容器。
脚本:clean_dangling.sh
#!/bin/bash echo "正在清理悬空镜像 (dangling images)..." # 删除所有悬空镜像 docker image prune -f echo "清理完成。"
参数说明:
docker image prune:清理所有未使用的镜像。-f:强制删除,无需确认。
如果需要更彻底的清理(包括未被容器使用的镜像,但不包括悬空镜像),可以加上 -a 参数,但请注意,这会删除所有未被任何容器(包括已停止的容器)引用的镜像,风险稍高。
# 稍微更激进:删除所有未被任何容器使用的镜像 docker image prune -a -f
清理“所有未使用”的镜像(包括悬空 + 未关联容器的镜像)
这个脚本会删除未被任何容器(包括已停止的)引用的镜像,它比 prune -a 更彻底,但也更危险,因为如果你后来重新创建一个需要某镜像的容器,该镜像必须重新下载。
脚本:clean_unused.sh
#!/bin/bash echo "正在清理所有未使用的镜像(包括悬空和未被容器引用的镜像)..." # 删除所有未被任何容器使用的镜像 docker image prune -a -f echo "清理完成。"
保留最近 N 个镜像(适用于频繁构建的场景)
如果你在持续构建相同标签的镜像(myapp:latest),最新版本通常有效,旧版本可能已无用,你可以保留最近的几个版本,删除更旧的。
脚本:clean_old_versions.sh
#!/bin/bash
IMAGE_NAME="your-registry.com/your-app:your-tag"
KEEP=3 # 保留最近的3个镜像
echo "正在为镜像 $IMAGE_NAME 保留最近的 $KEEP 个版本..."
# 1. 获取该镜像所有版本(按创建时间降序排序)
# 2. 跳过前 KEEP 个(最新的),删除剩余的
docker image ls --filter=reference="$IMAGE_NAME" --format="{{.ID}} {{.Repository}}:{{.Tag}}" | \
sort -k2 | \
head -n -$KEEP | \
awk '{print $1}' | \
xargs -r docker image rm -f
echo "清理完成。"
说明:
- 此脚本假设你的镜像标签遵循
name:tag格式。 - 它是基于镜像 ID 进行删除的,如果多个标签指向同一镜像,删除 ID 会同时移除所有相关标签,请谨慎使用。
-r参数使xargs在输入为空时不执行命令,防止报错。
清理特定日期之前的镜像(基于创建时间)
如果你知道镜像创建于某个时间点之前,可以直接基于时间删除。
脚本:clean_before_date.sh
#!/bin/bash
DAYS_OLD=7 # 清理7天前的镜像
echo "正在清理 $DAYS_OLD 天以前创建的镜像..."
docker image ls --format "{{.CreatedAt}} {{.ID}} {{.Repository}}:{{.Tag}}" | \
while IFS= read -r line; do
# 提取创建时间戳(假设格式为 "2023-01-01 12:00:00")
CREATED_DATE=$(echo "$line" | awk '{print $1}')
# 转换为时间戳(秒)
if [[ "$(uname)" == "Darwin" ]]; then
# macOS
CREATED_EPOCH=$(date -j -f "%Y-%m-%d" "$CREATED_DATE" +%s 2>/dev/null)
else
# Linux
CREATED_EPOCH=$(date -d "$CREATED_DATE" +%s 2>/dev/null)
fi
if [ -z "$CREATED_EPOCH" ]; then
continue
fi
# 计算过期时间
EXPIRED_EPOCH=$(( $(date +%s) - (DAYS_OLD * 86400) ))
if [ "$CREATED_EPOCH" -lt "$EXPIRED_EPOCH" ]; then
IMAGE_ID=$(echo "$line" | awk '{print $2}')
echo "删除过期镜像: $IMAGE_ID ($line)"
docker image rm -f "$IMAGE_ID" 2>/dev/null
fi
done
echo "清理完成。"
注意: 日期格式可能因 Docker 版本和系统 locale 而异,如果你的 docker image ls --format 输出格式不同,请调整 awk 字段序号,更健壮的方式是使用 docker images --filter "until=...h",但 until 过滤器只支持小时和分钟,不支持天数,需要手动转换。
组合清理(推荐用于定时任务)
结合多个清理策略,既安全又高效:
脚本:safe_cleanup.sh
#!/bin/bash echo "========== Docker 镜像清理脚本 ==========" echo "时间: $(date)" echo "" # 1. 清理悬空镜像(最安全) echo ">>> 步骤1: 清理悬空镜像..." docker image prune -f # 2. 清理未被使用超过7天的镜像(假设平均构建周期) echo ">>> 步骤2: 清理未被容器使用且创建超过7天的镜像..." docker image prune -a --filter "until=168h" -f # 3. 清理所有未被使用的构建缓存(可选) echo ">>> 步骤3: 清理构建缓存..." docker builder prune -f echo "" echo "清理完成,硬盘空间使用情况:" df -h /var/lib/docker 2>/dev/null || echo "(Docker 目录未找到)"
--filter "until=...":
168h= 7天,Docker 的until过滤器支持h(小时)和m(分钟),不支持天。- 使用该过滤器时,只删除满足 “未被任何容器使用” 且 “创建时间超过 X 时间” 的镜像,兼顾了安全性和清理效果。
如何自动化执行这些脚本?
你可以使用 cron(Linux/macOS)或 任务计划程序(Windows)定期运行这些脚本。
Linux/macOS 示例(每天凌晨 3 点执行):
crontab -e
添加一行:
0 3 * * * /path/to/your/clean_script.sh >> /var/log/docker_clean.log 2>&1
记得给脚本执行权限:
chmod +x /path/to/your/clean_script.sh
最终建议
| 场景 | 推荐脚本 |
|---|---|
| 日常维护,仅移除旧的无标签镜像 | docker image prune -f |
| 确保磁盘空间不被无限消耗 | 组合清理脚本 |
| 频繁构建特定 app 的多个版本 | 保留最近 N 个版本 |
| 定期清理所有无引用镜像(风险稍高) | docker image prune -a -f |
| 希望按时间清理(如只保留最近一周的镜像) | 方法四(或方法五中的 until 过滤器) |
最佳实践: 将方法五中的 safe_cleanup.sh 脚本加入 cron 定时任务,每天运行一次,它足够安全(仅清理悬空 + 超过7天的未使用镜像),且能有效控制磁盘增长。