プログラミングのゴミ箱

日々の学習の中で知らなかったことについて、調べたことを解説します。

DockerでRailsAPI + React(PostgreSQL)環境を作る!

はじめに

usconsort.com
今回はこの記事を参考に、自分なりに改造しながら作って行きました。
Dockerを勉強しているとわからない単語やプロパティがたくさん出てきますが、横着せずに全部理解しながら進めましょう。

1. ファイル構成

今回は以下のようなファイル構成にします。

Dockerfile
entrypoint.sh
Gemfile
Gemfile.lock

  • front↓

Dockerfile

  • docker-compose.yml

(なんかうまいことファイル構成を表現する方法って無いんですかね、、、)


2. docker-compose.ymlの作成

以下のようなプログラムを書きます。

version: '3.9'
services:
  db: #データベースイメージを定義
    image: postgres # postgresのイメージを使用
    volumes:
      - ./docker/db/data:/var/lib/postgresql/data # データのマウント場所を指定
    environment:
      POSTGRES_PASSWORD: password # passwordを設定
  api:
    build:
      context: ./api/ # ./api/ の下のDockerfileを読み込み。
      dockerfile: Dockerfile
    command: sh -c "rm -f /api/tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'" # コンテナ立ち上げのたびに実行するコマンドを定義
    volumes:
      - ./api:/api 
      - ./api/vendor/bundle:/api/vendor/bundle
    ports:
      - '3000:3000'
    depends_on:
      - db # 実行順を指定
  front:
    build:
      context: ./front/
      dockerfile: Dockerfile
    volumes:
      - ./front:/usr/src/app
    command: sh -c "cd reactapp && yarn start"
    ports:
      - '8000:3000'
volumes:
  postgresql_db:
    driver: local

特に変わったことは書いていないので説明は省略させて頂きます。


3. apiのDockerfileの作成

api側のDockerfileを作って行きます。
今回は以下のようなコマンドを書きました。

# syntax=docker/dockerfile:1
FROM ruby:2.5
RUN apt-get update -qq && apt-get install -y nodejs postgresql-client

RUN mkdir /api
WORKDIR /api # コマンドの実行ディレクトリを移動。
COPY Gemfile /api/Gemfile
COPY Gemfile.lock /api/Gemfile.lock
RUN bundle install

# Add a script to be executed every time the container starts.
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000

# Configure the main process to run when running the image
CMD ["rails", "server", "-b", "0.0.0.0"]

WORKDIRで指定した/apiというのはdockerのイメージ内のパスで、指定できるパスはdocker-compose.ymlで定義した

    volumes:
      - ./api:/api 
      - ./api/vendor/bundle:/api/vendor/bundle

ここから確認できます。
その他Dockerfile内のパスは全てイメージのパスを指しており、ローカルコンピューターのパスをしても動かない。


4. entrypoint.shの作成

entrypoint.shを作成して以下のように記述します。

#!/bin/bash
set -e

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

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

主にやっていることとしては、不要なファイルを削除するということと、コマンドライン上でエラーが起きたときにすぐ実行を中止すること。それとentrypointの処理が終わってからコマンドラインの入力を受け付けること。(多分)
https://stackoverflow.com/questions/39082768/what-does-set-e-and-exec-do-for-docker-entrypoint-scripts

5. frontのDockerfile作成

frontのDockefileに以下のように記述。

FROM node:17.5-alpine
WORKDIR /usr/src/app

6. 環境をbuild

まずはrails側の環境をを以下のコマンドで構築。

docker-compose run api rails new . --api --database=postgresql

次に、React環境を作成。

docker-compose run --rm front sh -c "npm install -g create-react-app && create-react-app reactapp"

ここで一旦build。

docker-compose build

Railsとデータベースを繋げるためにapiのconfig/database.ymlを編集。

default: &default
  adapter: postgresql
  encoding: unicode
  host: db
  username: postgres
  password: password # docker-compose.ymlで設定したパスワード
  # For details on connection pooling, see Rails configuration guide
  # http://guides.rubyonrails.org/configuring.html#database-pooling
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>

こんな感じ。
一旦コンテナを立ち上げ。

docker-compose up

最後にRails側のデータベースを作成。

docker-compose exec api bash rails db:create


出来たっぽい。

f:id:chanichiwasshoi:20220222000101p:plain
f:id:chanichiwasshoi:20220222000112p:plain

データベースとRailsがつながらなかったり、volumeの概念の理解に苦しんだり、ここまで来るのに色々ありましたが完成したんでとりあえず上出来だと思います。次はこれをVPSで実行できるか試してみようと思います。