mod_mruby、DockerのONBUILDを使ってビルドしたら便利

## すいませんでした...

24日に登録したつもりでいました。この記事は mod_mruby・ngx_mruby Advent Calendar 2014 **23日** の記事となります...

気を取り直して。

## Dockerでビルド君を作ろう

クリスマスなのでmod_mrubyをDockerでビルドします。ただビルドするだけでなく、バイナリを吐き出してみましょう。

公式をもとにこういうDockerfileを作る。

```docker:base/Dockerfile
FROM ubuntu:trusty
MAINTAINER Uchio KONDO <udzura@udzura.jp>

ENV DEBIAN_FRONTEND noninteractive
RUN apt-get -y update
RUN apt-get -y install \
    sudo git curl bison \
    apache2 apache2-dev apache2-utils \
    ruby2.0 ruby2.0-dev rake \
    libcurl4-openssl-dev libhiredis-dev libmarkdown2-dev libcap-dev libcgroup-dev

WORKDIR /usr/local/src/
RUN git clone https://github.com/matsumoto-r/mod_mruby.git

WORKDIR /usr/local/src/mod_mruby
RUN git submodule init
RUN git submodule update

ADD run-all.sh /usr/local/bin/run-all.sh
RUN chmod a+x /usr/local/bin/run-all.sh

ENTRYPOINT ["/usr/local/bin/run-all.sh"]
CMD ["build"]
```

`run-all.sh` はこんな感じで。

```sh:base/run-all.sh
#!/bin/bash
set -x
set -e

if [ "$1" = "check" ]; then
  check=true
fi

sh build.sh 1>&2
make install 1>&2

if [ -z "$check" ]; then
  cat /usr/local/src/mod_mruby/src/.libs/mod_mruby.so
else
  file /usr/local/src/mod_mruby/src/.libs/mod_mruby.so
  ls -l /usr/local/src/mod_mruby/src/.libs/mod_mruby.so
fi
```

あとは

```console
$ docker build -t udzura/mod_mruby-builder base/
$ docker run --rm udzura/mod_mruby-builder > out/mod_mruby.so
$ file out/mod_mruby.so 
out/mod_mruby.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, not stripped
```

これを64bit Ubuntuに突っ込めば動きます。便利!!!!（`apt-get -y install libhiredis0.10` はあらかじめ必要です）。

## `ONBUILD` で `build_config.rb` をカスタマイズする

ここまでなら、同じようなことを @hfm さんがやっていらっしゃる。

- https://github.com/tacahilo/docker-ngx_mruby-memcached

もうすこしDockerらしくするために `ONBUILD` で `build_config.rb` をカスタマイズするの術を使ってみます。

```diff
diff --git a/base/Dockerfile b/base/Dockerfile
index 36624ec..0145f7f 100644
--- a/base/Dockerfile
+++ b/base/Dockerfile
@@ -19,5 +19,7 @@ RUN git submodule update
 ADD run-all.sh /usr/local/bin/run-all.sh
 RUN chmod a+x /usr/local/bin/run-all.sh
 
+ONBUILD ADD build_config.rb /usr/local/src/mod_mruby/build_config.rb
+
 ENTRYPOINT ["/usr/local/bin/run-all.sh"]
 CMD ["build"]
```

onbuildを利用するためのDockerfileを別途用意...シンプル...

```docker:onbuild/Dockerfile
FROM udzura/mod_mruby-builder
MAINTAINER Uchio KONDO <udzura@udzura.jp>
```

以下の `build_config.rb` を同じディレクトリに用意する。

```rb:onbuild/build_config.rb
MRuby::Build.new do |conf|
  toolchain :gcc
  conf.gembox 'full-core'
  conf.gem :github => 'iij/mruby-io'
  conf.gem :github => 'iij/mruby-env'
  conf.gem :github => 'iij/mruby-dir'
  conf.gem :github => 'iij/mruby-digest'
  conf.gem :github => 'iij/mruby-process'
  conf.gem :github => 'iij/mruby-pack'
  conf.gem :github => 'mattn/mruby-json'
  conf.gem :github => 'mattn/mruby-onig-regexp'
  conf.gem :github => 'matsumoto-r/mruby-redis'
  conf.gem :github => 'matsumoto-r/mruby-vedis'
  conf.gem :github => 'matsumoto-r/mruby-sleep'
  conf.gem :github => 'matsumoto-r/mruby-userdata'
  conf.gem :github => 'matsumoto-r/mruby-uname'
  conf.gem '../mrbgems/mod_mruby_mrblib'

  # これを追加
  conf.gem :github => 'matsumoto-r/mruby-discount'

  conf.cc do |cc|
    if ENV['BUILD_TYPE'] == "debug"
      cc.flags << '-fPIC -g3 -Wall -Werror-implicit-function-declaration'
    else
      cc.flags << '-fPIC'
    end
    if ENV['BUILD_BIT'] == "64"
      cc.flags << ' -DMRB_INT64'
    end
  end

  conf.linker do |linker|
    if ENV['BUILD_BIT'] == "64"
      linker.flags = '-DMRB_INT64'
    end
  end
end
```

カスタムビルドしてみます。


```
$ docker build -t udzura/mod_mruby-builder base/
$ docker build -t udzura/mod_mruby-done onbuild/
$ docker run --rm udzura/mod_mruby-done > out/mod_mruby.so
```

この `mod_mruby.so` を同様にコピーし、 libmarkdown2 をインストールしてから

- https://gist.github.com/udzura/dccf796cc7bfae7c766e

:arrow_up: にあるようなmrubyスクリプトを動かすと:

![スクリーンショット 2014-12-24 14.36.35.png](https://qiita-image-store.s3.amazonaws.com/0/569/edcc7ec9-cb10-4f62-9e9a-238aa539509f.png)

動いた〜

## まとめ

と言うことで、こんな感じで僕だけの最強の `mod_mruby.so` バイナリを作ることができるDocker imageが出来上がりました。

mrubyは基本的にすべてのmrbgemsをスタティックリンクするので、新たなgemを利用するにあたってコンパイルのし直しが必要になります。ですが、こう言う簡単一発ビルド君を作っておくと何かと便利ではないかと思います（こう言うバイナリを作成できることは、逆にmrbgemsがスタティックリンクされることのメリットの一つと言えるでしょう）。

なお、同じようなことを ngx_mruby でもできると思います。

最後に、今回の手順がすぐに試せるプロジェクトを [GitHub](https://github.com/udzura/mod_mruby-builder) に置きました。

----

本当の24日は @cubicdaiya さんでした。

明日（25日）は @matsumotory さんによる最後の記事となります！