Nginx Ingress Controller:Kubernetes 云原生网关的路由、证书与金丝雀发布

讲解 Kubernetes 中 Nginx Ingress Controller 的完整实践,覆盖 Ingress 与 Controller 的概念分工、Helm 部署、路由规则与常用注解、cert-manager 证书管理、金丝雀发布与流量切分,以及与云负载均衡的集成和性能排错方法。

Kubernetes 集群内的服务默认只能集群内互访,暴露给外部需要一层统一的南北向网关。Ingress 就是 K8s 定义的网关抽象:它用声明式的规则描述「哪个域名/路径转发到哪个 Service」,而真正执行这些规则的是 Ingress Controller。Nginx Ingress Controller 是生态中最流行的实现,它把 Ingress 资源编译成 Nginx 配置并热加载,同时支持注解扩展、TLS 证书管理与金丝雀发布。本文从概念到部署再到生产实践,完整讲解如何在 K8s 里用好 Nginx 网关。

一句话总结: Ingress 是 K8s 的网关声明,Nginx Ingress Controller 把声明编译为 Nginx 配置,注解与金丝雀机制让网关能力可编程化。

1. Ingress 与 Ingress Controller 的概念分工

一句话总结: Ingress 是声明式的路由规则对象,Controller 是把规则变成真实流量的执行者,两者分离让网关能力随声明演进。

理解 Ingress 要先区分两个概念。Ingress 是一个 Kubernetes API 对象:它只描述「规则」,包括主机名、路径与后端 Service 的对应关系,是纯声明。Ingress Controller 则是一个运行在集群里的控制器进程:它 watch Ingress 对象的变化,把规则翻译成 Nginx 配置,reload Nginx,并负责负载均衡器的生命周期。规则与执行的分离,意味着开发者只改声明,网关的运维由 Controller 自动完成。

# 一个最基础的 Ingress 声明
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web-ingress
  namespace: production
spec:
  ingressClassName: nginx        # 指定使用 nginx 控制器
  rules:
    - host: shop.example.com
      http:
        paths:
          - path: /api/order
            pathType: Prefix
            backend:
              service:
                name: order-service
                port:
                  number: 8080
          - path: /static
            pathType: Prefix
            backend:
              service:
                name: static-service
                port:
                  number: 80

pathType 有 Prefix 与 Exact 两种:Prefix 按路径前缀匹配(等价于 Nginx 的 location /api/order/),Exact 则要求完全一致。多个 Ingress 规则、多个 Controller 并存时,用 ingressClassName 区分归属。集群里可以有多个 Ingress Controller(nginx、traefik、istio),每个 Controller 只处理声明了对应 ingressClassName 的 Ingress。

2. 部署 Nginx Ingress Controller

一句话总结: 生产环境推荐用 Helm 部署 Nginx Ingress Controller,核心参数是副本数、资源限制与准入 Webhook 的开关。

官方推荐用 Helm chart 安装 Nginx Ingress Controller。生产部署要关注几个参数:controller.replicaCount 决定控制器副本数(也是网关的容量),controller.resources 设置资源限额,controller.admissionWebhooks.enabled 控制准入校验(校验 Ingress 配置合法性,避免错误配置直接 reload 失败)。

# 用 Helm 安装 Nginx Ingress Controller
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update

helm upgrade --install ingress-nginx ingress-nginx/ingress-nginx \
  --namespace ingress-nginx --create-namespace \
  --set controller.replicaCount=3 \
  --set controller.resources.limits.cpu=2000m \
  --set controller.resources.limits.memory=2Gi \
  --set controller.service.type=LoadBalancer

部署后的架构是:云负载均衡器(Service 的 LoadBalancer)→ Nginx Ingress Controller Pod → 集群内 Service → 业务 Pod。Controller 的 Pod 需要调度到足够承载流量的节点上,通常会配置反亲和(多副本分散到不同节点)与 topologySpreadConstraints,避免单节点故障导致网关整体不可用。

# 控制器反亲和,让副本分散在不同节点
affinity:
  podAntiAffinity:
    preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchLabels:
              app.kubernetes.io/name: ingress-nginx
          topologyKey: kubernetes.io/hostname

Controller 生成 Nginx 配置后通过 reload 生效。默认每个 worker 会 watch 所有 Ingress,配置变更时执行热加载。观察 Controller 的日志可以确认配置生成与 reload 是否正常,kubectl logs -n ingress-nginx 里的 Configuration changes detected, backend reloaded 就是正常信号。

3. 路由规则与注解配置

一句话总结: Ingress 规则覆盖「域名 + 路径 + Service」的映射,注解则把 Nginx 的 location 级能力(重写、超时、限流)带入声明。

Ingress 规则能表达基本的路由,但 Nginx 丰富的 location 级能力需要靠注解(Annotation)带入。最常用的注解覆盖几类需求:路径重写、连接与读写超时、服务暴露方式(直连后端还是二次反代)。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api-ingress
  namespace: production
  annotations:
    # 路径重写:外部 /api/order 转发为后端的 /order
    nginx.ingress.kubernetes.io/rewrite-target: /$2
    # 服务暴露:与后端直连,Controller 不再二次反代
    nginx.ingress.kubernetes.io/service-upstream: "true"
    # 超时控制
    nginx.ingress.kubernetes.io/proxy-connect-timeout: "5"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
    # 按 IP 白名单
    nginx.ingress.kubernetes.io/whitelist-source-range: "10.0.0.0/8,203.0.113.0/24"
spec:
  ingressClassName: nginx
  rules:
    - host: api.example.com
      http:
        paths:
          - path: /api/order(/|$)(.*)
            pathType: ImplementationSpecific
            backend:
              service:
                name: order-service
                port:
                  number: 8080

注解并非无代价的魔法:每个注解都映射到底层 Nginx 配置的一个片段,写错注解会导致配置生成失败。Controller 的准入 Webhook 能在 apply 阶段就拦截语法错误,所以生产环境务必开启 admissionWebhooks。排错时查看 Controller 生成的 Nginx 配置最直接:kubectl exec 进 Controller Pod 后 cat /etc/nginx/nginx.conf 或查 ingress-nginx 的 ConfigMap。

注解作用等价 Nginx 指令
rewrite-target路径重写rewrite
proxy-connect-timeout连接上游超时proxy_connect_timeout
proxy-read-timeout读取响应超时proxy_read_timeout
limit-rps每 IP 限流limit_req
canary金丝雀开关生成分流 upstream
ssl-redirect强制跳转 HTTPSreturn 301

4. TLS 与证书管理

一句话总结: Ingress 通过 spec.tls 声明证书,cert-manager 自动签发与轮换证书,Controller 维护 Secret 并装载到 Nginx 配置。

Ingress 的 TLS 在 spec.tls 里声明,证书以 Secret 形式挂载。手动管理证书很痛苦,标准做法是引入 cert-manager:它监听 Ingress 的 TLS 声明,自动向 Let’s Encrypt 等签发机构申请证书,并把证书写回 Secret,到期前自动轮换。

# 使用 cert-manager 自动签发
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web-ingress
  namespace: production
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - shop.example.com
      secretName: shop-example-tls      # cert-manager 生成的 Secret
  rules:
    - host: shop.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: web-service
                port:
                  number: 80

证书轮换由 cert-manager 与 Controller 协作完成:cert-manager 在证书临近过期时重新签发并更新 Secret,Controller 检测到 Secret 变更后自动 reload。这个闭环意味着证书生命周期完全自动化,运维不需要再手工续期。

生产环境还要考虑 mTLS 与自定义证书的场景:nginx.ingress.kubernetes.io/auth-tls-secret 注解可以指定客户端证书 CA 的 Secret,为 Ingress 开启客户端证书校验,等价于裸 Nginx 的 ssl_client_certificate。证书相关的排错集中在 Secret 名称是否正确、ClusterIssuer 是否可访问、域名是否指向了集群入口三个环节。

5. 金丝雀发布与流量切分

一句话总结: Ingress 用 canary 注解把部分流量按权重或请求头导到新版本 Service,实现无停机灰度,权重调整即发布进度。

K8s 里的应用发布,用 Ingress 的金丝雀注解可以做到精细的流量控制。金丝雀发布的模型是:主 Ingress 指向稳定版本,金丝雀 Ingress 指向新版本,通过注解设定权重或匹配条件,Controller 自动生成按比例分流的 Nginx 配置。

# 主 Ingress:稳定版本
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api-ingress
  namespace: production
spec:
  ingressClassName: nginx
  rules:
    - host: api.example.com
      http:
        paths:
          - path: /api
            pathType: Prefix
            backend:
              service:
                name: api-service-v1
                port:
                  number: 8080
# 金丝雀 Ingress:新版本,先放 10% 流量
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api-ingress-canary
  namespace: production
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-weight: "10"
spec:
  ingressClassName: nginx
  rules:
    - host: api.example.com
      http:
        paths:
          - path: /api
            pathType: Prefix
            backend:
              service:
                name: api-service-v2
                port:
                  number: 8080

canary-weight 控制比例,也可以改用 canary-by-header 或 canary-by-cookie 做定向灰度——只有携带特定请求头或 Cookie 的用户进入新版本,适合内测团队先行验证。验证稳定后逐步调高 canary-weight 到 50%、100%,最后把主 Ingress 切到 v2 并删除金丝雀 Ingress。

金丝雀发布要观察的指标与裸 Nginx 灰度一致:新版本的 5xx 比例、p95 延迟与错误日志。金丝雀流量通常较小,指标波动可能来自噪声,建议把观察窗口拉长并结合请求量归一化。回滚时把 canary-weight 调回 0 或直接删除金丝雀 Ingress 即可,秒级生效。

6. 与云负载均衡的集成

一句话总结: Controller 的 Service 以 LoadBalancer 模式挂到云 LB 上,通过注解控制 LB 类型、外部流量策略与弹性伸缩。

Ingress Controller 是集群内部组件,它对外的入口是自身的 Service。生产环境通常把该 Service 声明为 LoadBalancer,由云厂商(AWS/阿里云/GCP)自动创建云负载均衡器,流量路径为「云 LB → Controller Pod → Service → 业务 Pod」。集成层面的关键配置都在这个 Service 上:

apiVersion: v1
kind: Service
metadata:
  name: ingress-nginx-controller
  namespace: ingress-nginx
  annotations:
    # AWS NLB(四层)或按云厂商选择
    service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
    # 保持客户端源 IP
    service.beta.kubernetes.io/aws-load-balancer-proxy-protocol: "*"
spec:
  type: LoadBalancer
  externalTrafficPolicy: Local      # 保留客户端真实 IP
  ports:
    - name: http
      port: 80
      targetPort: 80
    - name: https
      port: 443
      targetPort: 443

externalTrafficPolicy: Local 是源 IP 保真的关键:它让云 LB 只把流量转发到本节点的 Controller Pod,避免跨节点转发时源 IP 被 SNAT 覆盖。代价是流量分布可能不均,需要 Controller 副本数足够多且分散。开启 PROXY protocol 后,Controller 能从云 LB 的 PROXY 头还原真实客户端 IP,供限流与日志使用。

云 LB 之上还可以叠加 DNS 层:域名用 CNAME 或 A 记录指向云 LB,云 LB 再做 HTTPS 终结或直接透传 TLS 到 Controller。选择「云 LB 终结 TLS」还是「Controller 终结 TLS」取决于证书管理归属与性能需求:前者证书由云托管、卸载方便,后者统一由 cert-manager 管理、控制力更强,两种模式各有适用场景。

7. 性能与排错

一句话总结: Ingress 性能由 Controller 副本、Nginx worker 参数与云 LB 共同决定,排错按「声明 → 生成配置 → 转发链路」三层定位。

Nginx Ingress Controller 的性能取决于 Controller 的副本数与单 Pod 的 Nginx worker 配置。Controller 默认启用自动扩缩容(基于 CPU),但网关类工作负载波动大,建议设置最小副本数并基于请求量自定义 HPA。单 Pod 内可通过 ConfigMap 调整 worker 参数,与裸 Nginx 类似:

# ingress-nginx ConfigMap 关键参数
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
  namespace: ingress-nginx
data:
  worker-processes: "4"            # 与节点核数匹配
  max-worker-connections: "16384"
  keep-alive: "75"
  log-format-upstream: >-
    $remote_addr - $request_id [$time_local] "$request" $status
    $request_time $upstream_addr

排错的第一层是确认声明是否正确:kubectl describe ingress 看事件,准入 Webhook 会在 apply 时拦截语法错误。第二层是确认生成配置是否合理:进入 Controller Pod 检查 Nginx 配置与 upstream 列表。第三层是确认转发链路:从云 LB → Controller → Service → Pod 逐跳检查,用 kubectl exec 进 Pod 后用 curl 验证服务连通性。

# 进入 Controller Pod 检查生成的路由配置
kubectl exec -n ingress-nginx deploy/ingress-nginx-controller -- \
  cat /etc/nginx/nginx.conf | grep -A 8 'server_name shop.example.com'

# 从 Controller Pod 内验证到后端 Service 的连通性
kubectl exec -n ingress-nginx deploy/ingress-nginx-controller -- \
  curl -s -o /dev/null -w '%{http_code}\n' http://order-service.production.svc:8080/healthz
故障现象排查方向
访问超时云 LB 健康检查是否通过,Controller Pod 是否 Ready
404Ingress 路径与后端路径不匹配,rewrite-target 缺失
502后端 Service 无 Ready 端点,或 Pod 崩溃
证书报错Secret 缺失、cert-manager 签发失败、域名未指向
客户端 IP 不对externalTrafficPolicy 未设 Local,PROXY protocol 未开

8. 总结

环节要点
概念分工Ingress 是声明规则,Controller 把规则编译为 Nginx 配置
部署方式Helm 安装,配置副本数、资源限额与准入 Webhook
路由与注解域名/路径/Service 映射,注解带入重写、超时与限流
证书管理cert-manager 自动签发轮换,Secret 变更自动 reload
金丝雀发布canary 注解按权重或请求头分流,权重调整即进度
云 LB 集成LoadBalancer Service,Local 策略保真源 IP
性能调优副本数、worker 参数与 HPA 共同决定容量
排错三层声明 → 生成配置 → 转发链路,逐层定位

Kubernetes 里的 Nginx 从「手写配置的进程」变成了「声明驱动的控制器」:开发者描述想要的网关,Controller 负责把它变成高可用的 Nginx 集群。Ingress 注解、cert-manager 与金丝雀机制,让证书、灰度与路由能力全部可声明、可版本化。这套云原生网关模式,是 Nginx 在现代基础设施中最主要的形态之一。

延伸阅读

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「nginx」更多文章

  1. Nginx 监控与可观测性:stub_status 指标、Prometheus 集成与容量规划
  2. Nginx 静态资源与页面加速:零拷贝、缓存验证与 Brotli 压缩联动
  3. Nginx TLS 进阶与 mTLS:客户端证书认证、证书轮换与 TLS 1.3 优化