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

zomです。

この記事は[LIFULL Advent Calendar その3](https://qiita.com/advent-calendar/2018/lifull3)の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されていることが確認できます。
<img width="417" alt="スクリーンショット 2018-12-23 5.00.08.png" src="https://qiita-image-store.s3.amazonaws.com/0/46392/8855afd3-d48f-8c6e-3d33-ded3125d22e8.png">

## コマンドをいくつか解説

### 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](https://github.com/matsumotory/ngx_mruby/blob/master/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化でもしておくのがよいかなぁなどと思い着手していたのですが、思いついたのがアドベントカレンダー投稿日の直前で間に合いませんでした。無念。

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