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 | 强制跳转 HTTPS | return 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 |
| 404 | Ingress 路径与后端路径不匹配,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 反向代理与负载均衡 — 网关转发与 upstream 语义基础
- Nginx 核心配置结构 — Controller 生成配置背后的指令模型
- Nginx HTTPS 与 TLS 加固 — Ingress 证书与 TLS 参数参照
- Nginx 限流与安全防护 — 注解限流背后的 limit_req 实现
- Nginx 缓存与压缩优化 — 网关层的缓存与压缩对照
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。