Next.js + Ruby on Rails + RedisでDocker環境を構築する

#はじめに
　今回は、Docker環境を構築しようと思う。私自身、フロントエンドとバックエンドを一つのリポジトリに管理して、そこでDocker環境を構築した経験はないため、それなりの苦労を強いられた。今回は、私のように一つのリポジトリにフロントとバックを管理する環境下でDockerを導入することになった際に取る手順を紹介していきたいと思う。

　皆さんの開発環境は、私のポートフォリオの環境とは異なる部分もあるだろうから、適宜調整しながら参考にしてもらえたら幸いである。

##環境
Redis 6.2
Ruby on Rails 6.1.3.1
Next.js
Docker 20.10.0-rc1
MySQL 8.0.23
追記：今回は、フロントとバックエンドを一つのディレクトリで管理しているので注意してもらいたい。
Github等で別々のリポジトリで管理している場合は、リポジトリを統一するか別々のリポジトリでやる方法を調べていただけたら幸いである。

## 階層構造

│
├ m-api(API側) 
│　  └ config
│        └ database.yml
│    └ Dockerfile
├ m-front（クライアント側）
│  └ Dockerfile
│
├ mysql-confd
│      └ default_authentication.cnf
├ docker-compose.yml
│
├ .env　（環境変数を管理するファイル）



##1. database.ymlの設定

``` database.yml
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: <%= ENV['DB_USERNAME'] %> #.envにDB_USERNAMEを記入
  password: <%= ENV['DB_PASSWORD'] %> #.envにDB_PASSWORDを記入
+ host: db
- socket: /tmp/mysql.sock

development:
  <<: *default
  database: m_api_development

test:
  <<: *default
  database: m_api_test

production:
  <<: *default
  database: m_api_production
  username: m_api
  password: <%= ENV['M_API_DATABASE_PASSWORD'] %>

```

ここでは、hostを次に書く```docker-compose.yml```のdbのservice名に合わせる。



##2.docker-compose.ymlの作成
フロントエンドとバックエンドと同じ階層に```docker-compose.yml```を作成する。

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

services:
  redis:　　
    image: redis:6.2
    command: ["redis-server"]
    ports:
      - "6379:6379"
    volumes:
      - "./data/redis:/data"
    command: redis-server --appendonly yes ##MySQLとredis-serverの永続化

  db:
    image: mysql:8.0.23
    container_name: api-container
    command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    environment:
      MYSQL_ROOT_PASSWORD: $DB_PASSWORD
      MYSQL_DATABASE: sample
      MYSQL_PASSWORD: $DB_PASSWORD
    ports:
      - ${DB_PORT}:3306
    volumes:
      - ./mysql-confd:/etc/mysql/conf.d　

  api:　　
    std_open: true  #binding.irbでデバックする際に必要となる
    tty: true　　 　　 #binding.irbでデバックする際に必要となる
    depends_on:
      - db
    build:
      context: ./m-api/     #m-apiの部分は自身の環境に合わせて変える
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    links:
      - db
      - redis
    volumes:
      - ./m-api:/app   #m-apiの部分は自身の環境に合わせて変える
      - bundle_path:/bundle  #Gemの永続化
    command: /bin/sh -c "rm -f /app/tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    environment:
      REDIS_URL: redis://redis:6379

  front:
    build:
      context: ./m-front/　 #m-frontの部分は自身の環境に合わせて変える
      dockerfile: Dockerfile
    volumes:
      - ./m-front/app:/usr/src/app　 #m-frontの部分は自身の環境に合わせて変える
    command: 'yarn dev'
    ports:
      - "8080:8080"
volumes:
  bundle_path: #Gemの永続化
  mysql-data:
    driver: local
```
今回、Redis-server、MySQL、Next.js、Rails(APIモード)を使うということで、上記のようにする。

私は、Firebase Authでredis-serverを使っているため、今回はRedisを```docker-compose.yml```に記載したが、そうではない場合は書かなくてよい。
なお、```$DB_PASSWORD```と```DB_PORT```は.env（docker-compose.ymlと同じ階層）で環境変数を設定してもらいたい。

また、Redis-serverを使う際に、

```
command: redis-server --appendonly yes
```
の１行がなければ、Railsのサーバーを再起動するたびにUserやPost等のデータが消えてしまうため、データの永続化ができなくなる。そのため、redisとMySQLを使う場合は必ずこの１行は入れること。



##3. mysql-confの作成
MySQLのvolumeを管理するため、```docker-compose.yml```と同じ階層に```mysql-confd```を作成し、その中に```default_authentication.cnf```というファイルを作成する。

```default_authentication.cnf
[mysqld]
default_authentication_plugin= mysql_native_password
```



##4. Dockerfileの作成(クライアント側、API側)
まずはクライアント側から```m-front/Dockerfile```を作成する

```Dockerfile
FROM node:14-alpine
WORKDIR /usr/src/app
```
なお、1行目のnodeは [Docker Hub]("https://hub.docker.com/_/node")からnodeのバージョンを選択するのが望ましい。

次に、API側で```m-api/Dockerfile```を作成する

```Dockerfile
FROM ruby:2.7.3

ENV LANG=C.UTF-8 \
  TZ=Asia/Tokyo

RUN apt-get update -qq && apt-get install -y nodejs default-mysql-client

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

# Start the main process.
CMD ["rails", "server", "-b", "0.0.0.0"]
```

ここも、[Docker Hub]("https://hub.docker.com/_/ruby")からRubyのバージョンを選択するのが望ましい。

##5.Dockerコマンドの実行
まずは、

```
$ docker-compose build 
```
でDocker環境をビルドする。

次に、Docker環境の中にデータベースを作成するために、

```
$ docker-compose run api rails db:create
```

を実行する。
なお、ここでの```api```は、```docker-compose.yml```内で指定したAPI側のservice名である。
適宜調整してコマンドを実行すること。

そして、databaseを作ることができたら、

```
$ docker-compose run api rails db:migrate
```
を実行して、マイグレーションを実行する。

これでローカルで作成したデータベースはDocker環境でも再現できたことになる。

そして、

```
$ docker-compose up -d
```
または

```
$ docker-compose up 
```
を実行して、Dockerコンテナをupする。　　　　　
http://localhost:3000/　　　　　　　　　
にアクセスし、下記の画面が出てきたら成功である。

![スクリーンショット 2021-04-25 0.52.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/650686/33e18857-8900-f56b-41f1-bad4d424f241.png)
これで環境構築は終了である。

##おわりに
Dockerは一度作成するまでにかなりの時間を要するが、一度作ればずっと使える。そのため、エラーが出ても途中で折れずに進めることを推奨する。
また、今回の記事でどこか間違っている部分があれば指摘していただけると幸いである。