Docker初心者がRails + PostgreSQL or MySQLで仮想環境構築した手順を丁寧にまとめる

DockerでRails + PostgreSQL or MySQLの環境を構築する手順について解説します。
データの永続化（終了してもデータ残る設定）についても解説します。

## Docker for Macのインストール

Dockerをmacで使うためにはDocker for Macをインストールする必要があります。

https://store.docker.com/editions/community/docker-ce-desktop-mac

こちらのURLからインストールできます。

- stable(動作安定してるやつ）
- edge（最新機能使えるやつ）

の2種類がありますが、こだわりがなければstableでいいでしょう。

## 構築編

```shell
mkdir docker_ror
cd docker_ror
```

適当に、ディレクトリを作ります。
ここに```Dockerfile```というファイルを作ってください。

### Dockerfile

```docker_ror/Dockerfile
FROM ruby:2.3.3
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs
RUN mkdir /myapp
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
COPY . /myapp
```

中身をこのようにします。
一つ一つ解説すると


```
FROM ruby:2.3.3
```

docker-hubから、ruby2.3.3のイメージをダウンロード。

```
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs
```

パッケージのリストをアップデート。-qqオプションはエラー以外何も吐かないっていうやつ
コンパイラなどのビルドに必要なパッケージ、postgresqlの接続に必要なパッケージ、nodejsのパッケージをインストール。-yオプションは全部yesでやるってやつ

```
RUN mkdir /myapp
WORKDIR /myapp
```

コンテナ内にmyappというプロジェクト用のディレクトリをを作成して、そこを作業ディレクトリに指定。

```
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
```

GemfileとGemfile.lockをプロジェクトのディレクトリ内にコピー
（今の段階ではまだGemfileとGemfile.lockは作っていないので、あとで作ります）

```
RUN bundle install
COPY . /myapp
```

最後にbundle installを実行して（bundkeコマンドはFROMで指定したrubyのイメージに含まれている）
docker_rorの内容を全て/myappに置いている。

### GemfileとGemfile.lock

```docker_ror/Gemfile
source 'https://rubygems.org'
gem 'rails', '5.0.0.1'
```

と作成してください。
またdocker_ror/Gemfile.lockをtouchコマンドとかで作成してください。

```shell:/docker_ror
ls
# => Dockerfile Gemfile Gemfile.lock 
```

のようになっているはずです。

### docker-compose.yml

```yml:docker_ror/docker-compose.yml
version: '3'
services:
  db:
    image: postgres
    volumes:
      - datavol:/var/lib/postgresql/data
  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
    depends_on:
      - db
volumes:
  datavol:
```

servicesの所に、dbとwebを書いているので、二つのコンテナが起動します。
dbサービスにはpostgresのイメージを使用しています。

```
  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
    depends_on:
      - db
```

webのbuildの所に、```.```が指定されているので、さっき作成した```Dockerfike```からイメージをビルドして使用します。

commandの所では、Railsのサーバーを起動し、3000番ポートでリッスンします。
-bオプションで0.0.0.0を指定しているので、全てリッスンします。
ここのコマンドはコンテナ起動時に渡されたコマンドで上書きすることもできます。

volumesではカレントディレクトリを/myappにバインドマウントしています。

portsでは3000番で公開してコンテナの3000番に転送するように指定しています。
ここはcommandで指定した、3000番と合わせる必要があります。

depends_onではdbサービスを指定して、webサービスが起動する前にdbサービスが起動するようになっています。

#### データの永続化

通常、仮想環境でpostgresqlに保存されたデータは仮想環境が止まると、消えてしまいます。
それが永続化するようにしているのが、こちらの所です

```
  db:
    volumes:
      - datavol:/var/lib/postgresql/data
```

```
volumes:
  datavol:
```

このように書くことで、datavolというボリュームを作成し、postgresqlのデータ領域である、```/var/lib/postgresql/data```にマウントしています。

#### MySQLを使いたい場合 

```yml:docker_ror/docker-compose.yml
version: '3'
services:
  db:
    image: mysql
    environment:
      - MYSQL_ROOT_PASSWORD=password
    volumes:
      - datavol:/var/lib/mysql
  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
    depends_on:
      - db
volumes:
  datavol:
```

としてください。

```
    environment:
      - MYSQL_ROOT_PASSWORD=password
```

としてMySQLのパスワードを設定する必要があります。


## rails new

```shell
docker-compose run web rails new . --force --database=postgresql
```

コンテナ内でコマンドを実行するには

```shell
docker-compose run コンテナ名 コマンド
```

で実行することができます。

カレントディレクトリ配下にrailsプロジェクトが作成される。
--forceオプションをつけているためファイルが存在する場合には上書きされます。事前に作成したGemfileをプロジェクト作成時に上書きするのに必要。

### 修正

#### postgresqlの修正
デフォルトで入るpostgresqlは古くて、警告が出るため修正

```Gemfile
# Use postgresql as the database for Active Record
gem 'pg', '~> 0.20.0'
```

と変更

GemfileとGemfile.lockが更新されました。これをイメージに含めるためにビルドを実行する

```shell
docker-compose build
```

#### db設定の修正(postgresql)

```yml:config/database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  host: db
  username: postgres
  password:
```

このように変更。
hostがdbサービスのコンテナをさすように指定。
usernameとパスワードはデフォルトのものを使用。

#### db設定の修正(mysql)

```yml:config/database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: 5
  username: root
  password: password
  host: db
```

ここのpasswordがdocker-compose.ymlに書いたものと一致する必要があります。
## 起動

デタッチドモードでdocker-compose.ymlに定義したサービスを起動

```shell
docker-compose up -d
```

データベース作成

```shell

docker-compose run web rake db:create
```

これでlocalhostの3000番にアクセスすると、railsが立ち上がっているはずです。