Envoy に入門した話

この記事は、はてなエンジニア Advent Calendar 2019の11日目の記事です。

前置き

Envoyは今話題のIstioやApp Meshのコアに使われているなどサービスメッシュの文脈で名前が出ることが多いですが、Envoy自身はnginxはHAProxyのようなプロキシ・ロードバランサの一種なのでサービスメッシュ関係なく案外簡単に導入することができます。

そのEnvoyを利用する機会があったので、概念の整理とともにどうやって設定を書いていけば良いかまとめていきます。

ファイル分割

設定項目が多いのですぐに行数が増えていくのでファイル分割は最初から考えておくと良いです。

外部通信して設定更新するという仕組み(discovery service)があり、その仕組みの中でファイルから読み込む方法が取れるという世界観です。

機能ごとにCluster, Listener, Routerなどといった名前がついていてそれぞれが何を設定できるのか違ってます。

そしてそのClusterやRouterといった機能ごとの単位でしか分割できないので、さらに細かく区切るということはできません。

ファイル名の指定する場所も機能ごとに変わっていて、リスナとクラスタ設定であればdynamic_resourcesという部分で指定し、ルーティングの設定はリスナの中で指定します。

ファイル読み込みに関しては以下の記事が詳しいです。

www.katacoda.com

medium.com

フィルタ

リクエストを受け取ってなにか処理するものをフィルタと呼びます。

ルーティングするものはenvoy.router, Fault Injectionするものは envoy.fault というフィルタを使います。

フィルタは上に書いた順に処理されるので、ルーティングをするenvoy.routerは最後に書くのが普通です。

今紹介したフィルタはHTTPフィルタ*1 の一種で、他にはTCPフィルタやRedisフィルタなどもあります。

ログ

ログはリスナ設定のとこに書きます。*2

JSONでログを出す場合にはjson_formatというやつが使える...のですが、こちらはすべてクォートで囲まれて文字列になってしまい数値やboolなどを出せません。

なのでクォートで囲まれたくない場合は format で頑張ってJSONの形式を組み立てる必要があります。

まだ検証できていないけれどv1.12.2からあるtyped_json_format *3を使えば数値うまく出せるのかも知れません。

ちなみにログには必ずRESPONSE_FLAGSというものを出したほうが良いです。(デフォルトでも含まれています)

これはステータスコードの細かい理由が記録されるもので、サーキットブレーカー由来なのかそもそも接続に失敗したのかなどが書いてあります。

Envoyの設定チューニングする場合も、このフラグがどういう割合で出ているのか見ることが多いです。

設定ファイルの書式を確認する

ファイル分割をしていると起動->ファイル読み込みという順になり、設定に不備があってもその設定が読み込まれないだけで続行されるという感じになります。

またログもerrorではなくwarningなので知らないと気が付きにくいです。

なのでCI等で設定の検証を回したいなどの場合は、こういう感じで実際に数秒起動してみてwarningのログが出るかを見てチェックするのが良いです。

OUTPUT_FILE=/tmp/envoy.log
CONTAINER_ID=$(docker run -d -p 10000:10000 envoyproxy/envoy:latest envoy \
   --config-path /etc/envoy/envoy.yaml --service-node node \
   --service-cluster cluster --component-log-level \
   config:warning,upstream:error,main:error,runtime:error)
echo $CONTAINER_ID
sleep 5
docker logs $CONTAINER_ID 2> $OUTPUT_FILE
docker kill $CONTAINER_ID
if [ -s $OUTPUT_FILE ]; then
  cat $OUTPUT_FILE
  exit 1
fi

リトライ・タイムアウト

何回リトライするかとか、何秒でタイムアウトするとかを設定できます。

タイムアウトに関する設定はかなり多く最初は混乱しますが、基本的には timeoutper_try_timeout をよく考えるで良いです。

  • timeout:リトライも含む全体のタイムアウト
  • per_try_timeout: 1回のリクエストのタイムアウト
  • num_retries: リトライを何回するか

どういう場合にリトライするかも決められます。*4

5xx が他のルールを含んでいることもあり大体はカバーできているはずですが、POSTリクエストもある場合はretriable-4xxも入れておくとよいのかもしれません。

リトライのバックオフ間隔も変えることができますが*5、デフォルトで既に設定されているのであまり変えることはないかも知れません。

adminインタフェース

別のポートを指定して管理画面を起動することができます。

今動いている設定や統計情報がわかるのでメトリックを取りたい場合はこちらも立てておく必要があります。

多くの情報が確認できる上にこの管理画面からプロセスを落とすこともできるので間違って全世界に公開しないように気をつける必要があるのだけ注意です。

サーキットブレーカー

同時リクエスト数や同時リトライ数など設定できます*6

この中で一番有用なのはmax_retriesで、今このタイミングでリトライしている同時リクエスト数が一定値を超えている場合はそれ以上通信しません。

これにより特に難しいことしなくても詰まっている場合にだけ通信を減らすことができ影響を小さくすることができます。

そしてリトライが捌けたらまた通常通りリクエストを通すようになるという挙動です。

同時リトライ回数の他にもありますが総リクエスト数に影響されるものなので具体的に良い数字を決めるのは難しいと思います。

Fault Injection

Envoyが条件によって通信を遅延させたり、特定のステータスコードを返せる機能です。

これにより通信に時間がかかった際の表示や特定のステータスコードが返ってきた際の挙動を確認することができるので開発時にとても便利です。

確率や特定のヘッダを条件にできるので、ユーザから使われないヘッダで応答を変える条件を書いておいて、いつでも確認できる状態にしておくと良いと思います。

Keep-Alive を無効にする

毎回コネクションを切りたいときにどうすればよいかについて、前に記事を書きました。

通信先がHTTP/1.1だとわかっているなら最初から設定しておくと後ではまらなくていいと思います。

core.cohalz.co

終わりに

Envoyは設定項目が多くまだまだ知らないことがたくさんあります。

パフォーマンスチューニングなんかも全然できていないのでそこら辺も調べていきたいですね。

という記事を書いていたら Envoy Meetup Tokyo #1 というイベントを来年やるようでした。

envoytokyo.connpass.com

気づいたときには満員でLT枠も埋まっていたので行けるかどうかわからないですが...という話題でした

明日のはてなエンジニア Advent Calendar 2019担当は id:motemen です。

リンク集

  • Envoyをロードバランサとして利用する際にどう設定するか日本語で解説してくれている記事

i-beam.org

  • Envoyでユースケース別に設定を学べる
    • nginxやHAProxyとの構文比較もあり英語だけどかなり理解しやすいと思います。

www.katacoda.com