Rubyの未来を感じるようなmod_mrubyでApacheと戯れてみる


今回はmod_mrubyを使ってApacheと戯れたいと思います。
mod_mrubyとは、ペパボのMATSUMOTO Ryosuke氏が作成されたApacheのモジュールで、Rubyを使ってApacheのモジュールが作れるという代物のようです。
「ApacheモジュールをRubyで効率良く実装するためのApacheモジュール。」とのことです。

Apacheのモジュールを作る!なんて敷居が高くて全く手を出したことも考えたこともなかったわけですが、見ながらちょこっと弄くるくらいなら出来そう?
ってことで、やってみますか。

まずは、それどこ情報?どこ情報よー?(・∀・)

人間とウェブの未来 mod_mrubyインストール後入門
http://hb.matsumoto-r.jp/entry/2014/12/09/123816

200万 Webサイトを支える ロリポップ!と mruby
https://speakerdeck.com/harasou/200mo-websaitowozhi-eru-roripotupu-to-mruby

上のリンクからの情報です。

最初に書いておきますが、新しい試みはしていません!スパーン
参考サイトを見ながら動かしながら、ワクテカしながら挙動を見てるだけです。

参考サイト一覧

Githubのページ matsumoto-r/mod_mruby

Apacheによるバーチャルホスト構築レシピ mod_mruby編

ようへいの日々精進XP  mod_mruby を試してみる

Qiita cs_sonar Apacheのmod_vhost_aliasでログをバーチャルホスト単位で分割できない問題をmod_mrubyで解決する

そいではまずはインストールからいきまっする。

サーバーはこないだSuexec環境のテストに使っていたちょっと古いCentOS6を使います。
この事が後に重大な問題に!

関連記事
それもいいんじゃないでSKY

Rubyはrbenvで最新のバージョンをインストールしました。
あとbisonとhiredis-develをインストール。

わりと重要なのがSELINUXを無効化する。
無効化しておかないとハマるぜ!m9(^_^)
っと、ここでハマったのが10行前で言ってた重大な問題でした。

終。

続き。

$ git clone git://github.com/matsumoto-r/mod_mruby.git
$ cd mod_mruby
$ sh build.sh

*** Warning: Linking the shared library src/mod_mruby.la against the
*** static library /root/mod_mruby/mruby/build/host/mrbgems/mruby-redis/hiredis/lib/libhiredis.a is not portable!

*** Warning: Linking the shared library src/mod_mruby.la against the
*** static library ./mruby/build/host/lib/libmruby.a is not portable!
mod_mruby building ... Done
build.sh ... successful
# make install
/usr/sbin/apxs -i -a -n 'mruby' /root/mod_mruby/src/.libs/mod_mruby.so
/usr/lib64/httpd/build/instdso.sh SH_LIBTOOL='/usr/lib64/apr-1/build/libtool' /root/mod_mruby/src/.libs/mod_mruby.so /usr/lib64/httpd/modules
/usr/lib64/apr-1/build/libtool --mode=install cp /root/mod_mruby/src/.libs/mod_mruby.so /usr/lib64/httpd/modules/
libtool: install: cp /root/mod_mruby/src/.libs/mod_mruby.so /usr/lib64/httpd/modules/mod_mruby.so
Warning!  dlname not found in /usr/lib64/httpd/modules/mod_mruby.so.
Assuming installing a .so rather than a libtool archive.
chmod 755 /usr/lib64/httpd/modules/mod_mruby.so
[activating module `mruby' in /etc/httpd/conf/httpd.conf]

これでOKだと思われ。インストールじたいはとても簡単です。

# grep -R mruby /etc/httpd/conf/
/etc/httpd/conf/httpd.conf:LoadModule mruby_module       /usr/lib64/httpd/modules/mod_mruby.so

とりあえず普通にバーチャルホストの設定をします。

その前にMacから名前解決できるようにしとく。
とりあえず3つくらいでいいかしらっと。

$ vim /private/etc/hosts

192.168.24.81   example.com
192.168.24.81   take.example.com
192.168.24.81   jiro.example.com
192.168.24.81   sayo.example.com

httpd.confの編集。

<VirtualHost *:80>
  DocumentRoot /home/take/public_html
  ServerName  take.example.com
<Directory /home/*/public_html>
  Options All
  AllowOverride All
  AddHandler cgi-script .cgi .pl .php
</Directory>
</VirtualHost>

<VirtualHost *:80>
  DocumentRoot /home/jiro/public_html
  ServerName  jiro.example.com
<Directory /home/*/public_html>
  Options All
  AllowOverride All
  AddHandler cgi-script .cgi .pl .php
</Directory>
</VirtualHost>

これでtakeとjiroはローカル環境からは見れるようになったはずです。
次いでmrubyでバーチャルホストの設定をしてみます。

httpd.confに追加します。

mrubyTranslateNameMiddle  /etc/httpd/conf.d/mruby/vhost.rb

設定ファイルを作成。

vim /etc/httpd/conf.d/mruby/vhost.rb
#/usr/local/bin/ruby
# coding: utf-8

r = Apache::Request.new
if ["sayo.example.com"].include?(r.hostname) then
  r.filename = "/home/sayo/html/" + r.uri
          Apache::return(Apache::OK)
else
      Apache::return(Apache::DECLINED)
end

これで3つのドメインで確認ができるようになったと思います。
mrubyの記述の仕方によってはリクエスト毎にコンパイルされるというケースもあるみたいなので、サーバーへの負荷も変わってくると思われます。
適材適所でいこうぜよ。
キャッシュさせておくということもできるようです。

続いてはエラーログをバーチャルホスト毎に取るってのをやってみます。

httpd.confに追加。

mrubyInsertFilterMiddle /etc/httpd/conf.d/mruby/vhost-lo

設定ファイルの作成。

#/usr/local/bin/ruby
# coding: utf-8

r = Apache::Request.new

unless Dir.exist?("/var/log/httpd/" + r.hostname) then
    Dir.mkdir("/var/log/httpd/" + r.hostname , 0705)
end

r.error_log Apache::APLOG_NOTICE, "r.error_log"
r.error_log_into "/var/log/httpd/" + r.hostname + "/error_log"

Apache::return(Apache::OK)

この後に各ドメインにアクセスすると、以下のファイルができました。
気をつけるべくところはやっぱりパーミッションや所有者情報かなと。

# ls -l /var/log/httpd/ | grep "com$"
drwxr-xr-x. 2 apache apache   4096  7月 16 09:37 2015 sayo.example.com
drwx---r-x. 2 apache apache   4096  7月 16 09:39 2015 take.example.com
drwx---r-x. 2 apache apache   4096  7月 16 09:39 2015 jiro.example.com

存在しないファイルへアクセスしてエラーを吐かせます。

# tail /var/log/httpd/take.example.com/error_log
[Thu Jul 16 09:41:15 2015] [error] [client 192.168.24.56] File does not exist: /home/take/public_html/ijigj
[Thu Jul 16 09:41:16 2015] [error] [client 192.168.24.56] File does not exist: /home/take/public_html/ijigj
[Thu Jul 16 09:41:16 2015] [error] [client 192.168.24.56] File does not exist: /home/take/public_html/ijigj

こんな感じだと成功してます。

では最後にアクセスログを生成するっていう事をやってみます。

httpd.confに追加します。

mrubyInsertFilterFirst /var/www/request_dumper.rb

設定ファイルです。

vim /var/www/request_dumper.rb
LOG_FILE = "/var/log/httpd/request.txt"
MAX_LEN = 1024
IN_ONE_LINE = false

def format_time(time)
  sprintf("%04d-%02d-%02d %02d:%02d:%02d",
          time.year, time.month, time.day,
          time.hour, time.min, time.sec
         )
end

def log_write(r)
  File.open(LOG_FILE, "a") do |fh|
    body = r.body.to_s[0...MAX_LEN]
    if r.headers_in["Content-Type"].to_s[0,9] == "multipart"
      body = body.inspect
    end
    headers_str = r.headers_in.all.map{|k, v| "#{k}: #{v}"}.join("\n")
    record = ["[#{format_time(Time.now)}]",
      "#{r.the_request}\n#{headers_str}", "#{body}"]

      if IN_ONE_LINE
        record[1] = record[1].inspect
        fh.write(record.join(' ') + "\n")
      else
        fh.write('='*80 + "\n" + record.join("\n\n") + "\n")
      end
  end
end

r = Apache::Request.new
if r.method_number == Apache::M_GET || r.method_number == Apache::M_POST
  log_write(r)
end

アクセスしてみるとこんなログが出来ます。

================================================================================
[2015-07-16 10:09:08]

POST / HTTP/1.1
Host: sayo.example.com
Connection: keep-alive
Content-Length: 0
CSP: active
Origin: chrome-extension://hgmloofddffdnphfgcellkdfbfbjeloo
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.134 Safari/537.36
hoge: null
Content-Type: application/x-www-form-urlencoded
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: ja,en-US;q=0.8,en;q=0.6


================================================================================
[2015-07-16 10:09:20]

POST / HTTP/1.1
Host: take.example.com
Connection: keep-alive
Content-Length: 0
CSP: active
Origin: chrome-extension://hgmloofddffdnphfgcellkdfbfbjeloo
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.134 Safari/537.36
hoge: null
Content-Type: application/x-www-form-urlencoded
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: ja,en-US;q=0.8,en;q=0.6

ほぼほぼコピーして環境を合わせてという作業でしたがどうでしたでしょうか。
ぼんやり〜〜っとですが、mod_mrubyがどういうものなのかってのはじわじわと感じてきました。
harasouさんのスライドでみたようなプロセス制限やDoS対策とかも時間があれば挑戦してみたいと思います。

では、今日はこの辺で。
分からないと思いますが時刻の同期をとってないので、タイムスタンプがめちゃくちゃです・・。

Similar Posts:


Leave a Reply

Your email address will not be published. Required fields are marked *