dockerとdocker-composeを使って既存プロジェクトをdocker化した

## はじめに
dockerとdocker-composeを使って既存のRails＋PostgreSQLのプロジェクトをdocker化したので、備忘録として手順をまとめます。

## 作業環境
- M1Mac メモリ8GB
 
##  Dockerfileを用意する
Dockerコンテナを起動するためにはDockerImageの作成が必要になります。
DockerImageを作るために、Dockerfileを用意します。

:::note info
ちなみに。
Dockerコンテナ：オブジェクト指向的に言えばインスタンス
DockerImage：Dockerコンテナの元となるもの（オブジェクト指向的に言えばクラス）
Dockerfile：DockerImageの設計書のようなもの
:::

Rails用の Dockerfileを下記の通り用意しました。

```dockerfile:Dockerfile
FROM ruby:3.2.2
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
RUN apt-get update && apt-get install -y yarn
RUN mkdir /myapp
WORKDIR /myapp
ADD Gemfile /myapp/Gemfile
ADD Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
ADD . /myapp

```

`FROM`でDockerImageの元となるImageを指定します。
`RUN`で`build`時に実行する内容を指定します。ここではRails起動のために必要な各パッケージのインストールを行っています。
Railsを動かすために必要なものはRuby,Yarn,PostgreSQL(デフォルトはSQLiteですが今回は変更しています。)
なので、
- RubyのDockerImageを元に生成
- Yarnをインストール
といった流れで進めました。（PostgreSQLは別のコンテナで用意したため含めてません）

:::note warn
今回のバージョンはRuby3.2.2,Rails7.0.6で実行したため上記のパッケージでしたが、バージョンによってこの辺りは差異があるので注意が必要です。
:::
(Nodejsが必要だと思っていたけどこのバージョンだといらないっぽいですね)


`WORKDIR` で作業ディレクトリの指定を行います。ルート直下のmyappディレクトリを指定しています（ないのでmkdirでディレクトリを作成しています）。

`ADD`コマンドではDockerImageを作る際に、ホストからファイルをコピーします。`COPY`でも同じ役割を果たすコマンドですが`ADD`では圧縮したtarファイルを展開してコピーを行ってくれます。
（上記のDockerfileはtarファイルがないのでCOPYでも良かったかもしれない）

:::note warn
新しくRailsのプロジェクトを作る場合には必要なファイルなどを生成する必要があるため、下記のコマンドを実行します(今回は既存プロジェクトだったため、省略しました。)
```
$ docker-compose run web rails new . --force --database=postgresql
```
:::

## docker-compose.ymlを作成する
Dockerの考えとして、１コンテナで１サービスが基本とのこと。
そのため、今回 RailsとPostgreSQLのコンテナをそれぞれ用意します。
複数コンテナを効率的に作成、起動するために、docker-composeを利用しますが、そのためのdocker-compose.ymlを以下のように記述します。

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

volumes: 
  data-base:

services:
  db: 
    image: postgres:12
    environment:
      - 'POSTGRES_PASSWORD=password'
    volumes:
      - './data-base:/var/lib/postgresql/data'
  
  web:
    platform: linux/arm64/v8
    build: .
    environment:
      - 'DATABASE_PASSWORD=password'
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/myapp
    ports: 
      - "3000:3000"
    depends_on: 
      - db
    links: 
      - db
```

commandで複数のコマンドを指定したい場合には、bash -c ""でコマンドを囲うと実行できます。

:::note warn
今回は練習用だったので上記のようにDB接続用パスワードを記載していますが実際には他の方法で管理した方が良いかもしれません
:::

## ビルドを行う
以下のコマンドを行って、ビルドを行います
```docker
$ docker-compose build 
```

## DBの設定を変更する
DB接続用のユーザー名などの設定を変更します。
以下の内容を config/database.yml に記述していきます。
- RailsはデフォルトでSQLiteを利用する設定になっているため、一緒に作成したDBコンテナ（今回だとPostgreSQL）を利用するように記述
- 接続用ユーザー名、パスワードの設定

```yml:database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  #　以下を追加
  host: db
  username: postgres
  password: <%= ENV["POSTGRES_PASSWORD"] %>
```


:::note warn
パスワードなど機密情報に当たるものなどは直接記述するのではなく環境変数などを利用しましょう。
:::

## コンテナを起動する
```docker:
$ docker-compose up
```
Rails用のコンテナとPostgreSQLのコンテナが起動します。

しかし、この時点ではDBが生成されていないため、localhost:3000にアクセスしてもエラーになります。なので以下のコマンドでDB生成を行います。

```docker:
$ docker-compose run web rake db:create
```

DBが生成できたら再度以下のコマンドを実行します。
```docker:
$ docker-compose up
```

「PendingMigrationError」といったエラーが出る場合には、マイグレートが保留になっているためマイグレートを行います。
```docker:
$ docker-compose run web rake db:migrate
```

再度起動コマンドを実行。
```docker:
$ docker-compose up
```

無事に起動できました:sparkles:

## 参考文献
https://docs.docker.jp/compose/rails.html