Ingress - HTTP 路由
Ingress - HTTP 路由
为什么需要 Ingress
Service 只能提供 L4 负载均衡,无法实现:
- 域名路由:根据域名转发
- 路径路由:根据 URL 路径转发
- SSL/TLS 终止:HTTPS 证书管理
- 会话保持:Session Affinity
- 重定向和重写:URL 重定向
Ingress 提供 L7(HTTP/HTTPS)负载均衡和路由。
Ingress 架构
Internet
↓
[Ingress Controller]
↓
[Ingress Rules]
↓
┌──────────┬──────────┬──────────┐
│ Service1 │ Service2 │ Service3 │
└──────────┴──────────┴──────────┘
组件:
- Ingress Controller:实现 Ingress 规则的控制器
- Ingress:定义路由规则的 API 对象
安装 Ingress Controller
Nginx Ingress Controller
# 使用 Helm 安装
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm install nginx-ingress ingress-nginx/ingress-nginx
# 或使用 kubectl
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.8.1/deploy/static/provider/cloud/deploy.yaml
Minikube 启用
minikube addons enable ingress
# 验证
kubectl get pods -n ingress-nginx
基础示例
单个服务
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: simple-ingress
spec:
ingressClassName: nginx
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80
kubectl apply -f ingress.yaml
# 查看
kubectl get ingress
# 输出
NAME CLASS HOSTS ADDRESS PORTS AGE
simple-ingress nginx example.com 192.168.1.100 80 1m
访问:
curl http://example.com # 需要配置 DNS 或 /etc/hosts
多路径路由
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: path-based-ingress
spec:
ingressClassName: nginx
rules:
- host: myapp.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 8080
- path: /web
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80
- path: /
pathType: Prefix
backend:
service:
name: default-service
port:
number: 8080
路由规则:
myapp.com/api/*→ api-servicemyapp.com/web/*→ web-servicemyapp.com/*→ default-service
多域名路由
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: host-based-ingress
spec:
ingressClassName: nginx
rules:
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-service
port:
number: 8080
- host: web.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80
- host: admin.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: admin-service
port:
number: 3000
HTTPS/TLS 配置
创建 TLS Secret
# 生成自签名证书(测试用)
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout tls.key -out tls.crt \
-subj "/CN=example.com/O=example"
# 创建 Secret
kubectl create secret tls example-tls \
--cert=tls.crt \
--key=tls.key
配置 HTTPS
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tls-ingress
spec:
ingressClassName: nginx
tls:
- hosts:
- example.com
- www.example.com
secretName: example-tls
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80
现在可以通过 HTTPS 访问:
curl https://example.com
HTTP 重定向到 HTTPS
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: redirect-ingress
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- example.com
secretName: example-tls
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80
Ingress 注解
常用注解
metadata:
annotations:
# 重写路径
nginx.ingress.kubernetes.io/rewrite-target: /
# 请求体大小限制
nginx.ingress.kubernetes.io/proxy-body-size: "10m"
# 超时设置
nginx.ingress.kubernetes.io/proxy-connect-timeout: "60"
nginx.ingress.kubernetes.io/proxy-send-timeout: "60"
nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
# 会话保持
nginx.ingress.kubernetes.io/affinity: "cookie"
nginx.ingress.kubernetes.io/session-cookie-name: "route"
# CORS
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-origin: "*"
# 限流
nginx.ingress.kubernetes.io/limit-rps: "10"
# 白名单
nginx.ingress.kubernetes.io/whitelist-source-range: "10.0.0.0/24,192.168.1.0/24"
路径重写示例
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: rewrite-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
ingressClassName: nginx
rules:
- host: example.com
http:
paths:
- path: /api(/|$)(.*)
pathType: Prefix
backend:
service:
name: api-service
port:
number: 8080
请求映射:
example.com/api/users→api-service/usersexample.com/api/v1/products→api-service/v1/products
完整实战示例
部署多个服务
# Frontend Service
apiVersion: v1
kind: Service
metadata:
name: frontend
spec:
selector:
app: frontend
ports:
- port: 80
targetPort: 3000
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
spec:
replicas: 2
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: frontend
image: nginx:alpine
ports:
- containerPort: 3000
---
# Backend API Service
apiVersion: v1
kind: Service
metadata:
name: backend-api
spec:
selector:
app: backend-api
ports:
- port: 8080
targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend-api
spec:
replicas: 3
selector:
matchLabels:
app: backend-api
template:
metadata:
labels:
app: backend-api
spec:
containers:
- name: api
image: myapi:v1
ports:
- containerPort: 8080
---
# Admin Service
apiVersion: v1
kind: Service
metadata:
name: admin
spec:
selector:
app: admin
ports:
- port: 3000
targetPort: 3000
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: admin
spec:
replicas: 1
selector:
matchLabels:
app: admin
template:
metadata:
labels:
app: admin
spec:
containers:
- name: admin
image: admin-panel:v1
ports:
- containerPort: 3000
配置 Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/rewrite-target: /$2
nginx.ingress.kubernetes.io/proxy-body-size: "10m"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
ingressClassName: nginx
tls:
- hosts:
- myapp.com
- api.myapp.com
- admin.myapp.com
secretName: myapp-tls
rules:
# 主站
- host: myapp.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend
port:
number: 80
# API
- host: api.myapp.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: backend-api
port:
number: 8080
# 管理后台
- host: admin.myapp.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: admin
port:
number: 3000
高级功能
金丝雀发布
# 主版本
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-main
spec:
ingressClassName: nginx
rules:
- host: myapp.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app-v1
port:
number: 80
---
# 金丝雀版本(10% 流量)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-canary
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "10"
spec:
ingressClassName: nginx
rules:
- host: myapp.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app-v2
port:
number: 80
基于 Header 的路由
metadata:
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "X-Canary"
nginx.ingress.kubernetes.io/canary-by-header-value: "true"
基本认证
# 创建密码文件
htpasswd -c auth admin
kubectl create secret generic basic-auth --from-file=auth
metadata:
annotations:
nginx.ingress.kubernetes.io/auth-type: basic
nginx.ingress.kubernetes.io/auth-secret: basic-auth
nginx.ingress.kubernetes.io/auth-realm: "Authentication Required"
速率限制
metadata:
annotations:
nginx.ingress.kubernetes.io/limit-rps: "10"
nginx.ingress.kubernetes.io/limit-connections: "5"
Cert-Manager 自动证书
安装 Cert-Manager
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.0/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: admin@example.com
privateKeySecretRef:
name: letsencrypt-prod
solvers:
- http01:
ingress:
class: nginx
使用自动证书
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
ingressClassName: nginx
tls:
- hosts:
- example.com
secretName: example-tls # Cert-Manager 会自动创建
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80
常用命令
# 查看 Ingress
kubectl get ingress
kubectl describe ingress <name>
# 查看 Ingress Controller 日志
kubectl logs -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx
# 测试 Ingress
kubectl get ingress <name> -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
# 删除 Ingress
kubectl delete ingress <name>
# 查看 Ingress Class
kubectl get ingressclass
最佳实践
1. 使用 Ingress Class
spec:
ingressClassName: nginx # 明确指定
2. 合理设置超时
metadata:
annotations:
nginx.ingress.kubernetes.io/proxy-read-timeout: "300"
nginx.ingress.kubernetes.io/proxy-send-timeout: "300"
3. 启用 HTTPS
metadata:
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
4. 设置资源限制
metadata:
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "10m"
5. 监控和日志
# 查看访问日志
kubectl logs -n ingress-nginx <pod-name>
# 监控指标
kubectl port-forward -n ingress-nginx <pod-name> 10254:10254
curl http://localhost:10254/metrics
小结
Ingress 是 Kubernetes 中实现 HTTP/HTTPS 路由的核心资源:
核心功能:
- 域名路由:基于域名转发
- 路径路由:基于 URL 路径转发
- TLS 终止:HTTPS 证书管理
- 高级路由:重写、重定向、金丝雀
组件:
- Ingress Controller:实现者(Nginx、Traefik、HAProxy)
- Ingress:路由规则定义
最佳实践:
- 使用 HTTPS 和自动证书
- 合理配置超时和限流
- 监控 Ingress Controller
- 使用金丝雀发布
下一章我们将学习资源管理,优化集群资源使用。