ngx_mrubyでnginxの内部変数を操作する

最近はコード書きに時間をとれていませんが、昨日は久々にngx_mrubyを少し触る事ができたので、その際にできるようになったタイトルのような処理を紹介したいと思います。

ngx_mrubyでnginxの内部変数を操作

今のngx_mrubyは、nginx.conf上で設定した変数やnginxのコア変数をmruby上でgetしたり、mruby上で変数に値をsetしたりすることができるようになりました。

また、mruby_setというディレクトリを使うと、nginx.conf上での変数設定時に、mrubyのコードの結果を渡す事ができます。さらにはそのコード内で、それより以前にsetディレクティブで設定した変数を呼び出す事ができます。

confに直接Rubyを書く場合

日本語で書くと結構分かりにくいのでサンプルを示します。例えば、以下のようにconfを書きます。

[program lang=’ruby’ escaped=’true’]

location /check {

    # 変数fugaに100をset
    set $fuga "100";

    # mruby内で変数fugaを取得しその倍の値を変数hogeにset
    mruby_set_code $hoge ' 
      r = Nginx::Request.new
      r.var.fuga.to_i * 2
    ';

    # さらに変数をそれぞれ2倍する
    mruby_access_handler_code '
      r = Nginx::Request.new
      r.var.set "fuga", r.var.fuga.to_i * 2
      r.var.set "hoge", r.var.hoge.to_i * 2
    ';

    # レスポンスに変数表示
    echo "fuga => $fuga";
    echo "hoge => $hoge";
}

[/program]

内容はコメントの通りなのですが、基本的にやりたいことはnginx.confで変数を用意しておいて、それをmruby内で弄って、ちゃんとnginx.conf上で反映されているかを試したいのが意図です。

mruby_set_codeは、第二引数に記述したRubyコードの結果を、第一引数の変数にsetする処理になっていてます。また、Rubyコード内では、r.var.{変数名}でnginxの変数を取得でき、r.var.setで第一引数に渡したnginxの変数名に値を入れる事ができます。

この設定でアクセスすると、以下のようになるでしょう。

[program lang=’bash’ escaped=’true’]

$ curl http://127.0.0.1:8000/check
fuga => 200
hoge => 400

[/program]

きちんと、mrubyとnginx間で変数が共有されていることがわかります。

ファイルにRubyを書く場合

上記の例では、nginxのconfに直接書いているのでnginx起動後は変更できませんが、以下のようにファイルに書いてやれば、nginx起動後でも好きなように変更可能で、変更後は即時nginxに反映させることができます。

mruby_set.rbという以下のコードを書きます。

[program lang=’ruby’ escaped=’true’]

r = Nginx::Request.new

r.var.fuga.to_i * 2

[/program]

次に、mruby_access.rbという以下のコードを書きます。

[program lang=’ruby’ escaped=’true’]

r = Nginx::Request.new

r.var.set "hoge", r.var.hoge.to_i * 2
r.var.set "fuga", r.var.fuga.to_i * 2

[/program]

そして、nginx.confに以下のような設定を書きます。

[program lang=’ruby’ escaped=’true’]

location /var {
    set $fuga "200";
    mruby_set $hoge "/path/to/mruby_set.rb";
    mruby_access_handler "/path/to/mruby_access.rb";

    echo "fuga => $fuga";
    echo "hoge => $hoge";
}

[/program]

この設定で、nginxにアクセスすると以下のようになります。

[program lang=’bash’ escaped=’true’]

$ curl http://127.0.0.1:8000/var
fuga => 400
hoge => 800

[/program]

きちんと変数が処理できていますね。また、ファイルベースの場合は、mruby_set.rbを変更すると、その次のアクセスあからはその変更通りの動きになっていることが確認できると思います。

最後に

このように、ngx_mrubyを使えばnginxの内部変数をmruby側から自由に操作する事ができるようになってきました。

これをうまく使えば、nginxで書きにくかった条件分岐や、nginx特有の設定DSLをうまくRubyの記述に置き換える事ができるのではないでしょうか。それによって、nginxをさらに柔軟に拡張していけると思います。

非、色々試して頂いて、こんな事ができたという事例やバグ報告、さらにはコントリビュートしていただけるととても嬉しいです!