NGINX に追加された UDP ロードバランシングを試してみた
つい先日、 NGINX 公式ブログでアナウンスされた UDP ロードバランシング機能が気になっていたので、まだ正式リリース前ではありますが試してみました。
構成
UDP で代表的なプロトコルといえば DNS なので、今回は
example.com A 127.0.0.10] NGINX --- dns2[Dnsmasq2
example.com A 127.0.0.20]
という構成を Docker Compose で作り、 NGINX に対して dig
コマンドで example.com
の名前解決クエリを送った時に、 127.0.0.10
と 127.0.0.20
が交互に返ってくるかどうかを見ることにしました。この構成を作るに当たって必要なファイルは Github リポジトリとして公開しています。
準備
NGINX
まず、 UDP ロードバランシング機能が含まれている NGINX を用意する必要がありますが、現時点では開発リポジトリ上にのみ存在する状態のため( 1.9.13 で正式リリース予定)、 Mercurial 経由で
hg clone http://hg.nginx.org/nginx
としてソースコードを取得し、
cd nginx
./auto/configure --with-stream
make
make install
のように --with-stream
オプションをつけてコンパイルする必要があります。今回はこれらの一連の NGINX のビルド処理を、 NGINX の Docker 公式リポジトリ の alpine タグの Dockerfile を元に手を加えた Dockerfile を作り、自動化しています。
NGINX が用意できたところで設定ですが、 UDP のみのロードバランシングの場合非常にシンプルなものになります
worker_processes 1;
events {
worker_connections 1024;
}
stream {
upstream dns_udp_upstreams {
server ${DNS1_PORT_53_UDP_ADDR}:53;
server ${DNS2_PORT_53_UDP_ADDR}:53;
}
server {
listen 53 udp;
proxy_pass dns_udp_upstreams;
proxy_timeout 1s;
proxy_responses 1;
}
}
upstream
の設定は通常と同じで、ポイントは server
部ですが、新たに listen
ディレクティブに udp
が指定できるようになっています。
また、 proxy_responses
ディレクティブが追加され、それぞれのクライアント要求において、いくつアップストリームサーバから UDP パケットを受けとったかを数え、 proxy_responses
と同じだけパケットを受けとった場合には接続を閉じる、という処理を定義できます。デフォルトは無制限で、その場合、 proxy_timeout
の時間が経過するまで UDP パケットの到着を待ち続ける形となるようです。
Dnsmasq
実際の DNS リクエストに応答する Dnsmasq は andyshinn/dnsmasq の Docker イメージを使い、二つのサーバの起動オプションにシンプルに --host-record
を追加し、
dnsmasq -k --host-record=example.com,127.0.0.10
dnsmasq -k --host-record=example.com,127.0.0.20
という形でそれぞれ立ち上がるよう設定することとしました。
Docker Compose
上記の NGINX, Dnsmasq の一連の処理を docker-compose.yml にまとめ、 docker-compose up
で環境全体を構築できるようにしています。
動作確認
docker-compose up
を実行して環境を構築後、 Docker Machine を使っている場合はリクエスト先の IP アドレスを docker-machine ip your-machine
で調べておき、下記のようにコマンドを実行すると、交互に結果が返ってくることが確認できるかと思います。
$ dig @192.168.99.100 example.com +short
127.0.0.10
$ dig @192.168.99.100 example.com +short
127.0.0.20
$ dig @192.168.99.100 example.com +short
127.0.0.10
まとめ
非常にシンプルな設定で UDP ロードバランサが構築できることを確認できました。
これまで UDP ロードバランサを構築しようという場合には、ユーザーモードで動作するロードバランサ、リバースプロキシソフトウェアの選択肢がほぼ存在せず、たとえば Linux においては LVS を用いてのロードバランシングが一般的でした。しかしながら LVS はカーネルモードでの動作を必要とし、昨今隆盛を極めているコンテナ内では使用できないなど、 UDP をベースにしたプロトコルを持つサービスを構築する場合には、物理サーバまたは仮想マシンに頼らざるを得ない状況でした。
今回 NGINX による UDP ロードバランシング機能の提供により、他の TCP, HTTP などのプロトコルと同様に、 UDP もより自由度の高い形でロードバランサを構築することが可能となったことから、今後のサーバ構築時の選択肢を大きく変えていくのではないか、と期待しています