Traefik
現代的なHTTPリバースプロキシ・ロードバランサー。自動サービス検出、Docker/Kubernetes統合、Let's Encrypt自動証明書取得。
サーバー
Traefik Proxy
概要
Traefik Proxyは、マイクロサービスアーキテクチャ向けに設計された現代的なHTTPリバースプロキシ・ロードバランサーです。既存のインフラストラクチャコンポーネント(Docker、Kubernetes等)と統合し、自動的かつ動的に設定を行います。サービスレジストリ・オーケストレーターAPIを監視し、リアルタイムでルートを生成することで、マイクロサービスのデプロイメントを大幅に簡素化します。Let's Encrypt自動統合、包括的な可観測性機能、チェーン可能なミドルウェアシステムにより、現代的なクラウドネイティブ環境で幅広く採用されています。
詳細
Traefik Proxyは、EntryPoints(ネットワークリスナー)、Routers(ルーティングロジック)、Middlewares(リクエスト/レスポンス処理)、Services(バックエンドサーバー)から構成される洗練されたアーキテクチャを持ちます。静的設定(起動時読み込み)と動的設定(実行時更新)の二重設定システムにより、再起動なしでの設定変更を実現します。Docker、Kubernetes、Consul、Etcd等の多様なプロバイダーと統合し、サービスディスカバリー機能を提供します。Weighted Round Robin、ヘルスチェック、フェイルオーバー、ミラーリング等の高度な負荷分散機能を備えています。
主な特徴
- 動的設定管理: オーケストレーター連携による無停止設定変更
- 自動サービスディスカバリー: Docker/Kubernetes等からの自動ルート生成
- 自動HTTPS: Let's Encrypt統合によるワイルドカード証明書サポート
- 包括的可観測性: メトリクス、ログ、分散トレーシング機能
- ミドルウェアシステム: 認証、ヘッダー操作、リダイレクト等の柔軟な処理
- シングルバイナリ: 単一実行ファイルでの簡単デプロイメント
メリット・デメリット
メリット
- マイクロサービス・コンテナ環境に最適化された自動設定機能
- 再起動不要で設定変更が可能な動的設定システム
- Let's Encrypt自動統合による証明書管理の大幅簡素化
- Prometheus、OpenTelemetry等との豊富な観測機能統合
- チェーン可能なミドルウェアによる柔軟なリクエスト処理
- Docker公式イメージとシングルバイナリでの簡単デプロイメント
デメリット
- 静的・動的設定の組み合わせによる学習コストの高さ
- プロバイダー依存による設定の複雑化リスク
- 高度なルーティング設定での構成複雑性
- 従来の静的プロキシと比較した場合のオーバーヘッド
- 大規模環境でのデバッグ・トラブルシューティングの困難さ
- プロバイダー障害時の設定更新停止リスク
参考ページ
書き方の例
基本設定とHTTPルーティング
# traefik.yml (静的設定)
api:
dashboard: true
insecure: true
entryPoints:
web:
address: ":80"
websecure:
address: ":443"
providers:
file:
directory: "/etc/traefik/dynamic"
watch: true
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
certificatesResolvers:
letsencrypt:
acme:
email: [email protected]
storage: acme.json
httpChallenge:
entryPoint: web
log:
level: INFO
accessLog: {}
metrics:
prometheus:
addEntryPointsLabels: true
addServicesLabels: true
# dynamic.yml (動的設定)
http:
routers:
api-router:
rule: "Host(`api.example.com`)"
service: api-service
entryPoints:
- websecure
tls:
certResolver: letsencrypt
middlewares:
- auth-middleware
- rate-limit
frontend-router:
rule: "Host(`www.example.com`)"
service: frontend-service
entryPoints:
- websecure
tls:
certResolver: letsencrypt
middlewares:
auth-middleware:
basicAuth:
users:
- "admin:$2y$10$..."
rate-limit:
rateLimit:
burst: 100
average: 50
services:
api-service:
loadBalancer:
servers:
- url: "http://api-server1:8080"
- url: "http://api-server2:8080"
healthCheck:
path: "/health"
interval: "30s"
timeout: "5s"
frontend-service:
loadBalancer:
servers:
- url: "http://frontend-server:3000"
Docker Compose統合とサービスディスカバリー
# docker-compose.yml
version: '3.8'
services:
traefik:
image: traefik:v3.0
container_name: traefik
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "8080:8080"
command:
- --api.dashboard=true
- --api.insecure=true
- --providers.docker=true
- --providers.docker.exposedbydefault=false
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- --certificatesresolvers.letsencrypt.acme.httpchallenge=true
- --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web
- --certificatesresolvers.letsencrypt.acme.email=your-email@example.com
- --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json
- --log.level=INFO
- --accesslog=true
- --metrics.prometheus=true
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- letsencrypt:/letsencrypt
networks:
- traefik-network
web-app:
image: nginx:alpine
container_name: web-app
labels:
- "traefik.enable=true"
- "traefik.http.routers.webapp.rule=Host(`app.example.com`)"
- "traefik.http.routers.webapp.entrypoints=websecure"
- "traefik.http.routers.webapp.tls.certresolver=letsencrypt"
- "traefik.http.services.webapp.loadbalancer.server.port=80"
- "traefik.http.middlewares.webapp-auth.basicauth.users=admin:$$2y$$10$$..."
- "traefik.http.routers.webapp.middlewares=webapp-auth"
networks:
- traefik-network
api-app:
image: node:alpine
container_name: api-app
labels:
- "traefik.enable=true"
- "traefik.http.routers.api.rule=Host(`api.example.com`) && PathPrefix(`/api`)"
- "traefik.http.routers.api.entrypoints=websecure"
- "traefik.http.routers.api.tls.certresolver=letsencrypt"
- "traefik.http.services.api.loadbalancer.server.port=3000"
- "traefik.http.middlewares.api-ratelimit.ratelimit.average=100"
- "traefik.http.middlewares.api-ratelimit.ratelimit.burst=200"
- "traefik.http.routers.api.middlewares=api-ratelimit"
networks:
- traefik-network
volumes:
letsencrypt:
networks:
traefik-network:
external: true
Kubernetes統合(IngressRoute CRD)
# traefik-rbac.yaml
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: ["traefik.io"]
resources: ["*"]
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
---
# traefik-deployment.yaml
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
containers:
- name: traefik
image: traefik:v3.0
args:
- --api.dashboard=true
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- --providers.kubernetescrd
- --certificatesresolvers.letsencrypt.acme.httpchallenge=true
- --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web
- [email protected]
- --certificatesresolvers.letsencrypt.acme.storage=/data/acme.json
- --log.level=INFO
- --accesslog=true
- --metrics.prometheus=true
ports:
- name: web
containerPort: 80
- name: websecure
containerPort: 443
- name: admin
containerPort: 8080
volumeMounts:
- name: data
mountPath: /data
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
volumes:
- name: data
persistentVolumeClaim:
claimName: traefik-data
---
# traefik-ingressroute.yaml
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: api-ingressroute
namespace: default
spec:
entryPoints:
- websecure
routes:
- match: Host(`api.example.com`)
kind: Rule
services:
- name: api-service
port: 80
middlewares:
- name: api-auth
- name: api-ratelimit
tls:
certResolver: letsencrypt
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: api-auth
namespace: default
spec:
basicAuth:
secret: api-auth-secret
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: api-ratelimit
namespace: default
spec:
rateLimit:
average: 100
burst: 200
---
apiVersion: v1
kind: Secret
metadata:
name: api-auth-secret
namespace: default
data:
users: YWRtaW46JGFwcjEkSDZKeFhXb3lQYVhuE... # htpasswd格式
負荷分散とヘルスチェック設定
# 重み付きラウンドロビン設定
http:
services:
weighted-service:
weighted:
services:
- name: service-v1
weight: 70
- name: service-v2
weight: 30
service-v1:
loadBalancer:
servers:
- url: "http://app-v1-1:8080"
- url: "http://app-v1-2:8080"
healthCheck:
path: "/health"
interval: "10s"
timeout: "3s"
scheme: "http"
service-v2:
loadBalancer:
servers:
- url: "http://app-v2-1:8080"
- url: "http://app-v2-2:8080"
healthCheck:
path: "/health"
interval: "10s"
timeout: "3s"
# スティッキーセッション設定
sticky-service:
loadBalancer:
servers:
- url: "http://backend1:8080"
- url: "http://backend2:8080"
sticky:
cookie:
name: "server-session"
secure: true
httpOnly: true
# フェイルオーバー設定
failover-service:
failover:
service: primary-service
fallback: backup-service
primary-service:
loadBalancer:
servers:
- url: "http://primary-server:8080"
healthCheck:
path: "/health"
interval: "5s"
backup-service:
loadBalancer:
servers:
- url: "http://backup-server:8080"
高度なミドルウェア設定
# 認証・認可ミドルウェア
http:
middlewares:
# OAuth2認証
oauth-auth:
forwardAuth:
address: "http://oauth-provider:4181"
authResponseHeaders:
- "X-Forwarded-User"
- "X-Auth-User"
- "X-Secret"
# JWT認証
jwt-auth:
plugin:
jwt:
secret: "your-jwt-secret"
alg: "HS256"
# レート制限
rate-limit-strict:
rateLimit:
extractorFunc: "request.host"
rateLimitKey: "client.ip"
average: 6
period: "1m"
burst: 12
# CORS設定
cors-middleware:
headers:
accessControlAllowMethods:
- GET
- OPTIONS
- PUT
- POST
- DELETE
accessControlAllowOriginList:
- "https://example.com"
- "https://api.example.com"
accessControlMaxAge: 100
addVaryHeader: true
# セキュリティヘッダー
security-headers:
headers:
contentTypeNosniff: true
browserXssFilter: true
forceSTSHeader: true
stsIncludeSubdomains: true
stsPreload: true
stsSeconds: 31536000
# リクエスト変換
transform-request:
addPrefix:
prefix: "/api/v1"
# レスポンス変換
transform-response:
headers:
customRequestHeaders:
X-Custom-Request-Header: "request-value"
customResponseHeaders:
X-Custom-Response-Header: "response-value"
routers:
protected-api:
rule: "Host(`secure.example.com`)"
service: api-service
middlewares:
- oauth-auth
- rate-limit-strict
- cors-middleware
- security-headers
- transform-request
tls:
certResolver: letsencrypt
TCPルーティングとSSL終端
# TCP設定
tcp:
routers:
mysql-router:
rule: "HostSNI(`mysql.example.com`)"
service: mysql-service
tls:
passthrough: false
certResolver: letsencrypt
postgres-router:
rule: "HostSNI(`postgres.example.com`)"
service: postgres-service
tls:
passthrough: true
redis-router:
rule: "HostSNI(`*`)"
service: redis-service
entryPoints:
- redis
services:
mysql-service:
loadBalancer:
servers:
- address: "mysql-master:3306"
- address: "mysql-slave:3306"
proxyProtocol:
version: 1
postgres-service:
loadBalancer:
servers:
- address: "postgres-primary:5432"
- address: "postgres-secondary:5432"
redis-service:
loadBalancer:
servers:
- address: "redis-node1:6379"
- address: "redis-node2:6379"
- address: "redis-node3:6379"
entryPoints:
redis:
address: ":6379"
mysql:
address: ":3306"
postgres:
address: ":5432"
監視とログ設定
# traefik.yml
log:
level: INFO
format: json
accessLog:
filePath: "/var/log/traefik/access.log"
format: json
fields:
defaultMode: keep
headers:
defaultMode: drop
names:
User-Agent: keep
Authorization: drop
Content-Type: keep
metrics:
prometheus:
addEntryPointsLabels: true
addServicesLabels: true
buckets:
- 0.1
- 0.3
- 1.2
- 5.0
tracing:
jaeger:
samplingServerURL: "http://jaeger:14268/api/sampling"
localAgentHostPort: "jaeger:6831"
ping:
entryPoint: "ping"
entryPoints:
ping:
address: ":8082"
api:
dashboard: true
debug: true
トラブルシューティング
# Traefik状態確認
docker logs traefik
# 設定確認
curl http://localhost:8080/api/rawdata
# ルーター状態確認
curl http://localhost:8080/api/http/routers
# サービス状態確認
curl http://localhost:8080/api/http/services
# ミドルウェア状態確認
curl http://localhost:8080/api/http/middlewares
# ヘルスチェック確認
curl http://localhost:8082/ping
# メトリクス確認
curl http://localhost:8080/metrics
# 設定リロード(ファイルプロバイダー)
docker exec traefik kill -SIGUSR1 1
# ログレベル変更
docker exec traefik traefik --log.level=DEBUG
# SSL証明書確認
openssl s_client -connect your-domain.com:443 -servername your-domain.com
# Docker Compose設定確認
docker-compose config