DockerでRedmine3.4を動かす

DockerでRedmine3.4を動作させた時の作業メモです。
もしよかったら参考にしてください。
わかりづらいところ、間違っているところなどご指摘いただけると嬉しいです。

操作の流れとディレクトリの構成です。

**操作の流れ**

1. 作業用のディレクトリの作成
2. `Dockerfile`の作成
3. `docker-compose.yml`の作成
4. 必要なディレクトリの作成
5. Redmineの設定
6. Docker Imageの作成
7. Redmineの環境構築
8. Redmineの動作

**ディレクトリの構成**

redmine34/
  ┣ Dockerfile
  ┣ docker-compose.yml
  ┣ entrypoint.sh
  ┣ redmine/
  ┣ bundle/
  ┗ postgresql_data/

### 1. 作業用のディレクトリの作成

作業用のディレクトリを作成します。
場所と名前は自由です。
今回はホームディレクトリ以下に`redmine34`という名前で作成します。

```
$ mkdir ~/redmine34
$ cd ~/redmine34
```

### 2. `Dockerfile`の作成

イメージを作成するための`Dockerfile`を作成します。今回必要なイメージは2つ。

1. Redmineを動作させるためのイメージ
2. Redmineで使用するDBのイメージ

1のイメージはRubyのイメージを元に作成します。2のイメージは、既存のイメージをそのまま使用するので今回は`Dockerfile`は作成しません。
以下がRedmineを動作させるためのイメージの`Dockerfile`です。今回は`redmine34/`の直下に作成しています。

```dockerfile:Dockerfile
FROM ruby:2.4

RUN gem install bundler -v 1.17.3

COPY redmine /var/lib/redmine
WORKDIR /var/lib/redmine

COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000

CMD ["bundle", "exec", "rails", "server", "-b", "0.0.0.0"]
```

自分がなんとなくわかっているところだけを軽く説明します。

- `FROM ruby:2.4` : 元となるイメージを指定します。今回はRedmineの3.4を動かしたいのでrubyのバージョンを2.4に指定しました。
- `RUN gem install bundler -v 1.17.3` : イメージを作成するために実行するコマンドを指定します。rubyのイメージを使用しているので`gem`のコマンドが使えます。Redmineの3.4だと最新のbundlerを使えないので、今回はbundlerのバージョンを1.7.3に指定しています。
- `COPY redmine /var/lib/redmine` : ホストのファイルをイメージ上にコピーする指定です。Redmineのソース`./redmine`をイメージ上の`/var/lib`以下にコピーしています。Redmineのソースはあとで用意します。
- `WORKDIR /var/lib/redmine` : 作業ディレクトリを指定します。今回はRedmineを動かすため、作業ディレクトリは`/var/lib/redmine`になります。
- `COPY entrypoint.sh /usr/bin/` : `entrypoint.sh`を`/usr/lib/`以下にコピーします。`entrypoint.sh`はこのあと作成します。
- `RUN chmod +x /usr/bin/entrypoint.s` : `entrypoint.sh`に実行権限を付与しています。
- `ENTRYPOINT ["entrypoint.sh"]` : 理解不足なのでわかりません。コンテナを起動した時に実行されるんだと思いますが、`CMD`との違いがわかりません。
- `EXPOSE 3000` : コンテナ側で解放するポートを指定します。今回はRedmineを動作させるので3000番ポートを解放しています。
- `CMD ["bundle", "exec", "rails", "server", "-b", "0.0.0.0"]` : `ENTRYPOINT`との違いがわかりません。

**`entrypoint.sh`の作成**

イメージの中で使用する`entrypoint.sh`を作成します。
[Docker公式のRailsのサンプルアプリケーション](https://docs.docker.com/compose/rails/#define-the-project)のものをほとんどそのまま使用しています。
こちらも`redmine34/`直下に配置します。

```sh:entrypoint.sh
#!/bin/bash
set -e

# Remove a potentially pre-existing server.pid for Rails.
rm -f /var/lib/redmine/tmp/pids/server.pid

# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"
```

### 3. `docker-compose.yml`の作成

docker-composeは複数のコンテナを連携して動かす（オーケストレーション）際に便利な機能です。docker-composeを使用しない方法もあるため必須ではありませんが、大変便利なので今回は使用します。
以下がdocker-composeを使用するための`docker-compose.yml`です。

```yaml:docker-compose.yml
version: '3'

services:
  redmine:
    build: .
    ports:
      - '3001:3000'
    volumes:
      - ./redmine:/var/lib/redmine
      - ./bundle:/usr/local/bundle
    depends_on:
      - db
  db:
    image: postgres:9.6
    ports:
      - '4001:5432'
    volumes:
      - ./postgresql_data:/var/lib/postgresql/data
```

- `version: '3'` : docker-composeのバージョンを指定します。バージョンごとに書き方が変わるようなので書いたほうがいいと思います。
- `services:` : サービスを指定します。サービスはコンテナの数分必要になるはずです。今回はRedmine用のサービス`redmine`とDB用のサービス`db`があります。サービス名（今回でいうところの`redmine`と`db`）は自由です。サービス名はコンテナを操作する時に使用します。
- `build: .` : コンテナはイメージから、イメージは`Dockerfile`を元にして作られますが、そのイメージの元になる`Dockerfile`の場所（コンテキスト）を指定します。今回は`redmine34/`直下に`Dockerfile`を配置しているので、カレントディレクトリ（`.`）を指定しています。
- `image: postgres:9.6` : 使用するイメージを指定します。DBのコンテナは既存のイメージから作成するので`postgres:9.6`のイメージを指定します。
- `ports:` : ポートフォワードの設定です。`ホストのポート:コンテナのポート`のように記述します。ホストのポートは使用可能なポートであればなんでも構いません。コンテナのポート番号はサービスごとに決まっており、また、`EXPOSE`されている必要があります。
- `volumes:` : ボリュームを指定します。`./redmine:/var/lib/redmine`とかくと、コンテナの`/var/lib/redmine`ディレクトリでホストの`./redmine`ディレクトリをマウントする意味になります。`redmine:/var/lib/redmine`と書くと意味が異なってしまうので、今回のやり方でディレクトリをマウントする場合にはカレントディレクトリ（`./`)の指定も必要です。
- `depends_on:` : コンテナの依存関係を指定します。Redmineの起動には、先にDBが起動している必要があるため、`depends_on`を使ってDB起動後に起動する指定をしています。

**`volumes`について**

コンテナはdownするごとにデータは消えてしますため、永続化したいデータがある場合はvolumeして外だしにしておく必要があります。
Redmineのデータやpostgresqlのデータは、コンテナの消失とともに初期化されてしまわないように、コンテナから分離しておきます。また、コンテナの起動ごとにgemをインストールするのは非効率なので、`/bundle`も外だしにしています。
主要なgemはイメージを作成する時にインストールしてしまうのもありかもしれません。

### 4. 必要なディレクトリの作成

ここまでの手順で、ディレクトリの構成は以下の通りになっています。

redmine34/
  ┣ Dockerfile
  ┣ docker-compose.yml
  ┗ entrypoint.sh

残り必要なディレクトリは以下の4つです。

1. `Dockerfile`内で`COPY`しているRedmineのソース
2. `docker-compose.yml`内でvolumeしてる`redmine`ディレクトリ`
3. `docker-compose.yml`内でvolumeしてる`bundle`ディレクトリ`
4. `docker-compose.yml`内でvolumeしてる`postgresql_data`ディレクトリ`

2で使う`redmine`ディレクトリは、1で使うredmineのソースをそのまま使うので、3つのディレクトリを用意します。Redmineのソースは[Redmineのgithub](https://github.com/redmine/redmine)からcloneし、`bundle`と`postgresql`は直接作成します。

```
$ git clone https://github.com/redmine/redmine.git
$ mkdir bundle postgresql_data
```

### 5. Redmineの設定

2019年5月19日現在Redmineの最新バージョンは4.0なので、3.4のブランチに切り替える必要があります。

```
$ cd redmine
$ git checkout -b 3.4-stable origin/3.4-stable
$ cd ..
```

`database.yml`を編集します。

```ruby:database.yml
default: &default
  adapter: postgresql
  encoding: utf-8
  host: db
  username: postgres
  password:

development:
  <<: *default
  database: redmine_dev


test:
  <<: *default
  database: redmine_test
```

docker-compose.ymlで指定したサービス名がDBのホスト名になります。今回では`db`です。
DBのユーザ名はデフォルトの`postgres`になります。
DBのホスト名やパスワード等を設定したい場合は、Dockerfileを作成する必要があります。

`configuration.yml`の編集は今回は省略します。

### 6. Docker Imageの作成

次のコマンドでイメージを作成します。

```
$ docker-compose build
```

イメージを確認すると作業ディレクトリとサービスの名前から`redmine34_redmine`という名前のイメージが作成されています。
dbサービスのイメージは今回は作成されません。

```
$ docker image ls
REPOSITORY                  TAG                 IMAGE ID            CREATED             SIZE
redmine34_redmine           latest              17529e7c8707        4 hours ago         952MB
```

### 7. Redmineの環境構築

作成されたイメージから、コンテナを通してRedmineの環境を構築します。
`docker-compose run`コマンドを使って、redmineに対してコマンドを実行していきます。
以下のコマンドで、指定したサービスに対してコマンドを実行します。

```
$ docker-compose run [サービス名] [実行コマンド]
```

ここの[サービス名]は、`docker-compose.yml`に記述したサービス名になります。


```
$ docker-compose run redmine bundle install
$ docker-compose run redmine bundle exec rake generate_secret_token
$ docker-compose run redmine bundle exec rake db:create
$ docker-compose run redmine bundle exec rake db:migrate
$ ls postgresql_data/
PG_VERSION            pg_hba.conf           pg_serial/            pg_twophase/
base/                 pg_ident.conf         pg_snapshots/         pg_xlog/
global/               pg_logical/           pg_stat/              postgresql.auto.conf
pg_clog/              pg_multixact/         pg_stat_tmp/          postgresql.conf
pg_commit_ts/         pg_notify/            pg_subtrans/          postmaster.opts
pg_dynshmem/          pg_replslot/          pg_tblspc/            postmaster.pid
```

ここまで実行すると、空だったはずの`postgresql_data/`にデータが作成されます。
`docker-compose run`を実行するごとに、コンテナが新しく作成され、[実行コマンド]が終わるとコンテナは止まります。
つまり、ここでは3つのコンテナが作成されて、止まってを繰り返すことになります。

### 8. Redmineの起動

最後にコンテナを起動します。

```
$ docker-compose up
```

`Dockerfile`の`CMD`に記述したコマンドがRedmineのコンテナに対して実行され、Railsのサーバが起動します。
ブラウザから`localhost:3001`にアクセスするとRedmineの画面が表示されます。

#### DockerでのRedmineのPlugin開発

これは僕がRedmineのプラグインを開発するときのメモです。

コンテナは`-d`オプションを使ってデタッチモードで立ち上げます。

```
$ docker-compose up -d
```

実行中のコンテナに対しては、`docker-compose exec`コマンドを使って操作します。

```
$ docker-compose exec redmine bundle exec rake redmine:plugins:migrate
```

コンテナの再起動とlogを確認するコマンドです。

```
$ docker-compose restart
$ docker-compose logs -tf --tail=100
```

## 参考

[Quickstart: Compose and Rails | Docker Documentation](https://docs.docker.com/compose/rails/)