9804 字
49 分钟
第 8 篇:容器与 Kubernetes 中的 Nginx 实践

第 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 入口能力:

  1. 确定 Nginx 在后端架构中的位置;
  2. 理解配置模型与请求匹配;
  3. 完成反向代理、Header、超时、缓冲和流式传输;
  4. 完成多实例负载均衡、重试和高可用;
  5. 完成 HTTPS、证书和安全入口;
  6. 完成静态资源、缓存、压缩和 CDN 协作;
  7. 完成限流、结构化日志、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 的 GatewayClassGatewayHTTPRouteReferenceGrant 如何协作?
  • 配置变更怎样经过 Controller Reconcile 转换为 Nginx 配置?
  • 热更新是否真的可以做到完全无损?
  • 如何通过权重、Header、Cookie 和域名完成灰度发布?
  • TLS Secret 与 cert-manager 如何完成自动签发和续期?
  • 如何系统排查 Gateway Accepted 但请求仍然失败的问题?

这也是整个专栏从“会写 Nginx 配置”走向“理解云原生入口控制面与数据面”的收官篇。


学习目标#

完成本文后,你应当能够:

  1. 解释 Nginx 容器为什么需要使用 daemon off;
  2. 说明 Nginx Master 作为 PID 1 时如何接收 HUP、QUIT、TERM;
  3. 为容器设计只读配置、可写缓存目录和日志输出;
  4. 使用固定版本或镜像摘要,而不是生产环境直接使用 latest
  5. 使用 Docker Compose 网络和服务名 DNS 连接后端;
  6. 区分 depends_on、healthcheck 和运行期健康治理;
  7. 使用官方镜像模板目录和 envsubst 生成简单配置;
  8. 说明环境变量、ConfigMap、Secret 和配置中心的职责边界;
  9. 区分普通 Nginx Deployment、应用前置代理、Sidecar、Ingress Controller 和 Gateway API 实现;
  10. 解释 Service、ClusterIP、EndpointSlice 和 Pod Readiness 的关系;
  11. 解释 Nginx 访问 Service 与直接访问 Pod Endpoint 的差异;
  12. 区分 Ingress、IngressClass 和 Ingress Controller;
  13. 区分社区 ingress-nginx、F5 NGINX Ingress Controller 和 NGINX Gateway Fabric;
  14. 说明社区 ingress-nginx 退役对现有部署和新项目的影响;
  15. 解释 Ingress API 冻结与 Controller 退役不是同一件事;
  16. 使用 GatewayClassGatewayHTTPRoute 暴露 Spring Boot 服务;
  17. 使用 allowedRoutesReferenceGrant 管理跨 Namespace 权限;
  18. 使用 backendRefs.weight 实现权重灰度;
  19. 理解 Header、Cookie、域名和路径灰度的标准能力与实现差异;
  20. 解释 Controller 的 Watch、Reconcile、配置生成、校验和 Reload 流程;
  21. 说明 ConfigMap 文件更新不等于 Nginx 已自动 Reload;
  22. 设计 Readiness、PreStop、终止宽限期和连接排空流程;
  23. 使用 Gateway Listener 和 TLS Secret 配置 HTTPS;
  24. 使用 cert-manager 管理 Gateway 证书;
  25. 通过 Conditions、事件、Controller 日志、数据平面日志、Service 和 EndpointSlice 排查问题;
  26. 为新项目选择 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

01 nginx container runtime model

1.1 前台运行#

官方镜像的启动命令等价于:

Terminal window
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 → stdout
Error 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.conf
COPY 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 用户运行时,需要:

  1. 使用 1024 以上端口,例如 8080;
  2. 确保配置和静态文件可读;
  3. 确保 PID、Cache 和临时目录可写;
  4. 删除或调整 user 指令;
  5. 确保容器安全上下文一致。

示例:

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

02 docker compose network discovery

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

03 envsubst template rendering

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:ro

4.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

04 nginx kubernetes deployment modes

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

05 service endpointslice readiness flow

6.1 Pod IP 不稳定#

Pod 被重新调度后 IP 可能变化。直接配置 Pod IP:

upstream backend {
server 10.244.1.12:8080;
}

会导致配置很快过期。

Kubernetes 使用 Service 提供稳定入口:

apiVersion: v1
kind: Service
metadata:
name: backend
spec:
selector:
app: backend
ports:
- port: 80
targetPort: 8080

集群 DNS:

backend.default.svc.cluster.local

6.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: 5

Pod 未 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

06 ingress resource controller model

7.1 Ingress 只是 API 资源#

Ingress 示例:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: backend
spec:
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/v1
kind: IngressClass
metadata:
name: example
spec:
controller: example.com/ingress-controller

Controller 根据:

  • 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

07 nginx k8s project boundaries

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

08 gateway api role separation Gateway API 不只是“功能更多的 Ingress”,它重新设计了资源责任。

9.1 GatewayClass#

由基础设施提供者或集群管理员管理:

apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: nginx
spec:
controllerName: gateway.nginx.org/nginx-gateway-controller

它描述:

  • 哪个 Controller 接管;
  • 一类 Gateway 的实现;
  • 可选基础设施参数。

通常应用团队不应随意创建 GatewayClass。

9.2 Gateway#

由平台或集群团队管理:

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: public-gateway
namespace: gateway-system
spec:
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/v1
kind: HTTPRoute
metadata:
name: backend
namespace: app
spec:
parentRefs:
- name: public-gateway
namespace: gateway-system
hostnames:
- api.example.com
rules:
- matches:
- path:
type: PathPrefix
value: /api
backendRefs:
- name: backend
port: 80

HTTPRoute 描述:

  • 连接哪个 Gateway;
  • Host;
  • Path;
  • Header;
  • Query Parameter;
  • Method;
  • Filter;
  • Backend Service;
  • 权重。

独立插图 09:Gateway API 资源链路
对应文件:09-gateway-api-resource-chain.png

09 gateway api resource chain

9.4 ReferenceGrant#

Route 跨 Namespace 引用 Service 时,需要后端 Namespace 显式授权:

apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
name: allow-app-route
namespace: backend
spec:
from:
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: app
to:
- group: ""
kind: Service

这可以防止某个 Namespace 未经允许将其他团队的 Service 暴露到公网。

9.5 Conditions 是一等诊断入口#

不要只运行:

Terminal window
kubectl apply -f route.yaml

然后假设资源生效。

检查:

Terminal window
kubectl describe gateway public-gateway -n gateway-system
kubectl 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.yaml

10.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;
@RestController
public 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 build
WORKDIR /workspace
COPY pom.xml .
RUN mvn -q -DskipTests dependency:go-offline
COPY src ./src
RUN mvn -q -DskipTests package
FROM eclipse-temurin:21-jre
WORKDIR /app
COPY --from=build /workspace/target/*.jar /app/app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app/app.jar"]

10.4 kind 集群#

kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: worker

创建:

Terminal window
kind create cluster \
--name nginx-column-08 \
--config kind/cluster.yaml

10.5 构建并加载后端镜像#

Terminal window
docker build \
-t nginx-column-backend:1.0.0 \
./backend
kind load docker-image \
nginx-column-backend:1.0.0 \
--name nginx-column-08

10.6 安装 NGINX Gateway Fabric#

为了保证可重复性,固定版本:

Terminal window
kubectl kustomize \
"https://github.com/nginx/nginx-gateway-fabric/config/crd/gateway-api/standard?ref=v2.6.6" \
| kubectl apply -f -

安装:

Terminal window
helm install ngf \
oci://ghcr.io/nginx/charts/nginx-gateway-fabric \
--version 2.6.6 \
--create-namespace \
--namespace nginx-gateway \
--wait

检查:

Terminal window
kubectl get gatewayclass
kubectl get pods -n nginx-gateway

GatewayClass 应包含:

nginx

具体版本和受支持 Gateway API Bundle 必须以对应 Controller 的兼容性矩阵为准,不能独立升级 CRD 而忽略 Controller 支持范围。

10.7 Namespace#

apiVersion: v1
kind: Namespace
metadata:
name: nginx-column

10.8 v1 Deployment 与 Service#

apiVersion: apps/v1
kind: Deployment
metadata:
name: backend-v1
namespace: nginx-column
spec:
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: v1
kind: Service
metadata:
name: backend-v1
namespace: nginx-column
spec:
selector:
app: backend
version: v1
ports:
- port: 80
targetPort: 8080

10.9 v2 Deployment 与 Service#

apiVersion: apps/v1
kind: Deployment
metadata:
name: backend-v2
namespace: nginx-column
spec:
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: v1
kind: Service
metadata:
name: backend-v2
namespace: nginx-column
spec:
selector:
app: backend
version: v2
ports:
- port: 80
targetPort: 8080

10.10 Gateway#

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: nginx-column
namespace: nginx-column
spec:
gatewayClassName: nginx
listeners:
- name: http
protocol: HTTP
port: 80
hostname: nginx-column.example.com
allowedRoutes:
namespaces:
from: Same

10.11 HTTPRoute#

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: backend
namespace: nginx-column
spec:
parentRefs:
- name: nginx-column
sectionName: http
hostnames:
- nginx-column.example.com
rules:
- matches:
- path:
type: PathPrefix
value: /api
backendRefs:
- name: backend-v1
port: 80

应用:

Terminal window
kubectl apply -f kubernetes/namespace.yaml
kubectl apply -f kubernetes/backend-v1.yaml
kubectl apply -f kubernetes/backend-v2.yaml
kubectl apply -f kubernetes/gateway.yaml
kubectl apply -f kubernetes/route.yaml

检查:

Terminal window
kubectl get gateway,httproute -n nginx-column
kubectl describe gateway nginx-column -n nginx-column
kubectl describe httproute backend -n nginx-column
kubectl get pods,svc,endpointslices -n nginx-column

10.12 本地访问#

NGINX Gateway Fabric 会为 Gateway 创建数据平面 Deployment 和 Service。检查:

Terminal window
kubectl get deployment,service \
-n nginx-column

默认生成名称通常与 Gateway 相关,例如:

nginx-column-nginx

实际名称应以:

Terminal window
kubectl get svc -n nginx-column

为准。

端口转发:

Terminal window
kubectl port-forward \
-n nginx-column \
service/nginx-column-nginx \
8088:80

测试:

Terminal window
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

10 controller reconcile nginx reload

11.1 声明式变更不是直接修改配置文件#

执行:

Terminal window
kubectl apply -f route.yaml

后通常经历:

  1. API Server 保存资源;
  2. Controller Watch 到资源变化;
  3. 将相关 Gateway、Route、Service、Secret、EndpointSlice 加入队列;
  4. Reconcile 读取期望状态;
  5. 校验引用和实现能力;
  6. 生成数据平面配置;
  7. 执行配置检查;
  8. Reload 或动态更新 Nginx;
  9. 回写 Conditions;
  10. 记录事件和指标。

11.2 ConfigMap 更新不等于自动 Reload#

普通 Nginx Deployment 使用 ConfigMap Volume:

volumes:
- name: config
configMap:
name: nginx-config

ConfigMap 文件内容可能在一段时间后更新到 Pod,但 Nginx 不会因为磁盘文件变化自动执行:

Terminal window
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 时:

  1. Pod 标记为 Terminating;
  2. Endpoint 状态开始变化;
  3. 执行 preStop
  4. 容器运行时向 PID 1 发送停止信号;
  5. 等待 terminationGracePeriodSeconds
  6. 到期后强制 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

11 gateway api weighted canary

13.1 权重拆分#

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: backend
namespace: nginx-column
spec:
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,因此不能把它作为权限控制。

Gateway API 标准 Header 匹配可以匹配整个 Cookie Header,但对 Cookie 键值进行结构化匹配的能力可能依赖具体实现或扩展。

需要验证:

  • Controller 是否支持;
  • 匹配语义;
  • 正则引擎;
  • 多 Cookie 顺序;
  • 大小写;
  • 安全边界。

13.4 域名和路径灰度#

域名:

canary.example.com → v2
api.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

12 gateway tls cert manager lifecycle

14.1 TLS Secret#

apiVersion: v1
kind: Secret
metadata:
name: nginx-column-tls
namespace: nginx-column
type: kubernetes.io/tls
data:
tls.crt: <base64>
tls.key: <base64>

Gateway:

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: nginx-column
namespace: nginx-column
spec:
gatewayClassName: nginx
listeners:
- name: https
protocol: HTTPS
port: 443
hostname: nginx-column.example.com
tls:
mode: Terminate
certificateRefs:
- kind: Secret
name: nginx-column-tls

14.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

13 kubernetes nginx observability layers

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 资源#

Terminal window
kubectl get gatewayclass
kubectl get gateway,httproute -A
kubectl get pod,svc,endpointslice -A
kubectl get events -A --sort-by=.lastTimestamp
kubectl describe gateway <name>
kubectl describe httproute <name>

15.4 应用层#

即使 Gateway 和 Nginx 都健康,也可能存在:

  • 应用 500;
  • 数据库慢;
  • 线程池满;
  • 下游超时;
  • 业务错误;
  • 错误版本;
  • 配置中心异常。

应继续使用前一篇的 Request ID 和 Trace 体系。


十六、配置和运行期故障排查#

独立插图 14:Kubernetes 入口故障排查流程
对应文件:14-kubernetes-ingress-troubleshooting-flow.png

14 kubernetes ingress troubleshooting flow

16.1 Gateway 没有地址#

检查:

Terminal window
kubectl describe gateway nginx-column -n nginx-column
kubectl get gatewayclass nginx -o yaml
kubectl 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。

检查:

Terminal window
curl -v \
-H "Host: nginx-column.example.com" \
http://127.0.0.1:8088/api/instance

16.5 返回 502 / 504#

检查:

Terminal window
kubectl get svc,endpointslice -n nginx-column
kubectl get pods -n nginx-column -o wide
kubectl logs deployment/nginx-column-nginx -n nginx-column
kubectl exec deployment/nginx-column-nginx \
-n nginx-column \
-- nginx -T

从数据平面容器测试:

Terminal window
kubectl exec deployment/nginx-column-nginx \
-n nginx-column \
-- curl -v http://backend-v1/api/instance

实际镜像可能不包含 curl。生产镜像不应为了排障长期安装大量工具,可以使用临时 Debug Pod:

Terminal window
kubectl run net-debug \
--rm -it \
--image=curlimages/curl \
-- sh

16.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

15 nginx kubernetes solution selection

场景推荐方向核心原因
本地个人项目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: HTTPRoute
spec:
parentRefs:
- name: public-gateway

Route 在 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:latest
imagePullPolicy: Always

为什么生产风险高?

每次拉取可能得到不同镜像,无法确定版本和可靠回滚。应固定 Tag 和 Digest。


二十一、本文总结#

本篇完成了 Nginx 从传统入口代理到云原生流量基础设施的迁移。

核心结论:

  1. 容器中的 Nginx 必须以前台主进程运行,并正确处理信号;
  2. 只读根文件系统需要配合可写临时目录;
  3. Compose 服务名 DNS 不等于运行期健康治理;
  4. 环境变量不能自动出现在任意 Nginx 配置中;
  5. Kubernetes 中 Nginx 可能是应用组件,也可能是共享入口数据平面;
  6. Service 提供稳定入口,EndpointSlice 维护实际后端;
  7. Readiness 决定 Pod 是否进入正常流量;
  8. Ingress 是 API,Controller 才是真正的数据平面管理者;
  9. Ingress API 仍然存在,但已经冻结;
  10. 社区 ingress-nginx 已于 2026 年 3 月 24 日退役;
  11. F5 NGINX Ingress Controller 和 NGINX Gateway Fabric 是不同项目;
  12. Gateway API 通过 GatewayClass、Gateway 和 Route 实现角色分离;
  13. ReferenceGrant 提供跨 Namespace 引用授权;
  14. Controller 通过 Watch、Reconcile、校验和 Reload 管理 Nginx;
  15. ConfigMap 更新不代表 Nginx 已加载新配置;
  16. 热更新仍需考虑长连接、Pod 终止和 Reload 失败;
  17. 权重灰度必须结合指标、兼容性和快速回滚;
  18. TLS Secret 和 cert-manager 可以形成自动续期闭环;
  19. 故障排查必须同时看 Conditions、Controller、数据平面、Service、EndpointSlice 和应用;
  20. 新项目应优先评估受维护的 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;
  • 提供权重灰度;
  • 提供验证和排障命令;
  • 提供资源清理思路。

参考资料#

  1. Nginx Download
    https://nginx.org/en/download.html

  2. Controlling Nginx
    https://nginx.org/en/docs/control.html

  3. Docker Official Image: Nginx
    https://hub.docker.com/_/nginx

  4. Docker Compose Startup Order
    https://docs.docker.com/compose/how-tos/startup-order/

  5. Kubernetes Service
    https://kubernetes.io/docs/concepts/services-networking/service/

  6. Kubernetes EndpointSlice
    https://kubernetes.io/docs/concepts/services-networking/endpoint-slices/

  7. Kubernetes Probes
    https://kubernetes.io/docs/concepts/workloads/pods/probes/

  8. Kubernetes Pod Lifecycle
    https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/

  9. Kubernetes Ingress
    https://kubernetes.io/docs/concepts/services-networking/ingress/

  10. Ingress NGINX Retirement
    https://kubernetes.io/blog/2025/11/11/ingress-nginx-retirement/

  11. Ingress NGINX Retirement Status
    https://kubernetes.io/blog/2026/03/30/kubernetes-v1-36-sneak-peek/

  12. Before You Migrate from Ingress NGINX
    https://kubernetes.io/blog/2026/02/27/ingress-nginx-before-you-migrate/

  13. Kubernetes Gateway API
    https://kubernetes.io/docs/concepts/services-networking/gateway/

  14. Gateway API Documentation
    https://gateway-api.sigs.k8s.io/

  15. Gateway API HTTP Routing
    https://gateway-api.sigs.k8s.io/guides/user-guides/http-routing/

  16. Gateway API Traffic Splitting
    https://gateway-api.sigs.k8s.io/guides/user-guides/traffic-splitting/

  17. Migrating from Ingress
    https://gateway-api.sigs.k8s.io/guides/getting-started/migrating-from-ingress/

  18. NGINX Gateway Fabric
    https://docs.nginx.com/nginx-gateway-fabric/

  19. NGINX Gateway Fabric Installation
    https://docs.nginx.com/nginx-gateway-fabric/install/helm/

  20. NGINX Gateway Fabric Basic Routing
    https://docs.nginx.com/nginx-gateway-fabric/traffic-management/basic-routing/

  21. cert-manager Gateway
    https://cert-manager.io/docs/usage/gateway/

  22. cert-manager ACME HTTP-01 Gateway API
    https://cert-manager.io/docs/configuration/acme/http01/

资料访问日期:2026-07-08。

第 8 篇:容器与 Kubernetes 中的 Nginx 实践
https://jupiter-ws.cn/posts/backend/nginx/08_nginx_docker_kubernetes_gateway_api/
作者
Jupiter
发布于
2026-07-08
许可协议
CC BY-NC-SA 4.0