Traefik 云原生反向代理与负载均衡部署实战
一、Traefik 简介
Traefik 是一款现代化的云原生边缘路由器,专为微服务和容器化环境设计。与传统的 Nginx、HAProxy 相比,Traefik 具有以下特点:
核心优势
| 特性 |
说明 |
| 自动服务发现 |
自动从 Docker、Kubernetes、Consul 等发现服务 |
| 动态配置 |
配置变更无需重启,实时生效 |
| 内置 Dashboard |
提供可视化的路由和中间件管理界面 |
| Let’s Encrypt |
自动申请和续期 HTTPS 证书 |
| 中间件系统 |
灵活的请求处理链(认证、限流、重写等) |
| 多后端支持 |
Docker、K8s、File、Consul、Etcd 等 |
架构组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| ┌─────────────────────────────────────────────────────────┐ │ Traefik Proxy │ ├─────────────────────────────────────────────────────────┤ │ Entrypoints │ Routers │ Middlewares │ Services │ │ (入口点) │ (路由) │ (中间件) │ (服务) │ └─────────────────────────────────────────────────────────┘ │ │ │ ▼ ▼ ▼ Port:80/443 路由规则 认证/限流/重写 │ │ │ └────────────────┴────────────────┘ │ ▼ ┌───────────────────────┐ │ Backend Services │ │ (Docker/K8s/Static) │ └───────────────────────┘
|
二、部署方式
方式 1:Docker Compose 部署(推荐开发环境)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| version: '3.8'
services: traefik: image: traefik:v3.0 container_name: traefik restart: unless-stopped security_opt: - no-new-privileges:true ports: - "80:80" - "443:443" - "8080:8080" volumes: - /etc/localtime:/etc/localtime:ro - /var/run/docker.sock:/var/run/docker.sock:ro - ./traefik:/etc/traefik:ro - ./letsencrypt:/letsencrypt command: - "--api.dashboard=true" - "--api.insecure=true" - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" - "--providers.file.directory=/etc/traefik" - "--providers.file.watch=true" - "--entrypoints.web.address=:80" - "--entrypoints.websecure.address=:443" - "--certificatesresolvers.letsencrypt.acme.tlschallenge=true" - "--certificatesresolvers.letsencrypt.acme.email=admin@example.com" - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json" labels: - "traefik.enable=true" - "traefik.http.routers.dashboard.rule=Host(`traefik.example.com`)" - "traefik.http.routers.dashboard.entrypoints=websecure" - "traefik.http.routers.dashboard.tls.certresolver=letsencrypt" - "traefik.http.routers.dashboard.service=api@internal" - "traefik.http.routers.dashboard.middlewares=auth" - "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$xyz$$abc"
networks: default: name: traefik-network external: true
|
启动命令:
1 2 3 4 5 6 7 8
| docker network create traefik-network
docker run --rm httpd:2.4 htpasswd -nb admin your_password
docker-compose up -d
|
方式 2:Kubernetes Helm 部署(推荐生产环境)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| helm repo add traefik https://traefik.github.io/charts helm repo update
cat > traefik-values.yaml << 'EOF' deployment: kind: Deployment replicas: 2
ports: web: port: 8000 expose: true exposedPort: 80 protocol: TCP websecure: port: 8443 expose: true exposedPort: 443 protocol: TCP tls: enabled: true certResolver: letsencrypt traefik: port: 9000 expose: true
providers: kubernetesCRD: enabled: true allowCrossNamespace: true kubernetesIngress: enabled: true
certificatesResolvers: letsencrypt: acme: email: admin@example.com storage: /data/acme.json tlsChallenge: {}
logs: general: level: INFO access: enabled: true
metrics: prometheus: entryPoint: metrics addEntryPointsLabels: true addRoutersLabels: true addServicesLabels: true
globalArguments: - "--global.checknewversion=false" - "--global.sendanonymoususage=false"
additionalArguments: - "--serversTransport.insecureSkipVerify=true" - "--api.dashboard=true" EOF
helm install traefik traefik/traefik \ -n traefik-system \ --create-namespace \ -f traefik-values.yaml
|
方式 3:Kubernetes CRD 部署(灵活配置)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
| apiVersion: v1 kind: Namespace metadata: name: traefik-system --- apiVersion: v1 kind: ServiceAccount metadata: name: traefik namespace: traefik-system --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: traefik rules: - apiGroups: [""] resources: ["services", "endpoints", "secrets"] verbs: ["get", "list", "watch"] - apiGroups: ["extensions", "networking.k8s.io"] resources: ["ingresses", "ingressclasses"] verbs: ["get", "list", "watch"] - apiGroups: ["extensions", "networking.k8s.io"] resources: ["ingresses/status"] verbs: ["update"] - apiGroups: ["traefik.io"] resources: ["middlewares", "middlewarestcp", "ingressroutes", "traefikservices", "healthcheckedservices", "ingressroutestcp", "ingressrouteudp", "tlsoptions", "tlsstores", "serverstransports"] verbs: ["get", "list", "watch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: traefik roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: traefik subjects: - kind: ServiceAccount name: traefik namespace: traefik-system --- apiVersion: v1 kind: Service metadata: name: traefik namespace: traefik-system annotations: service.beta.kubernetes.io/aws-load-balancer-type: "nlb" spec: type: LoadBalancer selector: app: traefik ports: - name: web port: 80 targetPort: 8000 - name: websecure port: 443 targetPort: 8443 - name: traefik port: 9000 targetPort: 9000 --- apiVersion: apps/v1 kind: Deployment metadata: name: traefik namespace: traefik-system labels: app: traefik spec: replicas: 2 selector: matchLabels: app: traefik template: metadata: labels: app: traefik spec: serviceAccountName: traefik terminationGracePeriodSeconds: 60 containers: - name: traefik image: traefik:v3.0 args: - "--api.dashboard=true" - "--providers.kubernetesCRD=true" - "--providers.kubernetesIngress=true" - "--entrypoints.web.address=:8000" - "--entrypoints.websecure.address=:8443" - "--certificatesresolvers.letsencrypt.acme.tlschallenge=true" - "--certificatesresolvers.letsencrypt.acme.email=admin@example.com" - "--certificatesresolvers.letsencrypt.acme.storage=/data/acme.json" - "--log.level=INFO" - "--accesslog=true" ports: - name: web containerPort: 8000 - name: websecure containerPort: 8443 - name: traefik containerPort: 9000 volumeMounts: - name: data mountPath: /data livenessProbe: httpGet: path: /ping port: traefik initialDelaySeconds: 10 periodSeconds: 10 readinessProbe: httpGet: path: /ping port: traefik initialDelaySeconds: 10 periodSeconds: 10 resources: requests: cpu: "100m" memory: "128Mi" limits: cpu: "500m" memory: "512Mi" volumes: - name: data emptyDir: {}
|
三、核心概念配置
1. EntryPoints(入口点)
入口点定义 Traefik 监听的端口和协议:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| entryPoints: web: address: ":80" forwardedHeaders: insecure: true proxyProtocol: insecure: true websecure: address: ":443" http: tls: certResolver: letsencrypt domains: - main: "example.com" sans: - "*.example.com" metrics: address: ":9090"
|
2. Routers(路由)
路由定义请求如何匹配和转发:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: web-app namespace: default spec: entryPoints: - web - websecure routes: - match: Host(`app.example.com`) kind: Rule services: - name: web-service port: 80 middlewares: - name: secure-headers - match: Host(`app.example.com`) && PathPrefix(`/api`) kind: Rule services: - name: api-service port: 8080 middlewares: - name: rate-limit tls: certResolver: letsencrypt
|
3. Services(服务)
服务定义后端目标:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| apiVersion: traefik.io/v1alpha1 kind: TraefikService metadata: name: weighted-service namespace: default spec: weighted: services: - name: web-v1 port: 80 weight: 90 - name: web-v2 port: 80 weight: 10
|
4. Middlewares(中间件)
中间件处理请求/响应:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
| apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: auth namespace: default spec: basicAuth: secret: auth-secret removeHeader: true
---
apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: rate-limit namespace: default spec: rateLimit: average: 100 burst: 50 sourceCriterion: requestHeaderName: X-Forwarded-For
---
apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: secure-headers namespace: default spec: headers: customRequestHeaders: X-Forwarded-Proto: "https" customResponseHeaders: X-Frame-Options: "DENY" X-Content-Type-Options: "nosniff" X-XSS-Protection: "1; mode=block" Strict-Transport-Security: "max-age=31536000; includeSubDomains" Content-Security-Policy: "default-src 'self'"
---
apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: strip-prefix namespace: default spec: stripPrefix: prefixes: - /api - /v1
---
apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: redirect-https namespace: default spec: redirectScheme: scheme: https permanent: true
---
apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: retry namespace: default spec: retry: attempts: 3 initialInterval: 100ms
|
四、实战场景
场景 1:多域名路由
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: multi-domain namespace: default spec: entryPoints: - websecure routes: - match: Host(`www.example.com`) kind: Rule services: - name: web-frontend port: 80 - match: Host(`api.example.com`) kind: Rule services: - name: api-backend port: 8080 - match: Host(`admin.example.com`) kind: Rule services: - name: admin-panel port: 3000 middlewares: - name: auth tls: certResolver: letsencrypt
|
场景 2:蓝绿部署
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| apiVersion: traefik.io/v1alpha1 kind: TraefikService metadata: name: app-bluegreen namespace: default spec: weighted: services: - name: app-blue port: 80 weight: 100 - name: app-green port: 80 weight: 0
---
apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: app-route namespace: default spec: entryPoints: - websecure routes: - match: Host(`app.example.com`) kind: Rule services: - name: app-bluegreen port: 80 tls: certResolver: letsencrypt
|
切换流量:
1 2 3 4 5
| kubectl patch traefikservice app-bluegreen -n default --type=json -p='[ {"op": "replace", "path": "/spec/weighted/services/0/weight", "value": 0}, {"op": "replace", "path": "/spec/weighted/services/1/weight", "value": 100} ]'
|
场景 3:金丝雀发布
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| apiVersion: traefik.io/v1alpha1 kind: TraefikService metadata: name: app-canary namespace: default spec: weighted: services: - name: app-stable port: 80 weight: 95 - name: app-canary port: 80 weight: 5
|
场景 4:API 网关(认证 + 限流)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: oauth namespace: default spec: forwardAuth: address: "http://oauth2-proxy:4180" trustForwardHeader: true authResponseHeaders: - X-Forwarded-User - X-Forwarded-Email
---
apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: api-ratelimit namespace: default spec: rateLimit: average: 50 burst: 100 sourceCriterion: requestHeaderName: X-API-Key
---
apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: api-gateway namespace: default spec: entryPoints: - websecure routes: - match: Host(`api.example.com`) && PathPrefix(`/public`) kind: Rule services: - name: api-service port: 8080 middlewares: - name: api-ratelimit - match: Host(`api.example.com`) && PathPrefix(`/private`) kind: Rule services: - name: api-service port: 8080 middlewares: - name: oauth - name: api-ratelimit tls: certResolver: letsencrypt
|
场景 5:WebSocket 支持
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: websocket-app namespace: default spec: entryPoints: - websecure routes: - match: Host(`ws.example.com`) kind: Rule services: - name: websocket-service port: 8080 scheme: h2c tls: certResolver: letsencrypt
|
场景 6:gRPC 服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: grpc-service namespace: default spec: entryPoints: - websecure routes: - match: Host(`grpc.example.com`) kind: Rule services: - name: grpc-backend port: 50051 scheme: h2c tls: certResolver: letsencrypt
|
场景 7:TCP 路由(数据库代理)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| apiVersion: traefik.io/v1alpha1 kind: IngressRouteTCP metadata: name: mysql-proxy namespace: default spec: entryPoints: - mysql routes: - match: HostSNI(`mysql.example.com`) services: - name: mysql-service port: 3306 tls: passthrough: true
---
|
五、监控与日志
1. Prometheus 指标
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| additionalArguments: - "--metrics.prometheus=true" - "--metrics.prometheus.entryPoint=metrics" - "--metrics.prometheus.addEntryPointsLabels=true" - "--metrics.prometheus.addRoutersLabels=true" - "--metrics.prometheus.addServicesLabels=true"
---
apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: name: traefik namespace: traefik-system labels: release: prometheus spec: selector: matchLabels: app: traefik endpoints: - port: metrics interval: 30s
|
关键指标:
traefik_entrypoint_requests_total - 入口点请求数
traefik_router_requests_total - 路由请求数
traefik_service_requests_total - 服务请求数
traefik_service_server_up - 后端服务健康状态
traefik_open_connections - 当前连接数
2. 访问日志
1 2 3 4 5 6 7
| additionalArguments: - "--accesslog=true" - "--accesslog.filepath=/var/log/traefik/access.log" - "--accesslog.format=json" - "--accesslog.fields.defaultmode=keep" - "--accesslog.fields.names.ClientAddr=drop"
|
日志分析示例:
1 2 3 4 5 6 7 8
| cat access.log | jq -r '.RequestPath' | sort | uniq -c | sort -rn | head -10
cat access.log | jq -r 'select(.DownstreamStatus >= 400) | .RequestPath' | sort | uniq -c
cat access.log | jq -r '.Duration' | sort -n | awk 'NR==int(NR*0.99)'
|
3. Grafana Dashboard
导入官方 Dashboard:
六、高可用配置
1. 多副本部署
1 2 3 4 5 6 7
| spec: replicas: 3 strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 maxUnavailable: 0
|
2. Pod 反亲和性
1 2 3 4 5 6 7 8
| spec: affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchLabels: app: traefik topologyKey: kubernetes.io/hostname
|
3. 持久化 ACME 证书
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| volumes: - name: acme-storage persistentVolumeClaim: claimName: traefik-acme-pvc
--- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: traefik-acme-pvc namespace: traefik-system spec: accessModes: - ReadWriteOnce storageClassName: gp2 resources: requests: storage: 1Gi
|
4. 健康检查
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| additionalArguments: - "--ping=true" - "--ping.entryPoint=traefik"
livenessProbe: httpGet: path: /ping port: traefik initialDelaySeconds: 10 periodSeconds: 10
readinessProbe: httpGet: path: /ping port: traefik initialDelaySeconds: 5 periodSeconds: 5
|
七、安全加固
1. 禁用 Dashboard 外部访问
1 2 3 4 5 6
| additionalArguments: - "--api.dashboard=true" - "--api.insecure=false"
|
2. 配置 TLS 最低版本
1 2 3 4 5 6 7 8 9 10 11
| apiVersion: traefik.io/v1alpha1 kind: TLSOption metadata: name: tlsoption namespace: default spec: minVersion: VersionTLS12 sniStrict: true cipherSuites: - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
3. 限制管理接口访问
1 2 3 4 5 6 7 8 9 10 11 12
| apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: ip-whitelist namespace: traefik-system spec: ipWhiteList: sourceRange: - 10.0.0.0/8 - 172.16.0.0/12 - 192.168.0.0/16
|
4. 安全头部配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: security-headers namespace: default spec: headers: browserXssFilter: true contentTypeNosniff: true frameDeny: true stsIncludeSubdomains: true stsPreload: true stsSeconds: 31536000 customFrameOptionsValue: "SAMEORIGIN" customResponseHeaders: Referrer-Policy: "strict-origin-when-cross-origin" Permissions-Policy: "geolocation=(), microphone=(), camera=()"
|
八、故障排查
常见问题 1:证书申请失败
1 2 3 4 5 6 7 8 9
| kubectl logs -n traefik-system -l app=traefik | grep -i acme
dig example.com dig _acme-challenge.example.com TXT
kubectl exec -n traefik-system traefik-xxx -- cat /data/acme.json | jq
|
常见问题 2:后端服务不可达
1 2 3 4 5 6 7 8
| kubectl get endpoints <service-name>
kubectl get ingressroute <route-name> -o yaml
curl http://traefik-dashboard:9000/api/http/routers
|
常见问题 3:请求超时
1 2 3 4
| additionalArguments: - "--serversTransport.forwardingTimeouts.dialTimeout=30s" - "--serversTransport.forwardingTimeouts.responseHeaderTimeout=30s"
|
九、性能调优
1. 连接池配置
1 2 3
| additionalArguments: - "--serversTransport.maxIdleConnsPerHost=100" - "--serversTransport.forwardingTimeouts.dialTimeout=30s"
|
2. 资源限制
1 2 3 4 5 6 7
| resources: requests: cpu: "200m" memory: "256Mi" limits: cpu: "1000m" memory: "1Gi"
|
3. 日志级别调整
1 2 3 4 5 6 7
| additionalArguments: - "--log.level=INFO"
additionalArguments: - "--log.level=DEBUG"
|
十、总结
Traefik 作为云原生时代的反向代理,具有以下优势:
- 自动服务发现:与容器编排平台深度集成
- 动态配置:配置变更无需重启
- 中间件系统:灵活组合认证、限流、重写等功能
- 自动 HTTPS:Let’s Encrypt 集成,证书自动管理
- 可观测性:内置 Prometheus 指标和访问日志
适用场景:
- Kubernetes 集群入口网关
- 微服务 API 网关
- 多租户 SaaS 平台路由
- 蓝绿/金丝雀发布
最佳实践:
- 生产环境至少 2 副本部署
- 使用 CRD 而非 Ingress 注解
- 启用访问日志和监控指标
- 配置合理的资源限制和健康检查
- 定期备份 ACME 证书数据
参考文档: