コンテンツにスキップ

envoy.yaml@Envoy

はじめに

本サイトにつきまして、以下をご認識のほど宜しくお願いいたします。


01. セットアップ

インストール

かなり大変なため、DockerfileやIstio経由でインストールすることが推奨。


手動セットアップの場合

▼ Dockerfile

Dockerfileにて、自前の/etc/envoy/envoy.yamlファイルを組み込む。

拡張子は、.ymlではなく、.yamlとする。

FROM envoyproxy/envoy:v1.20.1
COPY envoy.yaml /etc/envoy/envoy.yaml
RUN chmod go+r /etc/envoy/envoy.yaml


自動セットアップの場合

▼ Istio

Istioは、Envoyをベースとしたリバースプロキシを自動的に挿入する。この場合、/etc/istio/proxy/envoy-rev0.jsonファイルを設定ファイルとして扱う。


設定ファイルに関する補足情報

▼ ドキュメントの探し方

執筆時点 (2022/11/16) では、設定ファイルのドキュメントの記載が不十分である。

設定ファイルのYAMLファイルのデータ型や階層は、APIのJSON形式と同じ構成になっている。

そのため、設定ファイルのドキュメントで探す代わりに、APIのドキュメントを確認した方が良い。

▼ 設計規約について

Envoyでは、YAMLファイルのキー名がスネークケースになっている。

一方で、サービスメッシュツール (例:Istio、Linkerd) では、ローワーキャメルケースを使用している。


02. admin

adminとは

記入中...


access_log_path

▼ access_log_pathとは

Envoyのアクセスログの出力先を設定する。

*実装例*

admin:
  access_log_path: /dev/null


03. admin.address

addressとは

記入中...


socket_address

▼ protocol

管理ダッシュボードで受信する通信のプロトコルを設定する。

*実装例*

admin:
  address:
    socket_address:
      protocol: TCP

▼ address

受信したパケットのうちで、宛先IPアドレスでフィルタリング可能にする。

0.0.0.0』とすると、任意の宛先IPアドレスを指定するパケットをフィルタリングできるようになる。

*実装例*

admin:
  address:
    socket_address:
      address: 0.0.0.0

▼ port_value

管理ダッシュボードでインバウンド通信を待ち受けるポート番号を設定する。

*実装例*

admin:
  address:
    socket_address:
      port_value: 9901


04. static_resources

static_resourcesとは

静的な値を設定する。

執筆時点 (2022/11/12) では、listenersキーとclustersキーのみを設定できる。


05. static_resources.listeners

listenersとは

受信する通信のリスナーを設定する。


address

▼ protocol

受信する通信のプロトコルを設定する。

*実装例*

static_resources:
  listeners:
    - address:
        socket_address:
          protocol: TCP

▼ address

受信したパケットのうちで、宛先IPアドレスでフィルタリング可能にする。

0.0.0.0』とすると、任意の宛先IPアドレスを指定するパケットをフィルタリングできるようになる。

*実装例*

static_resources:
  listeners:
    - address:
        socket_address:
          address: 0.0.0.0

▼ port_value

受信したパケットのうちで、宛先ポート番号でフィルタリング可能にする。

*実装例*

static_resources:
  listeners:
    - address:
        socket_address:
          port_value: 80


filter_chains.filters

▼ name

使用するフィルターを設定する

*実装例*

ネットワークフィルターであるnetwork.http_connection_managerを指定する。

static_resources:
  listeners:
    - filter_chains:
        - filters:
            - name: envoy.filters.network.http_connection_manager

▼ typed_config.access_log

Envoyのアクセスログの出力方法を設定する。

*実装例*

標準出力に出力する。

static_resources:
  listeners:
    - filter_chains:
        - filters:
            - typed_config:
                access_log:
                  - name: envoy.access_loggers.stdout
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog

▼ http_protocol_options

static_resources:
  clusters:
    - typed_extension_protocol_options:
        envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
          "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
          http_protocol_options:

▼ typed_config.stat_prefix

統計ダッシュボードのメトリクスの接頭辞を設定する。

*実装例*

static_resources:
  listeners:
    - filter_chains:
        - filters:
            - typed_config:
                stat_prefix: ingress_http


filter_chains.filters.typed_config.@type

▼ typed_config.@type

使用する拡張機能名を (例:フィルターなど) 設定する。

拡張機能名を指定することにより、その拡張機能の設定を定義できるようになる。

これは、Envoyではなく、gRPCの機能の由来している。

RPCでは、JSON内のデータのデータ型を指定するために使用する。

network.tcp_proxy

network.tcp_proxyはデフォルトで有効になっているネットワークフィルターである。

EnvoyがL4プロトコルを処理できるようになる。

network.http_connection_managerとは異なり、ルートではなくクラスターに処理を繋ぐ。

*実装例*

static_resources:
  listeners:
    - filter_chains:
        - filters:
            - name: envoy.filters.network.tcp_proxy
              typed_config:
                "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy
                # クラスター
                cluster: foo_cluster
                ...

network.http_connection_manager

network.http_connection_managerはデフォルトで有効になっているネットワークフィルターである。

EnvoyがL7プロトコルを処理できるようになる。

network.tcp_proxyとは異なり、ルートに処理を繋ぐ。

*実装例*

static_resources:
  listeners:
    - 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
                # ルート
                route_config:
                   name: foo_route
                   ...

http.router

http.routerはデフォルトで有効になっているHTTPフィルターである。

typed_config.route_configを使用できるようにする。

static_resources:
  listeners:
    - 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
                route_config:
                  name: foo_route
                  virtual_hosts:
                    # 仮想ホスト名
                    - name: foo_service

                      ...

                http_filters:
                  - name: envoy.filters.http.router
                    typed_config:
                      # HTTPフィルターを指定する
                      "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

http.grpc_web

http.grpc_webはデフォルトで有効になっているHTTPフィルターである。

受信したHTTP/1.1をHTTP/2.0 (例:gRPCなど) やHTTP/3.0に変換し、gRPCサーバーにプロキシする。

また、gRPCサーバーからのHTTP/2.0のレスポンスをHTTP/1.1に変換する。

http.grpc_http1_bridgeの後継でもある。

static_resources:
  listeners:
    - 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
                route_config:
                  name: foo_route
                  virtual_hosts:
                    # 仮想ホスト名
                    - name: foo_service

                      ...

                http_filters:
                  - name: envoy.filters.http.grpc_web
                    typed_config:
                      # HTTPフィルターを指定する
                      "@type": type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb


filter_chains.filters.typed_config.route_config

▼ route_configとは

特定のルーティング先に関する処理を設定する。

virtual_hosts

仮想ホスト名を設定する。

Envoyが、複数のドメインを仮想的に持ち、Hostヘッダー値で合致した条件に応じて分岐できる。

特にdomainsキーには、受信する通信のHostヘッダー値を設定する。

補足としてHostヘッダーには、インバウンド通信のルーティング先のドメイン名が割り当てられている。

*実装例*

static_resources:
  listeners:
    - 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
                route_config:
                  name: foo_route
                  virtual_hosts:
                    # 仮想ホスト名
                    - name: foo_service
                      # ホストベースルーティング
                      domains:
                        - "*"
                      routes:
                        - match:
                            # パスベースルーティング
                            prefix: "/"
                          route:
                            cluster: foo_cluster

                            ...

                http_filters:
                  - name: envoy.filters.http.router
                    typed_config:
                      # HTTPフィルターを指定する
                      "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

virtual_hosts.routes.route.max_stream_duration

max_stream_durationmax_grpc_timeoutの移行先として追加された設定である。

*実装例*

static_resources:
  listeners:
    - 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
                route_config:
                  name: foo_route
                  virtual_hosts:
                    # 仮想ホスト名
                    - name: foo_service
                      # ホストベースルーティング
                      domains:
                        - "*"
                      routes:
                        - match:
                            # パスベースルーティング
                            prefix: "/"
                          route:
                            cluster: foo_cluster
                            timeout: 30s
                            max_stream_duration:
                              # ストリーミングRPCの確立後のタイムアウト時間を設定する
                              max_connection_duration: 15
                              # ストリーミングRPC全体のタイムアウト時間を設定する
                              max_stream_duration: 30
                              # クライアント側でgrpc-timeoutヘッダーを使用している場合に、これをストリーミングRPCのタイムアウト時間として設定する (max_grpc_timeoutも同じ)
                              # ただし、grpc_timeout_header_maxの設定値を超えて、grpc-timeoutヘッダーを設定できない
                              grpc_timeout_header_max: 30

                http_filters:
                  - name: envoy.filters.http.router
                    typed_config:
                      # HTTPフィルターを指定する
                      "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

Envoyは、gRPCのストリーミングのタイムアウトを適切に処理できておらず、max_grpc_timeoutは非推奨となった。

gRPCは、TCPコネクションの確立前にタイムアウト時間を開始し、ストリーミング時に残りのタイムアウト時間をgrpc-timeoutヘッダーに設定する。

一方でEnvoyは、gRPCクライアントからのリクエストの終了後にタイムアウトを開始し、grpc-timeoutヘッダーとは別にタイムアウトを管理する。

これにより、クライアント側が想定しているタイムアウト時間よりも短い時間でEnvoyがタイムアウト時間を迎える可能性がある。

例えば、以下の図ではクライアント側で25秒のタイムアウト時間を設定したと仮定している。

sequenceDiagram

    foo->>envoy (client): クライアントストリーミング<br>(grpc-timeout: 25s)
    envoy (client)->>envoy (server): 
    envoy (server)->>bar: 

    foo->>envoy (client): 
    envoy (client)->>envoy (server): 
    envoy (server)->>bar: 

    foo->>envoy (client): 
    envoy (client)->>envoy (server): 
    envoy (server)->>bar: 

    envoy (client)->>envoy (client): 全てのリクエスト送信後に<br>grpc-timeoutとは別に<br>タイムアウト時間を管理

    bar-->>envoy (server): 24.5s経過<br>grpc-timeout: 残り0.5s

    envoy (server)-->>envoy (client): 0.25経過<br>grpc-timeout: 残り0.25s

    envoy (client)-->>foo: 0.25経過<br>grpc-timeout: 残0s

上記図の状況で、gRPCサーバーでタイムアウトが起こった時、適切にエラーを処理できないことがある。

例えば、以下のようにgRPCサーバーからのレスポンスよりも先に、gRPCクライアント側のEnvoyは通信を切断してしまうことがある。

そのため、gRPCクライアントにて、ステータスコードをDeadlineExceededではなく、Unavailableとしてしまう。

sequenceDiagram

    foo->>envoy (client): Unary RPC<br>(grpc-timeout: 25s)
    envoy (client)->>envoy (server): 
    envoy (server)->>bar: 
    envoy (client)->>envoy (client): リクエスト送信後に<br>grpc-timeoutとは別に<br>タイムアウト時間を管理

    envoy (client)->>envoy (client): タイムアウト時間切れで<br>grpc-timeoutの前に通信を切断<br>(24.9s)
    envoy (client)-->>foo: タイムアウト
    foo->>foo: Unavailable

    bar->>bar: DeadlineExceeded<br>(25s)
    bar-->>envoy (server): タイムアウト
# 期待する例外スロー
gRPCクライアント # タイムアウト (DeadlineExceededを受信)
⬇⬆︎︎
⬇⬆︎︎
Envoy
⬇⬆︎︎
--------------
⬇⬆︎︎
Envoy
⬇⬆︎︎
⬇⬆︎︎
gRPCサーバー # タイムアウト (DeadlineExceededを投げる)
gRPCクライアント # タイムアウト (Unavailableを受信)
⬇⬆︎︎
⬇⬆︎︎
Envoy
⬇⬆︎︎
--------------
⬇⬆︎︎
Envoy
⬇⬆︎︎
⬇⬆︎︎
gRPCサーバー # タイムアウト (DeadlineExceededを投げる)

しかし、移行先のmax_stream_durationにもgRPCによるHTTPレスポンスの送信とタイムアウトの切断のタイミングに問題がある。

そこで、サービスメッシュツール (例:Istio) では、max_grpc_timeoutを使用し続けている。


name

▼ nameとは

インバウンド通信を受信するリスナーの名前を設定する。

*実装例*

static_resources:
  listeners:
    - name: foo_listener


06. static_resources.clusters

clustersとは

インバウンド通信のルーティング先のマイクロサービスをグループ化する。

対象が1個であっても、clustersキーは必須である。


circuit_breakers

▼ circuit_breakersとは

ルーティング先の同時接続の上限数を設定する。

制限を超過した場合、宛先へのルーティングが停止し、直近の成功時の処理結果を返信する (サーキットブレイカー) 。

*実装例*

static_resources:
  clusters:
    - circuit_breakers:
        thresholds:
          - "priority": "DEFAULT",
            "max_connections": 100000,
            "max_pending_requests": 100000,
            "max_requests": 100000
          - "priority": "HIGH",
            "max_connections": 100000,
            "max_pending_requests": 100000,
            "max_requests": 100000


connect_timeout

▼ connect_timeoutとは

ルーティング時のタイムアウト時間を設定する。

*実装例*

static_resources:
  clusters:
    - connect_timeout: 10s


dns_lookup_family

▼ dns_lookup_familyとは

記入中...

*実装例*

static_resources:
  clusters:
    - dns_lookup_family: v4_only


lb_policy

▼ lb_policyとは

ルーティングのアルゴリズムを設定する。

*実装例*

static_resources:
  clusters:
    - lb_policy: round_robin


load_assignment

▼ endpoints

ルーティング先のIPアドレスとポート番号のリストを設定する。

*実装例*

static_resources:
  clusters:
    - load_assignment:
        endpoints:
          # いずれかのエンドポイントにロードバランシング
          - lb_endpoints:
              - endpoint:
                  address: 192.168.0.1 # クラスターのIPアドレス
                  port_value: 80
              - endpoint:
                  address: 192.168.0.1
                  port_value: 81
              - endpoint:
                  address: foo-service.foo-namespace.svc.cluster.local # クラスター (ここではKubernetesのService) の完全修飾ドメイン名
                  port_value: 82

▼ cluster_name

ルーティング先のグループの名前を設定する。

*実装例*

static_resources:
  clusters:
    - load_assignment:
        cluster_name: foo_cluster


name

▼ nameとは

ルーティング先のグループの名前を設定する。

*実装例*

static_resources:
  clusters:
    - name: foo_cluster


transport_socket

▼ name

ルーティング時に使用するソケット名を設定する。

*実装例*

static_resources:
  clusters:
    - transport_socket:
        name: envoy.transport_sockets.tls

▼ typed_config

HTTPSリクエストを送受信する場合に、証明書を設定する。

*実装例*

サービスメッシュツールを使用せずに、envoyコンテナを直接的に稼働させるとする。

また、静的な値を設定したとする。

static_resources:
  clusters:
    - connect_timeout: 0.25s
      load_assignment:
        cluster_name: local_service_tls
        transport_socket:
          name: envoy.transport_sockets.tls
          typed_config:
            # transport_sockets.tlsを指定する
            "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
            common_tls_context:
              # static_resources.secretsキーで定義したクライアント証明書を設定する。
              tls_certificate_sds_secret_configs:
                - name: client-cert

    ...

  listeners:
    - filter_chains:
        transport_socket:
          name: envoy.transport_sockets.tls
          typed_config:
            # transport_sockets.tlsを指定する
            "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
            common_tls_context:
              # static_resources.secretsキーで定義したSSL証明書を設定する。
              tls_certificate_sds_secret_configs:
                - name: server-cert
              validation_context_sds_secret_config:
                name: validation_context

    ...

  secrets:
    ## SSL証明書
    - name: server-cert
      tls_certificate:
        certificate_chain:
          filename: certs/server-cert.pem
        private_key:
          filename: certs/server-key.pem
    # クライアント証明書
    - name: client-cert
      tls_certificate:
        certificate_chain:
          filename: certs/client-cert.pem
        private_key:
          filename: certs/client-key.pem
    - name: validation_context
      validation_context:
        trusted_ca:
          filename: certs/ca-cert.pem
        verify_certificate_hash:
          E0:F3:C8:CE:5E:2E:A3:05:F0:70:1F:F5:12:E3:6E:2E:97:92:82:84:A2:28:BC:F7:73:32:D3:39:30:A1:B6:FD

*実装例*

サービスメッシュツールを使用せずに、envoyコンテナを直接的に稼働させるとする。また、コントロールプレーンのSDS-APIから取得した動的な値を設定したとする。


type

▼ typeとは

サービスディスカバリーの種類を設定する。

ルーティング先のアドレスをIPアドレスではなくドメイン名で指定する場合、必須である。

*実装例*

static_resources:
  clusters:
    - type: logical_dns


06-02. clusters.typed_extension_protocol_options

envoy.extensions.upstreams.http.v3.HttpProtocolOptions

▼ common_http_protocol_options

static_resources:
  clusters:
    - typed_extension_protocol_options:
        envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
          "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
          common_http_protocol_options:
            idle_timeout: 1s

▼ connect_timeout

static_resources:
  clusters:
    - typed_extension_protocol_options:
        envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
          "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
          connect_timeout: 5s

▼ http2_protocol_options

HTTP/2.0 (例:gRPCなど) について設定する。

static_resources:
  clusters:
    - typed_extension_protocol_options:
        envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
          "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
          http2_protocol_options:
            # ストリーミングRPCの最大同時接続数を設定する
            max_concurrent_streams: 100

▼ upstream_http_protocol_options

static_resources:
  clusters:
    - typed_extension_protocol_options:
        envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
          "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
          upstream_http_protocol_options:
            auto_sni: "true"


05. dynamic_resources

dynamic_resourcesとは

動的に宛先情報を設定する。


ads_config

▼ ads_configとは

ADS-APIに関して設定する。EnvoyがADS-APIにリクエストを送信するように設定できる。

▼ grpc_services

ADS-APIとして使用するクラスター名を設定する。クラスターとはgRPCを使用してパケットを送受信する。ADS-APIの宛先情報は、static_resources.clustersキー配下で設定しておく。

*実装例*

サービスメッシュツールを使用せずに、envoyコンテナを直接的に稼働させるとする。

dynamic_resources:
  ads_config:
    api_type: grpc
    grpc_services:
      - envoy_grpc:
          cluster_name: xds_cluster

# Envoyの識別子を設定する。
node:
  cluster: foo-cluster
  id: foo-id

static_resources:
  clusters:
    # XDS-APIをクラスターとする。
    - name: xds_cluster
      connect_timeout: 0.25s
      # 負荷分散方式
      lb_policy: ROUND_ROBIN
      http2_protocol_options: {}
      load_assignment:
        cluster_name: xds_cluster
        endpoints:
          # いずれかのエンドポイントにロードバランシング
          - lb_endpoints:
              - endpoint:
                  address:
                    # XDS-APIの宛先情報
                    socket_address:
                      address: 127.0.0.1
                      port_value: 15010
    # 定義したXDS-APIのクラスターを指定する。
    - name: services_cluster
      type: EDS
      connect_timeout: 0.25s
      # 負荷分散方式
      lb_policy: ROUND_ROBIN
      eds_cluster_config:
        eds_config:
          resource_api_version: V3
          api_config_source:
            api_type: GRPC
            transport_api_version: V3
            grpc_services:
              - envoy_grpc:
                  cluster_name: xds_cluster

*実装例*

Istioを使用して、envoyコンテナを稼働させるとする。

Kubernetesでは、YAMLファイルのキー名の設計規約がローワーキャメルケースであることに注意する。

dynamicResources:
  adsConfig:
    apiType: grpc
    grpcServices:
      - envoyGrpc:
          clusterName: xds-grpc

staticResources:
  clusters:
    - connectTimeout: 1s
      http2ProtocolOptions: {}
      name: xdsCluster
      type: static
      # xds-apiの宛先情報を設定する
      loadAssignment:
        clusterName: xdsCluster
        endpoints:
          - lbEndpoints:
              - endpoint:
                  address:
                    pipe:
                      # ここではソケットファイルを指定する
                      # envoyとxds-apiのプロセス間で、パケットを送受信する
                      path: ./etc/istio/proxy/xds

▼ set_node_on_first_message_only

記入中...

*実装例*

dynamic_resources:
  ads_config:
    set_node_on_first_message_only: "true"

▼ transport_api_version

記入中...

*実装例*

dynamic_resources:
  ads_config:
    transport_api_version: V3


cds_config

▼ cds_configとは

CDS-APIに関して設定する。

▼ path

cds.yamlファイル (CDS-APIから取得した動的な宛先情報が設定されたファイル) を読み込む。

*実装例*

dynamic_resources:
  cds_config:
    path: /var/lib/envoy/cds.yaml


lds_config

▼ lds_configとは

LDS-APIに関して設定する。

▼ path

lds.yamlファイル (LDS-APIから取得した動的な宛先情報が設定されたファイル) を読み込む。

*実装例*

dynamic_resources:
  lds_config:
    path: /var/lib/envoy/lds.yaml