Ingress

Kubernetes Ingress 原理详解

Ingress 是 Kubernetes 中用于管理集群外部访问集群内服务的 API 对象,提供 HTTP/HTTPS 路由功能。


🎯 Ingress 的作用

没有 Ingress 的问题

问题 1:每个服务需要一个 LoadBalancer
┌────────────────────────────────────┐
│  Service A (LoadBalancer)  $$$     │
│  Service B (LoadBalancer)  $$$     │
│  Service C (LoadBalancer)  $$$     │
└────────────────────────────────────┘
成本高、管理复杂、IP 地址浪费

问题 2:无法基于域名/路径路由
客户端 → NodePort:30001 (Service A)
客户端 → NodePort:30002 (Service B)
需要记住不同的端口,不友好

使用 Ingress 的方案

单一入口 + 智能路由
┌───────────────────────────────────────┐
│         Ingress Controller            │
│    (一个 LoadBalancer 或 NodePort)    │
└───────────┬───────────────────────────┘
            │ 根据域名/路径路由
    ┌───────┴───────┬──────────┐
    ▼               ▼          ▼
Service A       Service B   Service C
(ClusterIP)     (ClusterIP) (ClusterIP)

🏗️ Ingress 架构组成

核心组件

┌─────────────────────────────────────────────┐
│              Ingress 生态系统                │
├─────────────────────────────────────────────┤
│  1. Ingress Resource (资源对象)             │
│     └─ 定义路由规则(YAML)                   │
│                                              │
│  2. Ingress Controller (控制器)             │
│     └─ 读取 Ingress,配置负载均衡器          │
│                                              │
│  3. 负载均衡器 (Nginx/Traefik/HAProxy)      │
│     └─ 实际处理流量的组件                   │
└─────────────────────────────────────────────┘

📋 Ingress Resource (资源定义)

基础示例

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  # 1. 基于域名路由
  rules:
  - host: example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-service
            port:
              number: 80
  
  # 2. TLS/HTTPS 配置
  tls:
  - hosts:
    - example.com
    secretName: example-tls

完整功能示例

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: advanced-ingress
  namespace: default
  annotations:
    # Nginx 特定配置
    nginx.ingress.kubernetes.io/rewrite-target: /$2
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/rate-limit: "100"
    # 自定义响应头
    nginx.ingress.kubernetes.io/configuration-snippet: |
      add_header X-Custom-Header "Hello from Ingress";
spec:
  # IngressClass (指定使用哪个 Ingress Controller)
  ingressClassName: nginx
  
  # TLS 配置
  tls:
  - hosts:
    - app.example.com
    - api.example.com
    secretName: example-tls-secret
  
  # 路由规则
  rules:
  # 规则 1:app.example.com
  - host: app.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: frontend-service
            port:
              number: 80
  
  # 规则 2:api.example.com
  - host: api.example.com
    http:
      paths:
      # /v1/* 路由到 api-v1
      - path: /v1
        pathType: Prefix
        backend:
          service:
            name: api-v1-service
            port:
              number: 8080
      
      # /v2/* 路由到 api-v2
      - path: /v2
        pathType: Prefix
        backend:
          service:
            name: api-v2-service
            port:
              number: 8080
  
  # 规则 3:默认后端(可选)
  defaultBackend:
    service:
      name: default-backend
      port:
        number: 80

🎛️ PathType (路径匹配类型)

三种匹配类型

PathType匹配规则示例
Prefix前缀匹配/foo 匹配 /foo, /foo/, /foo/bar
Exact精确匹配/foo 只匹配 /foo,不匹配 /foo/
ImplementationSpecific由 Ingress Controller 决定取决于实现

示例对比

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: path-types-demo
spec:
  rules:
  - host: example.com
    http:
      paths:
      # Prefix 匹配
      - path: /api
        pathType: Prefix
        backend:
          service:
            name: api-service
            port:
              number: 8080
      # 匹配:
      # ✅ /api
      # ✅ /api/
      # ✅ /api/users
      # ✅ /api/v1/users
      
      # Exact 匹配
      - path: /login
        pathType: Exact
        backend:
          service:
            name: auth-service
            port:
              number: 80
      # 匹配:
      # ✅ /login
      # ❌ /login/
      # ❌ /login/oauth

🚀 Ingress Controller (控制器)

常见 Ingress Controller

Controller特点适用场景
Nginx Ingress最流行,功能强大通用场景,生产推荐
Traefik云原生,动态配置微服务,自动服务发现
HAProxy高性能,企业级大流量,高并发
KongAPI 网关功能API 管理,插件生态
Istio Gateway服务网格集成复杂微服务架构
AWS ALB云原生(AWS)AWS 环境
GCE云原生(GCP)GCP 环境

🔧 Ingress Controller 工作原理

核心流程

┌─────────────────────────────────────────────┐
│  1. 用户创建/更新 Ingress Resource          │
│     kubectl apply -f ingress.yaml           │
└────────────────┬────────────────────────────┘
                 │
                 ▼
┌─────────────────────────────────────────────┐
│  2. Ingress Controller 监听 API Server      │
│     - Watch Ingress 对象                    │
│     - Watch Service 对象                    │
│     - Watch Endpoints 对象                  │
└────────────────┬────────────────────────────┘
                 │
                 ▼
┌─────────────────────────────────────────────┐
│  3. 生成配置文件                             │
│     Nginx:  /etc/nginx/nginx.conf          │
│     Traefik: 动态配置                       │
│     HAProxy: /etc/haproxy/haproxy.cfg      │
└────────────────┬────────────────────────────┘
                 │
                 ▼
┌─────────────────────────────────────────────┐
│  4. 重载/更新负载均衡器                      │
│     nginx -s reload                         │
└────────────────┬────────────────────────────┘
                 │
                 ▼
┌─────────────────────────────────────────────┐
│  5. 流量路由生效                             │
│     客户端请求 → Ingress → Service → Pod    │
└─────────────────────────────────────────────┘

📦 部署 Nginx Ingress Controller

方式 1:使用官方 Helm Chart (推荐)

# 添加 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 \
  --set controller.service.type=LoadBalancer

# 查看部署状态
kubectl get pods -n ingress-nginx
kubectl get svc -n ingress-nginx

方式 2:使用 YAML 部署

# 下载官方 YAML
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/cloud/deploy.yaml

# 查看部署
kubectl get all -n ingress-nginx

核心组件

# 1. Deployment - Ingress Controller Pod
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ingress-nginx-controller
  namespace: ingress-nginx
spec:
  replicas: 2  # 高可用建议 2+
  selector:
    matchLabels:
      app.kubernetes.io/name: ingress-nginx
  template:
    metadata:
      labels:
        app.kubernetes.io/name: ingress-nginx
    spec:
      serviceAccountName: ingress-nginx
      containers:
      - name: controller
        image: registry.k8s.io/ingress-nginx/controller:v1.9.0
        args:
        - /nginx-ingress-controller
        - --election-id=ingress-nginx-leader
        - --controller-class=k8s.io/ingress-nginx
        - --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
        ports:
        - name: http
          containerPort: 80
        - name: https
          containerPort: 443
        livenessProbe:
          httpGet:
            path: /healthz
            port: 10254
        readinessProbe:
          httpGet:
            path: /healthz
            port: 10254

---
# 2. Service - 暴露 Ingress Controller
apiVersion: v1
kind: Service
metadata:
  name: ingress-nginx-controller
  namespace: ingress-nginx
spec:
  type: LoadBalancer  # 或 NodePort
  ports:
  - name: http
    port: 80
    targetPort: 80
    protocol: TCP
  - name: https
    port: 443
    targetPort: 443
    protocol: TCP
  selector:
    app.kubernetes.io/name: ingress-nginx

---
# 3. ConfigMap - Nginx 全局配置
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
  namespace: ingress-nginx
data:
  # 自定义 Nginx 配置
  proxy-body-size: "100m"
  proxy-connect-timeout: "15"
  proxy-read-timeout: "600"
  proxy-send-timeout: "600"
  use-forwarded-headers: "true"

🌐 完整流量路径

请求流程详解

客户端
  │ 1. DNS 解析
  │    example.com → LoadBalancer IP (1.2.3.4)
  ▼
LoadBalancer / NodePort
  │ 2. 转发到 Ingress Controller Pod
  ▼
Ingress Controller (Nginx Pod)
  │ 3. 读取 Ingress 规则
  │    Host: example.com
  │    Path: /api/users
  │ 4. 匹配规则
  │    rule: host=example.com, path=/api
  │    backend: api-service:8080
  ▼
Service (api-service)
  │ 5. Service 选择器匹配 Pod
  │    selector: app=api
  │ 6. 查询 Endpoints
  │    endpoints: 10.244.1.5:8080, 10.244.2.8:8080
  │ 7. 负载均衡(默认轮询)
  ▼
Pod (api-xxxx)
  │ 8. 容器处理请求
  │    Container Port: 8080
  ▼
应用响应
  │ 9. 原路返回
  ▼
客户端收到响应

网络数据包追踪

# 客户端发起请求
curl -H "Host: example.com" http://1.2.3.4/api/users

# 1. DNS 解析
example.com → 1.2.3.4 (LoadBalancer External IP)

# 2. TCP 连接
Client:54321 → LoadBalancer:80

# 3. LoadBalancer 转发
LoadBalancer:80 → Ingress Controller Pod:80 (10.244.0.5:80)

# 4. Ingress Controller 内部处理
Nginx 读取配置:
  location /api {
    proxy_pass http://api-service.default.svc.cluster.local:8080;
  }

# 5. 查询 Service
kube-proxy/iptables 规则:
  api-service:8080 → Endpoints

# 6. 负载均衡到 Pod
10.244.0.5 → 10.244.1.5:8080 (Pod IP)

# 7. 响应返回
Pod → Ingress Controller → LoadBalancer → Client

🔒 HTTPS/TLS 配置

创建 TLS Secret

# 方式 1:使用自签名证书(测试环境)
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout tls.key -out tls.crt \
  -subj "/CN=example.com"

kubectl create secret tls example-tls \
  --cert=tls.crt \
  --key=tls.key

# 方式 2:使用 Let's Encrypt (生产环境,推荐)
# 安装 cert-manager
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.0/cert-manager.yaml

# 创建 ClusterIssuer
kubectl apply -f - <<EOF
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
EOF

配置 HTTPS Ingress

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: https-ingress
  annotations:
    # 自动重定向 HTTP 到 HTTPS
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    # 使用 cert-manager 自动申请证书
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - example.com
    - www.example.com
    secretName: example-tls  # cert-manager 会自动创建这个 Secret
  rules:
  - host: example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-service
            port:
              number: 80

验证 HTTPS

# 检查证书
curl -v https://example.com

# 查看 Secret
kubectl get secret example-tls
kubectl describe secret example-tls

# 测试 HTTP 自动重定向
curl -I http://example.com
# HTTP/1.1 308 Permanent Redirect
# Location: https://example.com/

🎨 高级路由场景

场景 1:基于路径的路由

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: path-based-routing
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
  rules:
  - host: myapp.com
    http:
      paths:
      # /api/v1/* → api-v1-service
      - path: /api/v1(/|$)(.*)
        pathType: Prefix
        backend:
          service:
            name: api-v1-service
            port:
              number: 8080
      
      # /api/v2/* → api-v2-service
      - path: /api/v2(/|$)(.*)
        pathType: Prefix
        backend:
          service:
            name: api-v2-service
            port:
              number: 8080
      
      # /admin/* → admin-service
      - path: /admin
        pathType: Prefix
        backend:
          service:
            name: admin-service
            port:
              number: 3000
      
      # /* → frontend-service (默认)
      - path: /
        pathType: Prefix
        backend:
          service:
            name: frontend-service
            port:
              number: 80

场景 2:基于子域名的路由

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: subdomain-routing
spec:
  rules:
  # www.example.com
  - host: www.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: website-service
            port:
              number: 80
  
  # api.example.com
  - host: api.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: api-service
            port:
              number: 8080
  
  # blog.example.com
  - host: blog.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: blog-service
            port:
              number: 80
  
  # *.dev.example.com (通配符)
  - host: "*.dev.example.com"
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: dev-environment
            port:
              number: 80

场景 3:金丝雀发布 (Canary Deployment)

# 主版本 Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: production
spec:
  rules:
  - host: myapp.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: app-v1
            port:
              number: 80

---
# 金丝雀版本 Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: canary
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    # 10% 流量到金丝雀版本
    nginx.ingress.kubernetes.io/canary-weight: "10"
    
    # 或基于请求头
    # nginx.ingress.kubernetes.io/canary-by-header: "X-Canary"
    # nginx.ingress.kubernetes.io/canary-by-header-value: "always"
    
    # 或基于 Cookie
    # nginx.ingress.kubernetes.io/canary-by-cookie: "canary"
spec:
  rules:
  - host: myapp.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: app-v2-canary
            port:
              number: 80

场景 4:A/B 测试

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ab-testing
  annotations:
    # 基于请求头进行 A/B 测试
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-by-header: "X-Version"
    nginx.ingress.kubernetes.io/canary-by-header-value: "beta"
spec:
  rules:
  - host: myapp.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: app-beta
            port:
              number: 80
# 普通用户访问 A 版本
curl http://myapp.com

# Beta 用户访问 B 版本
curl -H "X-Version: beta" http://myapp.com

🔧 常用 Annotations (Nginx)

基础配置

metadata:
  annotations:
    # SSL 重定向
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    
    # 强制 HTTPS
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
    
    # 后端协议
    nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"  # 或 HTTP, GRPC
    
    # 路径重写
    nginx.ingress.kubernetes.io/rewrite-target: /$2
    
    # URL 重写
    nginx.ingress.kubernetes.io/use-regex: "true"

高级配置

metadata:
  annotations:
    # 上传文件大小限制
    nginx.ingress.kubernetes.io/proxy-body-size: "100m"
    
    # 超时配置
    nginx.ingress.kubernetes.io/proxy-connect-timeout: "600"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
    
    # 会话保持 (Sticky Session)
    nginx.ingress.kubernetes.io/affinity: "cookie"
    nginx.ingress.kubernetes.io/session-cookie-name: "route"
    nginx.ingress.kubernetes.io/session-cookie-expires: "172800"
    nginx.ingress.kubernetes.io/session-cookie-max-age: "172800"
    
    # 限流
    nginx.ingress.kubernetes.io/limit-rps: "100"  # 每秒请求数
    nginx.ingress.kubernetes.io/limit-connections: "10"  # 并发连接数
    
    # CORS 配置
    nginx.ingress.kubernetes.io/enable-cors: "true"
    nginx.ingress.kubernetes.io/cors-allow-origin: "*"
    nginx.ingress.kubernetes.io/cors-allow-methods: "GET, POST, PUT, DELETE, OPTIONS"
    
    # 白名单
    nginx.ingress.kubernetes.io/whitelist-source-range: "10.0.0.0/8,192.168.0.0/16"
    
    # 基本认证
    nginx.ingress.kubernetes.io/auth-type: basic
    nginx.ingress.kubernetes.io/auth-secret: basic-auth
    nginx.ingress.kubernetes.io/auth-realm: "Authentication Required"
    
    # 自定义 Nginx 配置片段
    nginx.ingress.kubernetes.io/configuration-snippet: |
      more_set_headers "X-Custom-Header: MyValue";
      add_header X-Request-ID $request_id;

🛡️ 安全配置

1. 基本认证

# 创建密码文件
htpasswd -c auth admin
# 输入密码

# 创建 Secret
kubectl create secret generic basic-auth --from-file=auth

# 应用到 Ingress
kubectl apply -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: secure-ingress
  annotations:
    nginx.ingress.kubernetes.io/auth-type: basic
    nginx.ingress.kubernetes.io/auth-secret: basic-auth
    nginx.ingress.kubernetes.io/auth-realm: "Authentication Required - Please enter your credentials"
spec:
  rules:
  - host: admin.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: admin-service
            port:
              number: 80
EOF

2. IP 白名单

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: whitelist-ingress
  annotations:
    # 只允许特定 IP 访问
    nginx.ingress.kubernetes.io/whitelist-source-range: "10.0.0.0/8,192.168.1.100/32"
spec:
  rules:
  - host: internal.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: internal-service
            port:
              number: 80

3. OAuth2 认证

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: oauth2-ingress
  annotations:
    nginx.ingress.kubernetes.io/auth-url: "https://oauth2-proxy.example.com/oauth2/auth"
    nginx.ingress.kubernetes.io/auth-signin: "https://oauth2-proxy.example.com/oauth2/start?rd=$escaped_request_uri"
spec:
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: protected-service
            port:
              number: 80

📊 监控和调试

查看 Ingress 状态

# 列出所有 Ingress
kubectl get ingress

# 详细信息
kubectl describe ingress example-ingress

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

# 查看生成的 Nginx 配置
kubectl exec -n ingress-nginx <ingress-controller-pod> -- cat /etc/nginx/nginx.conf

测试 Ingress 规则

# 测试域名解析
nslookup example.com

# 测试 HTTP
curl -H "Host: example.com" http://<ingress-ip>/

# 测试 HTTPS
curl -k -H "Host: example.com" https://<ingress-ip>/

# 查看响应头
curl -I -H "Host: example.com" http://<ingress-ip>/

# 测试特定路径
curl -H "Host: example.com" http://<ingress-ip>/api/users

常见问题排查

# 1. 检查 Ingress 是否有 Address
kubectl get ingress
# 如果 ADDRESS 列为空,说明 Ingress Controller 未就绪

# 2. 检查 Service 和 Endpoints
kubectl get svc
kubectl get endpoints

# 3. 检查 Ingress Controller Pod
kubectl get pods -n ingress-nginx
kubectl logs -n ingress-nginx <pod-name>

# 4. 检查 DNS 解析
kubectl run -it --rm debug --image=busybox --restart=Never -- nslookup example.com

# 5. 检查网络连通性
kubectl run -it --rm debug --image=curlimages/curl --restart=Never -- \
  curl -H "Host: example.com" http://web-service.default.svc.cluster.local

🎯 Ingress vs Service Type

对比表

维度IngressLoadBalancerNodePort
成本1 个 LB每个服务 1 个 LB免费
域名路由✅ 支持❌ 不支持❌ 不支持
路径路由✅ 支持❌ 不支持❌ 不支持
TLS 终止✅ 支持⚠️ 需要额外配置❌ 不支持
7 层功能✅ 丰富❌ 4 层❌ 4 层
适用场景HTTP/HTTPS 服务需要独立 LB 的服务开发测试

💡 关键要点总结

Ingress 的价值

  1. 成本优化:多个服务共享一个 LoadBalancer
  2. 智能路由:基于域名、路径的 7 层路由
  3. TLS 管理:集中管理 HTTPS 证书
  4. 高级功能:限流、认证、重写、CORS 等
  5. 易于管理:声明式配置,统一入口

核心概念

  • Ingress Resource:定义路由规则的 YAML
  • Ingress Controller:读取规则并实现路由的控制器
  • 负载均衡器:实际处理流量的组件(Nginx/Traefik/HAProxy)

典型使用场景

  • ✅ 微服务 API 网关
  • ✅ 多租户应用(基于子域名隔离)
  • ✅ 蓝绿部署/金丝雀发布
  • ✅ Web 应用统一入口
  • ❌ 非 HTTP 协议(如 TCP/UDP,考虑使用 Gateway API)

🚀 高级话题

1. IngressClass (多 Ingress Controller)

在同一集群中运行多个 Ingress Controller:

# 定义 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

---
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: traefik
spec:
  controller: traefik.io/ingress-controller

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

使用场景:

  • 内部服务使用 Nginx,外部服务使用 Traefik
  • 不同团队使用不同的 Ingress Controller
  • 按环境划分(dev 用 Traefik,prod 用 Nginx)

2. 默认后端 (Default Backend)

处理未匹配任何规则的请求:

# 创建默认后端服务
apiVersion: v1
kind: Service
metadata:
  name: default-backend
spec:
  selector:
    app: default-backend
  ports:
  - port: 80
    targetPort: 8080

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: default-backend
spec:
  replicas: 1
  selector:
    matchLabels:
      app: default-backend
  template:
    metadata:
      labels:
        app: default-backend
    spec:
      containers:
      - name: default-backend
        image: registry.k8s.io/defaultbackend-amd64:1.5
        ports:
        - containerPort: 8080

---
# 在 Ingress 中指定默认后端
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-with-default
spec:
  defaultBackend:
    service:
      name: default-backend
      port:
        number: 80
  rules:
  - host: example.com
    http:
      paths:
      - path: /app
        pathType: Prefix
        backend:
          service:
            name: app-service
            port:
              number: 80

效果:

  • 访问 example.com/app → app-service
  • 访问 example.com/other → default-backend(404 页面)
  • 访问 unknown.com → default-backend

3. ExternalName Service 与 Ingress

将 Ingress 路由到集群外部服务:

# 创建 ExternalName Service
apiVersion: v1
kind: Service
metadata:
  name: external-api
spec:
  type: ExternalName
  externalName: api.external-service.com  # 外部域名

---
# Ingress 路由到外部服务
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: external-ingress
  annotations:
    nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
    nginx.ingress.kubernetes.io/upstream-vhost: "api.external-service.com"
spec:
  rules:
  - host: myapp.com
    http:
      paths:
      - path: /external
        pathType: Prefix
        backend:
          service:
            name: external-api
            port:
              number: 443

使用场景:

  • 集成第三方 API
  • 混合云架构(部分服务在云外)
  • 灰度迁移(逐步从外部迁移到集群内)

4. 跨命名空间引用 (ExternalName 方式)

Ingress 默认只能引用同一命名空间的 Service,跨命名空间需要特殊处理:

# Namespace: backend
apiVersion: v1
kind: Service
metadata:
  name: api-service
  namespace: backend
spec:
  selector:
    app: api
  ports:
  - port: 8080

---
# Namespace: frontend
# 创建 ExternalName Service 指向 backend 命名空间的服务
apiVersion: v1
kind: Service
metadata:
  name: api-proxy
  namespace: frontend
spec:
  type: ExternalName
  externalName: api-service.backend.svc.cluster.local
  ports:
  - port: 8080

---
# Ingress 在 frontend 命名空间
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: cross-ns-ingress
  namespace: frontend
spec:
  rules:
  - host: myapp.com
    http:
      paths:
      - path: /api
        pathType: Prefix
        backend:
          service:
            name: api-proxy  # 引用同命名空间的 ExternalName Service
            port:
              number: 8080

5. TCP/UDP 服务暴露

Ingress 原生只支持 HTTP/HTTPS,对于 TCP/UDP 需要特殊配置:

Nginx Ingress Controller 的 TCP 配置

# ConfigMap 定义 TCP 服务
apiVersion: v1
kind: ConfigMap
metadata:
  name: tcp-services
  namespace: ingress-nginx
data:
  # 格式: "外部端口": "命名空间/服务名:服务端口"
  "3306": "default/mysql:3306"
  "6379": "default/redis:6379"
  "27017": "databases/mongodb:27017"

---
# 修改 Ingress Controller Service,暴露 TCP 端口
apiVersion: v1
kind: Service
metadata:
  name: ingress-nginx-controller
  namespace: ingress-nginx
spec:
  type: LoadBalancer
  ports:
  - name: http
    port: 80
    targetPort: 80
  - name: https
    port: 443
    targetPort: 443
  # 添加 TCP 端口
  - name: mysql
    port: 3306
    targetPort: 3306
  - name: redis
    port: 6379
    targetPort: 6379
  - name: mongodb
    port: 27017
    targetPort: 27017
  selector:
    app.kubernetes.io/name: ingress-nginx

---
# 修改 Ingress Controller Deployment,引用 ConfigMap
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ingress-nginx-controller
  namespace: ingress-nginx
spec:
  template:
    spec:
      containers:
      - name: controller
        args:
        - /nginx-ingress-controller
        - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
        # ...其他参数

访问方式:

# 连接 MySQL
mysql -h <ingress-lb-ip> -P 3306 -u root -p

# 连接 Redis
redis-cli -h <ingress-lb-ip> -p 6379

6. 灰度发布策略详解

基于权重的流量分配

# 生产版本 (90% 流量)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: production
spec:
  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: canary
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-weight: "10"
spec:
  rules:
  - host: myapp.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: app-v2
            port:
              number: 80

基于请求头的灰度

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: canary-header
  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"
spec:
  rules:
  - host: myapp.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: app-v2
            port:
              number: 80

测试:

# 普通用户访问 v1
curl http://myapp.com

# 带特殊请求头的用户访问 v2
curl -H "X-Canary: true" http://myapp.com
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: canary-cookie
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-by-cookie: "canary"
spec:
  rules:
  - host: myapp.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: app-v2
            port:
              number: 80

使用:

  • Cookie canary=always → 路由到 v2
  • Cookie canary=never → 路由到 v1
  • 无 Cookie → 根据权重路由

7. 性能优化

Nginx Ingress Controller 优化配置

apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
  namespace: ingress-nginx
data:
  # 工作进程数(建议等于 CPU 核心数)
  worker-processes: "auto"
  
  # 每个工作进程的连接数
  max-worker-connections: "65536"
  
  # 启用 HTTP/2
  use-http2: "true"
  
  # 启用 gzip 压缩
  use-gzip: "true"
  gzip-level: "6"
  gzip-types: "text/plain text/css application/json application/javascript text/xml application/xml"
  
  # 客户端请求体缓冲
  client-body-buffer-size: "128k"
  client-max-body-size: "100m"
  
  # Keepalive 连接
  keep-alive: "75"
  keep-alive-requests: "1000"
  
  # 代理缓冲
  proxy-buffer-size: "16k"
  proxy-buffers: "4 16k"
  
  # 日志优化(生产环境可以禁用访问日志)
  disable-access-log: "false"
  access-log-params: "buffer=16k flush=5s"
  
  # SSL 优化
  ssl-protocols: "TLSv1.2 TLSv1.3"
  ssl-ciphers: "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256"
  ssl-prefer-server-ciphers: "true"
  ssl-session-cache: "true"
  ssl-session-cache-size: "10m"
  ssl-session-timeout: "10m"
  
  # 启用连接复用
  upstream-keepalive-connections: "100"
  upstream-keepalive-timeout: "60"
  
  # 限制
  limit-req-status-code: "429"
  limit-conn-status-code: "429"

Ingress Controller Pod 资源配置

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ingress-nginx-controller
  namespace: ingress-nginx
spec:
  replicas: 3  # 高可用建议 3+
  template:
    spec:
      containers:
      - name: controller
        image: registry.k8s.io/ingress-nginx/controller:v1.9.0
        resources:
          requests:
            cpu: "500m"
            memory: "512Mi"
          limits:
            cpu: "2000m"
            memory: "2Gi"
        # 启用性能分析
        livenessProbe:
          httpGet:
            path: /healthz
            port: 10254
          initialDelaySeconds: 10
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /healthz
            port: 10254
          periodSeconds: 5

8. 监控和可观测性

Prometheus 监控集成

# ServiceMonitor for Prometheus Operator
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: ingress-nginx
  namespace: ingress-nginx
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: ingress-nginx
  endpoints:
  - port: metrics
    interval: 30s

查看 Ingress Controller 指标

# 访问 metrics 端点
kubectl port-forward -n ingress-nginx svc/ingress-nginx-controller-metrics 10254:10254

# 浏览器访问
http://localhost:10254/metrics

# 关键指标:
# - nginx_ingress_controller_requests: 请求总数
# - nginx_ingress_controller_request_duration_seconds: 请求延迟
# - nginx_ingress_controller_response_size: 响应大小
# - nginx_ingress_controller_ssl_expire_time_seconds: SSL 证书过期时间

Grafana 仪表盘

# 导入官方 Grafana 仪表盘
# Dashboard ID: 9614 (Nginx Ingress Controller)
# Dashboard ID: 11875 (Nginx Ingress Controller Request Handling Performance)

9. 故障排查清单

问题 1: Ingress 没有分配 Address

# 检查
kubectl get ingress
# NAME       CLASS   HOSTS         ADDRESS   PORTS   AGE
# my-app     nginx   example.com             80      5m

# 原因:
# 1. Ingress Controller 未运行
kubectl get pods -n ingress-nginx

# 2. Service type 不是 LoadBalancer
kubectl get svc -n ingress-nginx

# 3. 云提供商未分配 LoadBalancer IP
kubectl describe svc -n ingress-nginx ingress-nginx-controller

问题 2: 502 Bad Gateway

# 原因 1: 后端 Service 不存在
kubectl get svc

# 原因 2: 后端 Pod 不健康
kubectl get pods
kubectl describe pod <pod-name>

# 原因 3: 端口配置错误
kubectl get svc <service-name> -o yaml | grep -A 5 ports

# 原因 4: 网络策略阻止
kubectl get networkpolicies

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

问题 3: 503 Service Unavailable

# 原因: 没有健康的 Endpoints
kubectl get endpoints <service-name>

# 如果 ENDPOINTS 列为空:
# 1. 检查 Service selector 是否匹配 Pod labels
kubectl get svc <service-name> -o yaml | grep -A 3 selector
kubectl get pods --show-labels

# 2. 检查 Pod 是否 Ready
kubectl get pods

# 3. 检查容器端口是否正确
kubectl get pods <pod-name> -o yaml | grep -A 5 ports

问题 4: TLS 证书问题

# 检查 Secret 是否存在
kubectl get secret <tls-secret-name>

# 查看证书内容
kubectl get secret <tls-secret-name> -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -text -noout

# 检查证书过期时间
kubectl get secret <tls-secret-name> -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -noout -dates

# cert-manager 问题
kubectl get certificate
kubectl describe certificate <cert-name>
kubectl get certificaterequests

问题 5: 路由规则不生效

# 1. 检查 Ingress 配置
kubectl describe ingress <ingress-name>

# 2. 查看生成的 Nginx 配置
kubectl exec -n ingress-nginx <controller-pod> -- cat /etc/nginx/nginx.conf | grep -A 20 "server_name example.com"

# 3. 测试域名解析
nslookup example.com

# 4. 使用 Host header 测试
curl -v -H "Host: example.com" http://<ingress-ip>/path

# 5. 检查 annotations 是否正确
kubectl get ingress <ingress-name> -o yaml | grep -A 10 annotations

10. 生产环境最佳实践

✅ 高可用配置

# 1. 多副本 Ingress Controller
spec:
  replicas: 3
  
  # 2. Pod 反亲和性(分散到不同节点)
  affinity:
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app.kubernetes.io/name
            operator: In
            values:
            - ingress-nginx
        topologyKey: kubernetes.io/hostname

  # 3. PodDisruptionBudget(确保至少 2 个副本运行)
---
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: ingress-nginx
  namespace: ingress-nginx
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app.kubernetes.io/name: ingress-nginx

✅ 资源限制

resources:
  requests:
    cpu: "500m"
    memory: "512Mi"
  limits:
    cpu: "2"
    memory: "2Gi"

# HPA 自动扩缩容
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: ingress-nginx
  namespace: ingress-nginx
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: ingress-nginx-controller
  minReplicas: 3
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80

✅ 安全加固

# 1. 只暴露必要端口
# 2. 启用 TLS 1.2+
# 3. 配置安全头
metadata:
  annotations:
    nginx.ingress.kubernetes.io/configuration-snippet: |
      more_set_headers "X-Frame-Options: DENY";
      more_set_headers "X-Content-Type-Options: nosniff";
      more_set_headers "X-XSS-Protection: 1; mode=block";
      more_set_headers "Strict-Transport-Security: max-age=31536000; includeSubDomains";

# 4. 配置 WAF(Web Application Firewall)
nginx.ingress.kubernetes.io/enable-modsecurity: "true"
nginx.ingress.kubernetes.io/enable-owasp-core-rules: "true"

# 5. 限流保护
nginx.ingress.kubernetes.io/limit-rps: "100"
nginx.ingress.kubernetes.io/limit-burst-multiplier: "5"

✅ 监控告警

# Prometheus 告警规则示例
groups:
- name: ingress
  rules:
  - alert: IngressControllerDown
    expr: up{job="ingress-nginx-controller-metrics"} == 0
    for: 5m
    annotations:
      summary: "Ingress Controller is down"
  
  - alert: HighErrorRate
    expr: rate(nginx_ingress_controller_requests{status=~"5.."}[5m]) > 0.05
    for: 5m
    annotations:
      summary: "High 5xx error rate"
  
  - alert: HighLatency
    expr: histogram_quantile(0.95, nginx_ingress_controller_request_duration_seconds_bucket) > 1
    for: 10m
    annotations:
      summary: "High request latency (p95 > 1s)"

📚 总结对比:Ingress vs 其他方案

Ingress vs LoadBalancer Service

场景:部署 10 个微服务

方案 A:每个服务一个 LoadBalancer
- 成本:10 个 LoadBalancer × $20/月 = $200/月
- 管理:10 个独立的 IP 地址
- 路由:无智能路由
- TLS:每个服务单独配置

方案 B:一个 Ingress
- 成本:1 个 LoadBalancer × $20/月 = $20/月 ✅
- 管理:1 个 IP 地址 ✅
- 路由:基于域名/路径智能路由 ✅
- TLS:集中管理证书 ✅

Ingress vs API Gateway

功能IngressAPI Gateway (Kong/Tyk)
基础路由
认证鉴权⚠️ 基础✅ 完善
限流熔断⚠️ 基础✅ 高级
插件生态❌ 有限✅ 丰富
学习曲线✅ 简单⚠️ 复杂
性能✅ 高⚠️ 中等

🎓 学习路径建议

  1. 入门 (1-2 周)

    • 理解 Ingress 概念
    • 部署 Nginx Ingress Controller
    • 创建基本的 Ingress 规则
    • 配置 HTTP/HTTPS 访问
  2. 进阶 (2-4 周)

    • 掌握各种路由策略
    • TLS 证书管理(cert-manager)
    • 金丝雀发布
    • 性能调优
  3. 高级 (1-2 月)

    • 多 Ingress Controller 管理
    • WAF 和安全加固
    • 监控和告警
    • 故障排查
  4. 专家 (持续学习)

    • 源码阅读
    • 自定义插件开发
    • Gateway API 迁移

需要我详细展开某个特定主题,比如 cert-manager 自动化证书管理、Ingress Controller 源码分析,或者 Gateway API 新标准吗? 🚀