Docker基礎 Docker-composeを使ってRails環境構築

Docker-composeを使って初めてRails+PostgreSQLの環境構築したときのメモです。
## Dockerfile作成
```terminal:ターミナル
$ mkdir product-register && cd product-register
$ touch Dockerfile Gemfile Gemfile.lock
```
```docker:Dockerfile
FROM ruby:2.5
RUN apt-get update && apt-get install -y \
  build-essential \
  libpq-dev \
  nodejs \
  postgresql-client \
  yarn
WORKDIR /product-register
COPY Gemfile Gemfile.lock /product-register/
RUN bundle install
```
```ruby:Gemfile
source 'https://rubygems.org'
gem 'rails', '~>5.2'
```
GemfileをDockerfileでCOPYすることでRailsをインストールします。

```
$ docker build .
```
## Docker-composeを使う
### どんな時に使うのか？
- `$ docker run`のコマンドが長くなる時

今回もしこのまま`$ docker run`をするならコマンドは、以下のように長くなるので使用。

```docker
$ docker run -it -v ~/Desktop/product-register:/product-register -p 3000:3000 <image> bash
``` 
- 複数のコンテナをまとめて起動する時。

今回はRailsのコンテナとPostgreのコンテナを使うので使用。



### docker-compose.ymlの使い方と書き方
- `docker-compose.yml`というファイルを作りそこに`$ docker run`時のオプションコマンドなどを書いて設定しておく。

```yml:docker-compose.ymlの雰囲気
今からDocker compose書くよ宣言
service1:
  service1のパラメータ
  service1のパラメータ
service2
  service2のパラメータ
  service2のパラメータ
```

- `kye:value`の組み合わせで書く。
- value部分が複数ある場合は`-`を使ってリスト形式
- docker-composeでのパスの指定は相対パスで書く。

## docker-compose.yml
```yml:docker-compose.yml
version: "3"

services:
  web:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - ".:/product-register"
    tty: true
    stdin_open: true
```
- `build`は`$ docker build .`
- `ports`は`-p`オプション
- `volumes`は`-v`オプション
- `tty`と`stdin_open`は`-it`オプション

## Docker composeコマンド一覧
- `$ docker build <build context>` 

```
$ docker-compose build
```
- `$ docker run <image>`

```
$ docker-compose up
```
```
$ docker-compose up --build
```
`up`はimageが作られてない場合、`build`も一緒にする。
Dockerfileを更新した場合は`-- build`をつけることで`build`してから`run`してくれるのでimageも更新される。

- `$ docker ps`

```
$ docker-compose ps
```
- `$ docker exec <container> <command>`

```
$ docker-compose exec <service> <command>
```
- 便利コマンド

```docker
$ docker-compose down
```
コンテナをstopしてから消してくれる。

実際に起動してみる。
バックグラウンドで動かしたいので`-d`オプションをつける

```
$ docker-compose up -d 
$ docker-compose ps
NAME                     COMMAND             SERVICE             STATUS              PORTS
product-register-web-1   "irb"               web                 running             0.0.0.0:3000->3000/tcp
```
起動が確認できたので実際にコンテナに入ってみる。

```docker
$ docker-compose exec web bash
root@8d2ab4ae68c0:/product-register#
```
入れてたらOK

## Railsセットアップ
コンテナ内で実行します。

```docker
$ rails new . --force --database=postgresql --skip-bundle
```
`--force`は全て上書き `--database`でデータベースの指定 `--skip`で`bundle install`をskipしています。
`bundle install`をskipしている理由は、Dockerfileの最後に`RUN`で`bundle install`を指定していて、Gemfileが更新されたらその都度コンテナを抜けて再度コンテナをbuildするので`bundle install`をわざわざここでする必要はないからです。

コンテナを抜けコンテナを削除します。

```
$ exit
$ docker-compose down
```
再度`build`して確認します。

```
$ docker-compose up --build -d 
$ docker-compose ps
NAME                     COMMAND             SERVICE             STATUS              PORTS
product-register-web-1   "irb"               web                 running             0.0.0.0:3000->3000/tcp
```
buildされていたらOKです。
## docker-compose.ymlのDB部分を追記する
DBはDB用のコンテナを作るのでDBの設定を記述していきます。

```yml:config/database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  host: db
  user: postgres
  port: 5432
  password: <%= ENV.fetch("DATABASE_PASSWORD") %>
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
```
`host`で指定した名前(今回はdb)がdocker-compose.ymlの`service`部分になります。

```yml:docker-compose.yml
version: "3"

volumes:
  db-data:

services:
  web:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - ".:/product-register"
    environment:
      - "DATABASE_PASSWORD=postgres"
    tty: true
    stdin_open: true
    depends_on:
      - db
    links:
      - db

  db:
    image: postgres
    volumes:
      - "db-data:/var/lib/postgresql/data"
    environment:
      - "POSTGRES_USER=postgres"
      - "POSTGRES_PASSWORD=postgres"
```
`volumes`の部分はデータベースで保存したものをhost側で保管するための記述。
`environment`は環境変数。
`depends_on`で指定したものができてから`$ docker run`するという記述。
`links`はここで指定したものがwebからアクセスできるようにするための記述。

## RailsとDBをセットアップ
Docker composeでそれぞれのコンテナを立ち上げRailsのコンテナに入ります。

```
$ docker-compose up -d
$ docker-compose exec web bash 
```
入ったコンテナ内でDBを作成します。

```
$ rails db:create
```
```
$ rails s -b 0.0.0.0
```
サーバーを立ち上げていつものRailsの最初の画面が出たら完成。
# 参考
https://www.udemy.com/course/aidocker/