第 8 篇:容器与 Kubernetes 中的 Nginx 实践——从 Docker 反向代理到 Gateway API 流量入口
专栏:《Nginx 从入口代理到云原生流量治理》
文章序号:第 8 篇
Nginx 实验版本:Nginx Open Source 1.30.3(稳定版)
Nginx 当前主线版本:1.31.2
Kubernetes 实验版本:1.36
Gateway API:使用gateway.networking.k8s.io/v1;版本包与 Controller 兼容性必须同步核验
NGINX Gateway Fabric 实验版本:2.6.6
后端实验版本:Spring Boot 4.1.0、Java 21
实验环境:Docker Compose、kind、kubectl、Helm
更新时间:2026-07-08
本文在专栏中的位置
前七篇已经从单机和虚拟机视角建立了一套完整的 Nginx 入口能力:
- 确定 Nginx 在后端架构中的位置;
- 理解配置模型与请求匹配;
- 完成反向代理、Header、超时、缓冲和流式传输;
- 完成多实例负载均衡、重试和高可用;
- 完成 HTTPS、证书和安全入口;
- 完成静态资源、缓存、压缩和 CDN 协作;
- 完成限流、结构化日志、Trace ID 和故障排查。
第八篇把这些能力放入容器和 Kubernetes 后,重点回答以下问题:
- Nginx 进入容器后,为什么必须前台运行?
- PID 1、信号、优雅退出和只读文件系统之间有什么关系?
- Docker Compose 中为什么可以用服务名访问后端?
- 环境变量为什么不能直接写进任意
nginx.conf? - Kubernetes 中 Nginx 可以以哪些形态存在?
- Service、EndpointSlice、Pod Readiness 如何共同决定流量去向?
- Ingress 与 Ingress Controller 到底谁负责转发?
- 社区
ingress-nginx、F5 NGINX Ingress Controller 和 NGINX Gateway Fabric 有什么区别? ingress-nginx退役后,现有系统和新项目分别应该怎么办?- Gateway API 的
GatewayClass、Gateway、HTTPRoute和ReferenceGrant如何协作? - 配置变更怎样经过 Controller Reconcile 转换为 Nginx 配置?
- 热更新是否真的可以做到完全无损?
- 如何通过权重、Header、Cookie 和域名完成灰度发布?
- TLS Secret 与 cert-manager 如何完成自动签发和续期?
- 如何系统排查 Gateway Accepted 但请求仍然失败的问题?
这也是整个专栏从“会写 Nginx 配置”走向“理解云原生入口控制面与数据面”的收官篇。
学习目标
完成本文后,你应当能够:
- 解释 Nginx 容器为什么需要使用
daemon off;; - 说明 Nginx Master 作为 PID 1 时如何接收 HUP、QUIT、TERM;
- 为容器设计只读配置、可写缓存目录和日志输出;
- 使用固定版本或镜像摘要,而不是生产环境直接使用
latest; - 使用 Docker Compose 网络和服务名 DNS 连接后端;
- 区分
depends_on、healthcheck 和运行期健康治理; - 使用官方镜像模板目录和
envsubst生成简单配置; - 说明环境变量、ConfigMap、Secret 和配置中心的职责边界;
- 区分普通 Nginx Deployment、应用前置代理、Sidecar、Ingress Controller 和 Gateway API 实现;
- 解释 Service、ClusterIP、EndpointSlice 和 Pod Readiness 的关系;
- 解释 Nginx 访问 Service 与直接访问 Pod Endpoint 的差异;
- 区分 Ingress、IngressClass 和 Ingress Controller;
- 区分社区
ingress-nginx、F5 NGINX Ingress Controller 和 NGINX Gateway Fabric; - 说明社区
ingress-nginx退役对现有部署和新项目的影响; - 解释 Ingress API 冻结与 Controller 退役不是同一件事;
- 使用
GatewayClass、Gateway和HTTPRoute暴露 Spring Boot 服务; - 使用
allowedRoutes和ReferenceGrant管理跨 Namespace 权限; - 使用
backendRefs.weight实现权重灰度; - 理解 Header、Cookie、域名和路径灰度的标准能力与实现差异;
- 解释 Controller 的 Watch、Reconcile、配置生成、校验和 Reload 流程;
- 说明 ConfigMap 文件更新不等于 Nginx 已自动 Reload;
- 设计 Readiness、PreStop、终止宽限期和连接排空流程;
- 使用 Gateway Listener 和 TLS Secret 配置 HTTPS;
- 使用 cert-manager 管理 Gateway 证书;
- 通过 Conditions、事件、Controller 日志、数据平面日志、Service 和 EndpointSlice 排查问题;
- 为新项目选择 Ingress、Gateway API、API Gateway 或 Service Mesh。
一、为什么进入容器后,Nginx 的运行方式会变化
传统主机中的 Nginx 通常作为系统服务运行:
systemd→ Nginx Master→ Worker Processes容器中的运行链路变成:
Docker / containerd→ 容器 PID 1→ Nginx Master→ Worker Processes容器运行时判断容器是否存活,主要取决于容器的主进程是否仍然运行。因此 Nginx 不能像传统守护进程那样启动后脱离前台。
独立插图 01:Nginx 容器化运行模型
对应文件:01-nginx-container-runtime-model.png

1.1 前台运行
官方镜像的启动命令等价于:
nginx -g "daemon off;"如果 Nginx 进入后台,而容器入口脚本退出,容器运行时会认为主进程已经结束,并停止容器。
容器内不需要 systemd 再管理一层 Nginx。容器运行时本身负责:
- 启动;
- 重启;
- 资源限制;
- 日志收集;
- 健康状态;
- 停止信号;
- 编排。
1.2 PID 1 与信号
Nginx Master 作为容器 PID 1,需要正确接收停止和重载信号。
常见信号:
| 信号或命令 | 行为 |
|---|---|
nginx -s reload / HUP | 读取新配置、启动新 Worker、优雅关闭旧 Worker |
nginx -s quit / QUIT | 优雅停止 |
nginx -s stop / TERM | 快速停止 |
| USR1 | 重新打开日志文件 |
| USR2 | 可执行文件热升级相关流程 |
容器停止时,不应直接依赖强制 SIGKILL。应预留足够时间:
从负载均衡摘除→ 停止接收新请求→ 处理已有连接→ Nginx 优雅退出→ 超时后才强制终止1.3 日志输出
容器环境通常将:
Access Log → stdoutError Log → stderr交给 Docker 或 Kubernetes 日志系统收集。
不要把日志永久写在容器可写层而不做轮转。容器删除后本地文件会消失,日志也可能占满节点磁盘。
1.4 文件系统与权限
生产容器常采用:
- 只读根文件系统;
- 非 Root 用户;
- 禁止权限提升;
- 删除不必要 Capability;
- 高位监听端口;
- 临时目录使用
emptyDir; - Secret 和 ConfigMap 只读挂载。
需要注意:Nginx 即使配置文件只读,仍可能需要写入:
- PID 文件;
- 客户端请求体临时文件;
- Proxy 临时文件;
- FastCGI 临时文件;
- Cache;
- 日志文件;
- Unix Socket。
如果使用:
readOnlyRootFilesystem: true必须为实际需要写入的路径提供可写 Volume,或者调整配置关闭相关写入。
二、构建适合容器的 Nginx 镜像
2.1 固定镜像版本
开发环境可以临时使用:
image: nginx:1.30.3生产环境最好进一步固定摘要:
image: nginx:1.30.3@sha256:<digest>固定 Tag 可以避免大版本漂移;固定 Digest 可以保证实际镜像内容完全一致。
不要默认使用:
image: nginx:latest原因包括:
- 无法从部署文件判断实际版本;
- 重新拉取时内容可能变化;
- 回滚难以复现;
- 安全审计无法确定基线。
2.2 最小 Dockerfile
FROM nginx:1.30.3
COPY nginx.conf /etc/nginx/nginx.confCOPY conf.d/ /etc/nginx/conf.d/COPY html/ /usr/share/nginx/html/
RUN nginx -t构建阶段执行 nginx -t 可以提前发现基础语法问题,但它不能验证:
- 运行时 DNS;
- Secret 是否存在;
- 后端是否可访问;
- TLS 证书和私钥是否匹配;
- 动态模板渲染结果;
- Kubernetes 资源引用是否有效。
2.3 非 Root 运行
让 Nginx 完全以非 Root 用户运行时,需要:
- 使用 1024 以上端口,例如 8080;
- 确保配置和静态文件可读;
- 确保 PID、Cache 和临时目录可写;
- 删除或调整
user指令; - 确保容器安全上下文一致。
示例:
pid /tmp/nginx.pid;
events {}
http { client_body_temp_path /tmp/client_temp; proxy_temp_path /tmp/proxy_temp;
server { listen 8080; location / { return 200 "nginx container\n"; } }}不要仅添加:
runAsNonRoot: true然后假设镜像自动兼容。权限、端口和目录必须一起调整。
三、Docker Compose 中的 Nginx
独立插图 02:Docker Compose 网络与服务发现
对应文件:02-docker-compose-network-discovery.png

3.1 Compose 网络
同一个 Compose Project 的服务通常加入同一用户定义网络。服务可以通过服务名解析:
upstream backend { server backend:8080;}这里的 backend 不是宿主机 DNS,而是 Compose 网络中的服务名。
容器 IP 可能在重建后变化,所以不要手工写死容器 IP:
server 172.20.0.5:8080;3.2 depends_on 不代表服务已经可用
基础写法:
depends_on: - backend只保证启动顺序,不保证 Spring Boot 已经完成:
- JVM 启动;
- Spring Context 初始化;
- 数据库连接;
- 缓存预热;
- 迁移脚本;
- 健康检查。
使用 healthcheck:
backend: healthcheck: test: - CMD - wget - -qO- - http://localhost:8080/actuator/health/readiness interval: 5s timeout: 2s retries: 20
nginx: depends_on: backend: condition: service_healthy这只能改善初次启动。运行过程中后端异常时,仍需依赖:
- Nginx 超时;
- 被动故障判断;
- 多实例;
- 容器重启策略;
- 应用健康检查;
- 日志与告警。
3.3 完整 Compose 示例
services: nginx: image: nginx:1.30.3 ports: - "8088:8080" volumes: - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro - ./nginx/conf.d:/etc/nginx/conf.d:ro depends_on: backend: condition: service_healthy networks: - nginx-lab
backend: build: context: ./backend expose: - "8080" healthcheck: test: - CMD - wget - -qO- - http://localhost:8080/actuator/health interval: 5s timeout: 2s retries: 20 networks: - nginx-lab
networks: nginx-lab: driver: bridge四、环境变量与配置模板
独立插图 03:官方镜像模板渲染流程
对应文件:03-envsubst-template-rendering.png

4.1 Nginx 配置不会自动展开任意环境变量
下面的写法并不会因为容器中存在 BACKEND_HOST 就自动工作:
proxy_pass http://${BACKEND_HOST}:8080;Nginx 配置语法中的变量和操作系统环境变量不是同一个系统。
4.2 官方镜像模板机制
官方 Docker 镜像入口脚本会执行 /docker-entrypoint.d/ 中的脚本。可以将模板放在:
/etc/nginx/templates/*.template例如:
server { listen 8080;
location / { proxy_pass http://${BACKEND_HOST}:${BACKEND_PORT}; }}容器启动时渲染到:
/etc/nginx/conf.d/Compose:
services: nginx: image: nginx:1.30.3 environment: BACKEND_HOST: backend BACKEND_PORT: "8080" volumes: - ./templates:/etc/nginx/templates:ro4.3 模板适合什么
适合:
- 后端主机名;
- 端口;
- 域名;
- 简单开关;
- 环境差异较小的参数。
不适合:
- 大量嵌套条件;
- 复杂动态 upstream;
- 直接拼接用户输入;
- 保存私钥和 Token;
- 频繁变更的业务规则;
- 需要事务和版本治理的配置。
4.4 敏感配置
不要把 Secret 放在普通 ConfigMap。Kubernetes Secret 也不意味着数据天然不可被读取,它只是提供专门资源类型和访问边界。
生产环境还应考虑:
- RBAC;
- etcd 静态加密;
- Secret Store CSI Driver;
- 外部密钥系统;
- 审计日志;
- Secret 轮换;
- Namespace 隔离。
五、Kubernetes 中的四种 Nginx 形态
独立插图 04:Kubernetes 中 Nginx 的部署形态
对应文件:04-nginx-kubernetes-deployment-modes.png

5.1 普通 Deployment
Nginx 作为普通应用部署:
Service→ Nginx Deployment→ 后端 Service适用于:
- 应用独占入口;
- 自定义静态站点;
- 内部反向代理;
- 特殊协议转换;
- 团队希望完全控制 Nginx 配置。
缺点:
- 每个团队自行维护;
- 配置重复;
- TLS、监控和升级分散;
- 多租户治理困难。
5.2 应用前置代理
Nginx 与应用分别部署,但只服务某个应用:
Nginx Deployment→ Spring Boot Service适用于:
- 静态资源和 API 分离;
- 独立缓存策略;
- 兼容旧系统;
- 应用级代理逻辑。
5.3 Sidecar
Nginx 与应用在同一 Pod:
Pod├── Nginx└── Spring Boot优点:
- 通过 localhost 通信;
- 生命周期一致;
- 可以封装应用专属代理逻辑。
缺点:
- 每个 Pod 都运行 Nginx;
- 资源开销重复;
- 任一容器异常会影响整个 Pod;
- 配置发布与应用发布耦合;
- 不能天然替代集群统一入口。
不要因为“Sidecar 很云原生”就默认使用。除非代理逻辑确实与每个应用实例绑定。
5.4 Ingress Controller 或 Gateway API 实现
Controller 监听 Kubernetes API 资源并管理共享入口。
声明式资源→ Controller→ Nginx 数据平面→ Service→ Pod这时,应用团队通常不直接编辑 Nginx 配置,而是提交:
- Ingress;
- Gateway;
- HTTPRoute;
- 实现相关 Policy 或 CRD。
六、Service、EndpointSlice 与流量发现
独立插图 05:Service、EndpointSlice 与 Pod Readiness
对应文件:05-service-endpointslice-readiness-flow.png

6.1 Pod IP 不稳定
Pod 被重新调度后 IP 可能变化。直接配置 Pod IP:
upstream backend { server 10.244.1.12:8080;}会导致配置很快过期。
Kubernetes 使用 Service 提供稳定入口:
apiVersion: v1kind: Servicemetadata: name: backendspec: selector: app: backend ports: - port: 80 targetPort: 8080集群 DNS:
backend.default.svc.cluster.local6.2 EndpointSlice
Service Selector 持续选择 Pod。控制器将可用后端地址写入 EndpointSlice。
EndpointSlice 包含:
- IP;
- 端口;
- Ready 状态;
- Serving 状态;
- Terminating 状态;
- 拓扑信息。
旧的 Endpoints API 已被弃用方向替代,不应继续围绕单个 Endpoints 对象设计新的控制器。
6.3 Readiness 决定是否接收正常流量
Deployment:
readinessProbe: httpGet: path: /actuator/health/readiness port: 8080 initialDelaySeconds: 5 periodSeconds: 5Pod 未 Ready 时通常不会作为 Service 正常流量后端。
Readiness 不是 Liveness:
- Readiness 失败:临时从流量中摘除;
- Liveness 失败:Kubelet 重启容器;
- Startup Probe:保护慢启动应用,避免过早执行 Liveness。
不要用会被外部依赖轻微抖动触发的探针频繁重启整个应用。
6.4 Nginx 访问 Service 与直接发现 Pod
访问 Service
proxy_pass http://backend.default.svc.cluster.local;优点:
- 配置简单;
- Service 提供稳定地址;
- Endpoint 更新由 Kubernetes 网络数据平面处理。
缺点:
- Nginx 不直接知道每个 Pod 状态和耗时;
- 连接复用可能影响负载分配;
- 部分高级 upstream 能力难以逐 Pod 控制。
Controller 直接读取 EndpointSlice
Ingress Controller 和 Gateway Controller 通常会监听 EndpointSlice,并把 Pod IP 直接写入数据平面配置。
优点:
- 可逐 Pod 建立 upstream;
- 更直接地感知 Ready Endpoint;
- 可以在数据平面实现更精细负载均衡。
代价:
- Controller 需要 RBAC;
- Endpoint 变化会触发 Reconcile;
- 需要处理大规模 Endpoint 更新;
- 配置生成和 Reload 复杂度更高。
七、Ingress、IngressClass 与 Controller
独立插图 06:Ingress 资源与 Controller 关系
对应文件:06-ingress-resource-controller-model.png

7.1 Ingress 只是 API 资源
Ingress 示例:
apiVersion: networking.k8s.io/v1kind: Ingressmetadata: name: backendspec: ingressClassName: example rules: - host: api.example.com http: paths: - path: / pathType: Prefix backend: service: name: backend port: number: 80创建 Ingress 不会凭空出现代理。集群必须安装匹配的 Ingress Controller。
7.2 IngressClass
apiVersion: networking.k8s.io/v1kind: IngressClassmetadata: name: examplespec: controller: example.com/ingress-controllerController 根据:
ingressClassName;- Controller Name;
- 监听范围;
- Namespace 策略;
决定是否接管某个 Ingress。
7.3 Ingress API 已冻结
Ingress API 仍然是 GA,Kubernetes 没有计划直接删除它。但是它已经冻结:
- API 不再增加新能力;
- 新的标准流量治理方向是 Gateway API;
- 复杂能力长期依赖 Controller Annotation 或 CRD;
- 不同 Controller 的 Annotation 很难迁移。
“冻结”不等于“立即不可用”。已有系统不必因为 Ingress 冻结就在一天内全部重写,但新项目应认真评估 Gateway API。
八、必须区分的三个项目
独立插图 07:Nginx Kubernetes 项目边界
对应文件:07-nginx-k8s-project-boundaries.png

8.1 社区 ingress-nginx
项目:
kubernetes/ingress-nginx它由 Kubernetes 社区维护,使用 Nginx 作为数据平面。
截至 2026 年 3 月 24 日,该项目已经退役:
- 仓库和制品仍可供参考;
- 已有部署不会自动停止;
- 不再发布功能更新;
- 不再修复 Bug;
- 不再发布安全更新。
因此:
- 不应在新项目中继续默认安装;
- 现有系统应建立迁移计划;
- 不能因为当前仍然工作就忽略未来安全风险;
- 迁移前必须盘点 Annotation、Snippet、默认行为和定制模板。
8.2 F5 NGINX Ingress Controller
这是 F5 NGINX 维护的独立项目,不等于社区 ingress-nginx。
它具有自己的:
- 发布节奏;
- Helm Chart;
- CRD;
- Annotation;
- NGINX Open Source / NGINX Plus 能力;
- 商业支持。
社区项目退役不代表 F5 NGINX Ingress Controller 同时退役。
8.3 NGINX Gateway Fabric
NGINX Gateway Fabric 是 F5 NGINX 的 Gateway API 实现,以 Nginx 作为数据平面。
它主要监听:
- GatewayClass;
- Gateway;
- HTTPRoute;
- GRPCRoute;
- TLSRoute / TCPRoute 等受支持资源;
- NginxProxy 和其他实现扩展。
不要将它称为“新版 ingress-nginx”。二者 API、控制模型、资源角色和迁移方式不同。
8.4 迁移不是简单改 Kind
Ingress:
kind: Ingress不能机械替换为:
kind: HTTPRoute还需要处理:
- Controller 特定 Annotation;
- Regex Path 行为;
- Rewrite;
- Snippet;
- 默认 Backend;
- TLS Secret;
- 跨 Namespace;
- 外部鉴权;
- Sticky Session;
- Rate Limit;
- Canary;
- 自定义 Header;
- Error Page;
- Source IP;
- 日志格式;
- Timeout 和 Retry。
迁移工具可以生成初始资源,但不能替代行为验证。
九、Gateway API 的核心模型
独立插图 08:Gateway API 角色分离
对应文件:08-gateway-api-role-separation.png
Gateway API 不只是“功能更多的 Ingress”,它重新设计了资源责任。
9.1 GatewayClass
由基础设施提供者或集群管理员管理:
apiVersion: gateway.networking.k8s.io/v1kind: GatewayClassmetadata: name: nginxspec: controllerName: gateway.nginx.org/nginx-gateway-controller它描述:
- 哪个 Controller 接管;
- 一类 Gateway 的实现;
- 可选基础设施参数。
通常应用团队不应随意创建 GatewayClass。
9.2 Gateway
由平台或集群团队管理:
apiVersion: gateway.networking.k8s.io/v1kind: Gatewaymetadata: name: public-gateway namespace: gateway-systemspec: gatewayClassName: nginx listeners: - name: http protocol: HTTP port: 80 hostname: "*.example.com"Gateway 描述:
- 网络入口;
- Listener;
- 端口;
- 协议;
- Hostname;
- TLS;
- 允许哪些 Namespace 和 Route 挂载。
9.3 HTTPRoute
由应用团队管理:
apiVersion: gateway.networking.k8s.io/v1kind: HTTPRoutemetadata: name: backend namespace: appspec: parentRefs: - name: public-gateway namespace: gateway-system hostnames: - api.example.com rules: - matches: - path: type: PathPrefix value: /api backendRefs: - name: backend port: 80HTTPRoute 描述:
- 连接哪个 Gateway;
- Host;
- Path;
- Header;
- Query Parameter;
- Method;
- Filter;
- Backend Service;
- 权重。
独立插图 09:Gateway API 资源链路
对应文件:09-gateway-api-resource-chain.png

9.4 ReferenceGrant
Route 跨 Namespace 引用 Service 时,需要后端 Namespace 显式授权:
apiVersion: gateway.networking.k8s.io/v1beta1kind: ReferenceGrantmetadata: name: allow-app-route namespace: backendspec: from: - group: gateway.networking.k8s.io kind: HTTPRoute namespace: app to: - group: "" kind: Service这可以防止某个 Namespace 未经允许将其他团队的 Service 暴露到公网。
9.5 Conditions 是一等诊断入口
不要只运行:
kubectl apply -f route.yaml然后假设资源生效。
检查:
kubectl describe gateway public-gateway -n gateway-systemkubectl describe httproute backend -n app关注:
Accepted;Programmed;ResolvedRefs;Conflicted;UnsupportedProtocol;InvalidRouteKinds;NoMatchingParent。
十、完整 Gateway API 实验
10.1 实验目录
nginx-column-08/├── backend/│ ├── Dockerfile│ ├── pom.xml│ └── src/main/java/com/example/demo/│ ├── DemoApplication.java│ └── DemoController.java├── docker/│ ├── compose.yaml│ └── nginx/│ └── templates/│ └── default.conf.template├── kind/│ └── cluster.yaml└── kubernetes/ ├── namespace.yaml ├── backend-v1.yaml ├── backend-v2.yaml ├── gateway.yaml ├── route.yaml ├── canary-route.yaml └── tls/ ├── secret.yaml └── gateway-https.yaml10.2 Spring Boot 接口
package com.example.demo;
import org.springframework.beans.factory.annotation.Value;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;
import java.time.Instant;import java.util.Map;
@RestControllerpublic class DemoController {
@Value("${APP_VERSION:unknown}") private String version;
@GetMapping("/api/instance") public Map<String, Object> instance() { return Map.of( "version", version, "time", Instant.now().toString() ); }
@GetMapping("/actuator-ready") public Map<String, String> ready() { return Map.of("status", "UP"); }}10.3 Dockerfile
FROM maven:3.9.11-eclipse-temurin-21 AS buildWORKDIR /workspaceCOPY pom.xml .RUN mvn -q -DskipTests dependency:go-offlineCOPY src ./srcRUN mvn -q -DskipTests package
FROM eclipse-temurin:21-jreWORKDIR /appCOPY --from=build /workspace/target/*.jar /app/app.jar
EXPOSE 8080ENTRYPOINT ["java", "-jar", "/app/app.jar"]10.4 kind 集群
kind: ClusterapiVersion: kind.x-k8s.io/v1alpha4nodes: - role: control-plane - role: worker - role: worker创建:
kind create cluster \ --name nginx-column-08 \ --config kind/cluster.yaml10.5 构建并加载后端镜像
docker build \ -t nginx-column-backend:1.0.0 \ ./backend
kind load docker-image \ nginx-column-backend:1.0.0 \ --name nginx-column-0810.6 安装 NGINX Gateway Fabric
为了保证可重复性,固定版本:
kubectl kustomize \ "https://github.com/nginx/nginx-gateway-fabric/config/crd/gateway-api/standard?ref=v2.6.6" \ | kubectl apply -f -安装:
helm install ngf \ oci://ghcr.io/nginx/charts/nginx-gateway-fabric \ --version 2.6.6 \ --create-namespace \ --namespace nginx-gateway \ --wait检查:
kubectl get gatewayclasskubectl get pods -n nginx-gatewayGatewayClass 应包含:
nginx具体版本和受支持 Gateway API Bundle 必须以对应 Controller 的兼容性矩阵为准,不能独立升级 CRD 而忽略 Controller 支持范围。
10.7 Namespace
apiVersion: v1kind: Namespacemetadata: name: nginx-column10.8 v1 Deployment 与 Service
apiVersion: apps/v1kind: Deploymentmetadata: name: backend-v1 namespace: nginx-columnspec: replicas: 2 selector: matchLabels: app: backend version: v1 template: metadata: labels: app: backend version: v1 spec: terminationGracePeriodSeconds: 30 containers: - name: backend image: nginx-column-backend:1.0.0 imagePullPolicy: IfNotPresent env: - name: APP_VERSION value: v1 ports: - containerPort: 8080 readinessProbe: httpGet: path: /actuator-ready port: 8080 periodSeconds: 5 livenessProbe: httpGet: path: /actuator-ready port: 8080 initialDelaySeconds: 20 periodSeconds: 10 resources: requests: cpu: 100m memory: 128Mi limits: cpu: "1" memory: 512Mi---apiVersion: v1kind: Servicemetadata: name: backend-v1 namespace: nginx-columnspec: selector: app: backend version: v1 ports: - port: 80 targetPort: 808010.9 v2 Deployment 与 Service
apiVersion: apps/v1kind: Deploymentmetadata: name: backend-v2 namespace: nginx-columnspec: replicas: 1 selector: matchLabels: app: backend version: v2 template: metadata: labels: app: backend version: v2 spec: containers: - name: backend image: nginx-column-backend:1.0.0 imagePullPolicy: IfNotPresent env: - name: APP_VERSION value: v2 ports: - containerPort: 8080 readinessProbe: httpGet: path: /actuator-ready port: 8080---apiVersion: v1kind: Servicemetadata: name: backend-v2 namespace: nginx-columnspec: selector: app: backend version: v2 ports: - port: 80 targetPort: 808010.10 Gateway
apiVersion: gateway.networking.k8s.io/v1kind: Gatewaymetadata: name: nginx-column namespace: nginx-columnspec: gatewayClassName: nginx listeners: - name: http protocol: HTTP port: 80 hostname: nginx-column.example.com allowedRoutes: namespaces: from: Same10.11 HTTPRoute
apiVersion: gateway.networking.k8s.io/v1kind: HTTPRoutemetadata: name: backend namespace: nginx-columnspec: parentRefs: - name: nginx-column sectionName: http hostnames: - nginx-column.example.com rules: - matches: - path: type: PathPrefix value: /api backendRefs: - name: backend-v1 port: 80应用:
kubectl apply -f kubernetes/namespace.yamlkubectl apply -f kubernetes/backend-v1.yamlkubectl apply -f kubernetes/backend-v2.yamlkubectl apply -f kubernetes/gateway.yamlkubectl apply -f kubernetes/route.yaml检查:
kubectl get gateway,httproute -n nginx-columnkubectl describe gateway nginx-column -n nginx-columnkubectl describe httproute backend -n nginx-columnkubectl get pods,svc,endpointslices -n nginx-column10.12 本地访问
NGINX Gateway Fabric 会为 Gateway 创建数据平面 Deployment 和 Service。检查:
kubectl get deployment,service \ -n nginx-column默认生成名称通常与 Gateway 相关,例如:
nginx-column-nginx实际名称应以:
kubectl get svc -n nginx-column为准。
端口转发:
kubectl port-forward \ -n nginx-column \ service/nginx-column-nginx \ 8088:80测试:
curl \ -H "Host: nginx-column.example.com" \ http://127.0.0.1:8088/api/instance十一、Controller Reconcile 与配置热更新
独立插图 10:Controller Reconcile 与 Nginx Reload
对应文件:10-controller-reconcile-nginx-reload.png

11.1 声明式变更不是直接修改配置文件
执行:
kubectl apply -f route.yaml后通常经历:
- API Server 保存资源;
- Controller Watch 到资源变化;
- 将相关 Gateway、Route、Service、Secret、EndpointSlice 加入队列;
- Reconcile 读取期望状态;
- 校验引用和实现能力;
- 生成数据平面配置;
- 执行配置检查;
- Reload 或动态更新 Nginx;
- 回写 Conditions;
- 记录事件和指标。
11.2 ConfigMap 更新不等于自动 Reload
普通 Nginx Deployment 使用 ConfigMap Volume:
volumes: - name: config configMap: name: nginx-configConfigMap 文件内容可能在一段时间后更新到 Pod,但 Nginx 不会因为磁盘文件变化自动执行:
nginx -s reload需要额外机制:
- Sidecar 监听文件并 Reload;
- Controller;
- Reloader 触发 Deployment Rollout;
- GitOps 更新 Pod Template Annotation;
- 应用发布新版本 ConfigMap 并滚动替换 Pod。
使用 subPath 挂载单文件时,ConfigMap 后续更新通常不会自动反映到现有挂载,尤其需要注意。
11.3 Nginx Reload
Reload 时:
Master 读取新配置→ 校验成功→ 创建新 Worker→ 新 Worker 接收新连接→ 旧 Worker 停止接收新连接→ 处理完已有请求后退出如果配置无效,旧 Worker 和旧配置继续运行。
11.4 热更新仍可能失败
可能的问题:
- 配置生成错误;
- 引用 Secret 不存在;
- 端口冲突;
- Controller 快速重复 Reload;
- 大量 Route 导致配置生成慢;
- 长 WebSocket/SSE 使旧 Worker 长期存在;
- Worker Shutdown Timeout 不足;
- Pod 同时滚动更新;
- 上游 Endpoint 快速抖动;
- Reload 后缓存和连接池重新建立。
十二、优雅终止与连接排空
12.1 Pod 终止基本流程
Kubernetes 删除 Pod 时:
- Pod 标记为 Terminating;
- Endpoint 状态开始变化;
- 执行
preStop; - 容器运行时向 PID 1 发送停止信号;
- 等待
terminationGracePeriodSeconds; - 到期后强制 SIGKILL。
默认终止宽限期通常是 30 秒。
12.2 PreStop 与宽限期
示例:
spec: terminationGracePeriodSeconds: 60 containers: - name: nginx lifecycle: preStop: exec: command: - /bin/sh - -c - sleep 5 && nginx -s quit需要注意:
- PreStop 使用同一个宽限期预算;
- PreStop 执行 55 秒后只剩 5 秒供 Nginx 退出;
- Hook 卡住仍会在宽限期结束后被强制杀死;
- 不应无依据地增加固定 Sleep;
- 必须根据 Service 摘流延迟、最长请求和连接类型设计。
12.3 长连接
对于:
- WebSocket;
- SSE;
- gRPC Stream;
- 大文件下载;
- 长轮询;
旧连接可能持续很久。必须明确:
- 发布时是否允许中断;
- 客户端是否自动重连;
- 是否携带恢复游标;
- Worker Shutdown Timeout;
- 最大连接生命周期;
- PodDisruptionBudget;
- 滚动更新并发度。
十三、灰度发布
独立插图 11:Gateway API 权重灰度
对应文件:11-gateway-api-weighted-canary.png

13.1 权重拆分
apiVersion: gateway.networking.k8s.io/v1kind: HTTPRoutemetadata: name: backend namespace: nginx-columnspec: parentRefs: - name: nginx-column hostnames: - nginx-column.example.com rules: - matches: - path: type: PathPrefix value: /api backendRefs: - name: backend-v1 port: 80 weight: 90 - name: backend-v2 port: 80 weight: 10权重是相对值:
90 : 10等价于9 : 1它不是保证每连续 10 个请求恰好有 1 个进入 v2。
13.2 Header 灰度
rules: - matches: - headers: - name: X-Canary value: "true" backendRefs: - name: backend-v2 port: 80 - backendRefs: - name: backend-v1 port: 80适用于:
- 测试人员;
- 内部流量;
- 特定客户端;
- 自动化验证。
公网用户可伪造 Header,因此不能把它作为权限控制。
13.3 Cookie 灰度
Gateway API 标准 Header 匹配可以匹配整个 Cookie Header,但对 Cookie 键值进行结构化匹配的能力可能依赖具体实现或扩展。
需要验证:
- Controller 是否支持;
- 匹配语义;
- 正则引擎;
- 多 Cookie 顺序;
- 大小写;
- 安全边界。
13.4 域名和路径灰度
域名:
canary.example.com → v2api.example.com → v1路径:
/api/v2 → v2/api → v1优点是路由可预测,缺点是用户路径或域名发生变化。
13.5 长连接与会话保持
权重是连接或请求选择策略的输入。对于长连接:
- WebSocket 一旦建立会长期固定在某个后端;
- 小流量样本比例可能偏差很大;
- Session Persistence 可能覆盖权重效果;
- 客户端重试可能放大某个版本;
- HPA 扩缩容会改变实际后端集合。
灰度验收必须观察:
- 业务成功率;
- P95/P99;
- 5xx;
- 重试;
- 连接数;
- 版本分布;
- 下游影响。
13.6 回滚
回滚不应依赖人工临时编辑:
backendRefs: - name: backend-v1 port: 80 weight: 100 - name: backend-v2 port: 80 weight: 0应使用:
- GitOps Commit;
- 发布平台;
- 自动指标门禁;
- 审计记录;
- 一键恢复稳定配置。
十四、TLS Secret 与 cert-manager
独立插图 12:Gateway TLS 与证书生命周期
对应文件:12-gateway-tls-cert-manager-lifecycle.png

14.1 TLS Secret
apiVersion: v1kind: Secretmetadata: name: nginx-column-tls namespace: nginx-columntype: kubernetes.io/tlsdata: tls.crt: <base64> tls.key: <base64>Gateway:
apiVersion: gateway.networking.k8s.io/v1kind: Gatewaymetadata: name: nginx-column namespace: nginx-columnspec: gatewayClassName: nginx listeners: - name: https protocol: HTTPS port: 443 hostname: nginx-column.example.com tls: mode: Terminate certificateRefs: - kind: Secret name: nginx-column-tls14.2 Secret Namespace
Listener 的 Secret 通常需要位于 Gateway Namespace。
如果实现支持跨 Namespace 引用,应通过 ReferenceGrant 显式授权,不能假设任意 Namespace Secret 都可读取。
14.3 cert-manager
cert-manager 可以:
- 创建 Certificate;
- 调用 ACME 或内部 CA;
- 写入 TLS Secret;
- 在到期前续期;
- 失败时回写状态和事件。
Gateway API 集成应核对:
- cert-manager 版本;
- Gateway API 版本;
- Controller 是否启用 Gateway API;
- HTTP-01 Route 是否能够挂载;
allowedRoutes;- DNS 是否指向入口;
- Challenge 是否可从公网访问。
14.4 多租户 TLS
Ingress 时代常见模式是应用团队自己创建 Ingress 和 TLS Secret。
Gateway API 将 Gateway 和 Route 角色分开后,多租户 Listener 和证书管理需要重新设计:
- 平台集中管理 Gateway Listener;
- 应用团队只管理 HTTPRoute;
- 使用 ListenerSet 等受支持能力扩展;
- 建立证书申请流程;
- 严格限制跨 Namespace Secret。
不要假设 Ingress 的证书自服务方式可以无修改迁移。
十五、可观测性
独立插图 13:Kubernetes Nginx 可观测性分层
对应文件:13-kubernetes-nginx-observability-layers.png

15.1 Controller
观察:
- Reconcile 次数;
- Reconcile 错误;
- 队列长度;
- 配置生成失败;
- Reload 成功率;
- Gateway 和 Route Conditions;
- Leader Election;
- API Server 错误;
- RBAC 拒绝。
15.2 数据平面
观察:
- 连接数;
- 请求数;
- 4xx/5xx;
- upstream 状态;
- upstream 延迟;
- 活跃 Worker;
- Reload;
- Access Log;
- Error Log;
- TLS 握手;
- 长连接。
NGINX Gateway Fabric 的 Prometheus 指标端点和具体指标取决于安装配置与版本,应通过官方文档核验。
15.3 Kubernetes 资源
kubectl get gatewayclasskubectl get gateway,httproute -Akubectl get pod,svc,endpointslice -Akubectl get events -A --sort-by=.lastTimestampkubectl describe gateway <name>kubectl describe httproute <name>15.4 应用层
即使 Gateway 和 Nginx 都健康,也可能存在:
- 应用 500;
- 数据库慢;
- 线程池满;
- 下游超时;
- 业务错误;
- 错误版本;
- 配置中心异常。
应继续使用前一篇的 Request ID 和 Trace 体系。
十六、配置和运行期故障排查
独立插图 14:Kubernetes 入口故障排查流程
对应文件:14-kubernetes-ingress-troubleshooting-flow.png

16.1 Gateway 没有地址
检查:
kubectl describe gateway nginx-column -n nginx-columnkubectl get gatewayclass nginx -o yamlkubectl logs -n nginx-gateway \ deployment/ngf-nginx-gateway-fabric可能原因:
- GatewayClass 不存在;
- Controller Name 不匹配;
- Controller 未运行;
- RBAC 不足;
- 数据平面 Service 创建失败;
- 云环境 LoadBalancer 无实现;
- NginxProxy 配置无效。
16.2 HTTPRoute 未 Accepted
检查 ParentRefs:
- Gateway Name;
- Namespace;
- Section Name;
- Hostname;
- allowedRoutes;
- Route Kind;
- Listener Protocol。
16.3 ResolvedRefs=False
常见原因:
- Service 不存在;
- Port 不存在;
- 跨 Namespace 缺少 ReferenceGrant;
- Secret 不存在;
- Backend 协议不支持;
- Controller 不支持该 Filter。
16.4 返回 404
先区分:
- 请求 Host 不匹配;
- Path 不匹配;
- Route 未挂载;
- Controller 默认 404;
- 后端应用 404。
检查:
curl -v \ -H "Host: nginx-column.example.com" \ http://127.0.0.1:8088/api/instance16.5 返回 502 / 504
检查:
kubectl get svc,endpointslice -n nginx-columnkubectl get pods -n nginx-column -o widekubectl logs deployment/nginx-column-nginx -n nginx-columnkubectl exec deployment/nginx-column-nginx \ -n nginx-column \ -- nginx -T从数据平面容器测试:
kubectl exec deployment/nginx-column-nginx \ -n nginx-column \ -- curl -v http://backend-v1/api/instance实际镜像可能不包含 curl。生产镜像不应为了排障长期安装大量工具,可以使用临时 Debug Pod:
kubectl run net-debug \ --rm -it \ --image=curlimages/curl \ -- sh16.6 Pod Ready 但请求失败
Readiness 只验证探针,不一定覆盖真实业务链路。
检查:
- 探针是否过于简单;
- Service
targetPort; - 应用监听地址;
- NetworkPolicy;
- mTLS;
- Host Header;
- Context Path;
- 资源耗尽;
- 数据库;
- 下游依赖。
16.7 ConfigMap 已更新但配置未生效
检查:
- Pod 内文件是否变化;
- 是否使用
subPath; - 是否执行 Reload;
- Reload 是否通过
nginx -t; - Controller 是否接管该配置;
- 是否更新了错误 Namespace;
- 是否存在多个 Controller。
16.8 灰度比例不准确
检查:
- 样本量;
- 长连接;
- Session Persistence;
- 客户端重试;
- 是否多个 Gateway 副本;
- Service Endpoint 数量;
- HPA;
- Controller 对权重的具体实现;
- 是否存在缓存。
十七、生产配置演进
17.1 第一阶段:本地 Docker Compose
目标:
- 固定 Nginx 镜像;
- 配置模板;
- healthcheck;
- stdout/stderr;
- 非 Root;
nginx -t;- 自动化请求验证。
17.2 第二阶段:普通 Kubernetes Deployment
目标:
- ConfigMap;
- Secret;
- Readiness;
- Resource Requests/Limits;
- SecurityContext;
- NetworkPolicy;
- Rolling Update;
- PodDisruptionBudget;
- 日志和指标。
17.3 第三阶段:共享入口 Controller
目标:
- 统一 TLS;
- Namespace 权限;
- 路由资源规范;
- Controller 高可用;
- 数据平面副本;
- 发布和回滚;
- 审计;
- 配置规模测试。
17.4 第四阶段:Gateway API
目标:
- 基础设施与应用角色分离;
- 标准 Route;
- Conditions;
- ReferenceGrant;
- 权重灰度;
- TLS;
- 实现 Conformance;
- 从 Annotation 迁移到结构化字段或 Policy。
17.5 第五阶段:平台化
目标:
- GitOps;
- Policy as Code;
- 自动证书;
- 自动灰度;
- 指标门禁;
- 多集群;
- 多区域;
- API Gateway;
- WAF;
- 成本与容量治理。
十八、常见错误与反例
18.1 使用 latest
问题
无法复现、难以审计、重新拉取后内容变化。
修复
固定版本,关键生产环境固定 Digest。
18.2 把 Nginx 容器当虚拟机
问题
在容器里运行 systemd、后台启动 Nginx、日志写本地而无人收集。
修复
一个主进程、前台运行、标准输出、容器编排管理生命周期。
18.3 配置只读但临时目录不可写
现象
上传、缓存或代理请求时报权限错误。
修复
为实际写入目录挂载 emptyDir,或调整路径到 /tmp。
18.4 认为 depends_on 等于运行期健康检查
现象
后端启动后又崩溃,Nginx 仍继续转发。
修复
多实例、超时、健康检查、重启策略和监控一起处理。
18.5 在 Nginx 配置中直接写 ${ENV}
现象
Nginx 报未知变量或把内容当普通字符串。
修复
使用官方模板目录和 envsubst,或在发布系统生成配置。
18.6 手工写 Pod IP
现象
Pod 重建后 502。
修复
使用 Service,或由 Controller 监听 EndpointSlice。
18.7 认为 Ingress 自己会转发
现象
创建 Ingress 后没有入口地址。
修复
安装并选择 Ingress Controller,检查 IngressClass。
18.8 将 ingress-nginx 和 NGINX Ingress Controller 混为一谈
问题
错误判断维护状态、配置能力和迁移方案。
修复
核对仓库、维护方、Controller Name 和 Chart 来源。
18.9 新项目继续安装已退役 ingress-nginx
问题
无法获得未来安全修复。
修复
选择受维护 Controller 或 Gateway API 实现。
18.10 认为 Ingress API 已被删除
问题
对现有系统做不必要的紧急重写。
修复
Ingress API 仍是 GA,只是冻结;按安全和业务风险规划迁移。
18.11 迁移时只转换 YAML
问题
Annotation、Rewrite、Snippet、Canary 等行为不一致。
修复
建立流量回放、配置差异、Header、状态码和性能测试。
18.12 ConfigMap 更新后不 Reload
现象
Pod 中配置文件变化,但请求行为未变化。
修复
引入受控 Reload 或滚动发布机制。
18.13 Reload 前不校验
现象
新配置失败,Controller 反复重试,Route 状态异常。
修复
生成配置后执行语法和语义校验,记录 Conditions。
18.14 所有 Namespace 都能挂载 Gateway
问题
应用可能未经允许把服务暴露到公网。
修复
使用 allowedRoutes、Namespace Selector 和 ReferenceGrant。
18.15 用灰度权重代替业务兼容性验证
问题
即使只放 1% 流量,数据库 Schema、消息格式和缓存 Key 仍可能不兼容。
修复
使用向后兼容变更、双写、契约测试和回滚设计。
十九、架构选择
独立插图 15:Nginx Kubernetes 方案选择矩阵
对应文件:15-nginx-kubernetes-solution-selection.png

| 场景 | 推荐方向 | 核心原因 |
|---|---|---|
| 本地个人项目 | Docker Nginx + Compose | 成本低、配置直观 |
| 少量虚拟机服务 | 云 LB + Nginx | 简单可靠 |
| Kubernetes 单应用专属代理 | 普通 Nginx Deployment | 团队独立控制 |
| 每个 Pod 需要专属代理 | Sidecar | 生命周期与实例绑定 |
| 已有受维护 Ingress Controller | 继续运行并规划演进 | 避免无价值重写 |
社区 ingress-nginx | 尽快制定迁移计划 | 已退役,无后续修复 |
| Kubernetes 新建北南向入口 | Gateway API 实现 | 标准化、角色分离 |
| 鉴权、配额、开发者门户 | API Gateway | 业务网关能力更完整 |
| 东西向服务治理 | Service Mesh / Gateway API Mesh | 服务间流量和身份治理 |
| AI 推理入口 | Gateway API + Inference Extension 等方案 | 模型、容量和请求特征更复杂 |
没有一个方案适用于所有团队。决策还取决于:
- 云厂商;
- Controller 维护状态;
- Conformance;
- 团队能力;
- 迁移成本;
- 商业支持;
- 多租户;
- 安全要求;
- 现有 Annotation;
- 多集群和多区域。
二十、面试与复习问题
20.1 核心问题
1. 为什么容器中的 Nginx 要使用 daemon off;?
容器运行时以主进程存活判断容器状态。Nginx 后台化后入口进程退出,容器会被停止。
2. Docker Compose 服务名为什么可以作为 upstream?
Compose 为同一用户定义网络提供内部 DNS,服务名解析到对应容器地址。
3. depends_on 是否保证后端永久健康?
不保证。它主要控制启动依赖,配合 healthcheck 可以等待初始就绪,但运行期故障仍需编排和代理治理。
4. Nginx 配置能否直接使用任意环境变量?
不能。通常需要 envsubst、模板脚本或配置生成系统。
5. Service 与 EndpointSlice 的关系是什么?
Service 提供稳定入口和选择器,EndpointSlice 保存实际后端地址及就绪状态。
6. Ingress 与 Ingress Controller 的区别是什么?
Ingress 是声明路由的 API;Controller 读取资源、配置数据平面并实际接收流量。
7. Ingress API 冻结是否意味着已经删除?
不是。Ingress 仍是 GA,Kubernetes 没有计划直接删除,但不再扩展新能力。
8. 社区 ingress-nginx 退役意味着什么?
现有部署不会自动停止,但项目不再发布 Bug 修复和安全更新,应规划迁移。
9. NGINX Gateway Fabric 是 ingress-nginx 的新名字吗?
不是。它是 F5 NGINX 维护的 Gateway API 实现,资源模型和控制方式不同。
10. GatewayClass、Gateway 和 HTTPRoute 分别由谁管理?
通常基础设施团队管理 GatewayClass,平台团队管理 Gateway,应用团队管理 Route。
11. ReferenceGrant 解决什么问题?
显式授权跨 Namespace 引用,防止 Route 未经许可引用其他 Namespace 的 Service 或 Secret。
12. ConfigMap 文件更新后 Nginx 会自动 Reload 吗?
不会。文件变化与进程 Reload 是两件事,需要 Controller、Sidecar 或滚动发布机制。
13. Gateway Accepted 是否说明请求一定成功?
不说明。还要检查 Programmed、Route Accepted、ResolvedRefs、Service、EndpointSlice、Pod Ready 和应用状态。
14. 权重 90/10 是否保证每 10 个请求有 1 个进入 v2?
不保证。权重是概率或相对选择依据,长连接、会话和样本量都会影响观察比例。
15. 为什么 Gateway API 比大量 Annotation 更容易治理?
标准字段具有明确 Schema、状态和 Conformance;Annotation 往往是字符串、实现相关且难以迁移。
20.2 场景题
场景一:Route Accepted,但访问 404
检查 Host、Path、Listener、SectionName、生成配置和默认 Route;区分 Controller 404 与应用 404。
场景二:Service 有 ClusterIP,但 EndpointSlice 为空
检查 Selector、Pod Label、Readiness、Namespace 和 Port。
场景三:ConfigMap 更新后行为不变
检查 Volume 是否刷新、是否使用 subPath、是否执行 Reload、是否更新正确 Pod 和 Namespace。
场景四:滚动发布时少量 502
检查 Endpoint 摘流时序、PreStop、终止宽限期、连接复用、最长请求和数据平面更新延迟。
场景五:从 ingress-nginx 迁移后 Rewrite 行为不同
盘点原有 Annotation、Regex 和尾部斜杠语义;使用流量回放和对照测试,不要仅比较 YAML。
20.3 配置排错题
题一
kind: HTTPRoutespec: parentRefs: - name: public-gatewayRoute 在 app Namespace,Gateway 在 gateway-system,为什么没有挂载?
未指定 Gateway Namespace,默认引用当前 Namespace。应增加:
namespace: gateway-system并确保 Gateway allowedRoutes 允许。
题二
backendRefs: - name: payment namespace: payment port: 80为什么 ResolvedRefs=False?
跨 Namespace 引用需要目标 Namespace 中的 ReferenceGrant。
题三
image: nginx:latestimagePullPolicy: Always为什么生产风险高?
每次拉取可能得到不同镜像,无法确定版本和可靠回滚。应固定 Tag 和 Digest。
二十一、本文总结
本篇完成了 Nginx 从传统入口代理到云原生流量基础设施的迁移。
核心结论:
- 容器中的 Nginx 必须以前台主进程运行,并正确处理信号;
- 只读根文件系统需要配合可写临时目录;
- Compose 服务名 DNS 不等于运行期健康治理;
- 环境变量不能自动出现在任意 Nginx 配置中;
- Kubernetes 中 Nginx 可能是应用组件,也可能是共享入口数据平面;
- Service 提供稳定入口,EndpointSlice 维护实际后端;
- Readiness 决定 Pod 是否进入正常流量;
- Ingress 是 API,Controller 才是真正的数据平面管理者;
- Ingress API 仍然存在,但已经冻结;
- 社区
ingress-nginx已于 2026 年 3 月 24 日退役; - F5 NGINX Ingress Controller 和 NGINX Gateway Fabric 是不同项目;
- Gateway API 通过 GatewayClass、Gateway 和 Route 实现角色分离;
- ReferenceGrant 提供跨 Namespace 引用授权;
- Controller 通过 Watch、Reconcile、校验和 Reload 管理 Nginx;
- ConfigMap 更新不代表 Nginx 已加载新配置;
- 热更新仍需考虑长连接、Pod 终止和 Reload 失败;
- 权重灰度必须结合指标、兼容性和快速回滚;
- TLS Secret 和 cert-manager 可以形成自动续期闭环;
- 故障排查必须同时看 Conditions、Controller、数据平面、Service、EndpointSlice 和应用;
- 新项目应优先评估受维护的 Gateway API 实现,而不是继续默认部署已退役 Controller。
至此,专栏 8 篇已经形成完整链路:
架构定位→ 配置模型→ 反向代理→ 负载均衡→ HTTPS 与安全→ 缓存与性能→ 限流与排障→ Docker、Kubernetes 与 Gateway API二十二、文章验收清单
内容完整性
- 覆盖 Nginx 容器前台运行和 PID 1;
- 覆盖信号与优雅退出;
- 覆盖非 Root 和只读文件系统;
- 覆盖 Docker Compose 网络和健康检查;
- 覆盖 envsubst 模板;
- 覆盖 Kubernetes 中多种 Nginx 形态;
- 覆盖 Service 和 EndpointSlice;
- 覆盖 Readiness;
- 覆盖 Ingress 与 Controller;
- 覆盖项目命名和维护状态;
- 覆盖 Gateway API;
- 覆盖 ReferenceGrant;
- 覆盖 Reconcile 和 Reload;
- 覆盖优雅终止;
- 覆盖权重和 Header 灰度;
- 覆盖 TLS Secret 和 cert-manager;
- 覆盖可观测性和排障;
- 提供 kind + NGF + Spring Boot 完整实验;
- 提供常见错误、面试题和选择矩阵。
技术边界
- 区分 Ingress API 与 Controller;
- 区分
ingress-nginx、F5 NGINX Ingress Controller 和 NGINX Gateway Fabric; - 标明社区
ingress-nginx已退役; - 没有把 Annotation 能力写成 Gateway API 标准能力;
- 强调具体 Controller Conformance;
- 强调 Gateway API CRD 与 Controller 版本兼容;
- 说明 Secret 与 ConfigMap 安全边界;
- 说明多租户和跨 Namespace 授权;
- 说明热更新不等于绝对无损。
实验可执行性
- 提供目录结构;
- 提供 Spring Boot 代码;
- 提供 Dockerfile;
- 提供 kind 配置;
- 提供固定版本 NGF 安装命令;
- 提供 Deployment 和 Service;
- 提供 Gateway 和 HTTPRoute;
- 提供权重灰度;
- 提供验证和排障命令;
- 提供资源清理思路。
参考资料
-
Nginx Download
https://nginx.org/en/download.html -
Controlling Nginx
https://nginx.org/en/docs/control.html -
Docker Official Image: Nginx
https://hub.docker.com/_/nginx -
Docker Compose Startup Order
https://docs.docker.com/compose/how-tos/startup-order/ -
Kubernetes Service
https://kubernetes.io/docs/concepts/services-networking/service/ -
Kubernetes EndpointSlice
https://kubernetes.io/docs/concepts/services-networking/endpoint-slices/ -
Kubernetes Probes
https://kubernetes.io/docs/concepts/workloads/pods/probes/ -
Kubernetes Pod Lifecycle
https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/ -
Kubernetes Ingress
https://kubernetes.io/docs/concepts/services-networking/ingress/ -
Ingress NGINX Retirement
https://kubernetes.io/blog/2025/11/11/ingress-nginx-retirement/ -
Ingress NGINX Retirement Status
https://kubernetes.io/blog/2026/03/30/kubernetes-v1-36-sneak-peek/ -
Before You Migrate from Ingress NGINX
https://kubernetes.io/blog/2026/02/27/ingress-nginx-before-you-migrate/ -
Kubernetes Gateway API
https://kubernetes.io/docs/concepts/services-networking/gateway/ -
Gateway API Documentation
https://gateway-api.sigs.k8s.io/ -
Gateway API HTTP Routing
https://gateway-api.sigs.k8s.io/guides/user-guides/http-routing/ -
Gateway API Traffic Splitting
https://gateway-api.sigs.k8s.io/guides/user-guides/traffic-splitting/ -
Migrating from Ingress
https://gateway-api.sigs.k8s.io/guides/getting-started/migrating-from-ingress/ -
NGINX Gateway Fabric
https://docs.nginx.com/nginx-gateway-fabric/ -
NGINX Gateway Fabric Installation
https://docs.nginx.com/nginx-gateway-fabric/install/helm/ -
NGINX Gateway Fabric Basic Routing
https://docs.nginx.com/nginx-gateway-fabric/traffic-management/basic-routing/ -
cert-manager Gateway
https://cert-manager.io/docs/usage/gateway/ -
cert-manager ACME HTTP-01 Gateway API
https://cert-manager.io/docs/configuration/acme/http01/
资料访问日期:2026-07-08。