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 Gateway | Service 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-serviceexample.com/web/*→web-serviceexample.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 会按以下规则选择:
- 最长路径优先:
/foo/bar优先于/foo - 精确匹配优先于前缀匹配:
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.com、bar.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"
小结
本章我们学习了:
- Ingress 概念:统一入口管理外部流量
- Ingress Controller:真正处理流量的组件
- 路由规则:基于域名和路径的流量分发
- TLS 配置:HTTPS 终止和证书管理
- 常用注解:扩展 Ingress 功能
- 故障排查:常见问题的解决方法
Ingress 是暴露 HTTP/HTTPS 服务的主要方式,掌握它对于生产环境部署至关重要。
练习
- 部署 NGINX Ingress Controller
- 创建一个基于路径的 Ingress,将
/api和/web路由到不同服务 - 配置 TLS 并验证 HTTPS 访问
- 使用 cert-manager 自动获取 Let's Encrypt 证书