出于更有效使用存储驱动程序,了解Docker构建和存储映像及容器使用方法很关键,可以在使用中以最佳方式保留程序数据避免更多问题。
Docker所使用存储驱动程序来存储镜像层,把数据存储在容器的可写层里面。容器可写层在容器删除后不会被保留。但是可以用于存储在运行时临时生成的临时数据。存储驱动程序对空间利用效率有一定优化,但对于写入速度低于本机系统性能,特别是对使用写时复制文件系统的存储驱动程序。写入密集型应用程序会受到性能开销的影响,特别是如果只读层中存在预先存在的数据。
Docker卷可以存储写入密集型数据,必须在容器生命周期之外存在数据及在容器之间共享的数据。
Docker镜像是由一个系统层组成,每层代表镜像Dockerfile中的一条指令,除最后一层之外,每层都只读:
# syntax=docker/dockerfile:1
FROM ubuntu:22.04
LABEL org.opencontainers.image.authors="org@example.com"
COPY . /app
RUN make /app
RUN rm -r $HOME/.cache
CMD python /app/app.py
以上dockerfile包含4个命令。修改文件系统的命令会创建一个层,改FROM语句首先是ubuntu:22.04 镜像创建一个层。该LABEL命令仅修改镜像的元数据,不会生成新层。该COPY命令从 Docker 客户端的当前目录添加一些文件。第一个RUN命令使用该命令构建应用程序make,并将结果写入新层。第二个RUN命令删除缓存目录,并将结果写入新层。最后,该CMD指令指定在容器内运行什么命令,这个命令只会修改镜像的元数据,不会生成镜像层。
每个层上面都是与前一层的一组差异。添加或者删除文件都会产生一个新层,如$HOME/.cache被删除,但仍将在前一层中可用,并添加到镜像的总大小中。
这些层都是互相堆叠,创建新容器是,又会在底层上面添加一个新的可写层。这些层通常称为:容器层。对于运行的容器所做全部更改,如写入新文件、修改现有文件和删除文件等都会写入此薄的可写容器层。
存储驱动程序在处理这些层间交互方式等细节时,不同存储驱动程序在不同情况下有各自的优缺点。
容器和镜像之间主要区别是在最上面的可写层。对容器的全部写入,添加新数据或修改现有数据都存储在此可写层中。删除容器时,可写层也会被删除,底层镜像保持不变。但是每个容器都可共享对同一底层映像的访问权限,但同时也有自己的数据状态。
如果是想查看正在运行的容器大致大小,可以用docker ps -s命令列出不同两列的大小。
Size是用于每个容器的可写层的数据量(在磁盘上)。
virtual size是容器使用的只读映像数据加上容器的可写层的数据量size。多个容器可能共享部分或全部只读映像数据。从同一映像启动的两个容器共享 100% 的只读数据,而具有不同映像但具有共同层的两个容器共享这些共同层。因此,不能只将虚拟大小相加。这会高估总磁盘使用量,可能会高估很多。
全部在运行的容器在磁盘上使用总磁盘空间是每个容器size和virtual size值的某种组合。当多个容器从同一映像启动,这些容器在磁盘上总大小将是size容器数的总和加上一个映像大小。这还没计入容器占用磁盘空间的其他方式。