くま's Tech系Blog

基本的には技術で学んだことを書き留めようと思います。雑談もやるかもね!

DockerでRailsアプリケーションを動かす

今回はRails環境をDockerで構築する方法についてです。

Docker Compose V1が非推奨となり、Docker Compose V2が推奨となることも踏まえてV2で行おうと思います。

Docker Desktopはインストール済み、アプリケーションを格納するフォルダは作成済みの状態で進めます。

Dockerfileの作成

まずはDockerfileを作成します。
DockerfileはRailsの実行環境用のイメージを作成するためのファイルです。 次のコマンドでDockerfileを作成します。(今回はsamplev2というフォルダを作成したとします)

samplev2 % touch Dockerfile

そして、Dockerfileに以下の記述を追加します。 今回はRuby3.1.0を使用するため、冒頭にFROM ruby:3.1.0を記載します。

FROM ruby:3.1.0
RUN apt-get update -qq && apt-get install -y postgresql-client
WORKDIR /samplev2
COPY Gemfile/samplev2/Gemfile
COPY Gemfile.lock/samplev2/Gemfile.lock
RUN bundle install

COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000

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

少し記述について補足します。

RUN apt-get update -qq && apt-get install -y nodejs postgresql-clientRailsアプリケーションに必要なNode.jsとPostgreSQLのインストールを行うように指定します。(PostgreSQLは必須ではありません)

WORKDIR /samplev2は作業ディレクトリを指定します。ここに誤りがあるとうまくプロジェクトが作成されないので、注意が必要です。

COPY Gemfile/samplev2/GemfileはローカルのGemfileをsamplev2配下にコピーします。 COPY Gemfile.lock /samplev2/Gemfile.lockはローカルのGemfile.lockをsamplev2配下にコピーします。

RUN bundle install先程コピーしたGemfileに記載されているGemをbundle installするように指定します。

COPY entrypoint.sh /usr/bin/はローカルのentrypoint.shを/usr/bin配下にコピーします。

RUN chmod +x /usr/bin/entrypoint.shでコピーしたentrypoint.shに権限を付与します。

ENTRYPOINT ["entrypoint.sh"]

EXPOSE 3000 CMD ["rails", "server", "-b", "0.0.0.0"]でポート番号を指定して、Railsを実行します。

exec形式([""]の形式)は指定したコマンドと引数がそのまま実行されるので、ENTRYPOINTやCMDはexec形式で記載しましょう。

Gemfileの作成

次にGemfileを作成します。
今回はRails7.0.4.2のアプリケーションを使用するため、作成したGemfileには次のように、gem 'rails', '7.0.4.2'を記載します。

source 'https://rubygems.org'
gem "rails", '7.0.4.2'

そして、Dockerfileをビルドするため、Gemfile.lockも作成します。 Gemfile.lockは空の状態で作成します。

entrypoint.shの作成

次にentrypoint.shを作成します。 既にserver.pidファイルが存在してしまうことで、サーバーを再起動できない問題を解消するために追加します。 (server.pidはサーバー起動時に生成されます。生成されている場合、サーバーは起動状態にあると認識されます。 サーバー終了後、server.pidが残存する恐れがあり、サーバーを再起動する場合に「サーバーは起動しています」というエラーが発生する場合があります。 よって、明示的に残存したserver.pidを削除する事で問題なくサーバーを起動する事ができるようになります)

samplev2 % touch entrypoint.shで空のファイルを作成して、次のように設定します。

#!/bin/bash
set -e

# すでにserver.pidがある場合には削除
rm -f /samplev2/tmp/pids/server.pid

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

exec "$@"でDockerfileのCMDで渡されたコマンド(→Railsのサーバー起動)を実行します。

compose.ymlの作成

次にアプリケーションを構成するサービス一覧を記載し、それらを一括で実行してくれるcompose.ymlを作成します。 V3からはcompose.ymlという名前が使えます。 以前使用していたdocker-compose.yml後方互換のためにしばらくサポートしているだけみたいなので、compose.ymlの方を使った方がいいと思います。

今回は、作成したcompose.ymlにdbとwebの2つを記載します。 dbはPostgreSQLを指定します。 samplev2 % touch compose.ymlで空のファイルを作成して、次のように設定します。

services:
  db:
    image: postgres
    volumes:
      - ./tmp/db:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: password
  web:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/samplev2
    ports:
      - "3000:3000"
    depends_on:
      - db

services:はservices配下にコンテナを定義します(今回はwebとdbのみ)。

image:は利用するイメージの指定します(今回はPostgreSQL)。

volumes:はデータを永続的に保存する場所を指定します(手元のデータをマウントしているなら、コンテナを立ち上げる度にデータが消えない)。 今回の場合は、手元でプロジェクトルートにファイルを作ると、コンテナ内の/sample2にも、ファイルが作られます。

environment:PostgreSQLに関する環境変数の設定(今回はパスワードを設定)

build: .はDockerfileがあるディレクトリを指定しています。

depends_on:はコンテナの実行順序の指定します(今回はDB起動からweb起動する設定にしています)

また、compose.yml内でversion: '3'のようにバージョンを記述する項目が非推奨になったので設定を入れていません。

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

ここまでファイルを作成したら、Railsの新規アプリケーションを作成します。

samplev2 % docker compose run --no-deps web(ここはcompose.ymlで定義したサービス名) rails new . --force --database=postgresql

--forceを設定することで実行時にGemfileの上書きを行います。

--no-depsを設定することでリンクされたコンテナを起動させないようにします。

--skip-bundleを設定することでbundle installをスキップします(今回はgemを追加していないので)

ビルド

rails newで作成した新規アプリケーションのGemfileを更新するため、ビルドを実行します。

samplev2 % docker compose build

DBの作成

ビルドまで成功していれば、デフォルトのフォルダやファイルが作成されていると思います。 ここでDBを作成します。

まずはdatabase.ymlの編集を行います。 デフォルトではRailslocalhost上でDBが動作してしまうため、先ほど記述したDBコンテナを動作先に指定しましょう。 config/database.ymlのdefault部分を以下のように編集します。

// 編集前

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
  host: db
  username: postgres
  password: password
  pool: 5

編集後は以下のコマンドでDBを起動します。

samplev2 % docker compose run web rails db:create

成功すると次のようにDBが作られると思います。

Created database 'samplev2_development'
Created database 'samplev2_test'

アプリケーションの起動

ここまででDockerの設定を一通り終了しました。 最後にアプリケーションを立ち上げます。 Dockerを起動した状態で、次のコマンドを実行します。

samplev2 % docker compose up

http://localhost:3000/にアクセスしてみて次のような画面が表示されれば成功です。

参照

www.docker.com

docs.docker.com

qiita.com

matsuand.github.io

github.com

github.com

qiita.com

qiita.com

zenn.dev