repl.info

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