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高性能,企业级大流量,高并发
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 新标准吗? 🚀

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;
    • 启用缓存
      • 静态资源缓存: 使用 expiresadd_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. 分析日志 使用工具如 goaccessawstats 分析访问日志,了解流量模式和瓶颈。

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

总结与建议

  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 完全没有这个问题。

总结与选型建议

特性TraefikNginx 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 胜在“性能”和“功能深度”,是一个经过千锤百炼的、可靠的强大引擎。