Dockerで既存のRailsアプリの環境構築を行う

# はじめに
Dockerの学習として既存のRailsアプリの環境構築を行ったため、作業内容をまとめます。

# 開発環境
下記を使用して環境構築を行いました。

- Mac(M1 chip)
- Ruby 3.0.2
- postgres 12.0
- node 12.4
- yarn 1.16.0

# フォルダ構成
既存のアプリのフォルダ内に`Dockerfile`、`docker-compose.yml`、空のファイルである`Gemfile.lock`を追加しました。

```
/rails-docker
    ├─app
    ├─bin
    ├─config
    │     └─database.yml
    ├─db
    ├─lib
    ├─log
    ├─public
    ├─storage
    ├─test
    ├─tmp
    ├─vendor
    ├─babel.config.js
    ├─config.ru
    ├─Gemfile
    ├─Gemfile.lock
    ├─package.json
    ├─postcss.config.js
    ├─Rakefile
    ├─README.md
    ├─yarn.lock
    ├─Dockerfile
    └─docker-compose.yml
```

# Dockerfileの作成
`Dockerfile`の入力内容です。
ポイントは以下の２点です。

・nodeをマルチステージビルドを利用してインストールをしている。
・`package.json`と`yarn.lock`を追加している。


```docker:Dockerfile
FROM node:12.4-stretch as node

FROM ruby:3.0.2
RUN apt-get update -qq && apt-get install -y \
    build-essential \
    libpq-dev 

ENV YARN_VERSION 1.16.0
RUN mkdir -p /opt
COPY --from=node /opt/yarn-v$YARN_VERSION /opt/yarn
COPY --from=node /usr/local/bin/node /usr/local/bin/
COPY --from=node /usr/local/lib/node_modules/ /usr/local/lib/node_modules/
RUN ln -s /opt/yarn/bin/yarn /usr/local/bin/yarn \
  && ln -s /opt/yarn/bin/yarn /usr/local/bin/yarnpkg \
  && ln -s /usr/local/bin/node /usr/local/bin/nodejs \
  && ln -s /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm \
  && ln -s /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npx 

RUN mkdir /myapp
WORKDIR /myapp
ADD Gemfile /myapp/Gemfile
ADD Gemfile.lock /myapp/Gemfile.lock
RUN gem install bundler
RUN bundle install
ADD package.json yarn.lock /myapp/
RUN yarn install
COPY . /myapp

EXPOSE 3000
CMD ["rails", "server", "-b", "0.0.0.0"]
```

### マルチステージビルドとは
マルチステージビルドとは、<strong>アプリを効率的にビルドするための手法</strong>です。
FROM行が複数あることが特徴です。

マルチステージビルドを使用するメリットは<strong>イメージサイズが軽量化できる</strong>ことです。
不要なプログラムをインストールせず、必要なファイルのみを抽出することにより、イメージサイズを小さくすることができます。
(今回の例で説明すると、Railsアプリを起動するために必要なnode,yarnのファイルを抽出しています。)

### Dockerfileでpackage.jsonとyarn.lockを追加する理由
`Dockerfile`内で`package.json`と`yarn.lock`を追加している理由は、アプリ起動時に<strong>Webpacker::Manifest::MissingEntryError</strong>のエラーを解消するためです。

![スクリーンショット 2023-07-02 1.56.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3332710/73733baa-aa08-39f0-7b26-835adf6c82fa.png)


`Dockerfile`内で`yarn install`を実行する場合、その時点で存在する`package.json`と`yarn.lock`に基づいて依存関係がインストールされるのですが、その時コンテナが完全では無い為（ファイルが未完成であったり、コード自体がまだコンテナにコピーされていなかったり）依存関係の解決が正しく行われず、エラーが発生します。


ちなみに、`Dockerfile`内に`package.json`、`yarn.lock`、`yarn install`を入力せず、コンテナ内で`yarn install`を実行する方法でも、その時点で存在する完全な`package.json`と`yarn.lock`に基づいて依存関係がインストールされるので依存関係のエラーは出ないです。 

# docker-compose.ymlの作成
docker-composeを使用することで、ターミナルで入力するDockerコマンドを簡潔なコマンドで実行できるようになります。
`docker-compose.yml`の入力内容です。

```dockerdocker-compose.yml
version: '3'
services:
  db:
    image: postgres 
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password
      POSTGRES_DB: postgres
    volumes:
      - .:/dbapp
      
  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password
    volumes:
      - .:/webapp
    ports:
      - "3000:3000"
    depends_on:
      - db
```

# database.ymlの修正
`database.yml`の入力内容です。
`adapter`を`postgresql`に変更しています。

```database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  host: db
  username: postgres
  password: password 

development:
  <<: *default
  database: db/development

# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
  <<: *default
  database: db/test

production:
  <<: *default
  database: db/production
```

# Gemfileへの追記
postgresqlを使うために必要なgemとして、`Gemfile`に`pg`を追加しています。

```ruby:Gemfile
gem 'pg'
```

# Railsアプリの起動方法
1.コンテナの起動
```
docker-compose up
```

2.ターミナルの新規タブを開き、ファイルが保存されているディレクトリへ移動

3.データベースを作成
```
docker-compose run web rake db:create
```

4.コンテナの中に入る
```
docker-compose exec web bash
```

5.データベースにテーブルを作成
```
rails db:migrate
```

6.ブラウザを開き、URLを入力
```
http://localhost:3000/
```
アプリが実行できれば成功です。