把 Docker 镜像从 1.2G 瘦到 180M,我踩过的坑和 4 个管用的招
技术笔记 2 次阅读

把 Docker 镜像从 1.2G 瘦到 180M,我踩过的坑和 4 个管用的招

前阵子接手公司 CI 改造的活儿,一上来就被镜像体积整懵了:每次构建出来的镜像 1.2G,推送到仓库要好几分钟,测试环境拉下来也慢得离谱。老板丢了一句"优化一下",我吭哧吭哧搞了两天,最后从 1.2G 瘦到 180M,部署时间从 4 分钟干到 40 秒。过程不算顺,但招数其实就那几招,今天掰开揉碎聊聊。

Docker镜像瘦身

先搞清楚镜像为什么这么大

很多人上来就瞎优化,其实先得明白体积都堆在哪。我那个项目是 Node 的,光基础镜像 node:18 就有 900 多 M,再加上构建时把 node_modules、源码、npm 缓存一股脑全塞进去,一层叠一层,想不大都难。说白了,镜像就是一层层的"快照",你每执行一条命令,它就给这层留个底,删都删不掉。

第一招:换 Alpine 基础镜像,立省 700M

这一招性价比最高。把 node:18 换成 node:18-alpine,基础镜像直接从 900 多 M 掉到 170M 左右,啥都不用干就省了七成。但有个坑得提前说:alpine 用的是 musl 而不是 glibc,遇到需要编译原生模块的依赖(比如 node-gyp 编译 sharp 这种),十有八九报错。解决办法也简单,Dockerfile 里提前装好 build-base 和 python3,编译完再清掉就行。

第二招:多阶段构建,把"施工现场"留在第一层

这是最核心的一招。以前是"一个阶段干到底":装依赖、跑构建、全留在最终镜像里。多阶段构建就是分两步走——第一阶段 FROM node:18-alpine AS build,把依赖装好、构建跑完;第二阶段重新 FROM 一个干净的基础镜像,只把构建产物 COPY 过来。我那个项目用 Vite 打包,产物就几十 M,几百 M 的 node_modules 全被丢在中间层,最后镜像里干干净净。

第三招:清缓存、合并 RUN,能省一点是一点

别小看细节。npm ci 装完依赖记得跟上 npm cache clean --force,那缓存动不动就几百 M。另外每一条 RUN 都会产生一个新层,能合并就合并,用 && 串起来写,少一层是一层。装完的临时文件该删就删,别客气。

第四招:追求极致就上 distroless

如果你对体积和安全都敏感,可以试试 gcr.io/distroless 系列镜像,连 shell 都没有,攻击面小到极致,体积还能再压一截。但代价是容器里没法 exec 进去调试,排查问题只能靠日志,团队不熟的话慎用。

最后汇报下战果:1.2G 到 180M,推送快了 8 倍不止,测试环境拉镜像从 2 分钟变 15 秒,同事都以为我偷偷换了服务器。总结就一句话——别把构建现场打包进镜像,该丢的丢,该清的清,镜像自然就瘦了。

分享

评论 (0)

评论通过后显示

暂无评论,来写第一条吧 ✍️