OSvのような環境でもサクっと動くmrubyのWebサーバ作った

OSvがとても面白いので色々いじっていると、結果的にmruby-simplehttpserverというWebサーバをmrubyで動かすためのmrubyモジュールができてしまいました。

これは、OSvのようにライブラリをがんがん入れられないような環境でも、とりあえずSocketとIOがあれば動くシンプルなWebサーバを動かすためのmrubyモジュールです。

そもそもOSvって何?という方はこの辺りを見るかsyuu1228さんに聞くのが良いと思います。簡単に言うと、これからの時代、ハイパーバイザにがんがん仮想マシンをデプロイする際に、その仮想マシンにリッチなOSがあまり必要ないケースって結構あって(例えばmemcachedだけが動いているVMとか)、OSvはそういう用途に省メモリかつCPUのオーバーヘッドを低減して高速に動作するまるでプロセスのように扱えるOSです。プロセスは言い過ぎましたが、仮想マシンにも関わらず起動はmruby使用の場合、1、2秒で起動するので非常に高速です。

で、通常はコアの上にJVMがのっていってその上にサーバ+アプリケーションが動く仕組みになっているのですが、そのJVMの部分を他のVM(言語処理系的な意味合いの)を載せ替える事もできて、そこにサクっとsyuu1228さんがmrubyのVMをのせるハックをして今では本家にもマージされ、コアの上でmrubyのVMを動くようにimageを作ればアプリケーションとしてmrubyで書いたコードが動くようになります。JVMもZFSも取り外しているのでかなり高速かつ軽量に動作します。

かといって、OSvはUbuntuとかそういうライブラリをどんどん入れられるようなリッチな環境ではないのですが、Javaアプリが動く程度にSocketやIO等は普通に動くのでそれにのみ依存したWeb機能を持ったmrubyアプリケーションサーバをつくろうと思った次第です。mruby-simplehttpserverを使えば、OSv上で動くmrubyでWebアプリケーションを容易に実装することができるようになりました。

このような特徴を持つOSvをうまく使えば、状態を持つデータはどこか別の場所に置いておいて、OSvやその上で動くアプリケーションをイミュータブルに動かしたりと、次の世代の使い捨てデプロイ手法を実現しやすくなるのではないでしょうか。そういう方向性でもOSvは興味深いOSだと思っています。

前置きが長くなりましたが、では実際に動かしてみましょう。

OSvでmrubyのWebサーバを動かしてみよう

OSvでmrubyを動かすのはこの辺りを見るとよいでしょう。

ここで、make moduleする際にbuild_config.rbにmruby-simplehttpserverをリンクさせるようにします。

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

conf.gem :git => https://github.com/matsumoto-r/mruby-simplehttpserver.git

[/program]

さらに、server.rbというRubyスクリプトを用意します。

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

#
# Server Configration
#

server = SimpleHttpServer.new({

  :server_ip => "0.0.0.0",
  :port  =>  8000,

  # not implemented
  :document_root => "./",
})

#
# HTTP Initialize Configuration Per Request
#

server.http do
  server.set_response_headers ["Server: OSv-mruby-WebServer"]
  server.set_response_headers ["Date: #{server.http_date}"]
end

#
# Location Configration
#

# You can use request parameters in location
#   r.method
#   r.schema
#   r.host
#   r.port
#   r.path
#   r.query
#   r.headers
#   r.body

server.location "/osv" do |r|
  server.response_body = "Hello OSv + mruby World.\n"
  server.create_response
end

# /mruby location config
server.location "/mruby" do |r|
  if r.method == "POST"
    server.response_body = "Hello mruby World. Your post is '#{r.body}'\n"
  else
    server.response_body = "Hello mruby World at '#{r.path}'\n"
  end
  server.create_response
end

# /mruby/ruby location config, location config longest match
server.location "/mruby/ruby" do |r|
  server.response_body = "Hello mruby World. longest matche.\n"
  server.create_response
end

server.location "/html" do |r|
  server.set_response_headers ["Content-Type: text/html; charset=utf-8"]
  # or server.response_headers << ["Content-Type: text/html; charset=utf-8"]
  server.response_body = "<H1>Hello mruby World.</H1>\n"
  server.create_response
end

# Custom error response message
server.location "/notfound" do |r|
  server.response_body = "Not Found on this server: #{r.path}\n"
  server.create_response "HTTP/1.0 404 Not Found"
end

server.run

[/program]

そして、server.rbをOSv上でも動かせるようにusr.manifestにコマンドを追加します。

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

/webserver: ${MODULE_DIR}/server.rb

[/program]

ではビルドしてOSvを起動させましょう。

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

sudo make all image=mruby && sudo ./scripts/run.py -v -n
(snip)
OSv v0.08-146-g255e786
eth0: 192.168.122.89
mruby-eshell

$

[/program]

するとこのように起動するので、以下のように先ほどのWebサーバを起動させましょう。

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

$ run webserver

[/program]

そして別端末から、上記のOSv起動時に表示されているIPの8000ポートに対してcurlしてみましょう。

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

$ curl http://192.168.122.89:8000/osv -v

* Hostname was NOT found in DNS cache

*   Trying 192.168.122.89…

* Connected to 192.168.122.89 (192.168.122.89) port 8000 (#0)

> GET /osv HTTP/1.1

> User-Agent: curl/7.35.0

> Host: 192.168.122.89:8000

> Accept: */*

>

* HTTP 1.0, assume close after body

< HTTP/1.0 200 OK

< Server: OSv-mruby-WebServer

< Date: Sun, 18 May 2014 11:58:32 GMT

< Content-Length: 25

<

Hello OSv + mruby World.

* Closing connection 0

[/program]

レスポンスが返って来ましたね。これはserver.rbのlocation設定の/osvに書かれている実装が反映されています。

まとめ

以上のように、比較的リッチな環境ではなくても、SocketとIOが動くような環境であれば動作するシンプルなWebサーバを作りました。これはOSvだけでなく、mrubyを使うような環境においてUbuntuとかリッチな環境ではないデバイス上で動作するLinuxやUnix環境でも、比較的容易にWebサーバ機能および、その上で動作するmrubyWebアプリケーションを動かす事ができるようになったのではないでしょうか。

また、それなりに設定も書きやすく実装したので、SocketやIOが動く程度のデバイスにmrubyを組み込んだ上でWebサーバ機能を動作して遊んでみてください。例のごとく、もっと便利な設定の書き方や工夫があればPull Requestもお待ちしております。