第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%だけアクセスを流す、ということもできそうだ。