【Rails6.0, Docker】ポートフォリオを作るために必要なDocker環境構築とコマンドをまとめてみた

筆者がRailsでポートフォリオを作る際に必要だったコマンドや環境構築についてまとめたいと思います。あくまでポートフォリオ作成レベルで必要なものになります。

# 概要
1. docker-composeを扱う上でよく使うコマンド
2. 各種ファイルの記載 (Dockerfile, docker-compose.yml, database.yml)

# 1. docker-composeを扱う上でよく使うコマンド
 
## railsコマンド(rails g model userやrails db:migrateなど)

```bash:terminal
$ docker compose run --rm web <railsコマンド>
```
--rmオプションは実行後、コンテナを削除するコマンド。これをつけないと不要なコンテナができてしまい、メモリを圧迫してしまうため必ずつける。


## 標準入出力へ接続（ローカルで開発するときにterminalに表示されるもの）

```bash:terminal
$ docker attach <webサーバのコンテナ名>
```
サーバーでの標準入出力に接続し通信状況を見れる。binding.pryでデバックをする場合もこのコマンド。
きちんとした処理ででデタッチする。（ctrl + Cするとコンテナが落ちてしまう）

```
Ctrl + P, Ctrl + Q
```

## データベース(mysql)へ接続
```bash:terminal
$ docker exec -it <dbのコンテナ名> bash
```

コンテナの中から

```bash:terminal
$ mysql -u root -p
```

## Dockerイメージを作成し、コンテナを起動し実行する。
```bash:terminal
$ docker-compose stop
# Dockerfileまたはdocker-compose.yml修正後
$ docker-compose up -d --build
```
Dockerfileやdocker-compose.ymlを修正したとき用。

## 削除コマンド
--rmオプションを付けていても開発しているといらないコンテナやイメージが溜まっていきます。ここからはそれらを削除するコマンドです。
### 停止コンテナ、タグ無しイメージ、未使用ボリューム、未使用ネットワークを一括削除
```bash:terminal
docker system prune
```
※ 使用中のvolumeは削除されないので大丈夫。
※ 複数プロジェクトが走っている場合は非推奨

### 停止中のコンテナ一括削除
```bash:terminal
docker container prune
```

### 未使用のイメージ一括削除
```bash:terminal
docker image prune
```

# 各種ファイルの記載
## Dockerfile
まずはDockerfile。まずは公式のDocumentに目を通す。
https://docs.docker.com/compose/rails/


```dockerfile:Dockerfile
FROM ruby:2.7.1

# Debianのインストール
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
    && echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list

RUN apt-get update -qq && apt-get install -y nodejs yarn imagemagick mariadb-client vim

RUN mkdir /myapp
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
COPY . /myapp

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

CMD ["rails", "server", "-b", "0.0.0.0"]

```


### yarnのインストール
rails6.0からJavaScriptコンパイラがwebpackerに変更され、webpackerの導入に必要なパッケージマネージャであるyarnをインストール

### ImageMagickのインストール
画像アップロード用にMiniMagicが使いたかったためインストール。
Rails アプリで MiniMagick を使おうとすると Rails アプリを実行している環境に ImageMagick をインストールする必要がある。以下はminimagicのReadMeより

> ImageMagick or GraphicsMagick command-line tool has to be installed. You can check if you have it installed by running

### mariadb-clientのインストール
rails db:consolを使いたい場合はインストール。
mysql-clientと書かれている記事もあるが、現在はmariadb-clientに統一されているため注意
データベースへは上述のコマンドでアクセスできるため不要かも

### vimのインストール
エディターは何かと必要になるためインストールしておく。筆者は本番環境へアプリをデプロイした後、下コマンドでcredentials.yml.encを編集したかったのですが、その際にvimを使いました。

```bash:terminal
$ docker-compose run -e EDITOR=vim web rails credentials:edit
```

## docker-compose.yml
お次はdocker-compose.yml

```docker-compose.yml
version: "3"
services:
  db:
    image: mysql:8.0
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: password
    ports:
      - 4306:3306
    
    command: --default-authentication-plugin=mysql_native_password
    volumes:
      - mysql-data:/var/lib/mysql

  web:
    build: .
    tty: true
    stdin_open: true
    # rails sした際に、A server is already running.というエラーが出ることがある。これを防ぐため、rm -f tmp/pids/server.pidしている。
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/myapp
      - bundle:/usr/local/bundle
    ports:
      - "3100:3000"
    depends_on:
      - db

volumes:
  bundle:
    driver: local
  mysql-data:
    driver: local
```

### ポート番号設定
```yml:docker-compose.yml
db
  ports:
    - 4306:3306
web
  ports:
    - 3100:3000
```
左側がホストマシンのポート番号で、右側がコンテナのポート番号。
ホストでMySQLが(LISTEN)の場合やlocalhost:3000を使いたい場合は、使用するポートが重複するためマシンの使用するポート番号を4306、3100にそれぞれ設定。かぶらなければ3307でも10000でも何でも可


### mysqlの認証方式を変更
```yml:docker-compose.yml
command: --default-authentication-plugin=mysql_native_password
```
MySQL8.0からデフォルトの認証方式が変更された(caching_sha2_password)が、まだRailsアプリが対応していないため、mysql_native_passwordに戻す。


### 標準入力の有効化
```yml:docker-compose.yml
tty: true
stdin_open: true
```
デバック用に非常に重要。これをしないとbinding.pryなどができないです。
#### tty: true
docker runの -tオプションに相当し、擬似端末を有効にする設定。有効にしても入力できないため、下のstdin_open： trueが必ずセットでついてくる。
#### stdin_open: true
docker runの -iオプションに相当し、標準入力を繋ぎっぱなしにする設定。これによりコマンド実行が可能になる。



### コンテナの起動順序を制御
```yml:docker-compose.yml
depends_on:
      - db
```
depends_onでコンテナが起動する順番を制御する（この場合、db→web）


### Data Volumeコンテナの作成
```yml:docker-compose.yml
volumes:
  bundle:
    driver: local
  mysql-data:
    driver: local
```
通常、コンテナを作り直すとbundle installしたファイルやデータベースのデータはすべて消えるため、再度buildしたりデータの登録を行わなければならない。それはあまりにも面倒なため、Data Volumeコンテナを使う。Data Volumeコンテナはデータだけを持つコンテナで、コンテナ間で共有する仕組みを使う。これをbundle, mysql-dataという名前で作る設定が上記になる。


### volumeへマウント
```yml:docker-compose.yml
volumes:
  - mysql-data:/var/lib/mysql
volumes:
  - .:/myapp
  - bundle:/usr/local/bundle
```
先程作ったData Volumeコンテナを使ってデータの永続化を行います。これで、コンテナを破棄してビルドし直してもデータベースのデータはそのままで、かつGemがインストールされすぐに使える状態となります。


## database.yml
最後にdatabase.yml

```database.yml
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: <%= ENV.fetch("MYSQL_USERNAME", "root") %>
  password: <%= ENV.fetch("MYSQL_PASSWORD", "password") %>
  host: <%= ENV.fetch("MYSQL_HOST", "db") %>

development:
  <<: *default
  database: myapp_development
```
### 文字コード

```yml:database.yml
encoding: utf8mb4
```
データベースに絵文字を登録したかったので、文字コードをutf8ではなくutf8ｍｂ４にしています。


何か他に便利な設定やコマンドがあれば教えてください^^

## 参考
https://docs.docker.com/compose/rails/
Docker/Kubernetes実践コンテナ開発入門
https://qiita.com/neko-neko/items/abe912eba9c113fd527e
https://qiita.com/chisaki0606/items/68e21d9a31f1eaaeac00
https://qiita.com/nsy_13/items/9fbc929f173984c30b5d