docker 容器磁盘空间管理
docker 主要包括镜像、容器和数据卷三部分,对docker的磁盘空间管理也主要从着三块入手,在做docker磁盘空间分析之前我们需要简单了解下容器的“镜像层”的概念,一般容器的磁盘管理有一大半是镜像层相关:
什么是镜像层?
说到镜像的层,就要说说Docker镜像的存储组织方式
docker 镜像是采用分层的方式构建的,每个镜像都由一系列的 “镜像层” 组成。”镜像层”用来存储一组镜像相关的元数据信息,主要包括镜像的架构(如 amd64)、镜像默认配置信息、构建镜像的容器配置信息、包含所有镜像层信息的 rootfs。当需要修改容器镜像内的某个文件时,docker 利用 rootfs 中的 diff_id 计算出内容寻址的索引(chainID) 来获取 layer 相关信息,进而获取每一个镜像层的文件内容,容器对镜像的修改只对处于最上方的读写层进行变动,不覆写下层已有文件系统的内容,已有文件在只读层中的原始版本仍然存在,但会被读写层中的新版本所隐藏。在多个容器之间共享镜像,每个容器在启动的时候并不需要单独复制一份镜像文件,而是将所有镜像层以只读的方式挂载到一个挂载点,再在上面覆盖一个可读写的容器层。联合挂载技术可以在一个挂载点同时挂载多个文件系统,将挂载点的原目录与被挂载内容进行整合,使得最终可见的文件系统将会包含整合之后的各层的文件和目录。联合挂载包括可读写部分(read-write layer 以及 volumes)、init-layer、只读层(read-only layer) 这 3 部分结构。
layer(镜像层) 是 docker 用来管理镜像层的一个中间概念,镜像是由镜像层组成的,而单个镜像层可能被多个镜像共享,所以 docker 将 layer 与 image 的概念分离。docker 镜像管理中的 layer 主要存放了镜像层的 diff_id、size、cache-id 和 parent 等内容。
dockers磁盘使用空间分析
查看docker目录空间
从docker目录看磁盘使用情况:
$ cd /var/lib/docker |
可以看出磁盘主要占用都在overlay2
和containers
这两个文件夹中,containers是容器运行时所产生的文件读写变更,overlay2是容器镜像的层的概念。
进到overlay2
继续排查:
$ du -h --max-depth=1 |
发现其中一个目录就占用了近200多G,妥妥的大头,看看具体是哪个容器:
import os |
找到最大的元凶容器了,livego是之前做得一个直播应用,因为当时只是作为试验容器,没有选择外挂的形式,因此容器空间很大,现在已经没什么用了,可以直接删掉:
docker rm -f livego |
磁盘使用空间资源释放
除了直接查看docker目录,还可以通过docker system
命令查看各类资源使用状况:
$ docker system df |
最后一列表示可回收的比例,可以看到有部分镜像、容器和卷可以回收了,一般是这些资源没有被使用,我们可以逐个去查看:
$ docker system df -v |
也可以通过docker system prune
的命令一键清理:
$ docker system prune --help |
再看看:
$ docker system df |
发现镜像和容器空间都被释放了。
docker 镜像精简
除了对已有运行系统进行容器磁盘空间管理外,我们还可以在镜像的源头进行磁盘空间的管理工作:
选择小体积基础镜像
docker 镜像精简最简单的方法就是用alpine
作为底层基础镜像,像 alphine 镜像 只有 5MB,是非常小的。或者可以用带 -slim 标签的镜像,一般这类镜像是通过瘦身的,镜像的体积会比较小。
减少RUN、ADD、COPY会改变容器Layer的命令
每个镜像都由一系列的 “镜像层” 组成,每次对文件的改动命令(RUN、ADD、COPY)都会被提交到一个版本,所以应该尽量减少这些命令的使用,比如多个RUN可以用&&
合并。
对于镜像层是否可以优化,我们可以通过docker history
命令查看镜像各层的构建:
$ docker history shikanon.com/hyperkube:v1.16.6-rancher1 |
利用FROM AS 和 COPY 实现编译阶段和代码阶段分离
Docker 17.05版本以后提供了COPY --from
的语法,他提供了从镜像层中直接拷贝文件:
# 将 编译阶段 命名为 builder |
COPY –from 不但可以从前置阶段中拷贝,还可以直接从一个已经存在的镜像中拷贝,例如:
COPY --from=quay.io/coreos/etcd:v3.3.9 /usr/local/bin/etcd /usr/local/bin/ |
这样最后运行的只有二进制而没有编译阶段的代码文件,容器体积会缩小很多。
借助distroless
借助镜像工具 distroless 减少镜像种不必要的依赖,distroless 是 google 开放的优化版容器镜像, “distroless”镜像仅包含了应用和运行时依赖。