Ambassador
Kubernetes専用のAPI Gateway。Envoyプロキシベースで、GitOpsワークフロー、カナリアデプロイメント、レート制限機能を提供。
概要
Ambassadorは、Kubernetes専用に設計されたオープンソースのAPI Gatewayです。Envoy Proxyをベースに構築され、Kubernetes CRD(Custom Resource Definitions)を使用した宣言的な設定が特徴です。現在は「Emissary-Ingress」として知られ、CNCFのIncubatingプロジェクトとして開発されています。
GitOpsワークフロー、カナリアデプロイメント、レート制限機能、高度な認証機能を提供し、Kubernetes環境でのマイクロサービス管理に最適化されています。Datawire(現Ambassador Labs)によって開発され、Kubernetes環境でのAPI Gateway標準選択肢として広く採用されています。
主要な特徴
- Kubernetes Native: CRDによる完全なKubernetes統合
- Envoy Proxy基盤: 高性能で実績のあるL7プロキシエンジン
- 宣言的設定: GitOpsフレンドリーなYAML設定
- 自動サービスディスカバリ: Kubernetesサービスとの自動統合
- 豊富な認証機能: OAuth、JWT、mTLSなどの包括的な認証サポート
主要機能
コア機能
- 動的ルーティング: 高度なトラフィックルーティングとロードバランシング
- TLS終端: 自動証明書管理とSSL/TLS終端
- 認証・認可: JWT、OAuth 2.0、Basic Auth、外部認証サービス統合
- レート制限: 柔軟なレート制限ポリシー
- カナリアデプロイメント: トラフィック分割による段階的デプロイ
高度な機能
- Circuit Breaker: 障害耐性のための回路ブレーカーパターン
- Retry Policy: 自動リトライ機能
- CORS支援: Cross-Origin Resource Sharing設定
- WebSocket対応: リアルタイム通信のサポート
- gRPC支援: gRPCプロトコルの完全サポート
インストール・セットアップ
Helmを使用したインストール
Emissary-Ingress(OSS版)のインストール
# Helm リポジトリ追加
helm repo add datawire https://app.getambassador.io
helm repo update
# 名前空間作成
kubectl create namespace emissary-system
# Emissary-Ingress インストール
helm install emissary-ingress datawire/emissary-ingress \
--namespace emissary-system \
--set service.type=LoadBalancer \
--set adminService.type=ClusterIP
# インストール確認
kubectl get pods -n emissary-system
kubectl get services -n emissary-system
Ambassador Edge Stack(Commercial版)のインストール
# Edge Stack インストール
helm install ambassador datawire/edge-stack \
--namespace ambassador \
--create-namespace \
--set service.type=LoadBalancer \
--set enableAES=true \
--set licenseKey.value=YOUR_LICENSE_KEY
マニフェストでのインストール
CRDインストール
# 最新のCRDを適用
kubectl apply -f https://app.getambassador.io/yaml/emissary/3.9.0/emissary-crds.yaml
# Emissary-Ingress本体をインストール
kubectl apply -f https://app.getambassador.io/yaml/emissary/3.9.0/emissary-emissaryns.yaml
# リソース確認
kubectl wait --timeout=90s --for=condition=available deployment emissary-ingress -n emissary-system
手動インストール設定
# emissary-ingress.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: emissary-ingress
namespace: emissary-system
spec:
replicas: 3
selector:
matchLabels:
service: ambassador
template:
metadata:
labels:
service: ambassador
spec:
serviceAccountName: emissary-ingress
containers:
- name: emissary
image: docker.io/emissaryingress/emissary:3.9.0
ports:
- name: http
containerPort: 8080
- name: https
containerPort: 8443
- name: admin
containerPort: 8877
env:
- name: AMBASSADOR_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
resources:
requests:
memory: "512Mi"
cpu: "200m"
limits:
memory: "1Gi"
cpu: "1000m"
livenessProbe:
httpGet:
path: /ambassador/v0/check_alive
port: admin
periodSeconds: 3
readinessProbe:
httpGet:
path: /ambassador/v0/check_ready
port: admin
periodSeconds: 3
---
apiVersion: v1
kind: Service
metadata:
name: emissary-ingress
namespace: emissary-system
spec:
type: LoadBalancer
ports:
- name: http
port: 80
targetPort: http
- name: https
port: 443
targetPort: https
selector:
service: ambassador
Dev Modeでの簡易セットアップ
# 開発用セットアップ(単一Pod)
kubectl apply -f - <<EOF
apiVersion: v1
kind: Service
metadata:
name: ambassador
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 8080
selector:
service: ambassador
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: ambassador
spec:
replicas: 1
selector:
matchLabels:
service: ambassador
template:
metadata:
labels:
service: ambassador
spec:
containers:
- name: ambassador
image: docker.io/emissaryingress/emissary:3.9.0
ports:
- containerPort: 8080
env:
- name: AMBASSADOR_SINGLE_NAMESPACE
value: "true"
EOF
基本的な使い方
基本的なMapping設定
シンプルなHTTPサービス
# basic-mapping.yaml
apiVersion: getambassador.io/v3alpha1
kind: Mapping
metadata:
name: httpbin-mapping
namespace: default
spec:
hostname: api.example.com
prefix: /httpbin/
service: httpbin:80
timeout_ms: 5000
retry_policy:
retry_on: "5xx"
num_retries: 3
パスベースルーティング
# path-based-routing.yaml
apiVersion: getambassador.io/v3alpha1
kind: Mapping
metadata:
name: api-v1-mapping
spec:
prefix: /api/v1/
service: backend-api-v1:8080
rewrite: /
---
apiVersion: getambassador.io/v3alpha1
kind: Mapping
metadata:
name: api-v2-mapping
spec:
prefix: /api/v2/
service: backend-api-v2:8080
rewrite: /v2/
ホストベースルーティング
# host-based-routing.yaml
apiVersion: getambassador.io/v3alpha1
kind: Mapping
metadata:
name: admin-mapping
spec:
hostname: admin.example.com
prefix: /
service: admin-dashboard:3000
---
apiVersion: getambassador.io/v3alpha1
kind: Mapping
metadata:
name: api-mapping
spec:
hostname: api.example.com
prefix: /
service: api-service:8080
Listenerの設定
# listener.yaml
apiVersion: getambassador.io/v3alpha1
kind: Listener
metadata:
name: ambassador-listener-8080
spec:
port: 8080
protocol: HTTP
securityModel: XFP
hostBinding:
namespace:
from: ALL
---
apiVersion: getambassador.io/v3alpha1
kind: Listener
metadata:
name: ambassador-listener-8443
spec:
port: 8443
protocol: HTTPS
securityModel: XFP
hostBinding:
namespace:
from: ALL
Hostリソースの設定
# host.yaml
apiVersion: getambassador.io/v3alpha1
kind: Host
metadata:
name: example-com-host
spec:
hostname: api.example.com
acmeProvider:
authority: https://acme-v02.api.letsencrypt.org/directory
email: [email protected]
tlsSecret:
name: example-com-tls
設定例
ロードバランシングとヘルスチェック
# load-balancing.yaml
apiVersion: getambassador.io/v3alpha1
kind: Mapping
metadata:
name: load-balanced-service
spec:
prefix: /api/
service: backend-service:8080
load_balancer:
policy: round_robin
circuit_breakers:
- priority: default
max_connections: 1024
max_pending_requests: 256
max_requests: 1024
max_retries: 3
consecutive_5xx: 5
interval: 30s
base_ejection_time: 30s
max_ejection_percent: 50
複数のバックエンドサービス
# weighted-routing.yaml
apiVersion: getambassador.io/v3alpha1
kind: Mapping
metadata:
name: canary-deployment
spec:
prefix: /app/
service: stable-app:8080
weight: 90
---
apiVersion: getambassador.io/v3alpha1
kind: Mapping
metadata:
name: canary-deployment-new
spec:
prefix: /app/
service: canary-app:8080
weight: 10
リクエスト・レスポンス変換
# transformations.yaml
apiVersion: getambassador.io/v3alpha1
kind: Mapping
metadata:
name: header-transformation
spec:
prefix: /api/
service: backend:8080
add_request_headers:
x-backend-version: "v1.0"
x-request-source: "ambassador"
add_response_headers:
x-powered-by: "Ambassador"
remove_request_headers:
- "x-internal-token"
remove_response_headers:
- "server"
認証・セキュリティ
JWT認証の実装
JWT Filter設定
# jwt-filter.yaml
apiVersion: getambassador.io/v3alpha1
kind: Filter
metadata:
name: jwt-filter
spec:
JWT:
jwksURI: "https://auth.example.com/.well-known/jwks.json"
validAlgorithms:
- "RS256"
- "HS256"
audience: "api.example.com"
issuer: "https://auth.example.com"
requireAudience: false
requireIssuedAt: true
requireExpiresAt: true
requireNotBefore: false
injectRequestHeaders:
- name: "X-User-ID"
value: "{{ .token.sub }}"
- name: "X-User-Email"
value: "{{ .token.email }}"
JWT FilterPolicyの適用
# jwt-policy.yaml
apiVersion: getambassador.io/v3alpha1
kind: FilterPolicy
metadata:
name: jwt-policy
spec:
rules:
- host: "api.example.com"
path: "/protected/*"
filters:
- name: jwt-filter
arguments:
scope: "read write"
---
apiVersion: getambassador.io/v3alpha1
kind: Mapping
metadata:
name: protected-api
spec:
hostname: api.example.com
prefix: /protected/
service: protected-service:8080
OAuth 2.0認証
# oauth-filter.yaml
apiVersion: getambassador.io/v3alpha1
kind: Filter
metadata:
name: oauth2-filter
spec:
OAuth2:
authorizationURL: "https://oauth.example.com/oauth/authorize"
tokenURL: "https://oauth.example.com/oauth/token"
clientID: "ambassador-client"
clientSecret: "ambassador-secret"
protectedOrigins:
- origin: "https://api.example.com"
grantType: "AuthorizationCode"
scopes:
- "read"
- "write"
- "admin"
外部認証サービス
# external-auth.yaml
apiVersion: getambassador.io/v3alpha1
kind: AuthService
metadata:
name: authentication
spec:
auth_service: "auth-service:80"
path_prefix: "/extauth"
timeout_ms: 5000
allowed_request_headers:
- "x-custom-auth"
allowed_authorization_headers:
- "authorization"
- "cookie"
include_body:
max_bytes: 4096
allow_partial: true
mTLS(相互TLS)設定
# mtls-host.yaml
apiVersion: getambassador.io/v3alpha1
kind: Host
metadata:
name: mtls-host
spec:
hostname: secure.example.com
tlsSecret:
name: mtls-secret
tls:
min_tls_version: v1.2
max_tls_version: v1.3
cipher_suites:
- "ECDHE-RSA-AES128-GCM-SHA256"
- "ECDHE-RSA-AES256-GCM-SHA384"
alpn_protocols:
- "h2"
- "http/1.1"
cert_required: true
APIキー認証
# api-key-filter.yaml
apiVersion: getambassador.io/v3alpha1
kind: Filter
metadata:
name: api-key-filter
spec:
Plugin:
name: "api-key-auth"
config:
keys:
- header: "X-API-Key"
secret: "api-keys-secret"
key: "valid-keys"
- query_param: "api_key"
secret: "api-keys-secret"
key: "valid-keys"
レート制限・トラフィック管理
レート制限の設定
# rate-limit-filter.yaml
apiVersion: getambassador.io/v3alpha1
kind: Filter
metadata:
name: rate-limit-filter
spec:
RateLimit:
domain: "ambassador"
rules:
- dimensions:
- remote_address
- header:
name: "X-API-Key"
skip_if_absent: true
timeout_ms: 500
failure_mode_deny: false
---
apiVersion: getambassador.io/v3alpha1
kind: RateLimitService
metadata:
name: rate-limit-service
spec:
service: "ratelimit:5000"
Rate Limitの詳細設定
# advanced-rate-limit.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: rate-limit-config
data:
config.yaml: |
domain: ambassador
descriptors:
- key: remote_address
rate_limit:
unit: minute
requests_per_unit: 100
- key: header
value: premium
descriptors:
- key: remote_address
rate_limit:
unit: minute
requests_per_unit: 1000
- key: header
value: basic
descriptors:
- key: remote_address
rate_limit:
unit: minute
requests_per_unit: 10
Circuit Breaker設定
# circuit-breaker.yaml
apiVersion: getambassador.io/v3alpha1
kind: Mapping
metadata:
name: circuit-breaker-mapping
spec:
prefix: /api/
service: backend-service:8080
circuit_breakers:
- priority: default
max_connections: 100
max_pending_requests: 50
max_requests: 200
max_retries: 3
consecutive_5xx: 5
interval: 30s
base_ejection_time: 30s
max_ejection_percent: 50
retry_policy:
retry_on: "5xx"
num_retries: 3
per_try_timeout: "10s"
トラフィック分割
# traffic-splitting.yaml
apiVersion: getambassador.io/v3alpha1
kind: Mapping
metadata:
name: feature-flag-routing
spec:
prefix: /api/
service: stable-service:8080
precedence: 1
headers:
feature-flag: "new-feature"
weight: 100
---
apiVersion: getambassador.io/v3alpha1
kind: Mapping
metadata:
name: default-routing
spec:
prefix: /api/
service: stable-service:8080
precedence: 0
weight: 100
モニタリング・ログ
Prometheusメトリクス設定
# prometheus-service.yaml
apiVersion: v1
kind: Service
metadata:
name: ambassador-admin
namespace: emissary-system
labels:
service: ambassador-admin
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8877"
prometheus.io/path: "/metrics"
spec:
ports:
- name: admin
port: 8877
targetPort: admin
selector:
service: ambassador
カスタムメトリクス
# custom-metrics.yaml
apiVersion: getambassador.io/v3alpha1
kind: Module
metadata:
name: ambassador
spec:
config:
diagnostics:
enabled: true
enable_grpc_http11_bridge: true
enable_grpc_web: true
stats:
- name: "request_duration"
type: "histogram"
labels:
- "method"
- "status"
- "service"
分散トレーシング設定
# tracing.yaml
apiVersion: getambassador.io/v3alpha1
kind: TracingService
metadata:
name: tracing
spec:
service: "jaeger:14268"
driver: zipkin
config:
collector_endpoint: "/api/v2/spans"
trace_id_128bit: true
shared_span_context: false
collector_endpoint_version: httpJson
ログ設定
# log-service.yaml
apiVersion: getambassador.io/v3alpha1
kind: LogService
metadata:
name: access-log
spec:
service: "log-collector:8080"
driver: http
config:
additional_log_headers:
- header_name: "x-request-id"
during_request: true
during_response: false
- header_name: "x-user-id"
during_request: true
during_response: false
Grafanaダッシュボード
{
"dashboard": {
"title": "Ambassador API Gateway",
"panels": [
{
"title": "Request Rate",
"type": "graph",
"targets": [
{
"expr": "rate(envoy_http_downstream_rq_total[5m])",
"legendFormat": "{{method}} {{response_code}}"
}
]
},
{
"title": "Response Time",
"type": "graph",
"targets": [
{
"expr": "histogram_quantile(0.95, rate(envoy_http_downstream_rq_time_bucket[5m]))",
"legendFormat": "95th percentile"
}
]
}
]
}
}
高度な機能
gRPCサポート
# grpc-mapping.yaml
apiVersion: getambassador.io/v3alpha1
kind: Mapping
metadata:
name: grpc-service
spec:
prefix: /grpc.example.v1.ExampleService/
service: grpc-backend:9000
grpc: true
timeout_ms: 10000
connect_timeout_ms: 5000
WebSocketサポート
# websocket-mapping.yaml
apiVersion: getambassador.io/v3alpha1
kind: Mapping
metadata:
name: websocket
spec:
prefix: /ws/
service: websocket-service:8080
use_websocket: true
timeout_ms: 0
connect_timeout_ms: 10000
allow_upgrade:
- websocket
GraphQL統合
# graphql-mapping.yaml
apiVersion: getambassador.io/v3alpha1
kind: Mapping
metadata:
name: graphql-api
spec:
prefix: /graphql
service: graphql-service:4000
method: POST
headers:
content-type: "application/json"
add_request_headers:
x-apollo-tracing: "true"
カスタムプラグイン
# custom-plugin.yaml
apiVersion: getambassador.io/v3alpha1
kind: Filter
metadata:
name: custom-lua-filter
spec:
Plugin:
name: "custom-auth"
config:
script: |
function envoy_on_request(request_handle)
local headers = request_handle:headers()
local auth_header = headers:get("authorization")
if not auth_header then
request_handle:respond(
{[":status"] = "401"},
"Unauthorized"
)
return
end
-- カスタム認証ロジック
if auth_header ~= "Bearer valid-token" then
request_handle:respond(
{[":status"] = "403"},
"Forbidden"
)
return
end
-- 認証成功時のヘッダー追加
headers:add("x-user-authenticated", "true")
end
DevPortal統合(Edge Stack)
# devportal.yaml
apiVersion: getambassador.io/v3alpha1
kind: Mapping
metadata:
name: openapi-docs
annotations:
getambassador.io/config: |
---
apiVersion: getambassador.io/v2
kind: DevPortal
name: api-docs
content:
url: https://api.example.com/openapi.json
docs:
- url: https://api.example.com/docs/
spec:
prefix: /docs/
service: api-docs-service:8080
パフォーマンス最適化
Envoy設定の最適化
# envoy-config.yaml
apiVersion: getambassador.io/v3alpha1
kind: Module
metadata:
name: ambassador
spec:
config:
# 接続設定
cluster:
connect_timeout: 5s
per_connection_buffer_limit_bytes: 1048576
# リソース制限
listener:
per_connection_buffer_limit_bytes: 1048576
# HTTP設定
http:
request_headers_timeout: 10s
request_timeout: 60s
stream_idle_timeout: 5m
# バッファ設定
buffer:
max_request_bytes: 8192
# 圧縮設定
gzip:
memory_level: 6
window_bits: 15
compression_level: 6
compression_strategy: default
リソース制限とHPA
# hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: ambassador-hpa
namespace: emissary-system
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: emissary-ingress
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
PodDisruptionBudget
# pdb.yaml
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: ambassador-pdb
namespace: emissary-system
spec:
minAvailable: 2
selector:
matchLabels:
service: ambassador
キャッシング設定
# caching.yaml
apiVersion: getambassador.io/v3alpha1
kind: Mapping
metadata:
name: cached-api
spec:
prefix: /api/cache/
service: backend-service:8080
add_response_headers:
cache-control: "public, max-age=300"
vary: "Accept-Encoding"
envoy_override:
route:
response_headers_to_add:
- header:
key: "x-cache-status"
value: "cached"
append: false
トラブルシューティング
デバッグとログ確認
Ambassador診断ページ
# Ambassador診断情報の取得
kubectl port-forward -n emissary-system svc/ambassador-admin 8877:8877
# ブラウザで以下にアクセス
# http://localhost:8877/ambassador/v0/diag/
# または curl で取得
curl http://localhost:8877/ambassador/v0/diag/
ログの確認
# Ambassadorのログ確認
kubectl logs -n emissary-system deployment/emissary-ingress -f
# 特定のPodのログ
kubectl logs -n emissary-system pod/emissary-ingress-xxxx -c emissary
# 設定エラーの確認
kubectl logs -n emissary-system deployment/emissary-ingress --grep="ERROR"
設定検証
# CRDリソースの確認
kubectl get mappings,hosts,filters,filterpolicies -A
# 設定の詳細確認
kubectl describe mapping my-mapping
kubectl describe host my-host
# envoy設定の確認
curl http://localhost:8877/config_dump
よくある問題と解決法
503 Service Unavailable エラー
# サービスエンドポイント確認
kubectl get endpoints
# バックエンドサービスの確認
kubectl describe service backend-service
# Mapping設定の確認
kubectl get mapping -o yaml
TLS/SSL証明書の問題
# Host設定の確認
kubectl describe host my-host
# 証明書の確認
kubectl get secret tls-secret -o yaml
# ACME Challenge の確認(Let's Encrypt)
kubectl get challenges
kubectl describe challenge my-challenge
パフォーマンス問題の診断
# メトリクス確認
curl http://localhost:8877/stats/prometheus
# Envoy管理画面
curl http://localhost:8877/stats
curl http://localhost:8877/clusters
curl http://localhost:8877/server_info
ヘルスチェック設定
# health-check.yaml
apiVersion: getambassador.io/v3alpha1
kind: Mapping
metadata:
name: health-check
spec:
prefix: /health
service: health-service:8080
bypass_auth: true
timeout_ms: 1000
headers:
x-health-check: "true"
設定バックアップとリストア
# 設定のバックアップ
kubectl get mappings,hosts,filters,filterpolicies,modules -A -o yaml > ambassador-config-backup.yaml
# 設定の復元
kubectl apply -f ambassador-config-backup.yaml
# 特定名前空間の設定のみバックアップ
kubectl get mappings,hosts,filters,filterpolicies -n production -o yaml > prod-config.yaml
参考リンク
公式ドキュメント
GitHub リポジトリ
ツールとエコシステム
- Telepresence - ローカル開発環境統合
- Forge - マイクロサービス開発ツール
- ArgoCD - GitOps デプロイメント