🐳

Rails7 APIモード + PostgreSQL + React (TypeScript)でのDocker環境を構築

2023/03/21に公開

Docker学習のために、タイトルのような環境構築をしました。
私のようなDocker初学者の方の参考になれば幸いです。

バージョン

Ruby:v3.1.3
Ruby on Rails:v7.0.4
React:v18.2.0
docker-compose:v3.8

1 ディレクトリ構成

今回はバックエンドとフロントエンドのディレクトリを分けて構築します。(Gitも分けて管理)
myappという名前のプロダクトを作る前提で進めます。
以下のような構成になります。

└── myapp
    ├── backend
    │   ├── Dockerfile
    │   ├── Gemfile
    │   ├── Gemfile.lock
    │   └── entrypoint.sh
    ├── frontend
    │   └── Dockerfile
    └── docker-compose.yml

環境構築したいディレクトリに移動し、以下コマンドを打っていきます。

mkdir myapp
cd myapp
mkdir backend
mkdir frontend
touch docker-compose.yml
touch backend/Dockerfile
touch backend/Gemfile
touch backend/Gemfile.lock
touch backend/entrypoint.sh
touch frontend/Dockerfile

2 バックエンド(Rails)側の設定

Dockerfileの設定

バックエンドのDockerfileには以下を記述していきます。

  • 使用したいRubyのimageを指定
  • 追加したいライブラリ(PostgreSQLクライアント, yarnパッケージ管理ツール, Node.js
  • Gemのインストール
  • Rails固有のエントリーポイント対応(entrypoint.shにて説明)
  • Railsサーバーの起動
backend/Dockerfile
# 使用したいRubyのimageを指定
FROM ruby:3.1.3
ARG RUBYGEMS_VERSION=3.3.20

# PostgreSQLクライアントをインストール
RUN apt-get update -qq && apt-get install -y postgresql-client

# yarnパッケージ管理ツールをインストール
RUN apt-get update && apt-get install -y curl apt-transport-https wget
RUN curl 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

# Node.jsをインストール
RUN curl https://deb.nodesource.com/setup_14.x | bash -
RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 1655A0AB68576280
RUN apt-get update && apt-get install -y nodejs

RUN mkdir /backend
WORKDIR /backend

# Gemをインストール
COPY Gemfile /Gemfile
COPY Gemfile.lock /Gemfile.lock
RUN gem install bundler
RUN cd /backend
RUN gem update --system ${RUBYGEMS_VERSION} && \
    bundle install
COPY . /backend

# Rails固有のエントリーポイント対応
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]

# Railsサーバーの起動
EXPOSE 3000

CMD ["rails", "server", "-b", "0.0.0.0"]

entrypoint.sh

Railsでは特定のserver.pidファイルが存在するとサーバーが再起動できない仕様があります。
Docker環境ではこの仕様が邪魔になってしまうので、起動前にserver.pidを削除する処理を追加する必要があります。
このentrypoint.shによってそれを実行しています。

backend/entrypoint.sh
#!/bin/bash
set -e

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

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

Gemfile

最低限のrailsを設定しておきます。

backend/Gemfile
source 'https://rubygems.org'
gem 'rails', '7.0.4'

docker-compose.ymlの設定

docker-compose.ymlには複数のDockerコンテナを動かすための設定を書きます。
後ほど説明しますが、docker-composeコマンドで実行します。
今回は以下の環境を設定していきます。
※()内はdocker-compose.ymlに設定するサービス名です。任意に命名してOKです。

  • データベース(db)
  • バックエンド(api)
  • フロントエンド(front)

まずはdbとapiのみ記述していきます。

docker-compose.yml
version: "3.8"
services:
  db:
    image: postgres
    volumes:
      - ./tmp/db:/var/lib/postgresql/data
    environment:
      - POSTGRES_HOST_AUTH_METHOD=trust
      - POSTGRES_PASSWORD=admin
    ports:
      - "15432:5432"
  api:
    build: ./backend/
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    image: api
    volumes:
      - ./backend:/backend
    environment:
      RAILS_ENV: development
    ports:
      - "3000:3000"
    depends_on:
      - db

コマンドを打っていく

これから打っていくコマンド の中にdocker-compose run xxx 〜というものがあります。
xxxにはdocker-compose.ymlに記述したサービス名のどれかを記述します。
つまりどのコンテナに対してのコマンドを打つのか明示するということです。
例えばバックエンドは今回apiと言うコサービス名にしたので、以下のように記述します。

docker-compose run [オプション] api 〜〜〜

docker-compose run apiの後はローカルで普段使うコマンドと同じで大丈夫です。
例えばrails newしたいのであれば、以下のようになります。

docker-compose run [オプション] api rails new 〜〜〜

Railsアプリケーションの作成

Docker環境にてrails newしていきます。
今回はAPIモードかつ、DBはpostgresqlを指定していきます。

docker-compose run --no-deps api rails new . --force --database=postgresql --api
指定したオプションについて
--no-deps

リンクしたサービスを起動しないようにします。今回はdocker-compose.ymlにてdepends_on: - dbを設定しているため必要になります。

--force

ファイルが存在する場合に上書きします。

--database

databseを指定します。

--api

APIモードで構築します。

build

rails newにより、Gemfileが更新されたと思います。
通常はbundle installを行うと思いますが、Docker環境においては以下を実行します。

docker-compose build

database.ymlの設定

backend/config/database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: postgres #デフォルトでは無いので設定
  password: admin #デフォルトでは無いので設定
  host: db #デフォルトでは無いので設定

development:
  <<: *default
  database: myapp_development #適宜修正

test:
  <<: *default
  database: myapp_test #適宜修正
  
production:
  <<: *default
  database: myapp_production #適宜修正
  username: myapp #適宜修正
  password: <%= ENV["MYAPP_DATABASE_PASSWORD"] %> #適宜修正

Databaseを作成する

$ docker-compose run api rails db:create

Railsを起動してみる。

ここまでできたら一度Railsを起動してみましょう!

docker-compose up

localhost:3000にアクセスして以下のような画面が出ればOKです。

3 フロントエンド(React)側の設定

続いてフロントエンド側を構築します。

Dockerfile

フロント側ではnodeのイメージを指定してWORKDIRのみを設定しておきます。

backend/Dockerfile
FROM node:16.16.0-alpine
WORKDIR /frontend

docker-compose.yml

先ほど作成したファイルの末尾に以下を追加します。

docker-compose.yml
version: "3.8"
services:
  db:
   ~~~~~
  api:
   ~~~~~
# 以下を追加
  front:
    build:
      context: ./frontend/
      dockerfile: Dockerfile
    volumes:
      - ./frontend:/frontend
    command: sh -c "cd app &&PORT=3001 yarn start"
    ports:
      - "3001:3001"

build

再度以下を実行します。

docker-compose build

Reactアプリケーションを作成

今回は以下を実行していきます。
npmで管理していくため、npx create-react-appにしています。

docker-compose run front sh -c "npx create-react-app app --template typescript"

Reactを起動する

ここまでできたら再度以下でコンテナを起動しましょう。

docker-compose up

localhost:3001にアクセスして以下が表示されればOKです。

4 まとめ

今回はRails7 APIモード + PostgreSQL + React (TypeScript)で作るSPAサービスのDocker環境を構築しました。
docker-composeには他にもさまざまなオプションが設定できるみたいですが、今回は最低限で試してみました。

以上です!

Discussion