Envoy と envoy-filter-example をビルドしてみた

はじめに

Sonmuさんのツイート で紹介されていた How we migrated Dropbox from Nginx to Envoy - Dropbox を読みました。

nginx や Go でプロキシーサーバーを構築することについて、ずっと気になっていたけど私の力不足で性能検証できなくてもやもやしていたことについて詳しく書かれていて非常に参考になりました。

Envoy は moonjit という LuaJIT のフォーク版が組み込まれているが出来ることは限定的なので Dropbox ではこれは使わずに C++ で拡張しているとのことでした。

そこでまずは Hello world 的なものを探すと envoyproxy/envoy-filter-example: Example of consuming Envoy and adding a custom filter というのがありました。

Building の項を見ると、サンプルのフィルター単体ではなく Envoy と合わせてスタティックな実行ファイルのバイナリーをビルドする方式らしいです。

ということでビルドを試してみたメモです。

サンプルではなく Envoy の Docker イメージのビルド

上記のサンプルを試すにはこの項は不要ですが、興味本位で先に Envoy の Docker ビルド手順を試してみることにしました。

Modifying Envoy から Building an Envoy Docker image — envoy tag-v1.15.0 documentation を読んで試しました。

Ubuntu 20.04 LTS に docker 公式パッケージをインストール

Install Docker Engine on Ubuntu | Docker Documentation の apt のレポジトリを追加してインストールしました。

sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"

のところはレポジトリのファイルを分けたいので以下のように変えています。

echo "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable" | sudo tee /etc/apt/sources.list.d/docker.list

Envoy の Docker イメージをビルドを試みるも問題発生

Building an Envoy Docker image — envoy tag-v1.15.0 documentation の Step 1: Build Envoy を試すわけですが、まず Envoy の git レポジトリを取得して移動します。

git clone https://github.com/envoyproxy/envoy
cd envoy

次に手順通り以下のコマンドで Envoy の Docker イメージのビルドを試してみました。

./ci/run_envoy_docker.sh './ci/do_ci.sh bazel.release'

試してた時の私のツイートのスレッド にもありますが、いくつか問題が発生しました。

Docker で IPv6 を有効にする必要がある

まずテストで cannot bind '[::1]:0' というエラーが出ました。

Control Docker with systemd | Docker DocumentationEnable IPv6 support | Docker Documentation を見て /etc/docker/daemon.json を以下の内容で作成しました。

{
  "ipv6": true,
  "fixed-cidr-v6": "2001:db8:1::/64"
}

その後以下のコマンドを実行して反映します。

sudo systemctl reload docker

ビルドの中間ファイルに 220GB 程度空きが必要

10 時間超えてもビルドが終わらないと思ったらルートファイルシステムの使用量が 100% になって Ubuntu の Gnome に警告ダイアログが表示されました。 調べてみると /tmp/envoy-docker-build というディレクトリが作られて約 200GB もディスクを消費していました。

ビルドを試していたマシンは Windows とのデュアルブート構成にしていたのですが、 Windows のパーティションを消して Ubuntu 20.04 LTS を再インストールして十分な空きを確保しました。

また /tmp/ 以下だと Linux の再起動時に消されてしまうと思ったので、場所を変える設定を調べました。

ci/README.mdBuilding and running tests as a developerOn Linux を見ると ENVOY_DOCKER_BUILD_DIR 環境変数で指定可能なことが分かりました。

が、下の

ただし、例の ~/build のように ~ を使うとエラーになり、文字通り ~ というディレクトリが作られてしまいました。

ビルドに時間がかかるので time コマンドで計測しようと思い、以下のコマンドでビルドしました。

time env "ENVOY_DOCKER_BUILD_DIR=$HOME/envoy-docker-build" ./ci/run_envoy_docker.sh './ci/do_ci.sh bazel.release'

上記のコマンドで以下の環境でビルドに4時間45分程度かかりました。

Docker の Spectre 対策を切る

3950Xで30分かからないくらいなので、上記は遅すぎではないかとツッコミのツイートを頂きました。 Lizan ZhouさんはTwitterを使っています 「@hnakamur2 それはかかりすぎな気がします、3950Xで30分かからないくらいなので。ディスクが遅いか、DockerのSpectre対策がオンのままになっているかでは?」 / Twitter

CPU律速なRuby/Pythonコードはデフォルト設定のdocker上で遅くなる - まめめも によると docker の実行時に --security-opt seccomp=unconfined あるいは --privileged を付けると Sepctre 対策が無効になるそうです。

一般にはここに書かれているように「Spectre攻撃に対して脆弱になるのでやめたほうがいい」でしょうが、自宅PCのような占有環境なら付けても良さそうです。

envoy-filter-example のビルド

でビルドしていたら

というツッコミを頂きました。ありがとうございます!