Subsections of Networking

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 高性能,企业级 大流量,高并发
Kong API 网关功能 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

对比表

维度 Ingress LoadBalancer NodePort
成本 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

功能 Ingress API 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 新标准吗? 🚀

Mar 7, 2024

Nginx 性能优化

从通用优化、操作系统层、Nginx 配置层、架构层等多个维度,为你详细梳理的方式。


一、操作系统与硬件层优化

这是优化的基础,为 Nginx 提供一个高性能的运行环境。

  1. 增加文件描述符限制 Nginx 每个连接(尤其是静态文件)都会消耗一个文件描述符。如果并发高,默认限制很容易成为瓶颈。

    # 临时生效
    ulimit -n 65536
    
    # 永久生效,修改 /etc/security/limits.conf
    * soft nofile 65536
    * hard nofile 65536
    
    # 同时,确保 nginx.conf 中使用了足够的 worker_rlimit_nofile
    worker_rlimit_nofile 65536;
  2. 优化网络栈

    • 调整 net.core.somaxconn: 定义等待 Nginx 接受的最大连接队列长度。如果遇到 accept() 队列溢出的错误,需要增加这个值。
      sysctl -w net.core.somaxconn=65535
      并在 Nginx 的 listen 指令中显式指定 backlog 参数:
      listen 80 backlog=65535;
    • 启用 TCP Fast Open: 减少 TCP 三次握手的延迟。
      sysctl -w net.ipv4.tcp_fastopen=3
    • 增大临时端口范围: 当 Nginx 作为反向代理时,它需要大量本地端口来连接上游服务器。
      sysctl -w net.ipv4.ip_local_port_range="1024 65535"
    • 减少 TCP TIME_WAIT 状态: 对于高并发短连接场景,大量连接处于 TIME_WAIT 状态会耗尽端口资源。
      # 启用 TIME_WAIT 复用
      sysctl -w net.ipv4.tcp_tw_reuse=1
      # 快速回收 TIME_WAIT 连接
      sysctl -w net.ipv4.tcp_tw_recycle=0 # 注意:在 NAT 环境下建议为 0,否则可能有问题
      # 增大 FIN_WAIT_2 状态的超时时间
      sysctl -w net.ipv4.tcp_fin_timeout=30
  3. 使用高性能磁盘 对于静态资源服务,使用 SSD 硬盘可以极大提升 IO 性能。


二、Nginx 配置优化

这是优化的核心,直接决定 Nginx 的行为。

  1. 工作进程与连接数

    • worker_processes auto;: 设置为 auto,让 Nginx 自动根据 CPU 核心数设置工作进程数,通常等于 CPU 核心数。
    • worker_connections: 每个工作进程可以处理的最大连接数。它与 worker_rlimit_nofile 共同决定了 Nginx 的总并发能力。
      events {
          worker_connections 10240; # 例如,设置为 10240
          use epoll; # 在 Linux 上使用高性能的 epoll 事件模型
      }
  2. 高效静态资源服务

    • 启用 sendfile: 绕过用户空间,直接在内核中完成文件数据传输,非常高效。
      sendfile on;
    • 启用 tcp_nopush: 与 sendfile on 一起使用,确保数据包被填满后再发送,提高网络效率。
      tcp_nopush on;
    • 启用 tcp_nodelay: 针对 keepalive 连接,强制立即发送数据,减少延迟。通常与 tcp_nopush 一起使用。
      tcp_nodelay on;
  3. 连接与请求超时 合理的超时设置可以释放闲置资源,避免连接被长期占用。

    # 客户端连接保持超时时间
    keepalive_timeout 30s;
    # 与上游服务器的保持连接超时时间
    proxy_connect_timeout 5s;
    proxy_send_timeout 60s;
    proxy_read_timeout 60s;
    # 客户端请求头读取超时
    client_header_timeout 15s;
    # 客户端请求体读取超时
    client_body_timeout 15s;
  4. 缓冲与缓存

    • 缓冲区优化: 为客户端请求头和请求体设置合适的缓冲区大小,避免 Nginx 写入临时文件,降低 IO。
      client_header_buffer_size 1k;
      large_client_header_buffers 4 4k;
      client_body_buffer_size 128k;
    • 代理缓冲区: 当 Nginx 作为反向代理时,控制从上游服务器接收数据的缓冲区。
      proxy_buffering on;
      proxy_buffer_size 4k;
      proxy_buffers 8 4k;
    • 启用缓存:
      • 静态资源缓存: 使用 expires 或 add_header 指令为静态资源设置长时间的浏览器缓存。
        location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
            expires 1y;
            add_header Cache-Control "public, immutable";
        }
      • 反向代理缓存: 使用 proxy_cache 模块缓存上游服务器的动态内容,极大减轻后端压力。
        proxy_cache_path /path/to/cache levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m;
        location / {
            proxy_cache my_cache;
            proxy_cache_valid 200 302 10m;
            proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
        }
  5. 日志优化

    • 禁用访问日志: 对于极高并发且不关心访问日志的场景,可以关闭 access_log。
    • 缓冲写入日志: 使用 buffer 参数让 Nginx 先将日志写入内存缓冲区,满后再刷入磁盘。
      access_log /var/log/nginx/access.log main buffer=64k flush=1m;
    • 记录关键信息: 精简日志格式,只记录必要字段。
  6. Gzip 压缩 对文本类型的响应进行压缩,减少网络传输量。

    gzip on;
    gzip_vary on;
    gzip_min_length 1024; # 小于此值不压缩
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
  7. 上游连接保持 当代理到后端服务时,使用 keepalive 保持一定数量的空闲连接,避免频繁建立和断开 TCP 连接的开销。

    upstream backend_servers {
        server 10.0.1.100:8080;
        keepalive 32; # 保持的空闲连接数
    }
    
    location / {
        proxy_pass http://backend_servers;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
    }

三、架构与部署优化

  1. 负载均衡 使用 Nginx 的 upstream 模块将流量分发到多个后端服务器,实现水平扩展和高可用。

    upstream app_cluster {
        least_conn; # 使用最少连接算法
        server 10.0.1.101:8080;
        server 10.0.1.102:8080;
        server 10.0.1.103:8080;
    }
  2. 动静分离 将静态资源(图片、CSS、JS)的请求与动态请求分开。可以让 Nginx 直接处理静态资源,而动态请求则代理给后端应用服务器(如 Tomcat, Node.js 等)。

  3. 启用 HTTP/2 HTTP/2 提供了多路复用、头部压缩等特性,能显著提升页面加载速度。

    listen 443 ssl http2;
  4. 使用第三方模块 根据需求编译第三方模块,如:

    • OpenResty: 基于 Nginx 和 LuaJIT,提供了强大的可编程能力。
    • ngx_brotli: 使用 Brotli 压缩算法,通常比 Gzip 压缩率更高。

四、监控与调试

优化不是一次性的,需要持续监控。

  1. 启用状态模块 使用 stub_status_module 来查看 Nginx 的基本状态信息。

    location /nginx_status {
        stub_status;
        allow 127.0.0.1; # 只允许本机访问
        deny all;
    }

    访问后可以看到活跃连接数、请求总数等信息。

  2. 分析日志 使用工具如 goaccess、awstats 分析访问日志,了解流量模式和瓶颈。

  3. 性能剖析 在极端情况下,可以使用 debug 日志或系统工具(如 perf, strace)进行深度性能剖析。

总结与建议

  1. 循序渐进: 不要一次性修改所有参数。一次只修改一两项,然后进行压测(如使用 wrk, ab, jmeter),观察效果。
  2. 监控先行: 在优化前、中、后都要有可靠的监控数据作为依据。
  3. 理解业务: 优化的策略很大程度上取决于业务类型。是高并发连接?是大文件下载?还是大量的短动态请求?
  4. 内核参数谨慎调整: 生产环境调整内核参数前,务必在测试环境充分验证。

通过以上这些方式的组合运用,你可以显著提升 Nginx 的性能和稳定性,使其能够轻松应对百万级别的并发连接。

Oct 7, 2024

Traefik VS Nginx

好的,这是一个非常经典的问题。Traefik 和 Nginx Ingress 都是 Kubernetes 生态中顶级的 Ingress Controller,但它们的设计哲学、使用体验和侧重点有显著不同。

简单来说:

  • Traefik 更像一个为云原生和微服务而生的动态、自动化的 API 网关。
  • Nginx Ingress 更像一个基于久经考验的 Nginx 的、高度可配置的强大、稳定的反向代理/负载均衡器。

下面我们详细对比一下 Traefik 相对于 Nginx Ingress 的主要优点。

Traefik 的核心优点

1. 极致的动态配置与自动化

这是 Traefik 最核心的卖点。

  • 工作原理:Traefik 会主动监听 Kubernetes API Server,实时感知 Service、Ingress Route、Secret 等资源的变化。一旦你创建或修改了一个 Ingress 资源,Traefik 几乎在秒级内自动更新其路由配置,无需任何重启或重载操作。
  • Nginx Ingress 的对比:Nginx Ingress 通常需要一个名为 nginx-ingress-controller 的组件来监控变化,然后生成一个新的 nginx.conf 配置文件,最后通过向 Nginx 进程发送 reload 信号来加载新配置。虽然这个过程也很快,但它本质上是一个 “生成-重载” 模型,在超大流量或配置复杂时,重载可能带来微小的性能抖动或延迟。

结论:在追求完全自动化和零重载的云原生环境中,Traefik 的动态模型更具吸引力。

2. 简化的配置模型与 “IngressRoute” CRD

Traefik 完美支持标准的 Kubernetes Ingress 资源,但它更推荐使用自己定义的 Custom Resource Definition (CRD),叫做 IngressRoute。

  • 为什么更好:标准的 Ingress 资源功能相对有限,很多高级特性(如重试、限流、断路器、请求镜像等)需要通过繁琐的 annotations 来实现,可读性和可维护性差。
  • Traefik 的 IngressRoute:它提供了一种声明式的、结构化的 YAML/JSON 配置方式。所有配置(包括 TLS、中间件、路由规则)都以清晰的结构定义在同一个 CRD 中,更符合 Kubernetes 的原生哲学,也更容易进行版本控制和代码审查。

示例对比: 使用 Nginx Ingress 的注解来实现路径重写:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /

使用 Traefik 的 IngressRoute 和中间件:

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: my-ingressroute
spec:
  routes:
  - match: PathPrefix(`/api`)
    kind: Rule
    services:
    - name: my-service
      port: 80
    middlewares:
    - name: strip-prefix # 使用一个独立的、可复用的中间件资源
---
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: strip-prefix
spec:
  stripPrefix:
    prefixes:
      - /api

可以看到,Traefik 的配置更加模块化和清晰。

3. 内置的、功能丰富的 Dashboard

Traefik 自带一个非常直观的 Web UI 控制台。只需简单启用,你就可以在浏览器中实时查看所有的路由器(Routers)、服务(Services)和中间件(Middlewares),以及它们的健康状况和配置关系。

  • 这对于开发和调试来说是巨大的福音。你可以一目了然地看到流量是如何被路由的,而无需去解析复杂的配置文件或命令行输出。
  • Nginx Ingress 官方不提供图形化 Dashboard。虽然可以通过第三方工具(如 Prometheus + Grafana)来监控,或者使用 kubectl 命令来查询状态,但远不如 Traefik 的原生 Dashboard 直观方便。

4. 原生支持多种后端提供者

Traefik 的设计是多提供者的。除了 Kubernetes,它还可以同时从 Docker、Consul、Etcd、Rancher 或者一个简单的静态文件中读取配置。 如果你的技术栈是混合的(例如,部分服务在 K8s,部分服务使用 Docker Compose),Traefik 可以作为一个统一的入口点,简化你的架构。

Nginx Ingress 虽然也可以通过其他方式扩展,但其核心是为 Kubernetes 设计的。

5. 中间件模式的强大与灵活

Traefik 的 “中间件” 概念非常强大。它允许你将各种功能(如认证、限流、头信息修改、重定向、断路器等)定义为独立的、可复用的组件。然后,你可以在任何路由规则上通过引用的方式组合使用这些中间件。

这种模式极大地增强了配置的复用性和灵活性,是构建复杂流量策略的理想选择。

Nginx Ingress 的优势领域(作为平衡参考)

为了做出全面选择,了解 Nginx Ingress 的优势也很重要:

  1. 极致的性能与稳定性:基于世界上最成熟的 Web 服务器 Nginx,在处理超高并发静态内容和长连接方面,经过了几十年的实战考验,性能和稳定性极高。
  2. 功能极其丰富:Nginx 本身的功能集非常庞大,加上 Nginx Ingress Controller 提供了大量的注解来暴露这些功能,其能力上限在某些方面可能高于 Traefik。
  3. 庞大的社区与生态:Nginx 的用户基数巨大,你遇到的任何问题几乎都能在网上找到解决方案或经验分享。
  4. 精细化控制:对于深度 Nginx 专家,可以通过 ConfigMap 注入自定义的 Nginx 配置片段,实现几乎任何你想要的功能,可控性极强。
  5. Apache 许可:Nginx 是 Apache 2.0 许可证,而 Traefik v2 之后使用的是限制更多的 Source Available 许可证(虽然对大多数用户免费,但会引起一些大公司的合规顾虑)。Nginx Ingress 完全没有这个问题。

总结与选型建议

特性 Traefik Nginx Ingress
配置模型 动态、自动化,无需重载 “生成-重载”模型
配置语法 声明式 CRD,结构清晰 主要依赖 Annotations,较繁琐
Dashboard 内置,功能强大,开箱即用 无官方 UI,需第三方集成
设计哲学 云原生优先,微服务友好 功能与性能优先,稳健可靠
学习曲线 较低,易于上手和运维 中等,需要了解 Nginx 概念
性能 优秀,足以满足绝大多数场景 极致,尤其在静态内容和大并发场景
可扩展性 通过中间件,模块化程度高 通过 Lua 脚本或自定义模板,功能上限高
许可证 Source Available(可能有限制) Apache 2.0(完全开源)

如何选择?

  • 选择 Traefik,如果:

    • 你追求极致的云原生体验,希望配置简单、自动化。
    • 你的团队更青睐 Kubernetes 原生的声明式配置方式。
    • 你非常看重内置的 Dashboard 用于日常运维和调试。
    • 你的应用架构是动态的,服务频繁发布和变更。
    • 你的场景不需要压榨到极致的性能,更看重开发效率和运维简便性。
  • 选择 Nginx Ingress,如果:

    • 你对性能和稳定性有极致要求(例如,超大规模网关、CDN边缘节点)。
    • 你需要使用非常复杂或小众的 Nginx 功能,需要精细化的控制。
    • 你的团队已经对 Nginx 非常熟悉,有深厚的知识积累。
    • 你对开源许可证有严格要求,必须使用 Apache 2.0 等宽松许可证。
    • 你的环境相对稳定,不需要频繁更新路由配置。

总而言之,Traefik 胜在“体验”和“自动化”,是现代微服务和云原生环境的理想伴侣。而 Nginx Ingress 胜在“性能”和“功能深度”,是一个经过千锤百炼的、可靠的强大引擎。