Docker基础教程(八十九)删除仓库镜像:别再“docker rmi”了!一招教你给仓库大扫除,空间秒释放,爽过删聊天记录!

第一章:从“盘古开天”说起——为什么你的磁盘又双叒叕满了?

想象一下,你是一位才华横溢的厨师(开发者)。你的厨房(服务器)里有一个神奇的冰箱(Docker Registry),里面塞满了你试验过的各种半成品菜(镜像):my-app:v1my-app:latestmy-app:that-buggy-version-i-hope-no-one-finds...

你不断地docker builddocker push,感觉一切尽在掌握。直到某一天,你的整个厨房系统发出了一声哀嚎:“No space left on device”!你慌了,像极了手机弹窗“存储空间不足”时的我们。

你试图用最朴素的方式解决它:docker rmi <image_id>。但你会发现,这就像是用勺子舀干一艘漏水的船——治标不治本,而且效率极低。因为你删除的,可能只是本地缓存,而那个巨大的、塞满无用版本的远程仓库,依然在默默地吞噬着你的磁盘和带宽。

所以,是时候来一场彻底的、科学的、优雅的Docker仓库大扫除了!

第二章:知己知彼,百战不殆——Docker镜像删除的“底层八卦”

在动手之前,我们必须搞清楚我们要删除的到底是什么。Docker的删除操作分为两个层面,理解它们至关重要。

1. 本地清理:docker rmi 的“爱恨情仇”

这是我们最熟悉的操作。但它背后有几个有趣的“坑”:

  • “虚悬镜像”(Dangling Images): 镜像界的“幽灵”。当你重新构建一个同名同标签的镜像(比如再次docker build -t my-app:latest .)时,旧的那个my-app:latest镜像就会失去它的名字,变成一个无名无姓的“虚悬镜像”。它仍然占用着空间,却不再出现在docker images的常规列表里。想看它们?请用docker images -f dangling=true。它们是清理的第一优先级!
  • “依赖”与“层”(Layers): Docker镜像像千层蛋糕,每一层(Layer)都是一个只读的文件系统变更集。多个镜像可以共享相同的层。当你docker rmi一个镜像时,Docker只会删除那些独属于该镜像的层。只要还有其他镜像依赖某一层,这一层就不会被删除。所以,清理空间的关键在于删除那些没有依赖的顶层镜像。

基础手动清理实战示例:

# 1. 查看磁盘占用情况(心里有个底)
docker system df

# 2. 删除所有虚悬镜像(幽灵克星)
docker image prune

# 3. 更激进一点,删除所有未被使用的镜像(谨慎操作!)
docker image prune -a

# 4. 按条件筛选并删除(精准打击)
# 删除所有在“my-app”仓库中,创建时间超过24小时的镜像
docker image prune -a --filter "until=24h" --filter "label=com.example.vendor=MyApp"

# 删除所有标签名为`<none>`的镜像(通常是虚悬镜像)
docker rmi $(docker images -f "dangling=true" -q)

2. 远程清理:Registry API的“核弹级”操作

docker rmi只影响本地!真正占用服务器硬盘的,是推送到远程仓库(如Docker Hub、Harbor、私有Registry)里的镜像。要清理它们,你必须直接与仓库的API进行交互。这就像是,你扔掉了家里的产品目录(本地镜像),但仓库里的货(远程镜像)还堆得满满的。

这是我们本次大扫除的核心重点。

第三章:终极奥义——手把手教你用API清理远程私有仓库

这里我们以最常用的私有Registry(v2) 为例。公共仓库如Docker Hub通常有速率限制和Web界面操作,但原理类似。

准备工作:

  • 一个需要清理的私有Registry地址,例如:my-registry.example.com:5000
  • 拥有该仓库的推送(push)和删除(delete)权限(通常需要配置HT证书和认证)。
  • 你的镜像名称,例如:my-registry.example.com:5000/my-team/my-app

步骤一:启用Registry的删除功能
默认情况下,Registry的删除功能是禁用的。你需要修改Registry的配置文件(config.yml),加入:

storage:
  delete:
    enabled: true

然后重启Registry服务。

步骤二:获取镜像的Manifest Digest
Docker Registryv2 API不通过标签(Tag)来删除镜像,而是通过一个唯一的、基于内容的哈希值——Digest。标签是可变的(latest今天指向A,明天可以指向B),但Digest是唯一且不可变的。

# 1. 获取镜像的Manifest,并接收返回的Digest头信息
# 注意:使用`-H "Accept: application/vnd.docker.distribution.manifest.v2+json"`来获取v2格式的manifest

curl -I -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
  -u <username>:<password> \
  https://my-registry.example.com:5000/v2/my-team/my-app/manifests/latest

# 在返回的HTTP头信息中,你会找到一行类似:
# Docker-Content-Digest: sha256:a1b2c3d4e5f6...(一长串哈希值)
# 把这个值复制下来,这就是我们要用的<digest>

步骤三:执行删除操作
拿到Digest后,我们就可以调用DELETE API了。

curl -X DELETE -u <username>:<password> \
  https://my-registry.example.com:5000/v2/my-team/my-app/manifests/sha256:a1b2c3d4e5f6...

注意! 到这里,镜像的Manifest已经被删除了,意味着你无法再通过任何标签拉取到这个镜像。但是,构成镜像的数据层(Blobs) 仍然物理存在于磁盘上。为了真正回收空间,你需要进行最后一步。

步骤四:运行垃圾回收(Garbage Collection)
登录到运行Registry服务的机器上,执行:

# 进入Registry容器内部(如果是在容器中运行)
docker exec -it <registry-container-id> /bin/sh

# 执行垃圾回收命令
registry garbage-collect /path/to/your/registry/config.yml

# 通常配置文件的路径是 /etc/docker/registry/config.yml
# 加上 `-m` 参数可以干式运行,先看看会删除什么
registry garbage-collect -m /etc/docker/registry/config.yml

执行完毕后,那些没有被任何Manifest引用的Blobs才会被彻底物理删除,空间就此释放!

第四章:懒人福音——自动化清理脚本与实践

每次都要手动找Digest太麻烦了?我们可以写脚本自动化!

场景: 删除my-registry.example.com:5000/my-team/my-app仓库中,除了最近5个版本以外的所有标签。

#!/bin/bash

# 配置
REGISTRY="my-registry.example.com:5000"
REPO="my-team/my-app"
USERNAME="your-username"
PASSWORD="your-password"
KEEP=5

# 获取所有标签的列表,按时间倒序排序,然后跳过前$KEEP个
TAGS_TO_DELETE=$(curl -s -u $USERNAME:$PASSWORD https://$REGISTRY/v2/$REPO/tags/list?n=100 | jq -r '.tags[]' | sort -r | tail -n +$(($KEEP+1)))

echo "以下标签将被删除:"
echo "$TAGS_TO_DELETE"

# 循环处理每一个要删除的标签
for TAG in $TAGS_TO_DELETE; do
  echo "正在处理标签: $TAG"
  
  # 获取该标签的Digest
  DIGEST=$(curl -I -s -u $USERNAME:$PASSWORD -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
    https://$REGISTRY/v2/$REPO/manifests/$TAG | grep -i 'Docker-Content-Digest' | awk '{print $2}' | tr -d '\r')
  
  # 删除Manifest
  curl -X DELETE -u $USERNAME:$PASSWORD https://$REGISTRY/v2/$REPO/manifests/$DIGEST
  echo "已删除标签: $TAG (Digest: $DIGEST)"
done

echo "所有旧版本标签已标记删除。请登录Registry服务器执行 'registry garbage-collect' 以彻底回收磁盘空间。"

使用提醒:

  1. 确保已安装 jq(JSON处理工具)。
  2. 此脚本只标记删除,最终回收仍需在服务器上执行garbage-collect
  3. 生产环境请务必先在测试环境验证!并做好备份!
第五章:总结与最佳实践

给Docker仓库做清理,是一场结合了手动技巧和自动化脚本的艺术。让我们再回顾一下核心要点:

  1. 分清层次: docker rmi管本地,Registry API管远程。
  2. 理解原理: 删除的是Manifest引用,物理清理靠Garbage Collection。
  3. 安全第一: 任何删除操作前,务必确认、备份、并在测试环境演练。
  4. 走向自动化: 使用类似上面的Shell脚本或更强大的工具(如Harbor的UI、regclient等)来制定清理策略(如:保留最近N个版本、按时间删除等)。
  5. 防患于未然: 在CI/CD流程中融入清理策略,例如每次成功构建新版本后,自动删除开发环境对应的旧版本镜像,从源头避免堆积。

现在,拿起这些“武器”,去给你的Docker仓库来一次酣畅淋漓的大扫除吧!那种看着磁盘空间瞬间释放的快感,真的堪比一次性清空所有聊天记录——极度舒适!

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

值引力

持续创作,多谢支持!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值