深色模式
Ingress-Nginx 实战与调优
摘要:本文给出 ingress-nginx 的生产部署要点、最常用注解调优(请求体大小、超时、限流、CORS、TLS),多 IngressClass 隔离,指标监控与排障,以及版本安全实践。覆盖版本:Kubernetes v1.28+,ingress-nginx 按当前稳定版为准。
适用版本与前提
- Kubernetes:v1.28+。
- ingress-nginx:请按目标集群已装版本核对注解与 CRD
[版本相关]。 - 工具:
kubectl、helm。 - 前提:理解 Ingress 与 Service(见
ingress.md、service.md)。
背景与问题
ingress-nginx 是最流行的 Ingress Controller 之一,基于 Nginx 实现。它在每个节点上运行 Nginx,把 Ingress 规则编译成 Nginx 配置。[厂商特定] 它的很多高级能力通过 nginx.ingress.kubernetes.io/* 注解实现,这些注解不跨 Controller 通用。本文聚焦生产最常用、最容易踩坑的调优点。
部署(Helm)
bash
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.publishService.enabled=true # 把 LB 地址写回 Ingress status1
2
3
4
5
2
3
4
5
部署后会产生一个 IngressClass(默认名 nginx)和一个 LoadBalancer 类型的 Service(见 north-south.md)。
设为默认 Controller
若要让未指定 ingressClassName 的 Ingress 也能被它处理,给它打默认注解:
bash
kubectl annotate ingressclass nginx \
ingressclass.kubernetes.io/is-default-class=true1
2
2
关键调优注解
请求体大小(413 常见元凶)
ingress-nginx 默认限制请求体 1MB,超过返回 413 Payload Too Large。文件上传场景必须调整:
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: upload
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
spec:
ingressClassName: nginx
rules:
- host: upload.example.com
http:
paths:
- path: /upload
pathType: Prefix
backend:
service:
name: upload-svc
port:
number: 801
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
注意
proxy-body-size: 0 会完全关闭限制,几乎总是安全风险(易被大请求打满内存/磁盘),不建议生产使用。
超时(大文件/长连接/流式)
默认 proxy-read-timeout / proxy-send-timeout 为 60 秒。大上传或 WebSocket/流式需调大,否则连接被过早关闭:
yaml
metadata:
annotations:
nginx.ingress.kubernetes.io/proxy-read-timeout: "120"
nginx.ingress.kubernetes.io/proxy-send-timeout: "120"
nginx.ingress.kubernetes.io/proxy-buffering: "off" # 流式关闭缓冲1
2
3
4
5
2
3
4
5
限流
保护后端不被打爆:
yaml
metadata:
annotations:
nginx.ingress.kubernetes.io/limit-rps: "10"
nginx.ingress.kubernetes.io/limit-connections: "5"
nginx.ingress.kubernetes.io/limit-burst-multiplier: "3"1
2
3
4
5
2
3
4
5
CORS
在边缘统一处理跨域,避免在每个应用里写:
yaml
metadata:
annotations:
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-origin: "https://frontend.example.com"
nginx.ingress.kubernetes.io/cors-allow-methods: "GET, POST, PUT, DELETE, OPTIONS"1
2
3
4
5
2
3
4
5
TLS 与重定向
yaml
metadata:
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
tls:
- hosts: ["app.example.com"]
secretName: app-tls1
2
3
4
5
6
7
2
3
4
5
6
7
全局默认值:ConfigMap
单条 Ingress 注解优先于全局;全局默认值通过 ingress-nginx 命名空间下的 nginx-configuration ConfigMap 设置,适合做集群基线:
yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-configuration
namespace: ingress-nginx
data:
client-max-body-size: "20m" # 全局默认,未覆盖的 Ingress 继承
proxy-read-timeout: "90"
proxy-send-timeout: "90"1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
优先级
Ingress 注解(具体) > nginx-configuration ConfigMap(全局默认) > 控制器硬编码默认(如 1m)。这样可“设合理基线 + 对特定服务覆盖”。
多 Controller / 多 IngressClass 隔离
大型集群可跑多个 ingress-nginx 实例(如公网/内网分离),用不同 ingressClassName 区分。安装第二个实例时换 class 名与 electionID:
bash
helm install ingress-nginx-internal ingress-nginx/ingress-nginx \
--namespace ingress-nginx-internal --create-namespace \
--set controller.ingressClassResource.name=nginx-internal \
--set controller.ingressClassResource.controllerValue=k8s.io/ingress-nginx-internal \
--set controller.electionID=ingress-controller-internal1
2
3
4
5
2
3
4
5
流量路径(mermaid)
监控与排障
- 指标:控制器在
:10254/metrics暴露 Prometheus 指标(请求率、上游响应时间、5xx、证书过期)。可用 kube-prometheus-stack 的 ServiceMonitor 自动抓取。 - 查看生成的 Nginx 配置:
kubectl exec -n ingress-nginx <controller-pod> -- cat /etc/nginx/nginx.conf(或 conf.d)。 - 看事件:
kubectl describe ingress <name>看是否被正确接纳、有无 reload 错误。 - controller 日志:
kubectl logs -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx。
生产危险(安全)
历史上 ingress-nginx 出现过严重准入控制器漏洞(如 CVE-2025-1974 类的 RCE/越权,社区曾统计大量集群受影响 [未实测])。务必保持 ingress-nginx 版本最新、限制能创建 Ingress 的 RBAC、不要把 admission 端点暴露到公网。 升级前在预发验证配置兼容。
生产实践
- 把
proxy-body-size、超时设为与后端一致的基线,避免“前端 413 / 后端没事”。 - 对外的 Ingress 强制 TLS(ssl-redirect + cert-manager 自动续期)。
- 用
limit-rps等做基础抗刷;精细限流仍应在应用/网关层。 - 控制平面高可用:ingress-nginx 多副本 +
publishService让 Ingress status 显示外部 IP。
验证
bash
kubectl get ingressclass
kubectl get ingress -A -o wide
curl -H 'Host: app.example.com' https://<lb-ip>/ # 无 DNS 时用 Host 头
curl -k -I https://<lb-ip>/ -H 'Host: app.example.com' | head # 看 301/2001
2
3
4
2
3
4
回滚与清理
bash
# 删除单个 Ingress
kubectl delete ingress upload
# 卸载控制器(会删除其 LB)
helm uninstall ingress-nginx -n ingress-nginx1
2
3
4
2
3
4
注意
升级 ingress-nginx 大版本可能改变默认行为或注解语义,先在预发验证再全量。回滚时用 Helm 回退到上一 revision。
故障排查
- 413:
proxy-body-size太小或后端也有 body 限制。 - 504 Gateway Timeout:后端慢或
proxy-read-timeout太小;检查后端日志与上游响应时间指标。 - 404 from nginx:
pathType/路径不匹配,或后端 Service 名/端口错。 - TLS 错误:Secret 缺失或证书格式不对(需
tls.crt/tls.keyPEM)。
安全与合规
- 保持版本最新,限制 Ingress/RBAC 权限。
- 不要为不可信用户开启
configuration-snippet注解(默认关闭),开启需allowSnippetAnnotations: true且信任用户,否则可写任意 nginx 配置[厂商特定]。
常见坑
- 忘记
proxy-body-size导致上传 413。 - 超时默认 60 秒,长任务/WebSocket 被断。
- 多个 Controller 抢同一个 Ingress(ingressClassName 没指定/默认类冲突)。
- 升级大版本未验证注解兼容性。
替代方案与权衡
- Traefik / Contour / Emissary(Envoy):原生 CRD、动态配置,注解体系不同。
- Gateway API(NGINX Gateway Fabric):未来方向,表达力更强(见
ingress.md)。 - 云厂商 LB Ingress(如 AWS ALB Ingress):与云深度集成,但锁定云厂商。