ngx_mrubyを使ってコンテンツベースのルーティングを行ってみる
第35会 PaaS勉強会 で Amalgam8 というルーティングサービスが紹介されていて、ふとngx_mrubyを使えばこういうものを作ることはできそうだな、と思ったので試してみた。なお、今回のコードはtakaishi/ngx_mruby-content-base-routingに置いてあります。
今回は、以下の図のような構成とする。基本的にngx_mrubyはproductionサービスにアクセスを流すが、「X-Environment」に「STAGING」を指定した場合だけstagingサービスに流す。
curlを用いた応答は以下のようになり、ヘッダによってレスポンスが変わる。
# production サービス
$ curl http://localhost:8000
Hello World!
# staging サービス
$ curl http://localhost:8000 -H 'X-Environment:STAGING'
[staging] Hello World!
これを実現するnginx.confが以下。ヘッダ情報を見て、条件に合致したかどうかでupstreamのサーバーを書き換えるような仕組み。
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
upstream dynamic {
server 127.0.0.1:80;
}
upstream dynamic_production {
server production:8000;
}
upstream dynamic_staging {
server staging:8000;
}
server {
listen 80;
location / {
mruby_rewrite_handler_code '
Server = get_server_class
u = Nginx::Upstream.new "dynamic"
production = Nginx::Upstream.new "dynamic_production"
staging = Nginx::Upstream.new "dynamic_staging"
hin = Nginx::Headers_in.new
if hin["X-Environment"] == "STAGING"
u.server = staging.server
else
u.server = production.server
end
Nginx.return Nginx::DECLINED
';
proxy_pass http://dynamic/;
}
}
}
現在ロードバランサとしてnginxを使っているのであれば試してみてもいいかもしれない。いきなり専用のツールを使うよりは障壁が低そうだ。もちろん、Kubernetesのようなオーケストレーションに最適化されているかというとそうではないので、場合に応じて使い分ける必要はあるだろう。また、serverの切り替えを確率ベースにすればstagingに全体の1%だけアクセスを流す、ということもできそうだ。