【Kubernetes从入门到精通】第18篇:Ingress Controller选型和实战——Nginx Ingress完全指南
摘要
上一篇文章咱们搞懂了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才是"实现":
- Nginx Ingress工作原理:Watch K8s API → 拼nginx.conf → reload——简单但可靠
- Annotations是你的日常武器:rewrite、CORS、rate-limit、whitelist、auth等几十个Annotation,覆盖了80%的HTTP网关需求
- 金丝雀发布:权重(百分比切流)、Header(内部测试)、Cookie(白名单灰度),三种玩法自由组合
- 选型建议:默认Nginx Ingress,追求开发体验用Traefik,已用Envoy生态选Contour
下一篇咱们聊Volume——容器一重启数据就没了,那数据库怎么办?K8s的存储方案有哪些?emptyDir和hostPath又是什么鬼?
更多推荐

所有评论(0)