引き続き「Try Envoy」を使って Envoy を学ぶ.今回は nginx と Envoy を比較したコンテンツ「Migrating from NGINX to Envoy Proxy」を紹介する.nginx の nginx.conf
を Envoy の envoy.yaml
にどのようにマイグレーションするのか?を学べる.
Migrating from NGINX to Envoy Proxy
手順は以下の「計7種類」ある.今回もサイトの表記は「Estimated Time: 10 minutes」と書いてあるけど,気にせずに進める.
- Step.1 「NGINX Example」
- Step.2 「NGINX Configuration」
- Step.3 「Server Configuration」
- Step.4 「Location Configuration」
- Step.5 「Proxy and Upstream Configuration」
- Step.6 「Logging Access and Errors」
- Step.7 「Launching」
Step.1 「NGINX Example」
nginx の設定には「ログ設定」や「ポート設定」や「ルーティング設定」などを書く.Envoy の場合は nginx と異なる仕組みとなり,大きく以下の4種類のコア設定から構成されている.詳しくは前回の記事にもまとめた.
- Listeners
- Filters
- Routers
- Clusters
Step.2 「NGINX Configuration」
まず nginx で「ワーカーコネクション」の設定をする場合,よく worker_processes
と worker_connections
をチューニングする.worker_processes
に CPU コア数を指定したり,auto
を指定する.Envoy の場合はどのようにコネクションを管理するのだろうか?
worker_processes 2; events { worker_connections 2000; }
Envoy の場合は,ハードウェアスレッドに対してワーカースレッドを作成し,ワーカースレッドはノンブロッキング処理をすると書いてある.それ以上は書いてなく,詳しい解説は Envoy 公式ブログを参照する必要がある.例えば「Main / Worker / File Flush」という個別のスレッドがあったり,アクセスログを出力するときはロックを取得したり,スレッドをうまく活用する仕組みの名前が「Thread Local Storage (TLS)」だったり,Envoy のスレッドモデルに興味があれば読んでおくと良さそう.
Step.3 「Server Configuration」
以下の nginx.conf
を読むと,server_name
に指定されたドメインから 8080 Port でリクエストを受けることになる.
server { listen 8080; server_name one.example.com www.one.example.com; }
もし同じ設定を Envoy に設定する場合,envoy.yaml
の listeners
にポート番号を設定する.ドメインはここには設定せず,次の filters
に設定する.前回と似ているため,envoy.yaml
は見慣れてきたような気がする.
static_resources: listeners: - name: listener_0 address: socket_address: { address: 0.0.0.0, port_value: 8080 }
Step.4 「Location Configuration」
引き続き nginx.conf
を読み解いていく.以下の設定は /
にリクエストをすると http://targetCluster/
に転送される.
location / { proxy_pass http://targetCluster/; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }
もし同じ設定を Envoy に設定する場合,envoy.yaml
の filters
で envoy.http_connection_manager
を使う.これは前回も出てきた HTTP を制御するフィルタで,ここにドメインとリクエストを受けるプレフィックスを設定している.転送する設定は次の clusters
に設定するため,ここでは Cluster
名を設定している.
filter_chains: - filters: - name: envoy.http_connection_manager config: codec_type: auto stat_prefix: ingress_http route_config: name: local_route virtual_hosts: - name: backend domains: - "one.example.com" - "www.one.example.com" routes: - match: prefix: "/" route: cluster: targetCluster http_filters: - name: envoy.router
前回は特に気にしなかったパラメータとして codec_type
がある.ドキュメントを読むと「AUTO
/ HTTP1
/ HTTP2
」を設定できる.基本的にはデフォルトの AUTO
で良さそうだけど,例えば HTTP1
を設定すると,通信を HTTP/1.1
に強制できる.
次に domains
で,これは virtual_hosts
の中で必須のパラメータになっている.one.example.com
のように正確なドメイン名を設定しても良いし,*
を使って部分一致を設定することもできる.
Step.5 「Proxy and Upstream Configuration」
nginx.conf
に upstream
を設定すると,クラスタを表現できる.今回は IP アドレスを2個設定している.
upstream targetCluster {
172.18.0.3:80;
172.18.0.4:80;
}
転送する設定は clusters
を使う.clusters
には「タイムアウト」や「負荷分散」などを設定できる.
clusters: - name: targetCluster connect_timeout: 0.25s type: STRICT_DNS dns_lookup_family: V4_ONLY lb_policy: ROUND_ROBIN hosts: [ { socket_address: { address: 172.18.0.3, port_value: 80 }}, { socket_address: { address: 172.18.0.4, port_value: 80 }} ]
まず,type
にサービスディスカバリの種類を設定する.デフォルトのパラメータは STATIC
で,リスト全てを対象とする.今回は STRICT_DNS
が設定されているため,名前解決をする.正直今回の構成だと STATIC
で良いのではないか?と思うけど,STRICT_DNS
になっている理由や,もう1個類似したパラメータとして LOGICAL_DNS
もあり,このあたりは別途調べないとクリアにならなそう.
lb_policy
には負荷分散のタイプを指定する.今回はデフォルトのパラメータ ROUND_ROBIN
でラウンドロビンになっているけど,他にも LEAST_REQUEST
や RING_HASH
など,気になるタイプが多く使えるようになっている.
Step.6 「Logging Access and Errors」
最後はログ設定となり,今回は envoy.file_access_log
を使って stdout
に出力する.なお,ログ設定は filters
に設定するため,抜粋すると以下のようになる(access_log
以外は省略している).format
を設定すると項目をカスタマイズできるし,json_format
を設定すると JSON 形式で出力できる.
filter_chains: - filters: - name: envoy.http_connection_manager config: access_log: - name: envoy.file_access_log config: path: "/dev/stdout" json_format: {"protocol": "%PROTOCOL%", "duration": "%DURATION%", "request_method": "%REQ(:METHOD)%"}
Step.7 「Launching」
作成した envoy.yaml
を試す.今回は以下の構成図のように Envoy コンテナと HTTP コンテナを2個起動する.HTTP コンテナは katacoda/docker-http-server
となり,これは Go の net/http
パッケージを使って,ホスト名を表示するだけの実装になっている.
$ docker run --name proxy1 -p 80:8080 --user 1000:1000 -v /root/envoy.yaml:/etc/envoy/envoy.yaml envoyproxy/envoy $ docker run -d katacoda/docker-http-server $ docker run -d katacoda/docker-http-server
実際に Envoy コンテナに Host Header 付きでリクエストをする.レスポンスのホスト名(コンテナ ID)を見ると,ラウンドロビンになっていることがわかる(date
は修正している).
$ curl -H "Host: one.example.com" localhost -i HTTP/1.1 200 OK date: Sat, 30 Nov 2019 17:00:00 GMT content-length: 58 content-type: text/html; charset=utf-8 x-envoy-upstream-service-time: 0 server: envoy <h1>This request was processed by host: 1c7446d81170</h1> $ curl -H "Host: one.example.com" localhost -i HTTP/1.1 200 OK date: Sat, 30 Nov 2019 17:00:00 GMT content-length: 58 content-type: text/html; charset=utf-8 x-envoy-upstream-service-time: 0 server: envoy <h1>This request was processed by host: 8c2ba95ccec2</h1>
さらに今回は envoy.yaml
でドメインを設定しているため,Host Header なしでリクエストをすると,404 になった.
$ curl localhost -i HTTP/1.1 404 Not Found date: Sat, 30 Nov 2019 17:00:00 GMT server: envoy content-length: 0
まとめ
- 「Try Envoy」のコンテンツ「Migrating from NGINX to Envoy Proxy」を試した
- 個人的に慣れている
nginx.conf
の設定項目をenvoy.yaml
に書き換えていくことにより,理解を深められた - Envoy の設定はバリエーションが多く,ドキュメントを読みながらどんどん試したいと思う