## 🐳 [[Docker]] 镜像瘦身的起点:用 `docker history` 揭秘其“族谱” {#sec-168deae1dd0f} 明明只是部署了一个轻量级应用,但查看镜像大小时却发现它轻松超过了1GB。你可能会感到困惑,心想“我到底加了什么东西?”。这时,我们需要做的就是揭开镜像的“族谱”,一探究竟。 ![Docker 镜像层级优化示意图](/media/whitedec/blog_img/de42f6f1949c4e91bc6defa030f10ea5.webp) ## “你到底吃了什么,怎么长这么大了?” {#sec-5eaafdc2833e} Docker 镜像就像层层堆叠的洋葱皮(层)。`docker history` 命令就像一台X光机,能一层层剥开这些“外衣”,找出导致镜像臃肿的“元凶”。 其基本用法非常简单: ```bash # 基本用法 docker history [选项] <镜像名称:标签> # 示例:查看我的应用历史 docker history my-app:latest ``` 执行该命令后,会从最新层开始,逆序显示镜像的所有层,直至基础镜像。 ```text IMAGE CREATED CREATED BY SIZE a6215f271958 5 minutes ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B 7 weeks ago /bin/sh -c #(nop) ADD file:f28242cf608f6... 7.81MB ``` 请仔细观察 **SIZE** 这一项。如果本应是 0B 的地方却显示了几百MB,那么它就是需要“瘦身”的对象。凭经验来看,总会有一些地方“不对劲”。 > **💡 实用技巧:`--no-trunc`** > > 默认情况下,如果命令过长,输出内容会被截断。此时,加上 `--no-trunc` 选项,就能完整显示所有命令,这对于精确分析至关重要。 > > `docker history --no-trunc my-app:latest` *** ## 实战案例:“罪魁祸首是 `chown`” {#sec-036665971432} 我来分享一个亲身经历的真实案例。我构建了一个 150MB 的项目文件,但镜像大小却诡异地超过了 300MB。而“罪魁祸首”就是 Dockerfile 中看似再普通不过的两行命令。 **[低效方法:创建两个层]** ```dockerfile # 1. 首先复制文件(默认以 root 用户复制) COPY . . # 2. 为安全起见更改所有权(作为单独命令执行) RUN chown -R appuser:appgroup /app ``` 构建之后,用 `docker history` 查看,结果如下: ```text IMAGE CREATED BY SIZE /bin/sh -c chown -R appuser:appgroup /app 150MB <-- (问题所在!) /bin/sh -c #(nop) COPY dir:abc in /app 150MB ``` Docker 层级的“可怕”之处就在这里。第一步复制 150MB 文件时,会创建一个层。但第二步执行 `chown` 命令时,Docker 会认为“咦?文件信息(所有权)变了?那我就把更改后的状态再创建一个新层!”它会将原有的 150MB 文件原封不动地复制一份,再堆叠一个新层。 结果,内容完全相同,只是所有权不同的文件却被双重存储,导致镜像大小翻倍。 *** ## 解决方案:一行命令搞定瘦身! {#sec-b564ee91d4d9} 解决方案很简单。只需在复制文件时直接指定所有权,就能将多个层合并为一个。 **[高效方法:创建单个层]** ```dockerfile # 复制文件时同时指定所有权! COPY --chown=appuser:appgroup . . ``` 将 Dockerfile 这样修改后,再次执行 `docker history`,结果会发生翻天覆地的变化。 ```text IMAGE CREATED BY SIZE /bin/sh -c #(nop) COPY --chown=appuser... dir:abc 150MB ``` 看到了吗?只创建了一个层,镜像大小又“苗条”地回到了 150MB。仅仅是将两条命令合并为一行,镜像容量就减少了一半。 *** ## 结论:构建后务必检查“历史记录”! {#sec-74645a10d229} 请记住,[[Docker]] 镜像的特点是**每条命令对应一个层**。 就像编写代码后进行测试一样,在构建镜像后,也请养成习惯性地运行 `docker history --no-trunc` 命令。当“这个 `apt-get` 为什么这么大?”、“为什么要特意将这个层分开?”之类的疑问接踵而至时,不知不觉中,您就会构建出非常轻量且高效的系统。 因为不必要的层是系统的敌人! *** **这篇文章对您有帮助吗?** 如果有,请点赞! 也请阅读相关文章。 **相关文章** [Docker 共享内存(shm_size 和 ipc)完全理解](/ko/whitedec/2025/11/5/docker-shm-size-ipc/) [Docker: 无需网络共享,通过主机端口实现容器间通信](/ko/whitedec/2025/11/4/docker-host-port-container-communication/) [Docker 卷(Volume)复制,‘为什么’要这样做?](/ko/whitedec/2025/11/10/docker-volume-copy-reason/)