Docker compose を使ってRails7.1系で新規アプリのひな型を作り、サーバーに接続しよう

# この記事のゴール
Docker composeを使ってRails newコマンドによる新規アプリのひな型とdevelop環境を作ります

最初にDockerについても触れていきます。
## 事前準備
まずは皆さん、Docker desktopをインストールしておいてください。

※Ruby,SQL,RailsのインストールはDockerfileにそれぞれをインストールするためのコマンドを書き込むことで省略されます。とても便利。



## 1. Dockerとは
### Dockerとは何か
Dockerとはコンテナという仮想化技術を用いてアプリケーションを簡単に構築、実行することができるプラットフォームです。

macでもwindowsでもDockerを使えば常に同じ環境を作り出し、アプリケーションを実行することができます。ゆえに環境の違いによる問題を最小限にできます。

また、開発環境から本番環境へ移行すること(デプロイ)が非常に容易になります。

## 2. Docker composeとは
複数のコンテナを実行するためのツールです。
コンテナをまとめてひとつのコマンドで操作することができます。

１つのコンテナにまとめて入れればいいと思うかもしれないですが、
それは一般的ではありません。

Web開発においてはwebサーバとデータベースサーバを別々のコンテナに格納することが一般的で、これにより各サービスの設定や管理が独立して行えます。
また、一方のサービスに問題が発生した場合、他サービスへ影響しづらく、対処しやすいです。

## 3.どのように使うのか
4つのファイルを作業ディレクトリに作成し、コマンドを実行するだけで完了です。

~~~
├── dockerfile
├── Gemfile
├── Gemfile.lock
└── docker-compose.yml
~~~

#### Dockerfileを作成しよう
まずDockerイメージを作るためのDockerfileを作成しましょう。コピペで大丈夫です。
[Docker公式ドキュメント](https://docs.docker.jp/compose/rails.html)のサンプルコードに少し書き加えています。
~~~
FROM ruby:3.1.1
WORKDIR /myapp
ADD Gemfile /myapp/Gemfile
ADD Gemfile.lock /myapp/Gemfile.lock
RUN gem install bundler
RUN bundle install
ADD . /myapp
~~~

- WORKDIR /myapp
Dockerイメージ内の作業ディレクトリを/myappに設定するためのコマンドです。
- ADD Gemfile /myapp/Gemfile
Dockerイメージ内にGemfileを追加するためのコマンドです。
- ADD Gemfile.lock /myapp/Gemfile.lock
Gemfile.lockをDockerイメージ内の/myapp/Gemfile.lockにコピーしています。
Gemfile.lockは、Gemfileをもとに実際にインストールされたgemの一覧とバージョンが記載されるファイルです。
- RUN bundle install
上記のGemfileに記載されているgemをインストールします。さらにGemfile.lockにGemの一覧とバージョンを自動で記述するコマンドです。
- ADD . /myapp
現在のディレクトリ(.)にあるすべてのファイルをmyappというディレクトリにコピーします。

#### Gemgileを作ろう
作業ディレクトリにあらかじめ以下のコードが書かれたGemfileという名前のファイルを作っておきましょう。
これでrails newを実行したときにrailsをロードできるようになります。
~~~
source 'https://rubygems.org'
gem 'rails', '7.1.2'
~~~
#### 空のGemfile.lockを作ろう
作業ディレクトリに空のGemfile.lockという名前のファイルを作りましょう。
#### Docker-compose.ymlを作ろう
以下のコードが書かれたファイルを作業ディレクトリに作ります。
~~~
version: '3'
services:
  db:
    image: postgres
    environment:
      POSTGRES_PASSWORD: password
  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
    depends_on:
      - db
~~~

- version: '3'
使用するDocker Composeのファイルフォーマットのバージョンを指定します。

- services:
起動するサービス（コンテナ）を定義します。

- db:とimage: postgres
dbという名前のサービス（コンテナ）を定義し、そのイメージとしてpostgresを使用します。

- web:
webという名前のサービス（コンテナ）を定義します。

- build: .
webサービスのDockerイメージを現在のディレクトリのDockerfileを使用してビルドします。

- command: bundle exec rails s -p 3000 -b '0.0.0.0'
webサービスのコンテナが起動したときに実行するコマンドを指定します123。この場合、Railsサーバーをポート3000で起動します。

- volumes: - . :/myapp
ホストの現在のディレクトリ（.）とwebサービスのコンテナ内の/myappディレクトリをマウント（同期）します。

- ports: - "3000:3000"
ホストのポート3000とwebサービスのコンテナのポート3000をマッピング（接続）します。

- depends_on: - db
webサービスがdbサービスに依存することを指定します123。これにより、dbサービスが先に起動した後にwebサービスが起動します。

#### docker-compose runしよう
Docker Desktopを起動し、以下のコマンドを実行します。
~~~
docker-compose run web rails new . --force --database=postgresql --skip-docker
~~~
rails newによりアプリひな型がまとめて生成されます。

また"--skip-docker"を入れることでrails7.1から導入された、
dockerfileをproduction環境用へ自動で書き換えられることがなくなります。
そのまま以下のコマンドを実行してもsecret_key_base関連のエラーでwebサービスが立ち上がりません。
私はこれに気付くのに時間がかかりました。

#### docker-compose build しよう
以下のコマンドでイメージをビルドします。
~~~
docker-compose build
~~~

#### config/databese.ymlを編集しよう
以下のように編集します。
~~~
default: &default
  adapter: postgresql
  encoding: unicode
  host: db
  username: postgres
  password: password
  pool: 5

development:
  <<: *default
  database: myapp_development


test:
  <<: *default
  database: myapp_test
  ~~~

#### データベースを生成しよう
以下のコマンドでデータベース(今回はpostgreSQL)を生成します。
~~~
docker-compose run web rake db:create
~~~
#### コンテナを起動させよう
以下のコマンドでコンテナを起動できます。
~~~
docker-compose up -d
~~~

#### サーバーに接続しよう
以下のアドレスをブラウザに入力すればサーバーに接続できるはずです。
~~~
localhost:3000
~~~

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638439/0e3f6792-54ba-6097-fe7a-01b53b8029ce.png)

お疲れさまでした

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