一、为什么需要清理Docker镜像仓库

相信很多用过Docker的朋友都遇到过这样的情况:某天突然发现服务器磁盘空间告急,一查发现是Docker镜像占用了大量空间。这种情况在持续集成/持续部署(CI/CD)环境中尤为常见,每次构建都会产生新的镜像,久而久之就会堆积如山。

举个例子,我们有个Java项目使用Maven构建,Dockerfile是这样的:

# 使用OpenJDK作为基础镜像
FROM openjdk:11
# 复制构建好的jar包
COPY target/myapp.jar /app.jar
# 设置启动命令
ENTRYPOINT ["java","-jar","/app.jar"]

每次代码提交后,CI系统都会构建一个新的镜像,即使只是修改了一个很小的bug。一个月下来,镜像仓库里可能堆积了几十个甚至上百个相似镜像,占用了大量存储空间。

二、Docker镜像仓库清理的基本方法

清理Docker镜像仓库主要有以下几种方法:

  1. 手动删除不需要的镜像
  2. 设置自动清理策略
  3. 使用垃圾回收机制

我们先来看最基础的手动清理方法。Docker提供了几个有用的命令:

# 列出所有镜像
docker images

# 删除指定镜像
docker rmi <image_id>

# 删除所有未被容器使用的镜像
docker image prune

# 强制删除所有镜像(包括正在使用的)
docker image prune -a

不过手动清理效率太低,我们需要更智能的解决方案。下面介绍一个实用的Shell脚本示例,可以自动清理超过30天的镜像:

#!/bin/bash
# 清理超过30天的Docker镜像
# 设置保留天数
DAYS_TO_KEEP=30

# 获取所有镜像ID
IMAGES=$(docker images -q)

# 遍历每个镜像
for IMAGE in $IMAGES; do
    # 获取镜像创建时间
    CREATED=$(docker inspect --format '{{.Created}}' $IMAGE)
    # 转换为时间戳
    CREATED_TS=$(date -d "$CREATED" +%s)
    # 计算天数差
    AGE_DAYS=$(( ( $(date +%s) - $CREATED_TS ) / 86400 ))
    
    # 如果超过保留天数就删除
    if [ $AGE_DAYS -gt $DAYS_TO_KEEP ]; then
        echo "删除镜像 $IMAGE (创建于 $CREATED)"
        docker rmi $IMAGE
    fi
done

三、高级清理策略与技巧

对于生产环境,我们需要更精细的清理策略。以下是几种常见的高级清理方法:

1. 按标签过滤清理

很多时候我们只需要保留特定标签的镜像,比如保留所有带"prod"标签的镜像:

# 删除所有不带"prod"标签的镜像
docker images | grep -v "prod" | awk '{print $3}' | xargs docker rmi

2. 保留最近N个版本

对于频繁发布的微服务,我们可以保留最近的5个版本:

# 保留每个仓库最近的5个镜像
docker images --format '{{.Repository}}' | sort -u | while read REPO; do
    docker images --format '{{.ID}}' $REPO | tail -n +6 | xargs docker rmi
done

3. 结合CI/CD流水线清理

在Jenkins等CI工具中,我们可以在构建后添加清理步骤:

pipeline {
    agent any
    stages {
        stage('Build') {
            steps {
                sh 'docker build -t myapp:${BUILD_NUMBER} .'
            }
        }
        stage('Cleanup') {
            steps {
                // 保留最近10个构建
                sh '''
                    docker images myapp --format '{{.ID}}' | \\
                    tail -n +11 | \\
                    xargs -r docker rmi
                '''
            }
        }
    }
}

四、注意事项与最佳实践

在实施镜像清理策略时,有几个重要注意事项:

  1. 谨慎删除正在使用的镜像:删除正在运行的容器使用的镜像会导致问题。可以先停止相关容器再删除。

  2. 保留足够的回滚版本:根据业务需求保留足够的历史版本,建议至少保留3-5个版本。

  3. 考虑镜像分层的影响:Docker镜像是分层存储的,多个镜像可能共享基础层。删除一个镜像不一定能释放预期大小的空间。

  4. 监控清理效果:定期检查磁盘使用情况,确保清理策略确实有效。

  5. 备份重要镜像:对于关键版本,建议推送到远程仓库或导出备份:

# 导出镜像到文件
docker save -o myapp_backup.tar myapp:1.0

# 从文件导入镜像
docker load -i myapp_backup.tar

五、总结与建议

Docker镜像仓库清理是容器化运维中不可忽视的一环。通过合理的清理策略,我们可以:

  • 节省宝贵的存储空间
  • 提高镜像拉取和推送效率
  • 保持开发和生产环境的整洁

建议根据实际需求组合使用多种清理方法,并建立定期清理的机制。对于大型团队,可以考虑使用Harbor等企业级镜像仓库管理系统,它们通常内置了更完善的垃圾回收和保留策略功能。

最后记住,自动化是关键。手动清理不仅效率低下,而且容易出错。通过脚本、CI/CD集成或专用工具来实现自动化清理,才能长期有效地管理镜像仓库。