DockerfileでCrowiのビルドとDocker ComposeでCrowiの実行


## 内容
[Crowiをdocker-nodeで動かすまでのメモ](http://qiita.com/nooby/items/9b197c2b666d6b8371e1)

前回はnodeコンテナを立ち上げた後、コンテナ上で作業することでcrowiを動かせるようにした。
今回はそれを整理してDockerfileにし、Dockerfileでイメージをビルドし出来るようにする。
またDocker Composeでnode(crowi), mongodb, redis, +追加でelasticsearchを個々のコンテナで起動するようにする。


## 参考にしたサイト

[https://hub.docker.com/r/bakudankun/crowi/](https://hub.docker.com/r/bakudankun/crowi/)

DockerfileやDocker Composeの方法などで大変参考になりました。感謝。
<span style="color: gray;">（ちなみにg++やmake、pythonがなくてもbuildできてるのはcrowiがv1.4.0だったから？）</span>


## 前準備

以下の構成で3つのファイルを用意する。

```console:ファイル構成
$ tree crowi
crowi
├── Dockerfile
├── docker-compose.yml
└── docker-entrypoint.sh
```

```bash:Dockerfile
FROM node:4.5-slim
MAINTAINER nooby

ENV DOCKERFILE_VERSION v1.0
ENV CROWI_VERSION v1.5.0

# 以下の3ステップ構成でビルド
# 一つのRUNコマンドで実行してるのは生成されるイメージを小さくするため
#
# 1. ビルドに必要なバイナリのインストール
# RUN apt-get update && apt-get install -y \
#     git \
#     g++ \
#     make \
#     python \
# 
# 2. crowiのクローンとビルド
# && git clone -b $CROWI_VERSION https://github.com/crowi/crowi.git \
# && cd /crowi \
# && npm install --unsafe-perm \
# 
# 3. 不要になったパッケージの削除
# && apt-get autoremove -y \
# && apt-get clean \
# && rm -rf /var/lib/apt/lists/* \
# && cd /crowi/node_modules && npm uninstall --save --unsafe-perm \
#     babel* \
#     gulp* \
#     webpack* \
# && rm -rf \
#     /root/.npm \
#     /tmp/*
RUN apt-get update && apt-get install -y \
    git \
    g++ \
    make \
    python \
&& git clone -b $CROWI_VERSION https://github.com/crowi/crowi.git \
&& cd /crowi \
&& npm install --unsafe-perm \
&& apt-get remove -y \
    git \
    g++ \
    make \
    python \
&& apt-get autoremove -y \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* \
&& cd /crowi/node_modules && npm uninstall --save --unsafe-perm \
    babel* \
    gulp* \
    webpack* \
&& rm -rf \
    /root/.npm \
    /tmp/*

ENV PORT ${PORT:-80}
EXPOSE $PORT

# timezoneをjstに
# ref: https://serverfault.com/questions/683605/docker-container-time-timezone-will-not-reflect-changes/683607
ENV TZ=Asia/Tokyo
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

WORKDIR /crowi
COPY ./docker-entrypoint.sh /
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["npm", "start"]
```


```bash:docker-entrypoint.sh
#!/bin/bash

export NODE_ENV=production
export MONGO_URI=${MONGO_URI:-mongodb://mongo:27017/crowi}
export REDIS_URL=${REDIS_URI:-redis://redis:6379/crowi}
export ELASTICSEARCH_URI=${ELASTICSEARCH_URI:-http://elasticsearch:9200/crowi}

exec "$@"
```


```Yaml:docker-compose.yml
version: '2'

services:
    crowi:
        build:
            context: .
            dockerfile: Dockerfile
        image: node:crowi
        links:
            - mongo:mogo
            - redis:redis
            - elasticsearch:elasticsearch
        ports:
            - 80:80

    mongo:
        image: mongo

    redis:
        image: redis:alpine
    
    # user: について
    #   commandを指定するとelasticsearchのdocker-entrypoint.shで
    #   user権限切り替えのスクリプトがうまく実行されずrootユーザーのままになる。
    #   root権限ではelasticsearchを実行できないのでuser: elasticsearchを指定する。
    #
    # command: について
    #   crowiの全文検索に必要なanalysis-kuromojiのインストールと、
    #   あると便利そうなウェブコンソールelasticsearch-headのインストールをしてから
    #   elasticsearchを実行
    elasticsearch:
        image: elasticsearch
        user: elasticsearch
        ports:
            - 9200:9200
        command:
            - "sh"
            - "-c"
            - "./bin/plugin install analysis-kuromoji; 
               ./bin/plugin install mobz/elasticsearch-head;
               elasticsearch;"
```

## Dockerfileのビルド

上記の[ファイル構成](#前準備)の通りにファイルを用意した後、`crowi`ディレクトリに移動し`docker build`コマンドを実行する。

```bash:console
$ docker build -t node:crowi .
```

ビルドには結構時間がかかる。大体10分くらい？

※ docker-compose.ymlにnode:crowiをbuildするコマンドを書いているため、docker-compose upでビルドとコンテナの起動をまとめて行うこともできるが、ビルドだけやたら時間かかるのは気持ちが悪いのでビルドだけ先に実行しておいた。


## 起動方法と終了方法

#### 起動方法

`crowi`ディレクトリに移動し`docker-compose up`を実行する。

```bash:console
$ docker-compose up
# docker-compose up -dとするとバックグラウンド実行
```

起動後、`http://localhost`にアクセスしCrowiのセットアップ画面が表示されればok。
※ docker for macを使ってる場合は`docker-machine ip`でdocker machineのIPを確認し、localhostのかわりにdocker machineのIPを入力


#### 終了方法
`ctrl-c`（バックグラウンド実行なら`docker-compose stop`）


## Crowi上でElasticsearchの有効化

Crowiにログイン後、管理 -> 検索管理 -> build nowから有効化する。

参考：[Crowi公式ブログ](https://medium.com/crowi-book/crowi-v1-5-0-5a62e7c6be90)

> はじめて利用するときに Build Now ボタンを押してインデックスを作成してください。以後はページの作成/更新ごとにインデックスサれるはずです。
> 
> ![](https://cdn-images-1.medium.com/max/1600/1*cMbyCWuXk_VKzbcE9RdCDQ.png)


## ハマった所

余力があれば時間があるときにそれぞれ記事にするかも...

* Dockerイメージのタイムゾーンの変更
* Dockerイメージのサイズの縮小化
* REDIS_URL
* Elasticsearchのプラグイン


## さいごに
今回作成したDockerイメージは後ほどDocker Hubに公開する予定です。

## 追記 2016-09-11 18:25

GithubとDocker Hubに公開しました。

Github
[https://github.com/nooby-noob/docker-node-crowi](https://github.com/nooby-noob/docker-node-crowi)

Docker Hub
[https://hub.docker.com/r/noobynoob/docker-node-crowi/](https://hub.docker.com/r/noobynoob/docker-node-crowi/)

以下のコマンドでイメージのpull及び各コンテナの立ち上げ、crowiの実行が出来ます。

```bash:console
git clone https://github.com/nooby-noob/docker-node-crowi.git
cd docker-node-crowi
docker-compose up
```

crowi単体でも実行可能です。

```bash:console
docker run -p 80:80 noobynoob/docker-node-crowi:v1.5.0
```

単体で実行する場合は適宜MONGO_URIやREDIS_URLを設定してください。