首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >镜像太臃肿?这个神器让你的Docker镜像瘦成闪电!

镜像太臃肿?这个神器让你的Docker镜像瘦成闪电!

作者头像
悠悠12138
发布2026-01-13 20:07:20
发布2026-01-13 20:07:20
1380
举报

前言

前几天在公司部署服务的时候,发现一个nodejs应用的镜像居然有2.5G!我当时就懵了,这不科学啊,一个简单的web应用怎么可能这么大。同事开玩笑说是不是把整个node_modules都打包进去了...结果还真被他说中了一部分。

这种情况在实际工作中真的太常见了,很多时候我们构建的镜像莫名其妙就变得很大,但是又不知道问题出在哪里。直到我发现了dive这个工具,才算是找到了分析镜像的利器。

dive是什么?为什么要用它

dive是一个用Go语言开发的Docker镜像分析工具,它可以让你深入了解镜像的每一层结构,看到每一层添加了什么文件,删除了什么内容,甚至可以计算出镜像的效率指标。

你可能会问,docker history命令不也能看镜像的层信息吗?确实可以,但是dive的优势在于:

  • • 交互式的界面,操作起来更直观
  • • 可以浏览每一层的文件系统变化
  • • 显示每个文件的大小信息
  • • 计算镜像的浪费空间和效率评分
  • • 支持CI/CD集成,可以设置镜像大小阈值

说白了,docker history只能告诉你"发生了什么",而dive能告诉你"具体发生了什么,影响有多大"。

安装dive的几种方式

直接下载二进制文件

最简单的方式就是从GitHub releases页面下载对应系统的二进制文件:

代码语言:javascript
复制
# Linux
wget https://github.com/wagoodman/dive/releases/download/v0.12.0/dive_0.12.0_linux_amd64.tar.gz
tar -xzf dive_0.12.0_linux_amd64.tar.gz
sudo mv dive /usr/local/bin/

# macOS
brew install dive

使用Docker运行dive

这种方式比较适合不想在本地安装的情况:

代码语言:javascript
复制
docker run --rm -it \
    -v /var/run/docker.sock:/var/run/docker.sock \
    wagoodman/dive:latest <镜像名>

我个人更喜欢直接安装,因为用起来更方便一些。

从源码编译

如果你想体验最新的功能,可以从源码编译:

代码语言:javascript
复制
go install github.com/wagoodman/dive@latest

不过说实话,直接用release版本就足够了,我用了这么久也没遇到什么bug。

dive的基本使用方法

安装完成后,使用dive分析镜像非常简单:

代码语言:javascript
复制
dive <镜像名>

比如分析一个nginx镜像:

代码语言:javascript
复制
dive nginx:latest

启动后你会看到一个分屏的界面,左边显示镜像的各个层,右边显示当前选中层的文件系统内容。

界面操作说明:

  • • 上下箭头键:选择不同的镜像层
  • • Tab键:在左右窗格之间切换焦点
  • • 空格键:展开/收起文件夹
  • • Ctrl+C:退出程序

深入分析一个臃肿的镜像

让我用一个真实的例子来演示。我之前构建了一个Python应用的镜像,Dockerfile是这样的:

代码语言:javascript
复制
FROM python:3.9
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["python", "app.py"]

看起来很正常对吧?但是构建出来的镜像有1.2G。用dive分析一下:

代码语言:javascript
复制
dive myapp:latest

通过dive分析,我发现了几个问题:

1. 基础镜像选择不当

python:3.9这个镜像本身就很大,包含了很多我不需要的系统工具和库。dive显示这个基础层就有900多MB。

在dive界面中,可以看到第一层(基础镜像层)的大小占了整个镜像的大部分。通过Tab键切换到右侧窗格,可以浏览基础镜像包含的文件,发现里面有gcc、各种开发工具等等。

2. pip缓存没有清理

RUN pip install这一层显示增加了300多MB,但实际的Python包应该没这么大。进入这一层的文件系统,发现/root/.cache/pip目录占用了很大空间。

3. 不必要的文件被复制

COPY . . 这一层虽然只有几MB,但是包含了.git目录、pycache、测试文件等不需要的内容。

优化后的Dockerfile

基于dive的分析结果,我重新编写了Dockerfile:

代码语言:javascript
复制
FROM python:3.9-slim
WORKDIR /app

# 只复制requirements文件,利用Docker缓存
COPY requirements.txt .

# 安装依赖并清理缓存
RUN pip install --no-cache-dir -r requirements.txt \
    && rm -rf /root/.cache/pip

# 只复制需要的应用文件
COPY src/ ./src/
COPY app.py .

CMD ["python", "app.py"]

还添加了一个.dockerignore文件:

代码语言:javascript
复制
.git
.gitignore
README.md
Dockerfile
.dockerignore
__pycache__
*.pyc
*.pyo
*.pyd
.Python
.pytest_cache
.coverage
test/
docs/

重新构建后用dive分析,镜像大小降到了180MB!效果非常明显。

dive的高级功能

效率评分

dive会给你的镜像打一个效率分数。在界面底部可以看到类似这样的信息:

代码语言:javascript
复制
Image efficiency score: 95%
Potential wasted space: 12MB

这个评分主要基于:

  • • 重复文件的数量
  • • 每层的大小合理性
  • • 文件的实际利用率

CI/CD集成

dive支持在CI/CD流水线中使用,可以设置镜像大小和效率的阈值:

代码语言:javascript
复制
# 设置镜像最大500MB,效率最低80%
dive myapp:latest --ci \
    --lowestEfficiency=80 \
    --highestWastedBytes=500MB

如果镜像不符合要求,dive会返回非0退出码,可以让构建失败。

我在公司的Jenkins流水线中就加了这个检查,避免有人提交过大的镜像。

输出格式

dive支持多种输出格式,方便集成到其他工具中:

代码语言:javascript
复制
# JSON格式输出
dive myapp:latest --json output.json

# 只显示汇总信息
dive myapp:latest --ci --quiet-ci

一些实用的分析技巧

1. 对比不同版本的镜像

经常需要对比优化前后的镜像差异,可以分别分析两个镜像:

代码语言:javascript
复制
dive myapp:v1.0
dive myapp:v2.0

通过对比两个版本的层结构和大小变化,可以快速定位问题。

2. 查看多阶段构建的效果

对于多阶段构建的Dockerfile,dive特别有用。可以清楚地看到哪些文件被复制到了最终镜像,哪些留在了构建阶段。

代码语言:javascript
复制
FROM node:16 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html

用dive分析这种镜像时,可以看到builder阶段的文件没有进入最终镜像,这样确保了镜像的精简。

3. 识别安全风险文件

在分析镜像时,注意查看是否包含了敏感文件,比如:

  • • SSH密钥
  • • 配置文件中的密码
  • • 开发工具和调试信息

dive可以帮你浏览整个文件系统,确保不会意外泄露敏感信息。

常见的镜像优化策略

通过长期使用dive分析各种镜像,我总结了一些常见的优化策略:

选择合适的基础镜像

  • • 优先使用slim或alpine版本
  • • 避免使用latest标签
  • • 根据实际需要选择版本

比如:

  • • python:3.9-slim 比 python:3.9 小很多
  • • node:16-alpine 比 node:16 更精简
  • • golang的编译完成后可以用scratch作为运行镜像

合并RUN指令

每个RUN指令都会创建一个新层,合并相关的RUN指令可以减少层数:

代码语言:javascript
复制
# 不好的写法
RUN apt-get update
RUN apt-get install -y git
RUN apt-get install -y curl
RUN apt-get clean

# 好的写法
RUN apt-get update && \
    apt-get install -y git curl && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

使用.dockerignore

这个真的很重要,很多人容易忽略。就像.gitignore一样,.dockerignore可以避免把不需要的文件复制到镜像中。

清理临时文件

在同一个RUN指令中安装软件并清理:

代码语言:javascript
复制
RUN apt-get update && \
    apt-get install -y python3-pip && \
    pip3 install -r requirements.txt && \
    apt-get remove -y python3-pip && \
    apt-get autoremove -y && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

实际应用中的一些坑

1. 删除文件不会减小镜像大小

这是很多新手会遇到的问题。如果在一个RUN指令中创建了文件,然后在另一个RUN指令中删除,文件还是会占用空间。

代码语言:javascript
复制
# 错误的做法
RUN wget https://example.com/largefile.tar.gz
RUN tar -xzf largefile.tar.gz && rm largefile.tar.gz

# 正确的做法
RUN wget https://example.com/largefile.tar.gz && \
    tar -xzf largefile.tar.gz && \
    rm largefile.tar.gz

dive可以清楚地显示这种情况,你会看到删除操作创建了一个新层,但总大小没有减少。

2. COPY指令的顺序很重要

Docker的缓存机制是基于层的,如果把经常变化的文件放在前面,会导致后续的层都需要重新构建。

代码语言:javascript
复制
# 不好的顺序
COPY . .
RUN pip install -r requirements.txt

# 好的顺序
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .

3. 多阶段构建的层共享

使用多阶段构建时,注意不同阶段之间不会共享层,每个FROM都会开始新的层计算。

dive的一些局限性

用了这么久dive,也发现了一些局限性:

  1. 1. 对于压缩层的分析不够详细,有时候显示的大小与实际略有差异
  2. 2. 界面操作需要一定的学习成本,特别是对于习惯图形界面的同学
  3. 3. 分析特别大的镜像时,加载速度会比较慢
  4. 4. 不支持直接分析tar格式的镜像文件

不过这些问题相对于它带来的价值来说都是小问题。

其他类似工具的对比

除了dive,还有一些其他的镜像分析工具:

docker-slim

这个工具不仅能分析镜像,还能自动优化:

代码语言:javascript
复制
docker-slim build myapp:latest

但是自动优化有时候会过于激进,可能会删掉必要的文件。

container-diff

Google开源的工具,主要用于对比两个镜像的差异:

代码语言:javascript
复制
container-diff diff daemon://image1:tag daemon://image2:tag

功能比较专一,适合做镜像对比分析。

skopeo

主要用于镜像的复制和检查,也有一些分析功能:

代码语言:javascript
复制
skopeo inspect docker://nginx:latest

相比之下,dive在交互性和详细程度方面还是有明显优势的。

写在最后

镜像优化这个事情说起来简单,做起来却需要很多细节的把控。dive这个工具真的帮了我很大忙,让镜像分析变得直观和高效。

记得第一次用dive的时候,那种"终于知道问题出在哪里"的感觉真的很爽。就像医生给病人做CT扫描一样,能清楚地看到镜像的"内脏结构"。

当然,工具只是手段,关键还是要养成好的构建习惯。合理选择基础镜像、善用.dockerignore、及时清理临时文件...这些看似简单的操作,日积月累下来效果是很明显的。

如果你也经常被镜像大小困扰,强烈建议试试dive。相信我,用过之后你就回不去了。

最后,如果这篇文章对你有帮助的话,别忘了点个赞和转发。有任何问题也欢迎留言交流,我看到会及时回复的。

关注@运维躬行录,一起在运维的路上精进技艺,让每一次部署都更加优雅!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-01-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 运维躬行录 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
    • dive是什么?为什么要用它
    • 安装dive的几种方式
      • 直接下载二进制文件
      • 使用Docker运行dive
      • 从源码编译
    • dive的基本使用方法
    • 深入分析一个臃肿的镜像
      • 1. 基础镜像选择不当
      • 2. pip缓存没有清理
      • 3. 不必要的文件被复制
    • 优化后的Dockerfile
    • dive的高级功能
      • 效率评分
      • CI/CD集成
      • 输出格式
    • 一些实用的分析技巧
      • 1. 对比不同版本的镜像
      • 2. 查看多阶段构建的效果
      • 3. 识别安全风险文件
    • 常见的镜像优化策略
      • 选择合适的基础镜像
      • 合并RUN指令
      • 使用.dockerignore
      • 清理临时文件
    • 实际应用中的一些坑
      • 1. 删除文件不会减小镜像大小
      • 2. COPY指令的顺序很重要
      • 3. 多阶段构建的层共享
    • dive的一些局限性
    • 其他类似工具的对比
      • docker-slim
      • container-diff
      • skopeo
    • 写在最后
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档