4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Envoy 初心者がいくつかハマったこと

Posted at

この記事について

Envoy の初心者である自分が Getting Started などをやってみてハマったことやその調査方法・解決策をまとめたものです。

  • 環境
    • Envoy 1.16.2
    • Ubuntu 18.04

ハマったこと

Google にしかリクエストが通らない?

概要

Envoy のドキュメントの Getting Started では、以下のような Google にリクエストをルーティングする設定ファイルを作る。

envoy.yaml
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: { host_rewrite_literal: www.google.com, cluster: service_google }
          http_filters:
          - name: envoy.filters.http.router
  clusters:
  - name: service_google
    connect_timeout: 0.25s
    type: LOGICAL_DNS
    # Comment out the following line to test on v6 networks
    dns_lookup_family: V4_ONLY
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: service_google
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: www.google.com
                port_value: 443
    transport_socket:
      name: envoy.transport_sockets.tls
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
        sni: www.google.com
admin:
  access_log_path: /tmp/admin_access.log
  address:
    socket_address: { address: 0.0.0.0, port_value: 9901 }

これ自体は問題ないが、試しに上記 YAML で www.google.com になってる個所を全て www.yahoo.comwww.httpbin.org など別のサイトにしたらエラーが返るようになった。ただ、まれに応答が返る場合もある。

$ curl http://localhost:10000
upstream connect error or disconnect/reset before headers. reset reason: local reset

原因

コネクションタイムアウトの時間が 0.25s(250ms) と短いためタイムアウトになっていた。10s とかにしたら問題が無くなった。

  clusters:
  - name: service_google
    connect_timeout: 0.25s  #ここを 10s とかにすればOK

調査方法

  • Envoy から upstream(この場合の www.yahoo.comwww.httpbin.org など)に送るパケットをキャプチャ。
  • Envoy が TLS の ClientHello を送ったすぐ後に自ら TCP の FIN を送っており、タイムアウトではないかと判断。
    • なお、キャプチャを見ると SYN ~ FIN の間が 250ms になってる
      yahoo_timeout.PNG

Upstream のサーバーから切られる

概要

これは単純ミスなので書くほどでないが、何が起きるかという記録のために記載。
先述の問題で試行錯誤しているうちに envoy.yaml の clusters 配下から transport_socket: 以下を削除してしまった。なお、問題とは直接関係ないがその過程で http2_protocol_options を付けている。

envoy.yamlの一部を掲載
  clusters:
  - name: target_service
    connect_timeout: 10s
    type: LOGICAL_DNS
    http2_protocol_options: {}
    dns_lookup_family: V4_ONLY
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: target_service
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: www.google.com
                port_value: 443

すると、以下のようなエラーになる。

$ curl http://localhost:10000
upstream connect error or disconnect/reset before headers. reset reason: connection termination

原因

上記の通り transport_socket: を削除してしまったため、HTTPSサーバー(Port 443)に対して TLS を介さずクリアテキスト(HTTP, h2c)でリクエストを送っていた。
h2c.PNG

ファイルベースの xDS で YAML が使えない

概要

TRY ENVOY の File Based Dynamic Routing Configuration を流すと EDS(Endpoint Discovery Service)の設定を eds.conf というファイルに外だしするが、中身は JSON で書かされる。
YAML で書きたいとググっていたところ、このあたりの記事で YAML で書いてる人を発見。

さっそく eds.conf を YAML 形式で書いてみたが全くリクエストが通らない。

$ curl http://localhost:10000
no healthy upstream

原因

eds.conf の拡張子を .conf から .yaml に変える必要がある。

調査方法

1. 管理サーバー
Envoy の 管理サーバー(っていう呼び方なのか知らないですが)にアクセスすると、クラスターの Endpoint が登録されてない。やはり Endpoint を定義してる eds.conf を読み込めてないらしい。
cluster_none.PNG

正常時はこんな感じ。
cluster_ok.PNG

2. デバッグログ
Envoy を --log-level オプションでデバッグログを有効にして起動。この時は docker-compose を使ったが command を以下のようにした。

version: "3.7"
services:
  envoy:
    // 中略
    command: 
      - "--config-path /etc/envoy/envoy.yaml"
      - "--log-level trace"

docker logs で見たらこんなログが出ていた(見やすさのために一部の情報は削除)。やはり JSON としてパースされてそう。

[2020-12-29 09:40:00.438] added watch for directory: '/etc/envoy' file: 'eds.conf' fd: 1
[2020-12-29 09:40:00.438] adding TLS initial cluster target_cluster
[2020-12-29 09:40:00.438] Filesystem config refresh for /etc/envoy/eds.conf
[2020-12-29 09:40:00.439] Filesystem config update failure: Unable to parse JSON as proto (INVALID_ARGUMENT:Unexpected token.
version_info: "0"
(以下略)

ログを元にソースを見たら拡張子を見て読み込み処理を分けていた。YAML の場合は .yaml にする必要がある(なお、該当するものがなければJSONとしてパースしてる)。

envoy/source/common/protobuf/utility.cc
void MessageUtil::loadFromFile(const std::string& path, Protobuf::Message& message,
                               ProtobufMessage::ValidationVisitor& validation_visitor,
                               Api::Api& api, bool do_boosting) {

  // ".pb" の場合
  if (absl::EndsWith(path, FileExtensions::get().ProtoBinary)) {
      //...
  }
  // ".pb_text" の場合
  if (absl::EndsWith(path, FileExtensions::get().ProtoText)) {
      //...
  }

  // YAML の場合
  if (absl::EndsWith(path, FileExtensions::get().Yaml)) {
    loadFromYaml(contents, message, validation_visitor, do_boosting);
  } else {
    // その他は JSON とみなす
    loadFromJson(contents, message, validation_visitor, do_boosting);
  }
envoy/source/common/protobuf/utility.h
  class FileExtensionValues {
  public:
    const std::string ProtoBinary = ".pb";
    const std::string ProtoBinaryLengthDelimited = ".pb_length_delimited";
    const std::string ProtoText = ".pb_text";
    const std::string Json = ".json";
    const std::string Yaml = ".yaml";  // YAML の場合の拡張子。
  };

  using FileExtensions = ConstSingleton<FileExtensionValues>;

調査方法まとめ

Envoy のデバッグログ

envoy のコマンドラインオプションで -l または --log-level によりログレベルを指定できる。詳細なログを見る場合は tracedebug を指定すればよさそう。

   -l <string>,  --log-level <string>
     Log levels: [trace][debug][info][warning
     |warn][error][critical][off]

Docker で起動する場合はこんな感じ。

docker run --name=envoy -d \
  -p 10000:10000 \
  -p 9901:9901 \
  -v $(pwd)/envoy.yaml:/etc/envoy/envoy.yaml \
  envoyproxy/envoy:v1.16.2 \
    --config-path /etc/envoy/envoy.yaml \
    --log-level debug

他にもログ関連のオプションがあるため、Command line options を見てください。

管理サーバー

envoy.yaml で admin: で定義するやつです。

admin:
  access_log_path: /tmp/admin_access.log
  address:
    socket_address: { address: 0.0.0.0, port_value: 9901 }

Envoy の構成やステータス情報を見れて、自分は今回主にclusters を見たけど他にも調査に役立つはず。

admin_server.PNG

ところで、envoy.yaml の access_log_path: /tmp/admin_access.log で指定してるログは、自分がハマったように Upstream からエラーが返るといった場合は記録が残らなかった(あくまで試した範囲では)。

その他

その他は定番ですがパケットキャプチャ、あとは、中身を見ないと分からない場合はEnvoyのソースを追う、などでしょうか。

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?