自动化脚本如何清理无用的镜像

wen 实用脚本 2

本文目录导读:

自动化脚本如何清理无用的镜像

  1. 方法一:清理“悬空镜像”(最安全,最常用)
  2. 方法二:清理“所有未使用”的镜像(包括悬空 + 未关联容器的镜像)
  3. 方法三:保留最近 N 个镜像(适用于频繁构建的场景)
  4. 方法四:清理特定日期之前的镜像(基于创建时间)
  5. 方法五:组合清理(推荐用于定时任务)
  6. 如何自动化执行这些脚本?
  7. 最终建议

清理无用的 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天的未使用镜像),且能有效控制磁盘增长。

抱歉,评论功能暂时关闭!