【初学者向け】DockerでRails APIとPostgreSQLの環境構築をする(M1 Mac)

今回の記事では、DockerとDocker Composeを用いてRails APIとPostgreSQLの環境構築の手順を解説していきます。
最終的に、rails new <app名> --api -d postgresqlコマンドを用いて、以下のようなRailsのデフォルトページを作成し、ブラウザからページが見れることを確認します。

Rails API デフォルトページ

この記事では、メソッドや語句の説明などの細かい知識は説明しません。
詳しい解説記事については、適宜リンクを貼っていますので、そちらを参考にしてください。

【用語の定義】

  • アプリケーション: ここでは、投稿サービスやSNSサービスなどのWebサービス、Docker Desktop for Mac等のデスクトップアプリの呼び方を「アプリケーション」に統一します。

※サンプルコード先頭の「$」はここから右側はコマンドだよ!という目印です。「$」以降のコードをターミナルで実行してください。

1. 今回使用する開発環境/バージョン

今回の記事では、以下の開発環境/バージョンを使用して解説します。

  • M1 Mac: Memory 16GB
  • Docker Desktop: v4.19.0
  • Docker
    • Dockerクライアント: v23.0.5
    • Dockerエンジン: v23.0.5
    • API: v1.42
  • Docker Compose: v2.17.3
  • Ruby: v2.7.7
  • Ruby on Rails: v7.0.5
  • PostgreSQL(サーバー): v15

Docker Desktop、Ruby on Railsに関しては、2023年5月28日(日)時点での最新バージョンを使用しています。

Docker、Docker Composeに関しては、2023年5月28日(日)時点でのDocker Desktopが採用している最新バージョンを使用しています。詳しくはこちらを参考にしてください。

Ruby(2.7.x)に関しては、今後の開発でバージョンによるエラーが起こるのを防ぐため、v2.7.7でバージョンを固定します。

PostgreSQLに関しては、今後RDSを使用することを想定して、2023年5月28日(日)時点でのAWSでの最新バージョンを使用しています。

MySQLとPostgleSQLの違いについては、こちらを参考にしてください。

2. Docker Desktop for Macをインストールする

※すでにDocker Desktop for Macをインストール済みの方は、次のステップに進んでください。

Docker Desktop for MacというアプリケーションをMac PCにインストールするだけで、開発環境でDockerを使用する準備が整います。

詳しいインストール方法は、こちらを参考にしてください。

それでは次のステップに進み、実際にDocker環境を構築していきます。

3. Docker環境を構築するためのフォルダを用意する

ここでは、VS Code(Visual Studio Code)を使用して開発を行います。インストール方法は省略します。

3-1. ターミナルでDesktopに移動する

まずVS Codeを開きます。

次に、画面上部バー「Terminal」内の「New Terminal」をクリックします。

VS Code New terminal

「New Terminal」をクリックすると、VS Code内下部にターミナルが表示されます。

今後のコマンド操作は、このターミナル内で行っていきます。

VS Code Terminal

ターミナルを開くと、カレントディレクトリ(現在のディレクトリ)が~になっています。

lsコマンドを実行すると、カレントディレクトリ内のファイルを見ることができます。

今回はDesktop内にファイルを作成するので、Desktopに移動します。

VS Code Terminal ls

下記コードを実行し、Desktopディレクトリに移動します。

$ cd Desktop
VS Code Terminal cd Desktop

ディレクトリを移動すると、先ほどのカレントディレクトリ~Desktopに変わっています。

これでカレントディレクトリが変更できました。

以下、lsコマンドと同じようにターミナルでコマンドを実行し、手順を進めてください。

3-2. GitとGitHubで管理するためのフォルダを作成する

まずはGitとGitHubで管理するためのGitHubフォルダを作成します。

$ mkdir GitHub

GitHubフォルダ内にターミナルから移動します。

$ cd GitHub

後ほどGitHubフォルダ内で作業をするため、VS Codeはそのまま開いておいてください。

なぜかというと、一度VS Codeを閉じてしまうと、再度Desktop内のGitHubフォルダにVS Codeのターミナルから移動する必要があるからです。

※手動で作成する場合は、Desktop上の画面を2本指でクリックをしてフォルダを作成してください。

4. GitHubで新しいリポジトリを作成する

※GitHubアカウントを作成していない方は、こちらを参考に登録してください。

それでは、GitHubでコードを管理するためにリポジトリを作成します。

まずは、自身のGitHubアカウントにアクセスし、「Repositories」内の緑色の「New」ボタンをクリックしてください。

GitHub Repositories

「New」をクリックすると、下記の「リポジトリ作成画面」が表示されます。ここでリポジトリ名の指定やリポジトリの公開設定等を行います。

下記に設定情報を列挙しますので、それに合わせてリポジトリ作成の必要項目を入力し、「Create repository」をクリックしてください。

  • Repository name: rails-api-docker
  • Description: 空白
  • 公開設定: Public
  • Initialize this repository with: 「Add a README file」にチェックを入れる
  • 上記以外: デフォルト設定のまま
GitHub Create a new repository 1
GitHub Create a new repository 2

リポジトリが作成されると、下記のように新しいリポジトリのページが作成されます。

GitHub rails-api-docker repository

5. GitHubからリポジトリをcloneし、Gitで管理できるようにする

※「cloneする」とは、「GitHubのリポジトリを自身のパソコンにコピーする」ようなイメージです。

5-1. 新しく作成したリポジトリのclone用コードを取得する

まずは、「4. GitHubでリポジトリを作成する」で作成したGitHubのrails-api-dockerリポジトリを開いてください。

次に、rails-api-dockerリポジトリ内の緑色の「Code」ボタンをクリックしてください。「Code」ボタンをクリックすると、下記のようなリポジトリのclone方法やダウンロード方法に関する情報が表示されます。

GitHub rails-api-docker clone用Code

表示中の「Local」の「Clone」の「HTTPS」にある、「https://github.com/<自身のユーザー名>/rails-api-docker」というコードをコピーしてください。コピーしたコードはclone時に使用します。

5-2. 自身のパソコンにGitHubリポジトリをcloneする

次に自身のMacへリポジトリをcloneします。

3.2 GitとGitHubで管理するためのフォルダを作成する」で作成した自身のDesktop内にあるGitHubフォルダ内に、VS Codeのターミナルから移動してください(もしくは、先程の開いたままのVS Codeに移動してください)。

移動後ターミナルで、「5.1 新しく作成したリポジトリのclone用コードを取得する」で取得したHTTPS接続用のURLを用いて、下記コードを実行します。

$ git clone https://github.com/<自身のユーザー名>/rails-api-docker

コードを実行すると、「README.md」ファイルの入った「rails-api-docker」フォルダが作成されます。

これで、「rails-api-docker」フォルダで編集を行い、「$ git commit ~」や「$ git push ~」等のコマンドを実行すると、自身のGitHubリポジトリにも変更が反映され、今までのコード履歴を見ることができます。

6. Dockerfile、docker-compose.yml、その他ファイルを作成する

6-1. Dockerfileを作成する

5.2 自身のパソコンにGitHubリポジトリをcloneする」でcloneしたrails-api-dockerファイル内に、下記Dockerfileを作成してください。

ここでは、Dockerfileの詳しい解説については省略します。

FROM ruby:2.7.7

RUN apt-get update && \
    apt-get install -y build-essential \
                       libmariadb-dev-compat

RUN mkdir /rails-api-docker
ENV APP_ROOT /rails-api-docker
WORKDIR $APP_ROOT

ADD Gemfile $APP_ROOT/
# ADD Gemfile.lock $APP_ROOT/ ※後で使用するため、コメントアウトしておいてください。
RUN bundle install

COPY . $APP_ROOT

RUN mkdir -p tmp/sockets tmp/pids
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["sh", "entrypoint.sh"]

※Dockerイメージにはalpine以外にも様々な種類があります。イメージの詳細やそれぞれのイメージで使用するコマンドについてはこちらを参考にしてください。

6-2. entrypoint.shを作成する

entrypoint.shは、コンテナを起動する前に初期処理をしたいときなどに使用することができます。

Dockerfileの作成と同じく、「5.2 自身のパソコンにGitHubリポジトリをcloneする」でcloneしたrails-api-dockerファイル内に、下記entrypoint.shを作成してください。

#!/bin/bash
set -e

# Remove a potentially pre-existing server.pid for Rails.
rm -f /rails-api-docker/tmp/pids/server.pid

# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"

ここでは、entrypoint.shの詳しい解説については省略します。詳しくはこちらを参考にしてください。

6-3. docker-compose.ymlを作成する

Dockerfileの作成と同じく、「5.2 自身のパソコンにGitHubリポジトリをcloneする」でcloneしたrails-api-dockerファイル内に、下記docker-compose.ymlを作成してください。

「db」がPostgreSQLのコンテナ、「app」がRails APIのコンテナです。

version: '3'
services:
  db:
    image: postgres:15
    container_name: db
    restart: unless-stopped
    environment:
      POSTGRES_USER: ${DB_USER}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: ${DB_HOST}
    volumes:
      - postgres-data:/var/lib/postgresql/data
    ports:
      - "5432:${DB_PORT}"

  app:
    build: .
    environment:
      DB_USER: ${DB_USER}
      DB_PASSWORD: ${DB_PASSWORD}
      DB_HOST: ${DB_HOST}
      FRONTEND_ORIGIN: ${FRONTEND_ORIGIN}
      RAILS_ENV: development
    command: "bundle exec rails s -p 3000 -b 0.0.0.0"
    volumes:
      - .:/rails-api-docker
      - log-data:/rails-api-docker/log
    ports:
      - "3000:3000"
    depends_on:
      - db
    tty: true
    stdin_open: true

volumes:
  log-data:
  postgres-data:

ここでは、docker-compose.ymlの詳しい解説については省略します。

6-4. 環境情報を.envに設定する

.envを使用すると、コードの中で環境変数を使用したいときにその情報をまとめて記載しておくことができます。主にデータベースのパスワードなどの秘匿情報を設定するときに活用します。

今回は、Dockerfileとdocker-compose.ymlの設定情報を.envに記載します。

Dockerfileの作成と同じく、「5.2 自身のパソコンにGitHubリポジトリをcloneする」でcloneしたrails-api-dockerファイル内に、下記.envを作成してください。

DB_USER=root
DB_PASSWORD=12345678
DB_HOST=db
DB_PORT=5432

FRONTEND_ORIGIN=http://localhost:3001

※Rails 5.2以降は、「dotenv-rails」を明示的にインストールしなくても、「.env」を作成し環境情報をセットするだけで、プロジェクト内で環境変数を使用することができます。

6-5. Gemfileを作成する

Dockerfileの作成と同じく、「5.2 自身のパソコンにGitHubリポジトリをcloneする」でcloneしたrails-api-dockerファイル内に、下記Gemfileを作成してください。

source 'https://rubygems.org'

ruby '2.7.7'

gem 'rails', '~> 7.0', '>= 7.0.5'

gem 'pg', '~> 1.5', '>= 1.5.3'

pgはPostgreSQLのクライアントライブラリで、RailsアプリケーションからPostgreSQLデータベースへの接続やクエリの実行を容易にします。

docker-compose.ymlで指定した「image: postgres:15」は、Dockerコンテナ内で実行されるPostgreSQLデータベースサーバーのイメージを指定しているので、pgのバージョンとは直接関係ありません。

7. rails new <app名> --api -d postgresqlでアプリケーションを作成する

7-1. コンテナイメージをビルドする

$ docker-compose build

上記ビルドを行わずにrails newコマンドを実行すると、下記エラーが出現します。

bundler: command not found: rails
Install missing gem executables with `bundle install`

7-2. rails new <app名> --api -d postgresqlを実行する

今回は、rails new <app名> --api -d postgresqlを使用してRuby on Rails環境を構築します。

rails newコマンドは、Railsを使用したアプリケーションの雛形を素早く作成するためのコマンドです。

データベースには、広く使用されており、ドキュメントも豊富なPostgreSQLを選定します。

まず、先ほど「5.2 自身のパソコンにGitHubリポジトリをcloneする」でcloneしたrails-api-dockerフォルダに移動します。

次に、VS Codeのターミナルで以下のコマンドを実行し、アプリケーションを作成します。

$ docker-compose run app rails new <app名> --api -d postgresql

今回はmy-appという名前のフォルダを作成するため、<フォルダ名>の部分をmy-appに変更してコマンドを実行します。

$ docker-compose run app rails new my-app --api -d postgresql

※docker-composeコマンドは、現在のディレクトリにdocker-compose.ymlファイルが存在する場合にのみ実行できます。

コマンドを実行すると、以下のような構造のディレクトリ/ファイル群が作成されます。

rails-api-docker
├── log # ルートディレクトリのlogを削除
├── my-app # 空になったmy-appフォルダを削除
│   ├── その他Railsのファイル/フォルダ群
│   ├── log
│   ├── Gemfile
│   ├── Gemfile.lock
│   └── README.md
├── .env
├── docker-compose.yml
├── Dockerfile
├── entrypoint.sh
├── Gemfile # ルートディレクトリのGemfileを削除
├── Gemfile.lock # ルートディレクトリのGemfile.lockを削除
└── README.md # どちらか一方のREADME.mdを削除

その後、以下の3つの変更を行います。

  1. プロジェクトルートのlog、Gemfile、Gemfile.lock、README.mdを削除する
  2. my-app内のすべてのファイルをrails-api-dockerに移動する
  3. 空のmy-appフォルダを削除する

最後に、Dockerfileのコメントアウト部分(ADD Gemfile.lock $APP_ROOT/)のコメントアウトを解除します。

【変更後のrails-api-dockerディレクトリ構造】
rails-api-docker
    ├── その他Railsのファイル/フォルダ群
    ├── log
    ├── docker-compose.yml
    ├── Dockerfile
    ├── entrypoint.sh
    ├── Gemfile
    ├── Gemfile.lock
   └── README.md
【変更前のDockerfile】
FROM ruby:2.7.7

・・・省略・・・

# ADD Gemfile.lock $APP_ROOT/

・・・省略・・・
【変更後のDockerfile】
FROM ruby:2.7.7

・・・省略・・・

ADD Gemfile.lock $APP_ROOT/

・・・省略・・・

最後に、下記コマンドを実行し、$ docker-compose runコマンドで立ち上がった不要なコンテナを停止させます。

$ docker-compose down

8. Docker環境を構築し、作成したアプリケーションを確認する

手順は以下の3ステップです。コマンドは全てターミナルで実行してください。

  1. $ docker-compose buildを実行し、イメージをビルドする
  2. $ docker-compose up -dを実行し、コンテナを起動する
  3. $ docker psを実行し、コンテナが起動していることを確認する

※Dockerにおける「イメージのビルド」とは、Dockerイメージを作成するためのプロセスを指します。イメージは、Dockerコンテナの実行に必要なすべての依存関係、設定、およびアプリケーションの実行に必要なファイルなどを含んだパッケージのことです。簡単にいうと、イメージのビルドは、Docker環境を構築するための準備作業の一部です。

まずは、下記コマンドを使用してイメージをビルドします。

$ docker-compose build
VS Code Terminal docker-compose build

次に、下記コマンドを使用してコンテナを起動します。

$ docker-compose up -d

up -dコマンドは、コンテナをバックグラウンドで起動してくれるため、コンテナが起動している最中でもターミナルにコマンドを入力し実行することができます。

VS Code Terminal docker-compose up -d

最後に、下記コマンドを実行して、rails-api-dockerコンテナが起動していることを確認してください。

$ docker ps

コマンドを実行すると、コンテナIDが割り振られ、使用しているイメージの名前、コンテナ内で実行されているコマンド、起動時間などが表示されます。

しかし、この状態でコンテナを起動し、設定したアプリケーションのURLである「localhost:3000」にブラウザからアクセスしても、appコンテナは下記エラーを吐き、立ち上がりません。

ActiveRecord::ConnectionNotEstablished

could not connect to server: No such file or directory
Is the server running locally and accepting
connections on Unix domain socket "/var/run/postgresql/.s.PGSQL.5432"?

上記エラーを解決するには、database.ymlでのデータベースの設定が必要です。

9. PostgreSQLの設定をdatabase.ymlで行う

9-1. database.ymlの設定

「/config/database.yml」をVS Codeで開いてください。

database.yml内の「default」欄に、「6-4. 環境情報を.envに設定する」で設定した環境情報を、変数(環境変数)としてセットします。

【変更前】
・・・省略・・・

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

・・・省略・・・
【変更後】
・・・省略・・・

default: &default
  adapter: postgresql
  encoding: unicode
  # For details on connection pooling, see Rails configuration guide
  # https://guides.rubyonrails.org/configuring.html#database-pooling
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: <%= ENV['DB_USER'] || 'postgres' %>
  password: <%= ENV['DB_PASSWORD'] || '' %>
  host: <%= ENV['DB_HOST'] || 'db' %>
  port: <%= ENV['DB_PORT'] || '5432' %>

・・・省略・・・

9-2. 古いデータベース設定情報を削除

現在のコンテナのまま、$ docker-compose up -dを実行しコンテナを起動させると、下記「ActiveRecord::ConnectionNotEstablished」エラーが出力されます。

これは、「9-1. database.ymlの設定」において、host名等を環境変数に置き換えたために発生しています。

「database.yml」の変更を反映させるため、古いコンテナを停止し、コンテナの再ビルド、再起動を行います。

下記手順を実行してください。

  1. コンテナ停止:$ docker-compose down
  2. ビルド:$ docker-compose build
  3. コンテナ起動:$ docker-compose up -d

10. データベースを作成する

このまま「http://localhost:3000/」にブラウザからアクセスすると、下記「ActiveRecord::NoDatabaseError」エラーが出力されます。

上記「ActiveRecord::NoDatabaseError」エラーを解決するには、下記「rails db:create」コマンドを実行します。

$ docker-compose exec app rails db:create

もしくは、エラーページ内の「Create database」を押すことでもエラーが解消されます。

「Create database」ボタンが表示されていない場合、rails db:createコマンドを使用してデータベースを作成してください。

11. 作成したアプリケーションを確認する

ブラウザのURLバーに「http://localhost:3000/」と入力し、Enterを押してください。

URLを入力すると、下記のようなRuby on Railsのデフォルトページが表示されるはずです。

Rails API デフォルトページ

環境を終了したい場合は、コンテナ終了用の下記コマンドを実行してください。

$ docker-compose down

$ docker-compose downコマンドを実行すると、コンテナが終了します。

VS Çode Terminal docker-compose down

環境を終了し「http://localhost:3000/」をリロードすると、先ほどのRuby on Railsのデフォルトページが見れなくなっていることがわかります。

This site can't be reached

これでDockerを用いたRails APIとPostgreSQLの環境構築が終わりました!

終わりに

更なるレベルアップとして、Rails APIの機能追加を行いたい場合は、こちら(準備中)を参考にしてください。