既存のrailsアプリをdockerを用いてコンテナ化する

# ゴール

既存のrailsアプリを
docker,docker-composeがインストールされているPCであれば、
**個人PCの環境に左右されることなく**[ローカル](http://localhost:3000)にて再現できるようにする。



# 事前準備
* 以下の環境にてローカルで動作確認済みのrailsアプリ
```ver.
ruby 3.2.2
Rails 7.0.6
postgresql 12
```

* docker,docker-composeのインストール

https://docs.docker.com/engine/install/

https://docs.docker.jp/v1.12/compose/install.html


# 手順

**1.Dockerfile、doccker-compose.ymlの作成と記述**
**2.database.ymlファイルの編集**
**3.コンテナ生成と実行**
**4.動作確認**

順番に解説していきます。

### 1.Dockerfile、docker-compose.ymlの作成と記述

ここでは**コンテナを生成するための準備として、**
Dockerfileとdocker-compose.ymlを作成、記述していきます。
上記はコンテナを作成するための設計図のようなものだと考えてください。

作成したファイルは**railsアプリファイルの直下に配置**するようにしてください。


![スクリーンショット 2023-10-02 12.38.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2265379/0e9c276a-508f-cfd2-d5c6-0212c9e0871f.png)




### Dockerfileの記述

**Dockerfile**は、オリジナルのDockerイメージを作成するための設計書のようなものです。
既存のDockerイメージをベースに、パッケージをインストールしたり、ファイルを書き換えたりした、新しいイメージを作成することができます。
今回はrailsアプリを動かすために下記のように記述します。

```Dockerfile:Dockerfile
FROM ruby:3.2.2
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs
RUN mkdir /rails-docker

WORKDIR /rails-docker

ADD Gemfile Gemfile.lock /rails-docker/

RUN gem install bundler
RUN bundle install

ADD . /rails-docker

// ※rails-dockerは今回のrailアプリが配置されているディレクトリ名を指しています。

```

### docker-compose.ymlの記述

**Docker compose** とは、複数のコンテナの構築、実行する手順を自動化するツールです。
その手順などを記したファイルが**docker-compose.yml**で、これのおかげで少ないコマンドの実行で複数のコンテナを起動することができます。
今回は下記のように記述します。


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

services:
  db:
    container_name: rails-docker-db
    image: postgres:12
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
    volumes:
      - postgresql-data:/var/lib/postgresql/data
  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/rails-docker
    ports:
      - "3000:3000"
    depends_on:
      - db
      
volumes:
  postgresql-data:
    driver: local
```
上記に記述されている単語について一つずつ解説していきます。

#### services

``services``の中で動かすコンテナを定義します。
今回は``Postgres``と``Rails``をコンテナ化するので、名前を分かりやすくするために `db`、`web`とします。

#### image

利用するimageを指定し、コンテナを構築します。
dbの場合は``postgres ver12``を使うのでその内容を記述し、webの場合は上記で記述して``Dockerfile``からbuildし、それぞれimageを作成します。

#### environment

Postgresに関する環境変数を設定します。
ユーザーID、パスワードはご自身で決めて構いません

#### volumes

``volume``はコンテナにおいて生成されるデータを永続的に保存することができます。
例えば、今回のPostgresの場合、Postgresをコンテナ化し、そこにデータを保存したとします。
しかし、そのPostgresのコンテナを削除すると、そこに保存されたデータも一緒に削除されてしまいます。
そこで、データだけをローカルにも保存しておく仕組みを``volume``といいます。
このvolumeを利用することで、仮にコンテナを削除して、新しくコンテナを立ち上げた時も、前回までのデータを保持した状態でシステムを利用することができます。

volumeを保存する方法は大きく分けて２つあり、
１つ目は、**保存したいディレクトリをマウントする方法**、**２つ目は、名前付きボリュームを利用する方法**です。

今回、``Rails``は、１つ目の``保存したいディレクトリをマウントする方法``
``Postgres``は2つ目の``名前付きボリュームを利用する方法``を使います。

まずRailのvolume箇所は下記のように記述されています。
```Dockerfile
volumes:
      - .:/rails-docker
```
上記の場合、``volumes:`` は ``- ローカル側の同期させたいディレクトリ : コンテナ側の同期させたいディレクトリ``で表します。
今回使用するrailアプリ``rails-docker``は``docker-compose.yml``ファイルから見て、同階層にあるので、ローカル側の同期させたいディレクトリは``.(カレントディレクリ)``で表し、

また下記コマンドにて
```
 web:
    build: .
```
コンテナ側には、``rails-docker``のファイルが作成されているので、コンテナ側の同期させたいディレクトリは``/rails-docker``と記述します。
これにより、コンテナ起動後、ローカルのrails-docker配下のファイルなどを編集すると、コンテナ側にも編集が反映されます。

そして、``Postgres``は2つ目の``名前付きボリュームを利用する方法``を使用します。
この方法は、ローカルに名前付きのボリュームを作成し、そこにコンテナ側の指定したディレクトリを保存するというものです。

名前付きボリュームの場合、``volumes:`` は ``- ボリューム名 : コンテナ側の保存させたいディレクトリ``で表します。
今回、ボリューム名 を ``postgresql-data``とし、コンテナ側の保存させたいディレクトリは Postgresのデータ保存場所である``/var/lib/postgresql/data``を指定します。
結果、
```
volumes:
  - postgresql-data:/var/lib/postgresql/data
```
という書き方になります。
そして、version: や services: と同じ段落(トップレベル)の、一番下に書いている``volumes:``にボリューム名を記載し、名前付きボリュームであることを明示します。
```
volumes:
  postgresql-data:
    driver: local
```

#### command

コンテナ起動時の実行されるコマンドを設定します。
今回実行される下記のコマンドは
```
command: bundle exec rails s -p 3000 -b '0.0.0.0'
```
コンテナ立ち上げと同時に``bundle exec rails s``でコンテナの中でrails　serverが立ち上がり、
``-p 3000 -b '0.0.0.0'``でポート番号:3000をlocalhost(0.0.0.0) でブラウザに表示できることを示しています。

#### depends_on:
コンテナの作成順序の設定です。
``depends_on:- db``は、``Postgresのコンテナ``が起動してから``Railsのコンテナ``を起動するという意味です。


### 2.database.ymlファイルの編集

```ruby:config > database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  host: db
  username: postgres
  password: postgres
  # For details on connection pooling, see Rails configuration guide
  # https://guides.rubyonrails.org/configuring.html#database-pooling
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>

development:
  <<: *default
  database: myapp_development
```
デフォルトではなかった``host`` ``username`` ``password``を今回追加しています。
今回は``docker-composer.yml``で設定した内容をもとに記述していきます。




### ３.コンテナの生成と実行

ここまでの作業で準備は整いました。
あとは下記のようにコマンドを実行していくだけで、railsのコンテナ環境の構築は完了です。

* イメージの作成

```
docker-compose build
```
* コンテナの作成と起動
```
docker-compose up -d
```


* DB作成
```
docker-compose run web rails db:create
```
* migrate実行
```
docker-compose run web rails db:migrate
```

これでrailsアプリをDocker化する手順は以上です。

#### 4.動作確認

最後に、``docker　compose ps``でrails serverが動いてるのを確認し
[ローカル](http://localhost:3000)に接続し、ブラウザにて画面が正しく表示されれば完了です！！


# おわりに
今回はrailsのdockerを用いたコンテナ環境の構築について解説させていただきました。
最初の設定は煩雑ですが、一度設定してしまえば、その後はコマンドを打ち込むだけで簡単に環境設定を完了させることができます。
是非ともこの記事を参考にお試しいただければと思います。