<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Docker镜像优化：体积减少80%的技巧 on SelfTechHub</title>
        <link>https://blog.irudder.me/tags/Docker%E9%95%9C%E5%83%8F%E4%BC%98%E5%8C%96%E4%BD%93%E7%A7%AF%E5%87%8F%E5%B0%9180%E7%9A%84%E6%8A%80%E5%B7%A7.html</link>
        <description>Recent content in Docker镜像优化：体积减少80%的技巧 on SelfTechHub</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>zh-cn</language>
        <lastBuildDate>Tue, 19 Nov 2024 00:00:00 +0000</lastBuildDate><atom:link href="https://blog.irudder.me/tags/Docker%E9%95%9C%E5%83%8F%E4%BC%98%E5%8C%96%E4%BD%93%E7%A7%AF%E5%87%8F%E5%B0%9180%E7%9A%84%E6%8A%80%E5%B7%A7/index.xml" rel="self" type="application/rss+xml" /><item>
        <title>Docker镜像从1.2G到80M：架构师的“瘦身”复盘</title>
        <link>https://blog.irudder.me/tech/jiagouyouhuashizhananlijiexi/dockerjingxiangyouhua_tijijianshao80%dejiqiao.html</link>
        <pubDate>Tue, 19 Nov 2024 00:00:00 +0000</pubDate>
        
        <guid>https://blog.irudder.me/tech/jiagouyouhuashizhananlijiexi/dockerjingxiangyouhua_tijijianshao80%dejiqiao.html</guid>
        <description>&lt;p&gt;凌晨两点，监控系统疯狂报警：“生产环境Kubernetes节点磁盘空间不足，Pod驱逐中”。&lt;/p&gt;
&lt;p&gt;排查后发现，罪魁祸首不是日志，而是那几个刚刚发布的、未经优化的Docker镜像。每个镜像动辄1.5GB，不仅撑爆了节点磁盘，更让扩容时的拉取时间变成了漫长的折磨。&lt;/p&gt;
&lt;p&gt;这曾是我带团队时踩过的最痛的一个坑。那时我误以为Docker只是个打包工具，把代码和依赖塞进去能跑就行。直到这次事故，我才意识到：&lt;strong&gt;镜像大小不仅关乎存储成本，更直接决定了发布速度、安全攻击面和系统的弹性伸缩能力。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这两年，我通过几十个项目的实战，总结了一套可落地的镜像优化方法论。今天咱们不谈空泛的理论，直接复盘我是如何把一个臃肿的Java应用镜像从1.2GB砍到80MB的。&lt;/p&gt;
&lt;h2 id=&#34;所谓多阶段构建不只是分两次写&#34;&gt;所谓“多阶段构建”，不只是分两次写
&lt;/h2&gt;&lt;p&gt;很多工程师知道多阶段构建（Multi-stage builds），但在Code Review中，我发现大部分人只是机械地照搬文档，并没有理解其核心价值——&lt;strong&gt;剥离构建环境与运行环境&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;在一个Spring Boot老项目的改造中，我发现之前的Dockerfile直接基于 &lt;code&gt;maven:3.8-jdk-11&lt;/code&gt; 构建，把源码、Maven仓库缓存（&lt;code&gt;.m2&lt;/code&gt;）、甚至测试报告都打进了最终镜像。这就像是你买了一套房子，交房时建筑队把脚手架、水泥搅拌机都留在了客厅里。&lt;/p&gt;
&lt;p&gt;我们做了一个简单的调整：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;第一阶段（Builder）&lt;/strong&gt;：负责编译、测试、打包。这里可以使用包含完整SDK的大体积基础镜像。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;第二阶段（Runner）&lt;/strong&gt;：只拷贝编译好的Jar包，并运行在最小化的JRE环境中。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;看看这个对比：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://picsum.photos/800/450?random=1768457741002&#34;
	
	
	
	loading=&#34;lazy&#34;
	
		alt=&#34;配图&#34;
	
	
&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-dockerfile&#34; data-lang=&#34;dockerfile&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# ❌ 错误示范：单阶段构建，产物含源码和Maven缓存&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;FROM&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;maven:3.8-jdk-11&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;WORKDIR&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;/app&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;COPY&lt;/span&gt; . .&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;RUN&lt;/span&gt; mvn package&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;CMD&lt;/span&gt; [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;java&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-jar&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;target/app.jar&amp;#34;&lt;/span&gt;]&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-dockerfile&#34; data-lang=&#34;dockerfile&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# ✅ 优化后：多阶段构建&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 阶段一：构建&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;FROM&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;maven:3.8-jdk-11&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;AS&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;builder&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;WORKDIR&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;/build&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;COPY&lt;/span&gt; pom.xml .&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;COPY&lt;/span&gt; src ./src&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;RUN&lt;/span&gt; mvn package -DskipTests&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 阶段二：运行&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;FROM&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;openjdk:11-jre-slim&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;WORKDIR&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;/app&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 关键点：只拷贝阶段一的产物&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;COPY&lt;/span&gt; --from&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;builder /build/target/app.jar .&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;CMD&lt;/span&gt; [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;java&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-jar&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;app.jar&amp;#34;&lt;/span&gt;]&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;结果非常直观&lt;/strong&gt;：镜像体积瞬间从 &lt;strong&gt;800MB+ 降到了 250MB&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;但这就够了吗？显然没有。对于高频发布的微服务来说，250MB依然是个负担。&lt;/p&gt;
&lt;h2 id=&#34;善用缓存机制别让你的带宽空转&#34;&gt;善用缓存机制，别让你的带宽空转
&lt;/h2&gt;&lt;p&gt;在CI/CD流水线中，我观察到一个奇怪现象：即使开发人员只修改了一行代码（比如改了个Log级别），整个镜像构建过程依然需要重新下载所有依赖，耗时3-5分钟。&lt;/p&gt;
&lt;p&gt;这是因为Docker的层级缓存（Layer Caching）机制失效了。&lt;/p&gt;
&lt;p&gt;Docker构建时会逐行检查指令，一旦某行指令的内容发生了变化（例如 &lt;code&gt;COPY . .&lt;/code&gt; 导致文件指纹变了），该行及其之后的所有指令缓存都会失效。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;大部分人的坏习惯是：&lt;/strong&gt; 先把所有代码拷进去，再安装依赖。
&lt;strong&gt;正确的姿势是：&lt;/strong&gt; 先拷依赖描述文件，安装依赖，最后才拷源码。&lt;/p&gt;
&lt;p&gt;我们将Python项目的Dockerfile做了如下调整：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-dockerfile&#34; data-lang=&#34;dockerfile&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# ❌ 优化前&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;COPY&lt;/span&gt; . /app&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;RUN&lt;/span&gt; pip install -r requirements.txt&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# ✅ 优化后&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;COPY&lt;/span&gt; requirements.txt /app/&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;RUN&lt;/span&gt; pip install -r requirements.txt&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;COPY&lt;/span&gt; . /app&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个改动看似微小，但效果惊人。在后续的几百次构建中，只要 &lt;code&gt;requirements.txt&lt;/code&gt; 没变，&lt;code&gt;pip install&lt;/code&gt; 这一层直接命中缓存。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;数据支撑&lt;/strong&gt;：我们的平均构建时间从 &lt;strong&gt;4分30秒缩短到了25秒&lt;/strong&gt;，开发体验完全不在一个量级。我个人习惯在每周五下午Review代码时，专门检查一遍所有服务的Dockerfile是否遵循了“依赖先行”的原则。&lt;/p&gt;
&lt;h2 id=&#34;极端瘦身distroless与alpine的抉择&#34;&gt;极端瘦身：Distroless与Alpine的抉择
&lt;/h2&gt;&lt;p&gt;到了这一步，我们的Java镜像还在200MB左右，Node.js镜像在500MB左右。瓶颈落在了**基础镜像（Base Image）**上。&lt;/p&gt;
&lt;p&gt;常规的 &lt;code&gt;ubuntu&lt;/code&gt; 或 &lt;code&gt;centos&lt;/code&gt; 镜像包含了大量你根本用不到的工具：&lt;code&gt;curl&lt;/code&gt;, &lt;code&gt;vim&lt;/code&gt;, &lt;code&gt;apt&lt;/code&gt;, &lt;code&gt;bash&lt;/code&gt; 等等。这些工具不仅占空间，还是黑客眼中的“趁手兵器”。&lt;/p&gt;
&lt;p&gt;这里有两个流派，我都亲测过：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Alpine流派&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;特点&lt;/strong&gt;：使用 musl libc 代替 glibc，体积极其精简（~5MB）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;坑点&lt;/strong&gt;：兼容性问题简直是噩梦。我曾在Python项目中因为C扩展库（如pandas, numpy）缺少预编译的wheel包，导致构建时需要现场编译gcc，反而让构建时间激增，甚至运行时出现莫名其妙的DNS解析问题。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Distroless流派（Google推荐）&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;特点&lt;/strong&gt;：只包含应用程序及其运行时依赖项，不包含包管理器、shell 或任何其他标准 Linux 发行版中常见的程序。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;实战&lt;/strong&gt;：我们将一个Go语言的网关服务，从 &lt;code&gt;alpine&lt;/code&gt; 迁移到了 &lt;code&gt;gcr.io/distroless/static&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-dockerfile&#34; data-lang=&#34;dockerfile&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 最终阶段使用 distroless&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;FROM&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;gcr.io/distroless/static-debian11&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;COPY&lt;/span&gt; --from&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;builder /go/bin/app /&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;CMD&lt;/span&gt; [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/app&amp;#34;&lt;/span&gt;]&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;最终战果&lt;/strong&gt;：
该Go服务镜像最终大小仅为 &lt;strong&gt;18MB&lt;/strong&gt;。
更重要的是安全扫描结果：&lt;strong&gt;高危漏洞（CVE）数量从原来的 30+ 降为 0&lt;/strong&gt;。因为镜像里连个 Shell 都没有，攻击者就算利用代码漏洞进来了，也无法执行系统命令。&lt;/p&gt;
&lt;h2 id=&#34;拒绝盲猜用工具看见大象&#34;&gt;拒绝盲猜：用工具看见“大象”
&lt;/h2&gt;&lt;p&gt;&lt;img src=&#34;https://picsum.photos/800/450?random=1768457740982&#34;
	
	
	
	loading=&#34;lazy&#34;
	
		alt=&#34;配图&#34;
	
	
&gt;&lt;/p&gt;
&lt;p&gt;很多时候，你以为镜像小了，其实里面还藏着“大象”。&lt;/p&gt;
&lt;p&gt;曾有一个实习生问我：“为什么我删除了大文件，镜像体积还是没变？”
原因是Docker的文件系统是分层的。你在下一层 &lt;code&gt;RUN rm huge_file&lt;/code&gt;，只是在当前层标记该文件为删除，上一层的实际数据依然存在于镜像历史中。&lt;/p&gt;
&lt;p&gt;我强制要求团队在本地开发环境安装 &lt;strong&gt;Dive&lt;/strong&gt; 这个工具。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Dive 是一个在终端运行的 Docker 镜像分析工具，它能以图形化方式展示每一层的文件变化。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;通过 &lt;code&gt;dive image:tag&lt;/code&gt;，我们可以清晰地看到每一层增加了多少体积，以及具体是哪些文件。&lt;/p&gt;
&lt;p&gt;有一次排查发现，某个Node.js镜像体积异常，用Dive一看，竟然是因为 &lt;code&gt;.dockerignore&lt;/code&gt; 没配置好，把 &lt;code&gt;.git&lt;/code&gt; 目录（包含历史所有的提交记录）完整地拷进去了，白白浪费了 150MB。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;这是一个价值 150MB 的教训，修复只需要一行配置。&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&#34;总结与行动指南&#34;&gt;总结与行动指南
&lt;/h2&gt;&lt;p&gt;Docker镜像优化不仅仅是“省硬盘”，它是架构师对交付质量、安全性和系统效率的一种极致追求。&lt;/p&gt;
&lt;p&gt;从 1.2GB 到 80MB 的过程，本质上是做减法的过程：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;减去构建环境&lt;/strong&gt;（多阶段构建）；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;减去重复劳动&lt;/strong&gt;（利用层级缓存）；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;减去操作系统&lt;/strong&gt;（使用 Distroless/Alpine）；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;减去无用文件&lt;/strong&gt;（使用 .dockerignore 和 Dive 分析）。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;最后，我想做一个小调查：&lt;/strong&gt;
在基础镜像的选择上，你更倾向于 &lt;strong&gt;A. Alpine（追求极致体积但牺牲部分兼容性）&lt;/strong&gt; 还是 &lt;strong&gt;B. Distroless（追求极致安全但调试不便）&lt;/strong&gt;？欢迎在评论区告诉我你的选择和理由。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;给读者的3个落地建议：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;立刻检查&lt;/strong&gt;：去看看你现有的Dockerfile，是否将 &lt;code&gt;COPY . .&lt;/code&gt; 放到了安装依赖之前？如果是，立刻改过来。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;安装工具&lt;/strong&gt;：在你的电脑上安装 &lt;code&gt;dive&lt;/code&gt;，随便分析一个你常用的镜像，你会发现新大陆。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;尝试迁移&lt;/strong&gt;：选择一个非核心业务的微服务，尝试将其基础镜像替换为 &lt;code&gt;distroless&lt;/code&gt; 或 &lt;code&gt;slim&lt;/code&gt; 版本，对比一下扫描出的漏洞数量变化。&lt;/li&gt;
&lt;/ol&gt;
</description>
        </item>
        
    </channel>
</rss>
