上一篇【第17篇】Ingress——HTTP流量的“总管家“
下一篇【第19篇】Volume——容器数据的"不动产"


摘要

上一篇文章咱们搞懂了Ingress资源怎么配,但Ingress本身只是个"规则说明书"——它不会转发任何一个HTTP请求。真正干活的是Ingress Controller。K8s社区有十几种Controller可选,最主流的是Nginx Ingress,其次是Traefik和Contour。

这篇文章以Nginx Ingress Controller为主角,先讲它的工作原理(监听Ingress→动态拼nginx.conf→reload),然后扒一扒那些高频使用的Annotations(你以后80%的日常配置全靠它),接着演示金丝雀发布的三种玩法(按权重、按Header、按Cookie),最后横向对比Traefik和Contour,帮你做出选型决定。我见过太多团队随便装了个Controller就上线了,结果踩了各种坑——看完这篇你能避免90%。


一、Nginx Ingress Controller的工作原理——“动态nginx.conf生成器”

Nginx Ingress Controller的核心逻辑非常简单:监听K8s API → 拼nginx.conf → reload nginx

【Nginx Ingress Controller 工作流程】

  K8s API Server
       │
       │ Ingress资源变更通知
       ▼
  ┌─────────────────────────────────────────────────────┐
  │           Nginx Ingress Controller Pod              │
  │                                                     │
  │  ┌───────────────────────┐                          │
  │  │  Ingress Watcher      │  监听Ingress/Service     │
  │  │  (持续watch API Server)│  /Secret等资源变化        │
  │  └───────────┬───────────┘                          │
  │              │                                       │
  │              │ 资源变更                               │
  │              ▼                                       │
  │  ┌───────────────────────┐                          │
  │  │  Template Engine      │  把Ingress规则翻译成      │
  │  │  (拼nginx.conf)       │  nginx的server/location   │
  │  └───────────┬───────────┘                          │
  │              │                                       │
  │              │ 生成新的nginx.conf                     │
  │              ▼                                       │
  │  ┌───────────────────────┐                          │
  │  │  Nginx Reloader       │  测试配置语法              │
  │  │  (nginx -t && reload) │  → 优雅重载               │
  │  └───────────────────────┘                          │
  │                                                     │
  │  ┌───────────────────────┐                          │
  │  │  Nginx 进程            │  真正转发HTTP流量         │
  │  │  :80 / :443           │                          │
  │  └───────────────────────┘                          │
  └─────────────────────────────────────────────────────┘
# 一个简单的Ingress规则
# 会被转换成下面的nginx.conf
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api-ingress
spec:
  ingressClassName: nginx
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /users
        pathType: Prefix
        backend:
          service:
            name: users-service
            port:
              number: 8080
# Nginx Ingress Controller 自动生成的 nginx.conf(简化版)
server {
    listen 80;
    server_name api.example.com;
    
    location /users {
        # 根据Ingress的annotations动态生成各种配置
        # rewrite规则、CORS头、限流...都注入在这里
        
        proxy_pass http://upstream-users-service:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

upstream upstream-users-service {
    # 动态服务发现:自动拉取users-service的Endpoints
    server 10.244.1.5:8080 max_fails=3 fail_timeout=30s;
    server 10.244.2.3:8080 max_fails=3 fail_timeout=30s;
    server 10.244.3.7:8080 max_fails=3 fail_timeout=30s;
}

要点:Nginx Ingress Controller的reload是有代价的——每次Ingress变更都会触发nginx -t && nginx -s reload。在几百个Ingress的大集群里,频繁reload会造成短暂的连接中断。Nginx官方已经推出了**Ingress NGINX Controller 1.0+**支持动态配置更新(通过Lua插件),减少reload次数。如果你用的是老版本,注意监控reload频率。


二、Annotations大全——80%的日常配置靠这个

Nginx Ingress Controller有上百个Annotations,但日常用的就那十几个。我按功能分类给你列出来。

2.1 路由和重写

Annotation 用途 示例
rewrite-target URL重写目标 /$2
use-regex 启用正则路径匹配 "true"
app-root 应用根路径 "/app"
server-snippet 自定义nginx server块 慎用!会影响全局
# URL重写:去掉/api前缀
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: rewrite-example
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2
    nginx.ingress.kubernetes.io/use-regex: "true"
spec:
  ingressClassName: nginx
  rules:
  - host: example.com
    http:
      paths:
      - path: /api(/|$)(.*)
        pathType: ImplementationSpecific
        backend:
          service:
            name: backend-svc
            port:
              number: 8080

2.2 安全和认证

metadata:
  annotations:
    # HTTPS强制跳转
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    
    # 强制使用HSTS
    nginx.ingress.kubernetes.io/hsts: "true"
    nginx.ingress.kubernetes.io/hsts-max-age: "31536000"
    
    # IP白名单
    nginx.ingress.kubernetes.io/whitelist-source-range: "10.0.0.0/8,172.16.0.0/12,1.2.3.4"
    
    # Basic认证(需要先创建Secret)
    nginx.ingress.kubernetes.io/auth-type: basic
    nginx.ingress.kubernetes.io/auth-secret: basic-auth-secret
    nginx.ingress.kubernetes.io/auth-realm: "请输入用户名和密码"
    
    # 客户端证书认证(mTLS)
    nginx.ingress.kubernetes.io/auth-tls-verify-client: "on"
    nginx.ingress.kubernetes.io/auth-tls-secret: default/ca-secret

2.3 CORS跨域配置

metadata:
  annotations:
    nginx.ingress.kubernetes.io/enable-cors: "true"
    nginx.ingress.kubernetes.io/cors-allow-origin: "https://example.com"
    nginx.ingress.kubernetes.io/cors-allow-methods: "GET, POST, PUT, DELETE, OPTIONS"
    nginx.ingress.kubernetes.io/cors-allow-headers: "Authorization, Content-Type, X-Request-ID"
    nginx.ingress.kubernetes.io/cors-allow-credentials: "true"
    nginx.ingress.kubernetes.io/cors-max-age: "3600"

要点:CORS配置在Ingress层做比在应用层做好得多——所有微服务共享一套跨域策略,不用每个服务自己写。而且改策略只改Ingress Annotation就行,不用重新部署服务。

2.4 连接和性能

Annotation 用途 推荐值
proxy-body-size 请求体大小限制 "20m"
proxy-connect-timeout 连接后端超时 "10"
proxy-read-timeout 读后端响应超时 "60"
proxy-send-timeout 向后端发送超时 "60"
proxy-buffering 代理缓冲 "on"
limit-rps 每秒请求限流 "10"
limit-burst-multiplier 突发倍数 "5"
metadata:
  annotations:
    # 请求体限制:防止大文件上传耗尽内存
    nginx.ingress.kubernetes.io/proxy-body-size: "20m"
    
    # 超时设置:WebSocket需要长超时
    nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
    
    # 速率限制:每秒5个请求,突发10个
    nginx.ingress.kubernetes.io/limit-rps: "5"
    nginx.ingress.kubernetes.io/limit-burst-multiplier: "2"

2.5 会话亲和和负载

metadata:
  annotations:
    # Cookie会话亲和(同一用户始终到同一Pod)
    nginx.ingress.kubernetes.io/affinity: "cookie"
    nginx.ingress.kubernetes.io/session-cookie-name: "ROUTE_ID"
    nginx.ingress.kubernetes.io/session-cookie-path: "/"
    nginx.ingress.kubernetes.io/session-cookie-expires: "3600"
    nginx.ingress.kubernetes.io/session-cookie-max-age: "3600"

三、金丝雀发布——三种玩法全掌握

Nginx Ingress原生支持金丝雀发布(Canary),不需要Service Mesh也能做灰度。三种方式:

3.1 按权重(Canary by Weight)

【权重金丝雀——按百分比分流】

  100% 流量
       │
       ▼
  ┌─────────────────────────────┐
  │     Ingress Controller      │
  │                             │
  │  canary-weight: "20"        │
  │       │                     │
  │   ┌───┴───┐                 │
  │   │ 分流   │                 │
  │   └───┬───┘                 │
  │  ┌────┴────┐               │
  │  │         │               │
  │  20%      80%              │
  └──┼────────┼───────────────┘
     │        │
     ▼        ▼
  ┌──────┐ ┌──────┐
  │v2.0  │ │v1.0  │
  │Canary│ │Stable│
  └──────┘ └──────┘
# Stable Ingress(主版本)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myapp-stable
spec:
  ingressClassName: nginx
  rules:
  - host: myapp.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: myapp-stable-svc     # 稳定版本
            port:
              number: 8080
---
# Canary Ingress(灰度版本)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myapp-canary
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-weight: "20"  # 20%流量
spec:
  ingressClassName: nginx
  rules:
  - host: myapp.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: myapp-canary-svc     # 灰度版本
            port:
              number: 8080

3.2 按Header(Canary by Header)

# 只有带了 x-canary: true 的请求才走到灰度版本
metadata:
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-by-header: "x-canary"
    nginx.ingress.kubernetes.io/canary-by-header-value: "true"
# 测试:正常用户走stable
curl -H "Host: myapp.example.com" http://ingress-ip/
# 返回 v1.0 内容

# 测试:灰度用户走canary
curl -H "Host: myapp.example.com" -H "x-canary: true" http://ingress-ip/
# 返回 v2.0 内容

3.3 按Cookie(Canary by Cookie)

# 设置了 always=yes Cookie的用户走灰度版本
metadata:
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-by-cookie: "canary_user"
【三种金丝雀方式对比】

  方式           │ 粒度         │ 适用场景
  ──────────────┼──────────────┼─────────────────────────
  权重(weight)   │ 流量百分比    │ 通用灰度,逐步切量
  Header        │ 请求级        │ 开发/QA测试,内部用户预览
  Cookie        │ 用户级        │ 白名单灰度,VIP用户优先体验

要点:金丝雀Annotation可以组合使用——比如同时设weight和header,"20%流量"中只有"带了header的请求"才转发到canary。这在精确控制灰度范围时非常有用。


四、安装和部署——三种主流方式

4.1 Helm安装(推荐)

# 添加Helm仓库
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update

# 安装(生产参数)
helm install ingress-nginx ingress-nginx/ingress-nginx \
  --namespace ingress-nginx \
  --create-namespace \
  --set controller.replicaCount=2 \
  --set controller.service.type=LoadBalancer \
  --set controller.service.externalTrafficPolicy=Local \
  --set controller.metrics.enabled=true \
  --set controller.config.use-forwarded-headers="true" \
  --set controller.config.compute-full-forwarded-for="true"

4.2 纯YAML安装

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.10.0/deploy/static/provider/cloud/deploy.yaml

4.3 验证部署

# 确认Controller Pod在运行
kubectl get pods -n ingress-nginx
# NAME                                        READY   STATUS
# ingress-nginx-controller-xxx-yyy            1/1     Running
# ingress-nginx-controller-xxx-zzz            1/1     Running

# 确认Service已分配外部IP
kubectl get svc -n ingress-nginx
# NAME                                 TYPE           EXTERNAL-IP   PORT(S)
# ingress-nginx-controller             LoadBalancer   1.2.3.4       80:30080/TCP,443:30443/TCP

五、主流Controller横向对比——怎么选?

K8s社区有十几种Ingress Controller,但真正值得考虑的就四个:

【Ingress Controller 选型决策树】

  你的需求是什么?
       │
  ┌────┴────────────────────────────────────┐
  │                                         │
  │ "我需要简单、稳定的HTTP反向代理"          │ "我要API网关级别的功能"
  │ 社区最大、文档最丰富                       │ 动态配置、中间件、可观测性
  │                                         │
  ▼                                         ▼
  Nginx Ingress ✅                     ┌────┴────┐
  (Kubernetes社区版)                    │         │
                                      ▼         ▼
                                   Traefik    Contour/Envoy
                                   (K8s原生)  (适合Istio用户)
Controller 优点 缺点 适合谁
Nginx Ingress 社区最大、文档最多、Annotations功能丰富、久经考验 reload性能开销、配置基于文件、较重 需要稳定可靠HTTP代理的团队
Traefik K8s原生、动态配置(不用reload)、自带Dashboard、自动HTTPS 社区相对小、复杂场景Annotations不足 中小团队,追求开箱即用
Contour + Envoy 基于Envoy、xDS动态配置、Gateway API原生支持 文档相对少、社区比Nginx小 用Istio/Envoy生态的团队
Istio Gateway 服务网格级控制、零信任安全 太重了——如果只做Ingress别用Istio 已用Istio Service Mesh的团队

要点:除非你有明确的理由选别的,默认选Nginx Ingress(Kubernetes社区维护版,不是Nginx公司的NIC)。它的文档最多、社区最活跃、你能Google到的各种问题基本都有解决方案。Traefik在开发体验上是更好的选择(自带Dashboard、动态配置、自动HTTPS),但在企业级功能深度上不如Nginx Ingress。

# 两个Nginx Ingress的区别(很多新人搞混)
# 
# Nginx Ingress (kubernetes/ingress-nginx) —— Kubernetes社区维护
#   GitHub: kubernetes/ingress-nginx
#   ★ 开源、免费、社区最活跃
#
# NGINX Ingress Controller (nginxinc/kubernetes-ingress) —— Nginx公司维护
#   GitHub: nginxinc/kubernetes-ingress
#   ★ 开源(有收费Plus版)、功能更全但更新慢
#
# 本文讲的是第一个(Kubernetes社区版)

各Controller的核心功能对比

功能 Nginx Ingress Traefik Contour
HTTP路由
HTTPS/TLS ✅ 自动
TCP/UDP ✅ ConfigMap
金丝雀发布 ✅ Annotations ✅ CRD
速率限制 ✅ Annotations ✅ Middleware
认证 ✅ Annotations ✅ Middleware
动态配置(无reload) ⚠️ 有限
Dashboard ⚠️ 需额外部署 ✅ 内置 ⚠️ 需额外
Gateway API ⚠️ 实验性

六、常见坑和调试技巧

6.1 最常见的坑

# 坑1:Ingress创建了但404
# 大概率是 ingressClassName 没写或写错了
kubectl get ingress myapp -o yaml | grep ingressClassName

# 坑2:TLS不生效
# 检查Secret是否存在、Secret是否正确的tls类型
kubectl get secret example-tls -o yaml | grep type
# type: kubernetes.io/tls  ← 必须是这个

# 坑3:rewrite没生效
# 检查正则捕获组——path里(.*)是$1还是$2取决于括号有几组
# path: /api/(.*)  →  rewrite-target: /$1  ✅
# path: /api(/|$)(.*)  →  rewrite-target: /$2  ✅

# 坑4:大文件上传失败
# 检查 proxy-body-size,默认只有1m!
kubectl describe ingress myapp | grep proxy-body-size

6.2 调试命令

# 看Ingress Controller日志
kubectl logs -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx -f

# 看生成的nginx.conf
kubectl exec -n ingress-nginx deploy/ingress-nginx-controller -- cat /etc/nginx/nginx.conf

# 测试某条Ingress规则是否生效
kubectl exec -n ingress-nginx deploy/ingress-nginx-controller -- nginx -t

# 看某个Ingress的详细状态
kubectl describe ingress myapp

本篇小结

Ingress Controller是K8s HTTP网关的真正核心——Ingress资源只是"接口",Controller才是"实现":

  1. Nginx Ingress工作原理:Watch K8s API → 拼nginx.conf → reload——简单但可靠
  2. Annotations是你的日常武器:rewrite、CORS、rate-limit、whitelist、auth等几十个Annotation,覆盖了80%的HTTP网关需求
  3. 金丝雀发布:权重(百分比切流)、Header(内部测试)、Cookie(白名单灰度),三种玩法自由组合
  4. 选型建议:默认Nginx Ingress,追求开发体验用Traefik,已用Envoy生态选Contour

下一篇咱们聊Volume——容器一重启数据就没了,那数据库怎么办?K8s的存储方案有哪些?emptyDir和hostPath又是什么鬼?


上一篇【第17篇】Ingress——HTTP流量的“总管家“
下一篇【第19篇】Volume——容器数据的"不动产"


Logo

AtomGit AI 社区提供模型库、数据集、Agent、Token等资源

更多推荐