5月27日 19:41

Kubernetes Ingress 是什么?它如何实现外部访问集群内服务?

Kubernetes Ingress 是什么

当你把一个 Web 应用部署到 Kubernetes 集群后,集群外部的用户怎么访问它?最直接的方式是用 Service 的 NodePort 或 LoadBalancer 类型暴露端口,但前者端口范围有限且不安全,后者每个 Service 都要占用一个云厂商的负载均衡器,成本很高。

Ingress 就是解决这个问题的方案。它是一种 API 对象,在集群入口处统一管理 HTTP 和 HTTPS 路由规则,根据域名和路径把流量分发到不同的 Service。你可以把它理解成集群的"前台接待"——所有外部请求先到 Ingress,再由它根据规则转给对应的后端服务。

Ingress 能做的事情包括:

  • 基于域名的路由api.example.com 走 A 服务,web.example.com 走 B 服务,共享同一个入口 IP
  • 基于路径的路由example.com/api 走后端 API 服务,example.com/app 走前端服务
  • TLS 终止:在 Ingress 层处理 HTTPS 握手,后端 Service 只需跑 HTTP,证书管理集中化
  • 路径重写:把 /v2/api 重写为 /api 再转发给后端
  • 负载均衡:在多个 Pod 副本之间分发请求

一个请求从到达到转发的完整链路

理解 Ingress 工作方式的关键是搞清楚请求的完整路径:

  1. 外部客户端发送请求到 https://api.example.com/users
  2. DNS 将域名解析到 Ingress Controller 暴露的 IP(通常是一个 LoadBalancer Service)
  3. 请求到达 Ingress Controller,Controller 检查 TLS 证书完成 HTTPS 握手
  4. Controller 根据 Host 头和路径匹配 Ingress 规则,找到对应的 Service
  5. Controller 将请求转发给 Service 关联的某个 Pod(通过 Endpoints 列表)
  6. Pod 处理请求并返回响应

注意:Ingress 资源本身只是规则定义,真正干活的是 Ingress Controller。没有 Controller,Ingress 规则就是一纸空文。

Ingress Controller 选型

Ingress Controller 是 Ingress 功能的实际执行者,它监听集群中 Ingress 资源的变化,动态更新自己的配置(比如 NGINX 的 upstream 配置),然后按照规则转发流量。

NGINX Ingress Controller

社区使用最广泛的方案,基于 NGINX/OpenResty 实现。功能成熟、社区活跃、文档齐全,支持限流、认证、CORS、自定义错误页、灰度发布等高级特性。如果你没有特殊需求,选它基本不会出错。

Traefik

云原生设计,原生支持自动服务发现和 Let's Encrypt 自动证书申请,配置方式比 NGINX 更直观(支持文件和 CRD 两种 provider)。适合追求配置简洁和自动化的团队。

HAProxy Ingress

基于 HAProxy 实现,强项是高性能和丰富的负载均衡算法(加权轮询、最少连接、一致性哈希等)。对性能有极致要求时可以考虑。

Istio Gateway

服务网格方案中的入口网关,除了基本路由还支持 mTLS、流量镜像、故障注入、熔断等服务网格能力。如果集群已经用了 Istio,直接用它就够了,不需要再额外部署 Ingress Controller。

AWS ALB Ingress Controller

专为 AWS 设计,直接创建 ALB 资源作为入口,和 AWS 的 WAF、ACM 证书、CloudWatch 等服务深度集成。纯 AWS 环境下的首选。

Ingress 资源配置实战

最基本的路由规则

下面这个示例把 example.com/app1example.com/app2 分别路由到两个不同的 Service:

yaml
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: simple-ingress annotations: nginx.ingress.kubernetes.io/rewrite-target: / spec: rules: - host: example.com http: paths: - path: /app1 pathType: Prefix backend: service: name: app1-service port: number: 80 - path: /app2 pathType: Prefix backend: service: name: app2-service port: number: 80

pathType 是 v1 版本必须指定的字段,有三个可选值:

  • Exact:精确匹配,只有路径完全一致才命中。/app 只匹配 /app,不匹配 /app//app1
  • Prefix:前缀匹配,按 / 分段进行前缀判断。/app 能匹配 /app/app//app/user,但不匹配 /app1
  • ImplementationSpecific:由 Controller 自行决定匹配逻辑

配置 HTTPS(TLS 终止)

要启用 HTTPS,需要先在集群中创建 TLS 证书的 Secret,然后在 Ingress 中引用:

yaml
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: tls-ingress spec: tls: - hosts: - secure.example.com secretName: tls-secret rules: - host: secure.example.com http: paths: - path: / pathType: Prefix backend: service: name: secure-service port: number: 80

Ingress Controller 会在 443 端口处理 TLS 握手,解密后以 HTTP 转发给后端 Service,后端无需关心证书。

默认后端(Default Backend)

当请求没有匹配到任何规则时,Ingress Controller 会把流量发给默认后端。通常是一个返回 404 的简单服务:

yaml
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: default-backend-ingress spec: defaultBackend: service: name: default-service port: number: 80 rules: - host: example.com http: paths: - path: /api pathType: Prefix backend: service: name: api-service port: number: 80

IngressClass:多 Controller 共存的关键

一个集群中可能部署了多个 Ingress Controller(比如 NGINX 处理外部流量,Traefik 处理内部流量)。IngressClass 用来指定一个 Ingress 资源由哪个 Controller 处理:

yaml
apiVersion: networking.k8s.io/v1 kind: IngressClass metadata: name: nginx-external annotations: ingressclass.kubernetes.io/is-default-class: "true" spec: controller: k8s.io/ingress-nginx --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: my-ingress spec: ingressClassName: nginx-external rules: - host: example.com http: paths: - path: / pathType: Prefix backend: service: name: my-service port: number: 80

标注 is-default-class: "true" 的 IngressClass 会被自动分配给没有指定 ingressClassName 的 Ingress 资源。

常用 Annotations 配置

Annotations 是 Ingress 的核心扩展机制,不同 Controller 支持不同的注解。以下是 NGINX Ingress Controller 最常用的几个:

路径重写:把匹配到的路径部分替换后再转发

yaml
nginx.ingress.kubernetes.io/rewrite-target: /$2

强制 HTTPS 重定向:HTTP 请求自动跳转到 HTTPS

yaml
nginx.ingress.kubernetes.io/ssl-redirect: "true"

限流配置:限制每个客户端的请求频率和并发连接数

yaml
nginx.ingress.kubernetes.io/limit-rps: "10" nginx.ingress.kubernetes.io/limit-connections: "5"

CORS 跨域:前后端分离场景经常需要

yaml
nginx.ingress.kubernetes.io/enable-cors: "true" nginx.ingress.kubernetes.io/cors-allow-origin: "https://example.com"

Basic 认证:简单的访问控制

yaml
nginx.ingress.kubernetes.io/auth-type: basic nginx.ingress.kubernetes.io/auth-secret: basic-auth

自定义错误页面:统一展示 404、503 等错误页

yaml
nginx.ingress.kubernetes.io/custom-http-errors: "404,503"

Ingress 和 Service、LoadBalancer 的区别

很多初学者容易混淆这三者的关系,这里做个明确对比。

Ingress vs Service:Service 是四层(L4)负载均衡,基于端口和 IP 转发 TCP/UDP 流量,不关心请求内容。Ingress 是七层(L7)负载均衡,能识别 HTTP 的 Host 头和 URL 路径,做更精细的路由。Service 是必须的(Ingress 最终还是把流量转给 Service),Ingress 是可选的增强。

Ingress vs LoadBalancer:LoadBalancer 类型的 Service 每个都占用一个云厂商负载均衡器,成本高且没有域名路由能力。Ingress 只需要一个 LoadBalancer(给 Ingress Controller 用),然后通过规则复用这个入口给多个 Service 使用。

维度IngressService (ClusterIP/NodePort)Service (LoadBalancer)
层级L7L4L4
路由能力域名 + 路径端口端口
TLS 终止支持不支持部分支持
成本低(共享入口)高(每 Service 一个 LB)
协议HTTP/HTTPSTCP/UDPTCP/UDP

部署 NGINX Ingress Controller

用 Helm 安装是最快的方式:

bash
# 添加 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

安装完成后验证:

bash
kubectl get pods -n ingress-nginx kubectl get svc -n ingress-nginx

如果看到 Service 有一个 EXTERNAL-IP(云环境)或 NodePort(本地环境),说明 Controller 已经就绪。

生产环境的最佳实践

命名空间隔离:把 Ingress Controller 部署在独立命名空间(如 ingress-nginx),和业务负载分开管理。

资源限制:Ingress Controller 是集群流量的咽喉,必须设置合理的 CPU 和内存 requests/limits,避免被其他 Pod 抢占资源。

监控告警:重点监控连接数、请求延迟、4xx/5xx 错误率、证书过期时间。Prometheus + Grafana 是主流方案。

证书管理:生产环境推荐用 cert-manager 自动签发和续期 Let's Encrypt 证书,避免手动管理证书过期。

健康检查:确保后端 Service 配置了正确的 readinessProbe,Ingress Controller 只会把流量发给就绪的 Pod。

配置备份与版本管理:Ingress 规则属于基础设施即代码的一部分,应该用 Git 管理 YAML 文件,而不是直接 kubectl edit

灰度发布:利用 nginx.ingress.kubernetes.io/canary 系列注解实现金丝雀发布,按权重或 Header 把部分流量导向新版本。

常见故障排查

排查 Ingress 问题有一个清晰的思路:从外到内,逐层验证。

第一层:Ingress 规则是否正确

bash
kubectl get ingress kubectl describe ingress <ingress-name>

检查 Rules 中的 Host、Path、Backend 是否符合预期,特别注意 pathType 是否匹配。

第二层:Controller 是否正常工作

bash
kubectl logs -n ingress-nginx <pod-name> --tail=100

看日志中是否有配置加载错误或后端连接失败的记录。

第三层:DNS 是否解析正确

bash
nslookup example.com dig example.com

确认域名指向 Ingress Controller 的外部 IP。

第四层:后端 Service 和 Pod 是否健康

bash
kubectl get svc kubectl get endpoints <service-name> kubectl get pods -l app=<your-app>

Endpoints 列表为空说明没有 Pod 通过了 readinessProbe,流量无处可去。

第五层:TLS 证书是否有效

bash
kubectl get secret tls-secret -o yaml openssl x509 -in <cert-file> -text -noout

检查证书是否过期、域名是否匹配、Secret 是否在正确的命名空间。

按照这个顺序逐层排查,绝大多数 Ingress 问题都能定位到原因。

标签:Kubernetes