跳到主要内容

Ingress 入口管理

Ingress 是 Kubernetes 中管理外部 HTTP/HTTPS 访问集群内服务的 API 对象。它充当集群入口的路由器,根据域名和路径将外部流量分发到不同的 Service。相比 NodePort 和 LoadBalancer,Ingress 提供了更灵活、更经济的流量管理方式。

为什么需要 Ingress?

在了解 Ingress 之前,我们先回顾一下暴露服务的几种方式,看看它们各自的局限性。

现有方案的局限

NodePort 在每个节点上开放一个端口,外部可以通过 节点IP:端口 访问服务。这种方式简单,但有几个问题:端口范围受限(30000-32767),需要知道节点 IP 地址,而且每个服务都需要一个端口,管理起来很混乱。

LoadBalancer 会为每个服务创建一个云负载均衡器,提供了稳定的外部 IP。但这种方式成本高昂——每个服务都需要一个独立的负载均衡器,如果有 10 个服务就需要 10 个负载均衡器,费用会迅速增长。

Ingress 的优势

Ingress 解决了上述问题。它只需要一个负载均衡器(或一个节点 IP),就可以根据请求的域名和路径将流量路由到不同的服务。这就像一个智能前台,根据访客要找的部门(域名和路径)将他们引导到正确的位置。

外部请求 → Ingress Controller → 根据域名/路径路由 → Service → Pod

Ingress 的核心价值在于:

  • 统一入口:所有外部流量通过一个入口进入集群
  • 基于域名的虚拟主机:一个 IP 可以服务多个域名
  • 基于路径的路由:根据 URL 路径分发到不同服务
  • TLS 终止:集中处理 HTTPS 证书,后端服务无需关心 TLS
  • 成本优化:减少对外部负载均衡器的需求

Ingress 与 Ingress Controller 的关系

这是理解 Ingress 最关键的一点:Ingress 资源本身不做任何工作,它只是定义了路由规则。真正实现流量转发的是 Ingress Controller。

打个比方,Ingress 就像一份路由表,而 Ingress Controller 才是真正执行路由的设备。你创建了 Ingress 资源,但如果集群中没有运行 Ingress Controller,那么什么都不会发生。

常见的 Ingress Controller

控制器特点适用场景
NGINX Ingress社区最活跃,功能全面通用场景
Traefik自动服务发现,配置简单微服务架构
HAProxy高性能,适合大规模高流量场景
Kong基于 Nginx,带 API 网关功能API 管理
Istio GatewayService Mesh 集成服务网格场景

部署 NGINX Ingress Controller

NGINX Ingress Controller 是最常用的选择。以下是部署方法:

# 使用 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

# 或使用 kubectl 直接应用清单
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.8.2/deploy/static/provider/cloud/deploy.yaml

安装完成后,检查 Ingress Controller 是否正常运行:

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

在云环境中,Ingress Controller 的 Service 类型通常是 LoadBalancer,云提供商会分配一个外部 IP 地址。在本地开发环境(如 Minikube)中,可以使用以下方式启用:

# Minikube 启用 Ingress 插件
minikube addons enable ingress

# 等待 Ingress Controller 就绪
kubectl wait --namespace ingress-nginx \
--for=condition=ready pod \
--selector=app.kubernetes.io/component=controller \
--timeout=120s

Ingress 资源详解

基本结构

一个最简单的 Ingress 资源如下所示:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: minimal-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- http:
paths:
- path: /testpath
pathType: Prefix
backend:
service:
name: test-service
port:
number: 80

这个 Ingress 将所有访问 /testpath 路径的请求转发到 test-service 服务的 80 端口。

Ingress 规则详解

Ingress 规则定义了如何将外部请求路由到内部服务。每条规则包含以下要素:

主机名(Host):可选,指定域名。如果指定了 foo.bar.com,则规则只对访问该域名的请求生效。如果不指定,则规则对所有请求生效。

路径(Path):URL 路径,如 /api/web 等。每条路径关联一个后端服务。

路径类型(PathType):Kubernetes 要求每条路径必须指定类型,支持三种:

  • Exact:精确匹配,路径必须完全相同
  • Prefix:前缀匹配,路径以指定值开头即可
  • ImplementationSpecific:由 Ingress Controller 决定如何匹配

路径匹配的规则需要特别注意。以下是 Prefix 类型的匹配示例:

路径定义请求路径匹配结果
/foo/foo匹配
/foo/foo/匹配
/foo//foo匹配
/foo/foo/bar匹配
/foo/foobar不匹配
/aaa/bbb/aaa/bbb/ccc匹配
/aaa/bbb/aaa/bbbxyz不匹配

注意最后两个例子:/foo/bar 匹配 /foo/bar/baz,但不匹配 /foo/barbaz。这是因为路径是按 / 分隔的元素进行匹配,最后一个元素必须完整匹配。

默认后端(Default Backend)

当请求不匹配任何规则时,Ingress Controller 会将其发送到默认后端。通常默认后端会返回 404 页面。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-with-default
spec:
ingressClassName: nginx
defaultBackend:
service:
name: default-http-backend
port:
number: 80

如果没有指定规则(spec.rules 为空),则必须指定 defaultBackend

实战示例

单服务入口

最简单的场景:将所有流量路由到单个服务。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: single-service-ingress
spec:
ingressClassName: nginx
defaultBackend:
service:
name: my-app
port:
number: 8080

基于路径的扇出(Fanout)

将同一个域名的不同路径路由到不同服务,这是最常见的场景。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: fanout-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
- path: /web
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80
- path: /static
pathType: Prefix
backend:
service:
name: static-service
port:
number: 80

这个配置的效果是:

  • example.com/api/*api-service
  • example.com/web/*web-service
  • example.com/static/*static-service

基于域名的虚拟主机

不同的域名路由到不同的服务,实现一个 IP 托管多个网站。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: name-based-virtual-hosting
spec:
ingressClassName: nginx
rules:
- host: foo.example.com
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: foo-service
port:
number: 80
- host: bar.example.com
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: bar-service
port:
number: 80

混合配置

结合域名和路径,实现更复杂的路由:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: complex-ingress
annotations:
nginx.ingress.kubernetes.io/use-regex: "true"
spec:
ingressClassName: nginx
rules:
- host: api.example.com
http:
paths:
- path: /v1
pathType: Prefix
backend:
service:
name: api-v1
port:
number: 80
- path: /v2
pathType: Prefix
backend:
service:
name: api-v2
port:
number: 80
- host: web.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-frontend
port:
number: 80

IngressClass

从 Kubernetes 1.18 开始,引入了 IngressClass 资源,用于指定 Ingress 应该由哪个 Ingress Controller 处理。

为什么需要 IngressClass?

当一个集群中有多个 Ingress Controller 时,需要明确每个 Ingress 由谁来处理。比如你可能同时运行了 NGINX Ingress Controller 和 Traefik,它们处理流量的方式不同。IngressClass 让你可以指定使用哪个控制器。

定义 IngressClass

apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: nginx
annotations:
ingressclass.kubernetes.io/is-default-class: "true"
spec:
controller: k8s.io/ingress-nginx

controller 字段指定控制器的名称,不同的控制器有不同的标识符:

  • NGINX: k8s.io/ingress-nginx
  • Traefik: traefik.io/ingress-controller

ingressclass.kubernetes.io/is-default-class 注解标记这是默认的 IngressClass。当 Ingress 没有指定 ingressClassName 时,会使用默认类。

在 Ingress 中使用 IngressClass

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
spec:
ingressClassName: nginx # 指定使用的 IngressClass
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-service
port:
number: 80

TLS 配置

Ingress 可以终结 TLS 连接,让后端服务使用明文 HTTP,简化证书管理。

基本 TLS 配置

首先创建一个 Secret 存储证书和私钥:

apiVersion: v1
kind: Secret
metadata:
name: tls-secret
namespace: default
type: kubernetes.io/tls
data:
tls.crt: LS0tLS1CRUdJTi... # Base64 编码的证书
tls.key: LS0tLS1CRUdJTi... # Base64 编码的私钥

然后在 Ingress 中引用这个 Secret:

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

TLS 配置说明:

  • hosts 列表中的域名将使用此证书
  • 一个 Ingress 可以配置多个 TLS 条目,每个使用不同的证书
  • 如果不指定 hosts,则证书对所有域名生效

自动证书管理(cert-manager)

手动管理证书很繁琐,cert-manager 可以自动申请和续期证书。

首先安装 cert-manager:

kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.3/cert-manager.yaml

配置 Let's Encrypt 颁发者:

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: your-[email protected]
privateKeySecretRef:
name: letsencrypt-prod
solvers:
- http01:
ingress:
class: nginx

在 Ingress 中添加注解,自动获取证书:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: auto-tls-ingress
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: nginx
tls:
- hosts:
- example.com
secretName: auto-tls-secret # cert-manager 会自动创建
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-service
port:
number: 80

常用注解

Ingress Controller 通过注解提供高级功能。以下是一些常用的 NGINX Ingress 注解:

重写路径

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

/api/v2/(.*) 重写为 /$1

速率限制

annotations:
nginx.ingress.kubernetes.io/limit-rps: "100"
nginx.ingress.kubernetes.io/limit-connections: "10"

限制每秒请求数和并发连接数。

白名单

annotations:
nginx.ingress.kubernetes.io/whitelist-source-range: "10.0.0.0/8,192.168.0.0/16"

只允许指定 IP 段访问。

代理配置

annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "10m"
nginx.ingress.kubernetes.io/proxy-connect-timeout: "10"
nginx.ingress.kubernetes.io/proxy-send-timeout: "300"

配置代理缓冲区大小、超时时间等。

SSL 重定向

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

强制 HTTPS 重定向。

多路径匹配优先级

当一个请求匹配多条路径时,Ingress Controller 会按以下规则选择:

  1. 最长路径优先/foo/bar 优先于 /foo
  2. 精确匹配优先于前缀匹配Exact 类型优先于 Prefix

例如,以下配置中,访问 /foo 会使用精确匹配规则:

paths:
- path: /foo
pathType: Exact
backend:
service:
name: exact-service
port:
number: 80
- path: /foo
pathType: Prefix
backend:
service:
name: prefix-service
port:
number: 80

通配符域名

Ingress 支持通配符域名,可以匹配子域名:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: wildcard-ingress
spec:
ingressClassName: nginx
rules:
- host: "*.example.com"
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: wildcard-service
port:
number: 80

*.example.com 可以匹配 foo.example.combar.example.com 等,但不能匹配 example.com(没有子域名前缀)。

故障排查

常见问题

Ingress 没有分配地址

检查 Ingress Controller 是否正常运行:

kubectl get pods -n ingress-nginx
kubectl logs -n ingress-nginx deployment/ingress-nginx-controller

404 Not Found

  • 检查 Service 是否存在且端口正确
  • 检查 Service 的 selector 是否匹配 Pod 标签
  • 检查 Ingress 规则的路径是否正确

502 Bad Gateway

  • 后端服务可能未就绪
  • 检查 Service 的 targetPort 是否正确
  • 检查应用是否监听正确的端口

调试命令

# 查看 Ingress 详情
kubectl describe ingress my-ingress

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

# 查看 Ingress Controller 配置
kubectl exec -n ingress-nginx -it <pod-name> -- cat /etc/nginx/nginx.conf

# 测试后端服务连通性
kubectl run test --rm -it --image=busybox -- wget -qO- http://my-service:80

Ingress 与 Gateway API

Kubernetes 社区正在开发 Gateway API 作为 Ingress 的继任者。Gateway API 提供了更丰富的功能,包括:

  • 面向角色的设计,分离基础设施和应用配置
  • 原生支持 TCP/UDP 路由
  • 更强的扩展性
  • 更好的跨命名空间路由支持

Ingress API 已被标记为冻结,不再接受新功能。对于新项目,建议考虑使用 Gateway API。但对于现有项目和简单场景,Ingress 仍然是可行的选择。

最佳实践

1. 使用 IngressClass 明确指定控制器

spec:
ingressClassName: nginx

2. 配置健康检查后端

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: health-check-ingress
spec:
defaultBackend:
service:
name: health-check
port:
number: 80

3. 使用 cert-manager 自动管理证书

避免手动管理证书,减少过期风险。

4. 合理配置资源限制

annotations:
nginx.ingress.kubernetes.io/limit-rps: "100"
nginx.ingress.kubernetes.io/limit-connections: "50"

5. 启用访问日志

annotations:
nginx.ingress.kubernetes.io/enable-access-log: "true"

小结

本章我们学习了:

  1. Ingress 概念:统一入口管理外部流量
  2. Ingress Controller:真正处理流量的组件
  3. 路由规则:基于域名和路径的流量分发
  4. TLS 配置:HTTPS 终止和证书管理
  5. 常用注解:扩展 Ingress 功能
  6. 故障排查:常见问题的解决方法

Ingress 是暴露 HTTP/HTTPS 服务的主要方式,掌握它对于生产环境部署至关重要。

练习

  1. 部署 NGINX Ingress Controller
  2. 创建一个基于路径的 Ingress,将 /api/web 路由到不同服务
  3. 配置 TLS 并验证 HTTPS 访问
  4. 使用 cert-manager 自动获取 Let's Encrypt 证书

参考资料