Alpine Linux ベースで ngx_mruby の Docker イメージを構築

「[Alpine Linux で Docker イメージを劇的に小さくする](http://qiita.com/asakaguchi/items/484ba262965ef3823f61)」で、Alpine Linux ペースでの Docker イメージについて紹介しました。今回は、ngx_mruby を Alpine Linux ベースで、Docker イメージを構築する例を紹介します。

作成にあたっては、[matsumoto-r/ngx_mruby](https://github.com/matsumoto-r/ngx_mruby) の [Dockerfile](https://github.com/matsumoto-r/ngx_mruby/blob/master/Dockerfile) と、Docker オフィシャルの Nginx の [Dockerfile](https://github.com/nginxinc/docker-nginx/blob/e82e776e7507868a887178bc7eaae5c1ed7aa47f/Dockerfile) を参考にしました。


## Dockerfile
ズバリ！ Dockerfile は、このように書きました。以下で公開しています。

- GitHub: https://github.com/asakaguchi/dockerfiles/tree/master/alpine-ngx_mruby
- Docker Hub: https://hub.docker.com/r/asakaguchi/ngx-mruby/

```
FROM alpine:3.3

ENV NGINX_CONFIG_OPT_ENV --with-http_stub_status_module \
                         --with-http_ssl_module \
                         --with-http_realip_module \
                         --with-http_addition_module \
                         --with-http_sub_module \
                         --with-http_gunzip_module \
                         --with-http_gzip_static_module \
                         --with-http_random_index_module \
                         --with-http_secure_link_module \
                         --prefix=/usr/share/nginx \
                         --sbin-path=/usr/local/sbin/nginx \
                         --conf-path=/etc/nginx/conf/nginx.conf \
                         --pid-path=/var/run/nginx.pid \
                         --http-log-path=/var/log/nginx/access.log \
                         --error-log-path=/var/log/nginx/error.log

RUN apk add --update openssl-dev pcre-dev git \
  && apk add --virtual build-dependencies build-base ruby-dev ruby-rake tar wget bison perl \
  && git clone https://github.com/matsumoto-r/ngx_mruby.git \
  && cd ngx_mruby \
  && sh build.sh \
  && make install \
  && cd / \
  && apk del build-dependencies \
  && rm -rf \
       ngx_mruby \
       /var/cache/apk/*

RUN ln -sf /dev/stdout /var/log/nginx/access.log
RUN ln -sf /dev/stderr /var/log/nginx/error.log

EXPOSE 80 443

ONBUILD ADD ngx-mruby/hook /usr/share/nginx/hook
ONBUILD ADD ngx-mruby/conf /etc/nginx/conf

CMD ["nginx", "-g", "daemon off;"]
```

この Dockerfile を使って作成した Docker イメージのサイズは、`docker images` コマンド調べで、49.27MB となりました！

```
$ docker images asakaguchi/ngx-mruby
REPOSITORY             TAG                 IMAGE ID            CREATED             SIZE
asakaguchi/ngx-mruby   latest              06187dc37c4b        5 hours ago         49.27 MB
```

参考までに、サイズを公式の Docker イメージと比較すると . . .、ナント！ 1/10 以下になりました！Alpine Linux と ngx_mruby の組み合わせは、最強かもしれませんね！

```
$ docker images
REPOSITORY                         TAG                 IMAGE ID            CREATED             SIZE
asakaguchi/ngx-mruby               latest              06187dc37c4b        5 hours ago         49.27 MB
matsumotory/ngx-mruby              latest              31526196d1b1        17 hours ago        582.2 MB
```



## Dockerfile の簡単な解説
以下、簡単ですが、Dockerfile の中身を解説しておきます。

### Nginx の configure オプション
Nginx の configure オプションは、次のように定義してみました。主な変更点は、prefix と path 周りです。

```
ENV NGINX_CONFIG_OPT_ENV --with-http_stub_status_module \
                         --with-http_ssl_module \
                         --with-http_realip_module \
                         --with-http_addition_module \
                         --with-http_sub_module \
                         --with-http_gunzip_module \
                         --with-http_gzip_static_module \
                         --with-http_random_index_module \
                         --with-http_secure_link_module \
                         --prefix=/usr/share/nginx \
                         --sbin-path=/usr/local/sbin/nginx \
                         --conf-path=/etc/nginx/conf/nginx.conf \
                         --pid-path=/var/run/nginx.pid \
                         --http-log-path=/var/log/nginx/access.log \
                         --error-log-path=/var/log/nginx/error.log
```


### ログ
ログ出力の部分は、Docker オフィシャルの Nginx の [Dockerfile](https://github.com/nginxinc/docker-nginx/blob/e82e776e7507868a887178bc7eaae5c1ed7aa47f/Dockerfile) の記述を参考に追加しました。

アクセスログ（access.log）とエラーログ（error.log）は、それぞれ標準出力（stdout）と標準エラー出力（stderr）から取れるようにしています。

```
RUN ln -sf /dev/stdout /var/log/nginx/access.log
RUN ln -sf /dev/stderr /var/log/nginx/error.log
```

と、これを書いていて気づきましたが、元ネタは `&&` を使って 1 行で処理していたのですが、なぜか 2 行に変えてしまっていました。これには、他意はないです。無意識に変えてしまっていました . . . 。思い切って、ngx_mruby を構築している `RUN` 中にまとめてしまっても良いと思います。


### ONBUILD
ONBUILD 部分も configure オプションで変更したパスに合わせて変えています。`docker/hook` や `docker/conf` を `ngx-mruby/hook` や `ngx-mruby/conf` に変えたのは、完全に好みの問題です。

```
ONBUILD ADD ngx-mruby/hook /usr/share/nginx/hook
ONBUILD ADD ngx-mruby/conf /etc/nginx/conf
```


### CMD
`CMD` の記述は、Docker オフィシャルの Nginx の [Dockerfile](https://github.com/nginxinc/docker-nginx/blob/e82e776e7507868a887178bc7eaae5c1ed7aa47f/Dockerfile) の `CMD` を採用しました。これも好みの問題です。

```
CMD ["nginx", "-g", "daemon off;"]
```

これは、Nginx を `-g daemon off;` オプションを使って、foreground で動かしています。よって、この方法を採用する場合は、`nginx.conf` で、`daemon off;` と記述しないように注意してください。`nginx.conf` で、`daemon off;` と記述したい場合は、`CMD ["nginx"]` としてください。

## 使用例
この Dockerfile は、以下のように使います。

まずは、Docker イメージを作成します。

```
mkdir learning-ngx-mruby && cd learning-ngx-mruby
vim Dockerfile # テキストエディタで、冒頭で紹介した Dockerfile の内容をコピー＆ペースト
docker build -t ngx-mruby .
```

続いて、作成した Docker イメージを使って、コンテナを起動します。

```
echo 'hello, world' > index.html
docker run -d -p 8080:80 -v $(pwd):/usr/share/nginx/html ngx-mruby
curl http://$(docker-machine ip default):8080
```

`hello, world` のメッセージが表示されたら OK です。最後の `curl` コマンドの実行は、OS X（Docker Toolbox 環境[^1]）での例です。Linux の場合は、`curl http://localhost:8080` で良いかと思います。

[^1]: Docker Toolbox を標準的にインストールした場合を想定しています。`docker-machine ip default` の `default` の部分は、環境によっては異なる可能性があります。`docker-machine ls` で対象となる仮想マシンの NAME を確認してください。