当前位置: 首页 > news >正文

Docker 多阶段构建深度实战:Nginx Ingress Controller 的三阶段源码构建

1. 引言

在云原生生态中,Nginx Ingress Controller 是 Kubernetes 集群流量入口的核心组件。它通常由两部分组成:Nginx 核心(负责流量转发)和Go 语言编写的 Controller(负责监听 Kubernetes API 并动态更新 Nginx 配置)。

为了构建一个生产可用的 Nginx Ingress Controller 镜像,我们需要经历三个关键阶段:

  1. GCC 构建阶段:从 Nginx 源码编译出 Nginx 二进制文件。
  2. Golang 构建阶段:编译 Go 语言编写的 Controller 二进制文件。
  3. Runtime 运行阶段:将前两个阶段产出的二进制文件合并到一个极简的运行镜像中。

本文将结合具体的 Dockerfile,深入讲解如何通过 Docker 多阶段构建实现这三个阶段的隔离与协作,最终得到一个体积小、安全性高的生产级镜像。

2. 为什么需要三阶段构建?

2.1 传统单阶段构建的困境

如果在一个 Dockerfile 中同时安装 GCC、Go 工具链、Nginx 源码和所有依赖,最终镜像将包含:

  • GCC、Make、Perl 等编译工具(数百 MB)
  • Go 编译器及标准库(数百 MB)
  • Nginx 源码及编译中间产物
  • 运行时不需要的调试工具和文档

这样的镜像体积通常在1.5GB 以上,且包含了大量不必要的攻击面。

2.2 多阶段构建的核心思想

Docker 多阶段构建允许我们在一个 Dockerfile 中使用多个FROM指令,每个阶段可以基于不同的基础镜像。我们可以:

  • 阶段 1(GCC Build):使用包含 GCC、Make 等编译工具的镜像,从 Nginx 源码编译出 Nginx 二进制。
  • 阶段 2(Golang Build):使用 Go 官方镜像,编译 Controller 二进制。
  • 阶段 3(Runtime):使用极简的 Alpine 或 Distroless 镜像,只从前面两个阶段复制编译好的二进制文件和必要的运行时依赖。

这样,最终镜像只包含运行所需的最小文件集,体积可缩小到50MB 以下

3. 三阶段 Dockerfile 实战

下面是一个完整的 Dockerfile 示例,展示了如何构建一个 Nginx Ingress Controller 镜像。

3.1 第一阶段:GCC 构建 Nginx

# ========== 第一阶段:GCC 构建 Nginx ========== # 使用包含完整编译工具链的镜像 FROM ubuntu:22.04 AS nginx-builder # 安装编译 Nginx 所需的工具和库 RUN apt-get update && apt-get install -y \ gcc \ make \ libpcre3-dev \ libssl-dev \ zlib1g-dev \ wget \ && rm -rf /var/lib/apt/lists/* # 下载并解压 Nginx 源码 WORKDIR /tmp RUN wget https://nginx.org/download/nginx-1.25.3.tar.gz && \ tar -xzf nginx-1.25.3.tar.gz # 编译 Nginx(配置常用模块,生成静态链接的二进制) WORKDIR /tmp/nginx-1.25.3 RUN ./configure \ --prefix=/usr/local/nginx \ --with-http_ssl_module \ --with-http_v2_module \ --with-http_realip_module \ --with-http_stub_status_module \ --with-stream \ --with-stream_ssl_module \ --without-http_autoindex_module \ --without-http_ssi_module \ && make -j$(nproc) \ && make install # 将编译好的 Nginx 二进制和配置文件复制到一个临时目录,方便后续阶段复制 RUN mkdir -p /nginx-output/usr/local/nginx && \ cp -r /usr/local/nginx/sbin /nginx-output/usr/local/nginx/ && \ cp -r /usr/local/nginx/conf /nginx-output/usr/local/nginx/ && \ cp -r /usr/local/nginx/html /nginx-output/usr/local/nginx/ && \ cp -r /usr/local/nginx/logs /nginx-output/usr/local/nginx/

关键点

  • 使用ubuntu:22.04作为基础镜像,它包含了 GCC、Make 等编译工具。
  • 通过apt-get install安装 Nginx 编译所需的依赖库(PCRE、OpenSSL、Zlib)。
  • 从源码编译 Nginx,并只保留编译产物(二进制、配置文件、静态文件)。
  • --without-http_autoindex_module等选项用于禁用不需要的模块,进一步精简。

3.2 第二阶段:Golang 构建 Controller

# ========== 第二阶段:Golang 构建 Controller ========== FROM golang:1.21 AS go-builder # 设置工作目录 WORKDIR /workspace # 复制 go.mod 和 go.sum,利用 Docker 缓存层 COPY go.mod go.sum ./ RUN go mod download # 复制所有源码 COPY . . # 编译 Go 项目,生成静态链接的二进制文件 # CGO_ENABLED=0 确保生成静态二进制,不依赖 libc RUN CGO_ENABLED=0 GOOS=linux go build \ -a -installsuffix cgo \ -ldflags="-s -w" \ -o nginx-ingress-controller \ ./cmd/nginx-ingress-controller # 将编译好的二进制文件复制到临时目录 RUN mkdir -p /go-output && \ cp /workspace/nginx-ingress-controller /go-output/

关键点

  • 使用golang:1.21作为 Go 编译环境。
  • CGO_ENABLED=0生成静态链接的 Go 二进制,不依赖任何动态库。
  • -ldflags="-s -w"用于去除调试信息,进一步减小二进制体积。
  • 只复制编译好的二进制文件到临时目录,Go 工具链和源码都被丢弃。

3.3 第三阶段:Runtime 运行环境

# ========== 第三阶段:Runtime 运行环境 ========== # 使用极简的 Alpine 镜像作为运行环境 FROM alpine:3.19 # 安装运行时依赖 # - ca-certificates:用于 HTTPS 证书验证 # - tzdata:时区数据 # - libcrypto3、libssl3:Nginx 运行时需要的 SSL 库 RUN apk add --no-cache \ ca-certificates \ tzdata \ libcrypto3 \ libssl3 \ pcre # 从第一阶段(GCC 构建)复制 Nginx 二进制和配置文件 COPY --from=nginx-builder /nginx-output/usr/local/nginx /usr/local/nginx # 从第二阶段(Golang 构建)复制 Controller 二进制 COPY --from=go-builder /go-output/nginx-ingress-controller /usr/local/bin/ # 创建必要的目录和用户 RUN addgroup -S nginx && \ adduser -S -G nginx nginx && \ mkdir -p /var/log/nginx && \ mkdir -p /var/cache/nginx && \ chown -R nginx:nginx /var/log/nginx /var/cache/nginx /usr/local/nginx # 暴露端口 EXPOSE 80 443 # 设置容器启动命令(实际启动由 Controller 管理 Nginx) CMD ["nginx-ingress-controller"]

关键点

  • 使用alpine:3.19作为运行基础镜像,体积仅约 5MB。
  • 只安装 Nginx 运行时需要的动态库(libcrypto3libssl3pcre),不安装任何编译工具。
  • 通过COPY --from=nginx-builderCOPY --from=go-builder分别从两个构建阶段复制产物。
  • 创建非 root 用户nginx,提升容器安全性。

4. 三阶段构建的优势分析

4.1 构建环境与运行环境完全隔离

方面传统单阶段构建三阶段多阶段构建
基础镜像ubuntu:22.04+golang:1.21(约 1.5GB)alpine:3.19(约 5MB)
包含工具GCC、Make、Go 编译器、Perl、调试工具等仅运行时动态库
最终镜像体积1.2GB - 1.8GB30MB - 60MB
攻击面大量不必要的工具和库最小化依赖,攻击面大幅减少

4.2 镜像体积对比

通过三阶段构建,最终镜像体积从1.5GB 降至约 50MB,提升了约30 倍。这意味着:

  • 更快的拉取和推送:在 CI/CD 流程中,镜像传输时间大幅缩短。
  • 更快的容器启动:镜像解压和加载时间减少。
  • 更低的存储成本:镜像仓库和节点本地存储占用减少。

4.3 安全性提升

  • 最小化攻击面:运行镜像中不包含 GCC、Make、Go 编译器、Perl 等工具,攻击者无法利用这些工具进行提权或横向移动。
  • 静态链接的 Go 二进制CGO_ENABLED=0生成的 Go 二进制不依赖libc,避免了libc漏洞(如 Shellshock、Ghost)的影响。
  • 非 root 用户运行:创建专用用户运行 Nginx 和 Controller,遵循最小权限原则。

4.4 构建缓存优化

# 利用 Docker 缓存层,避免重复下载依赖 COPY go.mod go.sum ./ RUN go mod download COPY . .

go.modgo.sum的复制放在源码复制之前,只要依赖文件没有变化,Docker 就会复用go mod download的缓存层,大幅加速构建过程。

5. 完整 Dockerfile 汇总

为了方便你直接使用,下面是完整的 Dockerfile 内容:

# ========== 第一阶段:GCC 构建 Nginx ========== FROM ubuntu:22.04 AS nginx-builder RUN apt-get update && apt-get install -y \ gcc make libpcre3-dev libssl-dev zlib1g-dev wget \ && rm -rf /var/lib/apt/lists/* WORKDIR /tmp RUN wget https://nginx.org/download/nginx-1.25.3.tar.gz && \ tar -xzf nginx-1.25.3.tar.gz WORKDIR /tmp/nginx-1.25.3 RUN ./configure \ --prefix=/usr/local/nginx \ --with-http_ssl_module \ --with-http_v2_module \ --with-http_realip_module \ --with-http_stub_status_module \ --with-stream \ --with-stream_ssl_module \ --without-http_autoindex_module \ --without-http_ssi_module \ && make -j$(nproc) && make install RUN mkdir -p /nginx-output/usr/local/nginx && \ cp -r /usr/local/nginx/sbin /nginx-output/usr/local/nginx/ && \ cp -r /usr/local/nginx/conf /nginx-output/usr/local/nginx/ && \ cp -r /usr/local/nginx/html /nginx-output/usr/local/nginx/ && \ cp -r /usr/local/nginx/logs /nginx-output/usr/local/nginx/ # ========== 第二阶段:Golang 构建 Controller ========== FROM golang:1.21 AS go-builder WORKDIR /workspace COPY go.mod go.sum ./ RUN go mod download COPY . . RUN CGO_ENABLED=0 GOOS=linux go build \ -a -installsuffix cgo \ -ldflags="-s -w" \ -o nginx-ingress-controller \ ./cmd/nginx-ingress-controller RUN mkdir -p /go-output && \ cp /workspace/nginx-ingress-controller /go-output/ # ========== 第三阶段:Runtime 运行环境 ========== FROM alpine:3.19 RUN apk add --no-cache \ ca-certificates tzdata libcrypto3 libssl3 pcre COPY --from=nginx-builder /nginx-output/usr/local/nginx /usr/local/nginx COPY --from=go-builder /go-output/nginx-ingress-controller /usr/local/bin/ RUN addgroup -S nginx && \ adduser -S -G nginx nginx && \ mkdir -p /var/log/nginx /var/cache/nginx && \ chown -R nginx:nginx /var/log/nginx /var/cache/nginx /usr/local/nginx EXPOSE 80 443 CMD ["nginx-ingress-controller"]

6. 总结

通过本文的实战,我们深入了解了 Docker 多阶段构建在 Nginx Ingress Controller 场景下的强大能力:

  1. GCC 构建阶段:从 Nginx 源码编译出 Nginx 二进制,使用完整的编译工具链。
  2. Golang 构建阶段:编译 Go 语言编写的 Controller,生成静态链接的二进制。
  3. Runtime 运行阶段:将前两个阶段的产物合并到极简的 Alpine 镜像中,只保留运行时依赖。

这种三阶段构建模式实现了构建环境与运行环境的完全隔离,最终镜像体积从 1.5GB 降至约 50MB,同时大幅提升了安全性。这是生产级容器化应用的最佳实践,值得在项目中推广使用。

http://www.jsqmd.com/news/1176603/

相关文章:

  • 为什么用 AI 去改 AI 写的内容,AIGC 率反而更高?
  • 2026年高温合金厂家推荐:选购指南与报价参考 - 优企名品
  • Transformer vs AGW:ReID-Survey两大技术路线的终极对比指南
  • 2026年7月最新天津欧米茄官方售后服务网点地址及客服电话一览 - 欧米茄服务中心
  • 2026年7月最新海口江诗丹顿官方售后客户服务热线与维修网点地址汇总 - 江诗丹顿官方服务中心
  • iOS架构进阶:为什么说iOS-Viper-Architecture是大型项目的最佳选择?
  • Django API Domains完整教程:5步实现领域分离与API优化
  • 如何通过System Design Interview面试:7个核心方法论与4S分析法详解
  • 使用next数组加速匹配过程
  • Orchestra核心架构深度解析:任务、智能体与工具的完美融合
  • 10个Try Puppeteer实用技巧:提升你的云端网页自动化效率
  • 2026年华东区域充电转接头相关企业名录梳理 - 起跑123
  • TDD-Katas项目解析:从Bowling Game到String Calculator的核心实现原理
  • 2026北京名表回收哪家回款快?毓典当场验货即刻到账 - 奢品流通笔谈
  • 如何快速上手Web Audio Samples:10个必学音频处理示例解析
  • 告别冗长代码:EasyDB实现PHP数据库CRUD操作的极简方案
  • 如何使用Spatie URL包进行URL路径分段处理与操作
  • 2026年7月最新大连江诗丹顿官方售后热线及客户服务网点地址 - 江诗丹顿服务中心
  • 第一章 Linux基础
  • Try Puppeteer核心功能揭秘:从网页截图到数据爬取的完整教程
  • OpenWhispr核心功能解析:本地Nvidia Parakeet与Whisper模型如何保护你的语音数据
  • Godot平台游戏状态机实战教程:构建流畅的角色动画和动作系统
  • 寒假第一周周日7.12总结
  • 5个步骤快速上手telegram-purple:Libpurple的Telegram插件安装教程
  • 15个实战项目突破性指南:从零打造惊艳作品集的系统性方案
  • 为什么选择CountryPicker?iOS国家选择控件的性能与兼容性分析
  • 2023最新版Saleor Platform配置教程:环境变量与数据库设置全攻略
  • 《凌微经》简介目录与思想总纲
  • 2026年7月最新苏州爱彼官方售后联系电话与客户服务中心网点地址 - 爱彼中国官方服务中心
  • Proteus性能优化:如何提高大型Go代码库的.proto文件生成速度