多阶段构建是解决Nginx源码编译镜像体积大的根本方案,其核心是分离编译环境(builder阶段,含gcc/make/源码)与运行环境(runtime阶段,仅复制/usr/local/nginx等必要文件),彻底剔除构建工具和中间产物,配合Alpine或distroless基础镜像及编译参数精简,可将镜像从数百MB压至几十MB。

源码编译 Nginx 时镜像体积大,核心原因是编译环境(gcc、make、依赖库、源码包等)全被打包进最终镜像。精简的关键不是“少装点”,而是**让运行时镜像完全不包含任何编译产物和构建工具**——这靠多阶段构建(Multi-stage build)实现。
用多阶段构建彻底分离编译与运行环境
第一阶段(builder)负责下载、解压、configure、make、make install;第二阶段(runtime)只复制编译好的二进制和配置文件,不带一行 gcc 或 .tar.gz。
- 第一阶段用 完整开发型基础镜像(如 rockylinux:9、centos:7),安装 pcre-devel、zlib-devel、openssl-devel、gcc 等
- 第二阶段换用 极简运行型基础镜像(如 alpine:3.20、distroless/cc、或甚至 scratch),仅保留 /usr/local/nginx 目录及必要动态库
- 使用 COPY --from=builder 显式拷贝指定路径,避免隐式残留(比如不拷 /src、不拷 /root/.cache)
编译参数与安装路径要“干净可迁移”
configure 阶段就决定后续能否轻量:路径固定、模块精简、不依赖系统全局库。
- 指定 --prefix=/usr/local/nginx,避免分散安装(如不混用 /opt/nginx + /etc/nginx)
- 禁用非必需模块,减少依赖和体积:--without-http_rewrite_module --without-http_gzip_module --without-mail_pop3_module
- 启用静态链接(可选):--with-ld-opt="-static",这样第二阶段可直接用 scratch 镜像,无需拷贝.so
- 避免使用 --with-http_ssl_module 以外的第三方模块,除非明确需要;每个模块都可能引入新依赖
运行阶段务必清理冗余内容
即使用了多阶段,第二阶段镜像仍可能因操作不当膨胀——比如忘了删 man、doc、临时文件,或错误保留了 builder 的用户/组信息。
- 第二阶段 COPY 后,立即 RUN rm -rf /usr/local/nginx/html/*(若自定义首页)并只 ADD 你真正需要的 index.html
- 删除文档和手册:RUN rm -rf /usr/local/nginx/conf/koi* /usr/local/nginx/conf/win-utf /usr/local/nginx/html/*.html
- 确认无调试工具:不安装 curl、vim、bash(除非 debug 镜像);alpine 镜像默认只有 busybox ash
- 若用 glibc 基础镜像,检查是否含调试符号:strip /usr/local/nginx/sbin/nginx 可再省 1–2MB
进阶技巧:替换基础镜像 + 自动化清理
在保证功能前提下,基础镜像选择对体积影响极大——从 centos(200MB+)到 alpine(5MB)再到 distroless(3MB),差距可达几十倍。
- 优先试 nginx:alpine 作为第二阶段 base,它已预装最小化 nginx 运行时,你只需覆盖 conf 和 html
- 若必须源码编译,用 gcr.io/distroless/cc-debian12(无 shell、无包管理器),仅含运行 nginx 所需的 libc 和 openssl 动态库
- 构建后可用 docker history your-nginx-image 查看每层大小,定位哪步写入了大文件(如未删的 .tar.gz)
- 配合 slim build 工具做二次瘦身(适合已有镜像快速优化):
slim build --http-probe=false your-image-id


















