一、简介与核心作用
Ingress 是 K8S 暴露 HTTP/HTTPS 服务的标准方式,核心价值:七层负载均衡 + 域名/路径路由。
| 对比项 | ClusterIP | NodePort | Ingress |
|---|---|---|---|
| 暴露范围 | 集群内部 | 节点端口 | 外部 HTTP/HTTPS |
| 路由能力 | 无 | 无 | 域名+路径+Header |
| SSL 终止 | 手动 | 手动 | 自动 |
| 依赖组件 | 无 | 无 | Ingress Controller |
二、工作原理
plaintext
请求流程: 用户 → DNS → Ingress Controller → Service → Pod
↓
解析 host/path 执行路由
执行 TLS 终止
生成 Nginx 配置
plaintext
┌────────────────────────────────────────────────────────────────────────────┐
│ Ingress Controller 架构 │
├────────────────────────────────────────────────────────────────────────────┤
│ K8s API Server: Ingress ← Service ← Endpoints ← Secret(TLS) │
│ ↓ List/Watch │
│ Ingress Controller: Config Reloader → nginx.conf → Nginx Worker │
└────────────────────────────────────────────────────────────────────────────┘
三、关键 YAML 配置
3.1 基础 Ingress(域名+路径路由)
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: multi-service-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
ingressClassName: nginx
rules:
- host: api.example.com
http:
paths:
- path: /users
pathType: Prefix
backend:
service:
name: user-service
port:
number: 80
- path: /orders
pathType: Prefix
backend:
service:
name: order-service
port:
number: 80
- path: /
pathType: Prefix
backend:
service:
name: default-backend
port:
number: 80
3.2 TLS 配置
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tls-ingress
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- api.example.com
secretName: example-tls
rules:
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-service
port:
number: 443
bash
kubectl create secret tls example-tls --cert=server.crt --key=server.key
3.3 Ingress Controller(DaemonSet + hostNetwork)
yaml
apiVersion: v1
kind: Namespace
metadata:
name: ingress-nginx
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: ingress-nginx
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: ingress-nginx
rules:
- apiGroups: [""]
resources: ["configmaps", "endpoints", "pods", "secrets"]
verbs: ["list", "watch"]
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get"]
- apiGroups: ["networking.k8s.io"]
resources: ["ingresses", "ingressclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: ingress-nginx
subjects:
- kind: ServiceAccount
name: ingress-nginx
namespace: ingress-nginx
---
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: nginx
annotations:
ingressclass.kubernetes.io/is-default-class: "true"
spec:
controller: k8s.io/ingress-nginx
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: ingress-nginx-controller
namespace: ingress-nginx
spec:
selector:
matchLabels:
app: ingress-nginx
template:
metadata:
labels:
app: ingress-nginx
spec:
serviceAccountName: ingress-nginx
hostNetwork: true
dnsPolicy: ClusterFirstWithHostNet
containers:
- name: controller
image: registry.k8s.io/ingress-nginx/controller:v1.9.4
args:
- /nginx-ingress-controller
- --election-id=ingress-controller-leader
- --controller-class=k8s.io/ingress-nginx
- --ingress-class=nginx
- --configmap=$(POD_NAMESPACE)/nginx-configuration
securityContext:
capabilities:
drop: ["ALL"]
add: ["NET_BIND_SERVICE"]
runAsUser: 101
ports:
- name: http
containerPort: 80
hostPort: 80
- name: https
containerPort: 443
hostPort: 443
livenessProbe:
httpGet:
path: /healthz
port: 10254
initialDelaySeconds: 10
---
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-configuration
namespace: ingress-nginx
data:
proxy-body-size: "50m"
proxy-read-timeout: "300"
use-forwarded-headers: "true"
3.4 路径重写
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: rewrite-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
nginx.ingress.kubernetes.io/use-regex: "true"
spec:
ingressClassName: nginx
rules:
- host: app.example.com
http:
paths:
# /api/v1/users → 后端收到 /v1/users
- path: /api(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: api-service
port:
number: 80
3.5 金丝雀发布
yaml
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: "always"
四、常用操作命令
bash
kubectl get ingress -n default # 查看 Ingress
kubectl get ing -A # 全命名空间
kubectl describe ingress <name> # 查看详情
# 查看 Nginx 配置
kubectl exec -n ingress-nginx \
$(kubectl get pods -n ingress-nginx -l app=ingress-nginx -o name) \
-- cat /etc/nginx/conf.d/default.conf
kubectl logs -n ingress-nginx -l app=ingress-nginx -f # 实时日志
curl -H "Host: api.example.com" http://<node-ip>/users # 测试
# 检查 Endpoints
kubectl get endpoints -n default
# 重启加载配置
kubectl delete pod -n ingress-nginx -l app=ingress-nginx
五、常见问题与排查
5.1 404/502/503 错误
plaintext
排查步骤:
1. kubectl describe ing <name> # 检查规则
2. kubectl get svc && kubectl get endpoints # 检查后端
3. kubectl get pods -o wide # 检查 Pod 状态
4. 检查 pathType: Prefix/Exact vs 实际路径
5. 检查 rewrite-target 配置
常见原因:
bash
# Service Selector 与 Pod Labels 不匹配
kubectl get svc api-service -o yaml | grep selector
kubectl get pods -l app=api --show-labels
# 路径末尾斜杠: /users ≠ /users/
5.2 TLS 证书问题
bash
# 检查证书
kubectl get secret example-tls -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -no_text -enddate
# 常见错误:
# - secret 与 Ingress 不在同一 namespace
# - 类型应为 kubernetes.io/tls
# - 证书 CN/SAN 与 host 不匹配
5.3 路径匹配不生效
yaml
# pathType:
# Prefix: /users 匹配 /users, /users/, /users/123
# Exact: /users 仅精确匹配 /users
# 正则匹配:
annotations:
nginx.ingress.kubernetes.io/use-regex: "true"
# path: /api(/|$)(.*) + rewrite-target: /$2
六、最佳实践
-
hostNetwork + DaemonSet:性能最优,高可用
-
IngressClass 设为默认:
yaml
annotations: ingressclass.kubernetes.io/is-default-class: "true" -
路径重写 :统一用
use-regex+rewrite-target -
TLS 强制跳转:
yaml
annotations: nginx.ingress.kubernetes.io/ssl-redirect: "true" nginx.ingress.kubernetes.io/force-ssl-redirect: "true" -
健康检查:Controller 和后端 Pod 必须配置
-
ConfigMap 全局配置:
yaml
data: proxy-body-size: "50m" proxy-read-timeout: "300" -
IP 白名单:
yaml
nginx.ingress.kubernetes.io/whitelist-source-range: "10.0.0.0/8" -
cert-manager:自动管理证书续期
核心命令速查:
bash
kubectl get ing -A # 查看所有
kubectl describe ing <name> # 详情
kubectl logs -n ingress-nginx -l app=ingress-nginx -f # 日志