Service 的 NodePort 方式需要记住端口号,且无法做基于域名的路由。Ingress 解决了这个问题 — 它充当集群的七层入口,根据域名和路径将流量转发到不同的 Service。
1. Ingress 工作原理
Ingress 由两部分组成:
- Ingress Controller — 实际执行反向代理的 Pod(如 Ingress-Nginx)
- Ingress 资源 — 定义路由规则的 K8s 对象(域名→路径→Service 的映射)
简言之:外部请求 → Ingress Controller(根据 Ingress 规则匹配)→ 内部 Service → Pod
2. 安装 Ingress-Nginx 控制器
2.1 通过 Helm 安装(推荐)
# 添加 ingress-nginx 仓库
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.service.type=NodePort \
--set controller.service.nodePorts.http=30080 \
--set controller.service.nodePorts.https=30443
2.2 验证安装
kubectl get pods -n ingress-nginx
kubectl get svc -n ingress-nginx
# 输出类似:
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
# ingress-nginx-controller NodePort 10.96.x.x 80:30080/TCP,443:30443/TCP
3. 第一个 Ingress 规则
3.1 准备后端服务
# 部署两个示例应用
kubectl create deployment web1 --image=nginx:1.25 --replicas=2
kubectl create deployment web2 --image=httpd:2.4 --replicas=2
kubectl expose deployment web1 --port=80
kubectl expose deployment web2 --port=80
3.2 编写 Ingress 规则
创建 ingress-demo.yaml:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-demo
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: web1.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web1
port:
number: 80
- host: web2.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web2
port:
number: 80
kubectl apply -f ingress-demo.yaml
3.3 测试访问
# 本地修改 /etc/hosts 将域名指向节点 IP
# 192.168.1.102 web1.example.com web2.example.com
curl -H "Host: web1.example.com" http://192.168.1.102:30080
# 返回 Nginx 欢迎页
curl -H "Host: web2.example.com" http://192.168.1.102:30080
# 返回 Apache 欢迎页
4. 路径路由与正则匹配
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: path-routing
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
ingressClassName: nginx
rules:
- host: myapp.example.com
http:
paths:
- path: /api(/|$)(.*) # /api → backend-api
pathType: ImplementationSpecific
backend:
service:
name: backend-api
port:
number: 8080
- path: / # / → frontend
pathType: Prefix
backend:
service:
name: frontend
port:
number: 80
5. HTTPS 配置
5.1 生成TLS证书(自签名示例)
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout tls.key -out tls.crt \
-subj "/CN=myapp.example.com"
# 创建 Secret
kubectl create secret tls myapp-tls --key tls.key --cert tls.crt
5.2 添加 TLS 配置到 Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tls-ingress
spec:
ingressClassName: nginx
tls:
- hosts:
- myapp.example.com
secretName: myapp-tls
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: myapp
port:
number: 80
生产环境建议使用 cert-manager 自动签发 Let's Encrypt 免费证书,后文会单独介绍。
6. 常用 Annotations
| Annotation | 作用 | 示例 |
|---|---|---|
| rewrite-target | 重写 URL 路径 | / |
| ssl-redirect | 强制 HTTP→HTTPS 跳转 | "true" |
| proxy-body-size | 请求体大小限制 | "50m" |
| proxy-read-timeout | 后端响应超时 | "60" |
| rate-limit | 限制请求速率 | "100" |
| cors-allow-origin | CORS 跨域配置 | "https://example.com" |
7. Ingress vs Gateway API
Ingress 是当前最广泛使用的方案,Kubernetes 社区正在推进 Gateway API(前身为 Istio/Mesh 中的 Gateway):
| 特性 | Ingress | Gateway API |
|---|---|---|
| 角色分离 | 不支持 | ✅ 基础设施管理者 vs 应用开发者 |
| TLS 管理 | 基础支持 | 更灵活的策略绑定 |
| 流量切分 | 需 annotation | ✅ 原生支持权重路由 |
| 成熟度 | GA | beta → 逐步 GA |
8. 完整部署流程总结
# 1. 安装 Ingress Controller
helm install ingress-nginx ingress-nginx/ingress-nginx \
--namespace ingress-nginx --create-namespace \
--set controller.service.type=NodePort
# 2. 部署后端应用并暴露 Service
kubectl create deployment myapp --image=nginx --replicas=2
kubectl expose deployment myapp --port=80
# 3. 创建 TLS Secret
kubectl create secret tls myapp-tls --key=tls.key --cert=tls.crt
# 4. 编写并应用 Ingress 规则
kubectl apply -f ingress-demo.yaml
# 5. 验证
kubectl get ingress
kubectl describe ingress ingress-demo
# 6. 访问测试
curl -k https://myapp.example.com:30443
9. 排错指南
| 现象 | 排查方向 |
|---|---|
| 503 Service Unavailable | 后端 Service 名称拼写错误或 Endpoints 为空 |
| 404 Not_found | Ingress 规则中 host/path 不匹配 |
| 证书错误 | Secret 不在同一命名空间或 tls 配置有误 |
| Ingress 规则不生效 | 检查 ingressClassName 和控制器的 watch 命名空间 |