涉及多种技术,没有一个解决方案。您可能需要执行以下几个操作:
首先,优化图像层以供重用。稍后在Dockerfile中进行频繁更改的步骤,以增加从早期构建中缓存早期层的机会。重用的层将在中显示为更多的磁盘空间docker image ls
,但是如果您检查基础文件系统,则每层只有一个副本存储在磁盘上。这意味着3张图像,每张2 GB,但是在构建的最后几层中只有50 MB的差异,尽管清单表明它使用的是6 GB,但清单仅显示2.1 GB的磁盘空间。重复计算每个重用层。
层重用是为什么您看到具有不经常更改的构建依赖关系的映像的原因,因此请先安装映像,然后再复制代码。查看任何具有以下模式的python示例:
FROM python
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
# note how the code is copied only after the pip install
# since code changes but requirements.txt doesn't
COPY . .
CMD ["gunicorn", "app:app"]
选择一个最小的基本图像。这就是为什么您会看到人们ubuntu
转向debian:slim
(苗条的款式更小,使用的工具更少)或什至是的原因alpine
。这减小了起点的大小,如果您不断拉动基础图像的新版本,这将非常有帮助。但是,如果基本映像很少更改,则层重用将消除最小化基本映像的许多优点。
您可以选择的最小基础映像是scratch
,它什么也不是,没有外壳或库,仅对静态编译的二进制文件有用。否则,请选择一个包含所需工具的基础映像,而不需要大量不需要的工具。
接下来,任何更改或删除文件的步骤都应与创建该文件的先前步骤结合使用。否则,即使在更改文件权限等情况下也使用写时复制的分层文件系统将在上一层具有原始文件,并且在删除文件时图像大小不会缩小。这就是为什么您的rm
命令对生成的磁盘空间没有影响的原因。相反,您可以链接命令,例如:
RUN apt-get update \
&& apt-get install -y \
a-package \
wget \
&& ... \
&& apt-get purge -y wget \
&& rm -r a-build-dir \
&& apt-get purge -y a-package
请注意,过度使用命令链会减慢您的构建速度,因为您需要在先决条件更改(例如,用wget提取代码)时重新安装同一工具集。请参阅下面的多阶段以获得更好的选择。
创建的文件中不需要的任何文件都应在创建该文件的步骤中删除。这包括程序包缓存,日志,手册页等。要发现每一层中正在创建什么文件,可以使用wagoodman / dive之类的工具(我没有亲自对其进行过审查,因此请谨慎使用,因为它可以完全root用户访问在您的主机上),或者您可以在不修剪中间容器的情况下构建docker映像,然后使用以下命令查看差异:
# first create and leave containers from any RUN step using options on build
docker image build --rm=false --no-cache -t image_name .
# review which layers use an unexpectedly large amount of space
docker image history image_name
# list all containers, particularly the exited ones from above
docker container ps -a
# examine any of those containers
docker container diff ${container_id}
# ... repeat the diff for other build steps
# then cleanup exited containers
docker container prune
与每个中间的那些容器,该差异将显示文件被添加什么,改变,或在该步骤删除(这些与所指示的A
,C
或D
之前的各文件名)。diff显示的是特定于容器的读/写文件系统,该文件系统是容器使用写时复制从映像状态更改的任何文件。
减小图像大小的最佳方法是从出厂的图像中消除任何不需要的组件,例如编译器。为此,多阶段构建使您可以在一个阶段进行编译,然后仅将生成的工件从构建阶段复制到运行时映像,该映像仅具有运行应用程序所需的最低要求。这避免了优化任何构建步骤的需要,因为它们不随结果映像一起提供。
FROM debian:9 as build
# still chain update with install to prevent stale cache issues
RUN apt-get update \
&& apt-get install -y \
a-package \
wget \
RUN ... # perform any download/compile steps
FROM debian:9-slim as release
COPY --from=build /usr/local/bin/app /usr/local/bin/app
CMD [ "/usr/local/bin/app" ]
多阶段是静态编译二进制文件的理想选择,您可以从头开始将其作为基本映像运行,也可以从JDK这样的编译环境过渡到JRE这样的运行时环境。这是在保持快速构建的同时显着减小图像大小的最简单方法。如果您具有更改或删除在先前步骤中创建的文件的步骤,则仍可以在发布阶段执行步骤的链接,但是在大多数情况下,COPY
从另一个阶段将发布阶段与早期构建阶段经历的任何层膨胀隔离开来。
请注意,我不建议挤压图像,因为这会缩小一个图像的大小,但以消除图层重用为代价。这意味着以后构建同一映像将需要更多磁盘和网络流量来发送更新。回到第一个示例,压扁可能会将您的映像从2 GB减少到1 GB,但是3张映像可能不会占用3 GB而不是2.1 GB。
2.37
vs.1.47 GB