如何清除Docker缓存并释放系统空间
# 简要回顾一下 Docker 缓存
Docker 使用层缓存来重用先前计算的构建结果。Dockerfile 中的每条指令都与一个层相关联,该层包含执行该指令所导致的更改。如果先前的层以及指令的任何输入均未更改,并且该指令先前已运行并缓存,则 Docker 将为其使用缓存的层。否则,Docker 将重建该层及其后面的所有层。
使用缓存层比从头开始重新计算指令要快得多。因此,通常情况下,您希望 Docker 构建尽可能多地来自缓存,并且只重建自上次构建以来发生变化的层。
影响需要重建镜像中多少层的主要因素之一是Dockerfile 中的操作顺序。 (opens new window)
# Docker 使用了多少磁盘空间?
第一步是了解 Docker 的磁盘使用情况。我们可以使用该docker system df
命令来了解各种工件占用了多少磁盘空间。
docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 138 34 36.18GB 34.15GB (94%)
Containers 74 18 834.8kB 834.6kB (99%)
Local Volumes 118 6 15.31GB 15.14GB (98%)
Build Cache 245 0 1.13GB 1.13GB
2
3
4
5
6
Docker 占用 36.18 GB 用于镜像,834.8 kB 用于容器,15.31 GB 用于本地卷,1.13 GB 用于 Docker 构建缓存。总共约 50 GB 的空间,其中很大一部分是可回收的。
# 在不影响 Docker 构建性能的情况下我们可以收回哪些空间?
删除未使用的 Docker 镜像和层通常非常安全 — 除非您正在 CI 中构建。对于 CI,清除层可能会影响性能,因此最好不要这样做。相反,请跳转到我们以 CI 为重点的部分 (opens new window)。
# 从 Docker 缓存中删除容器
我们可以使用该docker container prune
命令清除容器使用的磁盘空间。此命令将从系统中删除所有已停止的容器。
我们可以-f
在这里和后续示例中省略该标志,以便在删除工件之前得到确认提示。
docker container prune -f
Deleted Containers:
399d7e3679bf9b14a1c7045cc89c056f2efe31d0a32f186c5e9cb6ebbbf42c8e
Total reclaimed space: 834.6kB
2
3
4
5
# 哪些容器尚未使用?
docker ps
我们可以通过运行带有容器状态过滤器的命令来查看未使用容器的 ID 。如果容器的状态为exited
或 ,则表示容器未使用dead
。
docker ps --filter status=exited --filter status=dead -q
11bc2aa92622
355901f38ecb
263e9bde1f24
2
3
4
**注意:**如果我们想知道未使用的容器的大小,我们可以-q
用 替换标志-s
来获取有关容器的大小和其他元数据
# 删除所有容器
如果我们想从系统中删除所有容器,我们可以停止任何正在运行的容器,然后使用相同的 prune 命令。如果您想强制终止容器,请将 的输出输入docker ps -q
到docker stop
或命令中。docker kill
docker stop $(docker ps -q)
docker container prune
2
另一个选项是命令,它可以与删除所有容器docker rm
一起使用。docker ps -a -q
docker rm $(docker ps -a -q)
**注意:**该docker rm
命令通过信号强制删除正在运行的容器SIGKILL
。这与命令相同docker kill
。该docker ps -a -q
命令将列出系统上的所有容器(包括正在运行的容器),并将其输入到docker rm
命令中。
# 删除镜像
Docker 镜像会占用大量磁盘空间。docker build
例如,当基础镜像发生变化时,我们会累积新镜像,或者通过 构建新镜像。我们可以使用该docker image prune
命令从系统中删除未使用的镜像。
默认情况下,它只会删除与任何容器无关且没有标签的悬空镜像。
docker image prune -f
Deleted Images:
deleted: sha256:6f096c9fa1568f7566d4acaf57d20383851bcc433853df793f404375c8d975d6
...
Total reclaimed space: 2.751GB
2
3
4
5
6
通过删除悬空镜像,我们回收了超过 2.7 GB 的空间。但是,如果我们回顾一下命令的输出docker system df
,我们还有 34.15 GB 的可回收镜像。
剩余的空间来自哪里?这些是系统上标记或与容器关联的镜像。我们可以运行命令docker image prune- a
强制删除这些镜像,假设它们是未使用的镜像。
docker image prune -a -f
Deleted Images:
untagged: k8s.gcr.io/etcd:3.4.13-0
untagged: k8s.gcr.io/etcd@sha256:4ad90a11b55313b182afc186b9876c8e891531b8db4c9bf1541953021618d0e2
deleted: sha256:0369cf4303ffdb467dc219990960a9baa8512a54b0ad9283eaf55bd6c0adb934
deleted: sha256:f3cecccfe2bea1cbd18db5eae847c3a9c8253663bf30a41288f541dc1470b41e
Total reclaimed space: 22.66GB
2
3
4
5
6
7
8
通过这种方式,我们删除了所有与容器不关联的未使用的图像,而不仅仅是悬空的图像。
# 删除卷
Docker 永远不会自动清理卷,因为它们可能包含有价值的数据。但是,如果我们知道不再需要卷中的数据,我们可以使用该docker volume prune
命令将其删除。这将删除所有未被任何容器使用的匿名卷。
docker volume prune -f
Total reclaimed space: 0B
2
有趣的是,我们发现没有回收任何空间。这是因为我们有与容器关联的卷。我们可以通过运行docker volume ls
命令来查看这些卷。
DRIVER VOLUME NAME
local 0a44f085adc881ac9bb9cdcd659c28910b11fdf4c07aa4c38d0cca21c76d4ac4
local 0d3ee99b36edfada7834044f2caa063ac8eaf82b0dda8935ae9d8be2bffe404c
...
2
3
4
我们得到一个显示驱动程序和卷名称的输出。该命令docker volume prune
仅删除匿名卷。这些卷没有命名,也没有来自容器外部的特定来源。我们可以使用该docker volume rm -a
命令删除所有卷。
docker volume prune -a -f
Deleted Volumes:
c0c240b680d70fffef420b8699eeee3f0a49eec4cc55706036f38135ae121be0
2ce324adb91e2e6286d655b7cdaaaba4b6b363770d01ec88672e26c3e2704d9e
Total reclaimed space: 15.31GB
2
3
4
5
6
# 删除构建缓存
要删除 Docker 构建缓存,我们可以运行docker buildx prune
命令来清除默认构建器的构建缓存。
docker buildx prune -f
ID RECLAIMABLE SIZE LAST ACCESSED
pw11qgl0xs4zwy533i2x61pef* true 54B 12 days ago
y37tt0kfwn1px9fnjqwxk7dnk true 0B 12 days ago
sq3f8r0qrqh4rniemd396s5gq* true 154.1kB 12 days ago
Total: 5.806GB
2
3
4
5
6
7
如果我们想要删除特定构建器的构建缓存,我们可以使用该--builder
标志来指定构建器名称。
docker buildx prune --builder builder-name -f
# 删除网络
虽然 Docker 网络不会占用我们机器上的磁盘空间,但它们会创建网桥、iptables 和路由表条目。因此,与其他工件类似,我们可以使用命令删除未使用的网络docker network prune
以进行清理。
docker network prune -f
Deleted Networks:
test-network-1
2
3
# 删除所有内容docker system prune
docker clean all 的等效命令更广为人知的名字是 Docker prune。我们可以通过运行 来删除 Docker 生成的所有未使用的工件docker system prune
。这将删除所有未使用的容器、图像、网络和构建缓存。
docker system prune -f
Deleted Images:
deleted: sha256:93477d5bde9ef0d3d7d6d2054dc58cbce1c1ca159a7b33a7b9d23cd1fe7436a3
Deleted build cache objects:
6mm1daa19k1gdijlde3l2bidb
vq294gub98yx8mjgwila989k1
xd2x5q3s6c6dh5y9ruazo4dlm
Total reclaimed space: 419.6MB
2
3
4
5
6
7
8
9
10
默认情况下,Docker prune 不会删除卷,只会删除悬空的 Docker 镜像。我们也可以使用该--volumes
标志来删除卷。我们还可以-a
再次添加该标志以删除所有与容器无关的镜像。
docker system prune --volumes -af
# 在 CI 中管理 Docker 构建缓存
CI 环境中的 Docker 镜像构建略有不同。当然,您可以使用上述命令清理工件并操作 Docker 缓存。但是,由于以下原因,您的构建可能没有充分利用 Docker 构建缓存:
在具有临时运行器的 CI 环境中,例如 GitHub Actions 或 GitLab CI,如果不通过网络将构建缓存保存/加载到临时运行器之外的某个位置,则构建缓存不会在构建过程中持久保存。因此,由于网络传输速度较慢,因此保存和加载缓存的速度很慢。
默认情况下,除非您运行自己的 CI 运行器,否则所有 CI 运行器都是临时的。如果您选择运行自己的运行器,则可以启动具有持久卷的运行器,但您必须继续维护这些运行器。
如果您的非自托管运行器中确实有磁盘空间,通常上限为 10 到 15 GB。因此,如果您要构建具有大层的大型图像,则可能会耗尽它。该磁盘空间也是短暂的,每次构建后都会被清除。
即使您构建的图像非常小,并且仅在每个 CI 运行器上的 Docker 缓存中保留必要的层,您的构建也可能不会使用缓存,因此速度会非常慢,因为计算每次构建的每一层都需要一段时间。
那么如何优化CI系统中Docker缓存的使用呢?
# 使用 Depot 加速 CI 中的 Docker 构建
Depot 会自动将缓存保留在真实的 NVMe SSds 上,以便跨构建进行保存。这使得使用 Depot 的 Docker 构建比不使用 Depot 在 CI 上构建 Docker 镜像快 20 倍。使用 Depot,您的 Docker 构建缓存会自动保留在真实的存储设备上,因此无需再通过慢速 CI 网络保存和加载层缓存。
将 Depot 添加到您的构建中只需几分钟 — depot
CLI 是替代品docker build
,并接受所有相同的参数和标志。我们已与CI 集成文档中记录的所有主要提供商进行了集成。 (opens new window)