EC2にとりあえずnginx*mrubyの環境を作るときの手順


zomです。

この記事はLIFULL Advent Calendar その3の23日目の記事です。つまり私の誕生日です。

要件が非常に軽いもので、アプリケーションサーバを導入することですらオーバースペックなことも世の中にはあると思います。
最近ではそういった場合はLambdaでさっくり作ったりするのが最近のトレンドかと思います。

が、しかし私はJSに対して苦手意識があり、早くRubyが実行できるようになったらいいのに…なんて想いからLambdaを敬遠して生きてきました。(JavaやPythonは書けないです。。。)
(2018年のre:inventでRubyが実行できるようになったのがすごく嬉しいです。ちょっと早いAWSサンタさんありがとう)

といった事情からnginx*mrubyでアプリケーションサーバなしにRubyを実行する環境を作るに至りました。
あと、もともとRubyKaigi2018の影響でmrubyを触ってみたかったという理由もあります。

コマンドだけを抜粋

$ sudo yum -y install gcc pcre-devel zlib-devel git bison openssl-devel readline-devel
$ sudo git clone https://github.com/rbenv/ruby-build.git /usr/local/ruby-build; sudo PREFIX=/usr/local /usr/local/ruby-build/install.sh; sudo CONFIGURE_OPTS="--disable-install-rdoc" /usr/local/bin/ruby-build $(/usr/local/bin/ruby-build --definitions | grep -v - | tail -n 1) /usr/local
$ wget http://download.redis.io/redis-stable.tar.gz -O /tmp/redis-stable.tar.gz; tar xvzf /tmp/redis-stable.tar.gz -C /tmp/; cd /tmp/redis-stable; make; sudo make install
$ git clone https://github.com/redis/hiredis.git /tmp/hiredis.git; cd /tmp/hiredis; make; sudo make install
$ git clone https://github.com/matsumotory/ngx_mruby.git /tmp/ngx_mruby; cd /tmp/ngx_mruby/; NGINX_CONFIG_OPT_ENV='--prefix=/etc/nginx' sh build.sh; sudo PATH=$PATH:/usr/local/bin make install

これでインストールまでが完了します。
続いてnginxのconfファイルにmrubyのコードを書くことで動作確認ができます。

$ sudo vi /etc/nginx/conf/nginx.conf

+     48         location /hello {
+     49             mruby_content_handler_code '
+     50                 Nginx.echo "hello ngx_mruby world!"
+     51             ';
+     52         }

$ sudo /etc/nginx/sbin/nginx -t
nginx: the configuration file /etc/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/conf/nginx.conf test is successful
$ sudo /etc/nginx/sbin/nginx

今回お試しなのでpublic subnetに配置したEC2にEIPを振り、SGでも80でのアクセスを許可するようにしています。
なのでこのようにアクセスすることでmrubyのコードが実行されてhello worldされていることが確認できます。

コマンドをいくつか解説

yumでのインストール

各種コマンドに必要なライブラリを何らかの手段で入れておく必要があります。なので一番最初にyumでまとめてインストールします。
内訳としては以下のとおりです。

  • nginxのために
    • gcc
    • pcre-devel
    • zlib-devel
  • Rubyのために
    • openssl-devel
    • readline-devel
  • mrubyのために
    • git
    • bison

ruby-buildのインストール

mrubyをインストールするためにはrakeが実行できる必要があります。rakeはRuby製のビルドツールです。つまりRubyが実行できる環境が必要です。
ruby-buildはいろんなバージョンのRubyを簡単にインストールするためのコマンドラインツールです。よくrbenvと組み合わせて使われていますが、Rubyのバージョンを切り替える必要がない場面ではスタンドアロンとしても使えます。今回もあくまでもmrubyのインストールのためだけにRubyを使いたかったのでスタンドアロンで使います。

CONFIGURE_OPTS="--disable-install-rdoc"について

Rubyのインストールは非常に時間がかかります。
今回、検証用にt3.microインスタンスを使っていましたが、早くても10分、遅いときは20分以上かかっていました。
少しでもインストールを早くするためにrdoc、つまりドキュメントをインストールしないというオプションを指定しています。

/usr/local/bin/ruby-build $(/usr/local/bin/ruby-build --definitions | grep -v - | tail -n 1) /usr/localについて

端的に書くと、最新のRubyのバージョンを指定するための記述です。
※なんで絶対パスで書いたのか覚えてません…。絶対パスである必要はないかもしれません。

ruby-build --definitionsでインストール可能なRubyのバージョンの一覧が表示されます。
それに対しgrep -v -で-を含むバージョンを除外しています。
2018年末現在のRubyの命名ルールとして、幸いにも他の実装系やRC版などの命名が-を含んでくれているおかげでMRIだけに絞ることができます。
そしてtail -n 1で最終行、つまり最新版のものを取得しているというものです。
_区切りの命名の実装が出てきた瞬間にこの実装は破綻するのでいきなり動かなくなる可能性もあります。

redis、hiredisのインストール

redisを使わないなら必要ないかもしれません。
私の場合は、私が冒頭に述べた

要件が非常に軽いもの

というのがまさにredisにセットをしたい、というものでしたので入れてました。

nginxとmrubyのインストール

nginxのソースを事前にダウンロードして、tarを伸張しておきNGINX_SRC_ENVオプションでソースファイルを指定することもできます。
していない場合はnginx_versionファイルによって指定されているバージョンのnginxをダウンロード・インストールしてくれます。

NGINX_CONFIG_OPT_ENV='--prefix=/etc/nginx'このようにすることでnginxのインストール先が指定できます。

sudo PATH=$PATH:/usr/local/bin make installに関してですが、Rubyのインストール先を/usr/local/binにしています。特に何も設定をしていなければsudo時にはpathが引き継がれないためruby(rake)のコマンドが見つからずエラーになります。
ただsudoをつけずにmake installをしてしまうと/etcへの書き込み権限がなくてエラーになります。
ということで苦肉の策でPATHに/usr/local/binを一時的に追加することで問題を回避しています。ちょっとつらかった。

その他ここには書いていないこと(gitプロトコルのポートのこと)

mrubyのインストール時に内部的にgitプロトコルでgit cloneをする箇所があります。

$ find /tmp/ngx_mruby/ -type f -print | xargs grep "git clone git://"
/tmp/ngx_mruby/mruby/build/mrbgems/mruby-redis/mrbgem.rake:      run_command e, 'git clone git://github.com/redis/hiredis.git'
/tmp/ngx_mruby/mruby/build/mrbgems/mruby-redis/src/Makefile:    cd tmp; git clone git://github.com/mruby/mruby.git
/tmp/ngx_mruby/mruby/build/mrbgems/mruby-vedis/Rakefile:  sh "git clone git://github.com/mruby/mruby.git"
/tmp/ngx_mruby/mruby/build/mrbgems/mruby-vedis/mrbgem.rake:      run_command e, 'git clone git://github.com/symisc/vedis.git'

そのためgitプロトコルをNACLなどで許可するようにしておく必要があります。
githubでgit/httpsを切り替える際のリンクが「Use ssh」とか書いてあるから22番ポートを許可していればいいのかな、とか思っていたのですが、ここにあるのはgit::なので22番ではなく9418番ポートを使っているとのことで少しの間ハマっていました。
普段やらないことをやるといろんな気付きがありますね。

終わりに

まとめてみればわずか6行くらいのコマンドで済む話ではありますが、いくつかの試行錯誤をしながらの環境構築でした。
そして環境を構築するとなったときに毎回このコマンドを実行するっていうのも手間だよなぁと思ってansibleのplaybook化でもしておくのがよいかなぁなどと思い着手していたのですが、思いついたのがアドベントカレンダー投稿日の直前で間に合いませんでした。無念。

いつかやるかもしれないしやらないかもしれません。