Envoy Proxy

クラウドネイティブ高性能プロキシ。サービスメッシュ、API Gateway、ロードバランサー機能。observability、動的設定、gRPC対応。

サービスメッシュプロキシロードバランサーマイクロサービス可観測性xDSHTTP/2gRPC

サーバー

Envoy Proxy

概要

Envoy Proxyは、クラウドネイティブ環境とマイクロサービスアーキテクチャのために設計された高性能エッジプロキシ・サービスメッシュ用プロキシです。C++で開発され、毎秒数十万のリクエストを処理できる高いパフォーマンスを誇ります。動的設定管理(xDS API)、豊富な可観測性機能、多様なプロトコルサポート(HTTP/1.1、HTTP/2、HTTP/3、gRPC)により、現代のマイクロサービス環境で広く採用されています。IstioやAWS App Meshなどの主要サービスメッシュソリューションの基盤として使用されており、CNCF(Cloud Native Computing Foundation)卒業プロジェクトとして信頼性が確立されています。

詳細

Envoy Proxyは2016年にLyft社で開発開始され、2017年にオープンソース化されました。現在のバージョン1.31では、HTTP/3(QUIC)、WebAssembly(WASM)フィルター、OAuth2認証、外部処理フィルター等の先進的な機能を提供しています。イベント駆動型の非同期アーキテクチャとマルチスレッド設計により、極めて高いスループットと低いレイテンシを実現します。プラグアブルなフィルターチェーンアーキテクチャにより、HTTPフィルター、ネットワークフィルター、リスナーフィルターを組み合わせた柔軟な拡張が可能です。

主な特徴

  • 動的設定管理: xDS API(LDS、CDS、RDS、EDS)による設定の動的更新
  • 高度な負荷分散: サブセット負荷分散、地域加重負荷分散、カスタムポリシー対応
  • 包括的可観測性: 分散トレーシング、メトリクス収集、アクセスログ機能
  • モダンプロトコル対応: HTTP/2、HTTP/3、gRPC、WebSocketの完全サポート
  • 拡張性: フィルターチェーンとWebAssemblyによる柔軟なカスタマイズ
  • セキュリティ機能: mTLS、OAuth2、JWTバリデーション、レート制限

メリット・デメリット

メリット

  • Kubernetesとサービスメッシュのデファクトスタンダードプロキシ
  • 極めて高いパフォーマンスとリソース効率性
  • 豊富な可観測性機能により運用負荷を大幅に軽減
  • 動的設定により無停止での設定変更が可能
  • 主要クラウドプロバイダーとサービスメッシュソリューションでサポート
  • 活発な開発コミュニティとCNCFによる長期サポート保証

デメリット

  • 学習コストが高く、設定の複雑性が初期導入の障壁となる
  • YAML設定ファイルが大規模環境では非常に複雑になる傾向
  • デバッグ時に多層フィルターチェーンの問題特定が困難
  • メモリ使用量がやや多く、リソース制約環境では注意が必要
  • 従来のシンプルなロードバランサーと比較してオーバーヘッドが存在
  • プロダクション運用には専門的なサービスメッシュ知識が必要

参考ページ

書き方の例

基本設定とHTTPプロキシ

# envoy.yaml
admin:
  address:
    socket_address:
      address: 0.0.0.0
      port_value: 9901

static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address:
        address: 0.0.0.0
        port_value: 10000
    filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          stat_prefix: ingress_http
          codec_type: AUTO
          route_config:
            name: local_route
            virtual_hosts:
            - name: local_service
              domains: ["*"]
              routes:
              - match:
                  prefix: "/"
                route:
                  cluster: service_backend
          http_filters:
          - name: envoy.filters.http.router
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

  clusters:
  - name: service_backend
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: service_backend
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: backend.example.com
                port_value: 80

負荷分散とヘルスチェック設定

# 高度な負荷分散設定
clusters:
- name: web_service
  connect_timeout: 0.25s
  type: STRICT_DNS
  lb_policy: LEAST_REQUEST
  health_checks:
  - timeout: 1s
    interval: 5s
    unhealthy_threshold: 3
    healthy_threshold: 2
    http_health_check:
      path: "/health"
      expected_statuses:
      - start: 200
        end: 299
  load_assignment:
    cluster_name: web_service
    endpoints:
    - lb_endpoints:
      - endpoint:
          address:
            socket_address:
              address: web1.example.com
              port_value: 8080
          health_check_config:
            port_value: 8080
      - endpoint:
          address:
            socket_address:
              address: web2.example.com
              port_value: 8080
      - endpoint:
          address:
            socket_address:
              address: web3.example.com
              port_value: 8080

# サブセット負荷分散
- name: api_service
  connect_timeout: 0.25s
  type: EDS
  eds_cluster_config:
    eds_config:
      path: "./eds.yaml"
  lb_policy: LEAST_REQUEST
  lb_subset_config:
    fallback_policy: ANY_ENDPOINT
    subset_selectors:
    - keys: ["version"]
    - keys: ["stage", "version"]

SSL/TLS終端と高度なセキュリティ設定

# TLS設定
listeners:
- name: https_listener
  address:
    socket_address:
      address: 0.0.0.0
      port_value: 443
  filter_chains:
  - transport_socket:
      name: envoy.transport_sockets.tls
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
        common_tls_context:
          tls_certificates:
          - certificate_chain:
              filename: "/etc/ssl/certs/server.crt"
            private_key:
              filename: "/etc/ssl/private/server.key"
          validation_context:
            trusted_ca:
              filename: "/etc/ssl/certs/ca.crt"
          alpn_protocols: ["h2", "http/1.1"]
    filters:
    - name: envoy.filters.network.http_connection_manager
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
        stat_prefix: ingress_https
        codec_type: AUTO
        route_config:
          name: local_route
          virtual_hosts:
          - name: secure_service
            domains: ["secure.example.com"]
            routes:
            - match:
                prefix: "/"
              route:
                cluster: secure_backend
        http_filters:
        # JWT認証フィルター
        - name: envoy.filters.http.jwt_authn
          typed_config:
            "@type": type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.JwtAuthentication
            providers:
              auth0:
                issuer: "https://your-domain.auth0.com/"
                audiences:
                - "your-api-audience"
                remote_jwks:
                  http_uri:
                    uri: "https://your-domain.auth0.com/.well-known/jwks.json"
                    cluster: jwks_cluster
                    timeout: 5s
            rules:
            - match:
                prefix: "/api/"
              requires:
                provider_name: "auth0"
        # レート制限フィルター
        - name: envoy.filters.http.local_ratelimit
          typed_config:
            "@type": type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit
            stat_prefix: http_local_rate_limit
            token_bucket:
              max_tokens: 1000
              tokens_per_fill: 1000
              fill_interval: 1s
        - name: envoy.filters.http.router
          typed_config:
            "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

可観測性とトレーシング設定

# 分散トレーシング設定
tracing:
  http:
    name: envoy.tracers.zipkin
    typed_config:
      "@type": type.googleapis.com/envoy.config.trace.v3.ZipkinConfig
      collector_cluster: zipkin
      collector_endpoint: "/api/v2/spans"
      shared_span_context: false

# メトリクス設定
stats_sinks:
- name: envoy.stat_sinks.statsd
  typed_config:
    "@type": type.googleapis.com/envoy.config.core.v3.StatsdSink
    address:
      socket_address:
        address: statsd.example.com
        port_value: 8125
- name: envoy.stat_sinks.metrics_service
  typed_config:
    "@type": type.googleapis.com/envoy.config.core.v3.MetricsServiceConfig
    grpc_service:
      envoy_grpc:
        cluster_name: metrics_service

# アクセスログ設定
http_connection_manager:
  access_log:
  - name: envoy.access_loggers.file
    typed_config:
      "@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
      path: "/var/log/envoy/access.log"
      format: |
        [%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%"
        %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT%
        %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%REQ(X-FORWARDED-FOR)%"
        "%REQ(USER-AGENT)%" "%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%"
  - name: envoy.access_loggers.grpc
    typed_config:
      "@type": type.googleapis.com/envoy.extensions.access_loggers.grpc.v3.HttpGrpcAccessLogConfig
      common_config:
        grpc_service:
          envoy_grpc:
            cluster_name: access_log_service
        log_name: "envoy-access-log"

動的設定(xDS)とサービスディスカバリ

# 動的設定管理
dynamic_resources:
  # リスナーディスカバリサービス
  lds_config:
    api_config_source:
      api_type: GRPC
      grpc_services:
      - envoy_grpc:
          cluster_name: xds_cluster
      set_node_on_first_message_only: true
  
  # クラスターディスカバリサービス
  cds_config:
    api_config_source:
      api_type: GRPC
      grpc_services:
      - envoy_grpc:
          cluster_name: xds_cluster
      set_node_on_first_message_only: true

# ノード情報
node:
  cluster: service_cluster
  id: service_node_1
  metadata:
    zone: us-east-1a
    region: us-east-1
    version: "1.0"

static_resources:
  clusters:
  # xDS管理サーバー
  - name: xds_cluster
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    typed_extension_protocol_options:
      envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
        "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
        explicit_http_config:
          http2_protocol_options:
            connection_keepalive:
              interval: 30s
              timeout: 5s
    load_assignment:
      cluster_name: xds_cluster
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: control-plane.example.com
                port_value: 18000

WebAssembly拡張とカスタムフィルター

# WebAssemblyフィルター
http_filters:
- name: envoy.filters.http.wasm
  typed_config:
    "@type": type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm
    config:
      name: "custom_auth_filter"
      root_id: "custom_auth"
      configuration:
        "@type": type.googleapis.com/google.protobuf.StringValue
        value: |
          {
            "api_endpoint": "https://auth.example.com/validate",
            "timeout_ms": 1000
          }
      vm_config:
        vm_id: "custom_auth"
        runtime: "envoy.wasm.runtime.v8"
        code:
          local:
            inline_string: |
              class CustomAuth {
                constructor(rootContext) {
                  this.rootContext = rootContext;
                }
                
                onRequestHeaders() {
                  const authHeader = this.getRequestHeader("authorization");
                  if (!authHeader) {
                    this.sendLocalResponse(401, "Unauthorized", "Missing authorization header", []);
                    return FilterHeadersStatus.StopIteration;
                  }
                  return FilterHeadersStatus.Continue;
                }
              }

# Luaフィルター(軽量スクリプト)
- name: envoy.filters.http.lua
  typed_config:
    "@type": type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua
    inline_code: |
      function envoy_on_request(request_handle)
        -- カスタムヘッダーの追加
        request_handle:headers():add("x-custom-header", "added-by-lua")
        
        -- リクエストログ
        request_handle:logInfo("Processing request: " .. request_handle:headers():get(":path"))
      end
      
      function envoy_on_response(response_handle)
        -- レスポンス時間の追加
        local start_time = response_handle:headers():get("x-request-start")
        if start_time then
          local duration = os.time() - tonumber(start_time)
          response_handle:headers():add("x-response-time", tostring(duration) .. "ms")
        end
      end

TCPプロキシとマルチプロトコル対応

# TCPプロキシ設定
listeners:
- name: tcp_proxy
  address:
    socket_address:
      address: 0.0.0.0
      port_value: 3306
  filter_chains:
  - filters:
    - name: envoy.filters.network.tcp_proxy
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy
        stat_prefix: tcp_mysql
        cluster: mysql_cluster
        access_log:
        - name: envoy.access_loggers.file
          typed_config:
            "@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
            path: "/var/log/envoy/tcp_access.log"

# Redis Proxy
- name: redis_proxy
  address:
    socket_address:
      address: 0.0.0.0
      port_value: 6379
  filter_chains:
  - filters:
    - name: envoy.filters.network.redis_proxy
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.filters.network.redis_proxy.v3.RedisProxy
        stat_prefix: redis_stats
        prefix_routes:
          routes:
          - prefix: "user:"
            cluster: redis_user_cluster
          - prefix: "session:"
            cluster: redis_session_cluster
          catch_all_route:
            cluster: redis_default_cluster
        settings:
          op_timeout: 5s
          enable_redirection: true

# gRPCプロキシ設定
- name: grpc_proxy
  filter_chains:
  - filters:
    - name: envoy.filters.network.http_connection_manager
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
        stat_prefix: grpc_ingress
        codec_type: AUTO
        route_config:
          name: grpc_route
          virtual_hosts:
          - name: grpc_service
            domains: ["grpc.example.com"]
            routes:
            - match:
                prefix: "/api.UserService/"
              route:
                cluster: grpc_backend
                timeout: 30s
        http_filters:
        - name: envoy.filters.http.grpc_web
          typed_config:
            "@type": type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb
        - name: envoy.filters.http.router
          typed_config:
            "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router