概述
在构建 Docker 镜像时,容量意外增大是常见现象。大多数原因在于 不必要的层 被创建。本文将使用 docker history 命令来查看镜像的“家谱”,并分享通过此方法轻量化实际镜像的优化经验。
通过这个命令,可以准确找到使镜像变重的原因,并创建更高效的镜像。
docker history: 查看镜像的家谱
docker history 是一个命令,用于显示特定镜像的创建过程和构成细节。它可以显示 Dockerfile 中每个命令是如何叠加成 层(layer) 的,以及每层的生成时间和大小。
基本用法非常简单。
docker history [选项] <镜像名称:标签>
例如,查看本地 my-app:latest 镜像历史的命令如下所示。
docker history my-app:latest
输出结果将按顺序显示从镜像最新的最顶层到基础镜像(最旧的)。
IMAGE CREATED CREATED BY SIZE
a6215f271958 5 minutes ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B
<missing> 7 weeks ago /bin/sh -c #(nop) ADD file:f28242cf608f6... 7.81MB
-
CREATED BY: 生成此层的 Dockerfile 命令
-
SIZE: 此层占用的大小
实用提示: 使用 --no-trunc 查看完整命令
docker history 的默认输出如果 CREATED BY 列的命令过长,会被截断。在这种情况下,使用--no-trunc 选项可以查看完整命令,进行精确分析是至关重要的。
docker history --no-trunc my-app:latest
层分析的重要性: 实际优化经验
Docker 镜像的基本原则是为 Dockerfile 中的 每一行命令生成一个层。每层是对前一层的“更改”。
问题在于,如果不必要地分层,镜像的大小会急剧增加。
案例: COPY 和 RUN chown 的陷阱
在编写 Dockerfile 时,通常将项目文件复制到容器中(COPY),然后更改这些文件的所有权(RUN chown)。
低效方法: 产生两个层
最初,Dockerfile 被编写如下。
# 1. 复制文件 (复制为 root 所有)
COPY . .
# 2. 更改所有权 (单独命令执行)
RUN chown -R appuser:appgroup /app
通过 docker history 查看生成的镜像历史,可以看到产生了两个层。
IMAGE CREATED BY SIZE
<layer_id_2> /bin/sh -c chown -R appuser:appgroup /app 150MB <-- (问题!)
<layer_id_1> /bin/sh -c #(nop) COPY dir:abc in /app 150MB
这里出现了一个严重的问题。
-
COPY . .命令将150MB大小的文件添加到 层 1。 -
RUN chown命令将 层 1 的150MB文件复制 并仅更改所有权信息,然后再存入 层 2。
文件内容相同,但一个为 root 所有,一个为 appuser 所有,分别存储在不同的层中。结果是这两个层的 镜像总容量达300MB(150MB + 150MB),。
高效方法: 1个层
这个问题可以通过使用 COPY 命令的 --chown 选项来简单解决。
# 1. 复制并同时指定所有权
COPY --chown=appuser:appgroup . .
修改 Dockerfile 后,再次通过 docker history 查看。
IMAGE CREATED BY SIZE
<layer_id_1> /bin/sh -c #(nop) COPY --chown=appuser... dir:abc 150MB
仅生成一个层,镜像的总大小减少到 150MB。仅仅将两行命令合并为一行,镜像大小几乎减半。
结论
docker history 不只是查看镜像生成历史,它是 优化镜像的关键分析工具。
修改 Dockerfile 后,习惯性地执行 docker history --no-trunc 来检查层是否按预期生成,以及是否存在占用不必要空间的层,这是一个好习惯。这个小习惯将有助于构建轻量高效的镜像。
目前没有评论。