はじめに
こんにちは。RUNTEQにて学習中のかるめと申します。
今回はDockerを用いてRails + PostgreSQLの開発環境を構築し、Renderにデプロイするまでの記事となります。類似記事は既に多くありますが、開発環境構築からデプロイまでの流れを載せている記事は少なく感じたのと、個人的なアウトプット目的の意味合いもかねて書いておきます。
「よく分かってないけど、とりあえずDockerfileやcompose.yamlをコピペして開発環境を作ってる」という初心者を意識して説明も添付しています。
学習中の身のため、何か間違いなどありましたらご指摘いただけると幸いです。
基本情報
Ruby: 3.4.7
Ruby on Rails: 7.2.3
JavaScriptのバンドラー: importmap または esbuild
CSSフレームワーク: Tailwind CSS または Bootstrap
データベース: PostgreSQL 16
デプロイ先: RenderのRuby環境
開発環境構築の手順
開発環境を構築するおおまかな流れは以下のようになります。
- 開発用ディレクトリを作成&移動
- Dockerfile.dev、compose.yaml、Gemfileを作成&編集
- rails new
- config/database.yamlを編集
- Procfile.devを編集
- ビルド&データベース準備
- docker compose upを実行
以下から順に進めていきます。
1. 開発用ディレクトリを作成&移動
プロジェクトを置くディレクトリを作成して、そこに移動します。
mkdir myapp && cd $_
2. Dockerfile.dev、compose.yaml、Gemfileを作成&編集
開発環境用のDockerfileであるDockerfile.dev、compose.yaml、Gemfile、Gemfile.lockをそれぞれ作成します。
touch Dockerfile.dev compose.yaml Gemfile Gemfile.lock
Gemfile
以下のように編集します。
source "https://rubygems.org"
gem "rails", "7.2.3"
空のGemfile.lockを用意しておくことで、この後のdocker compose buildコマンドを実行時の「Gemfile.lock が見つからない」というエラーを回避できます。
Dockerfile.dev
Rails7.1以降では、この後のrails newコマンド実行時に本番環境用のDockerfileが自動生成されます。そのため開発環境用としてDockerfile.devという名前で別に用意します。使いたいCSSフレームワークに合わせて編集します。
追記
必要なものがあれば追加でインストールしましょう。Dockerfile.devのRUN命令のインストール部分に追加すればOKです。
例1:コンテナ内でconfig/credentials.yml.encを編集するためにVimをインストールする
例2:Active Storageのvariant機能を使うためにlibvipsをインストールする
Tailwind CSSを使う場合
JavaScriptのバンドラーはデフォルトのimportmapで大丈夫なのでNode.jsやYarnをインストールする必要はありません。以下のように編集します。
FROM ruby:3.4.7
ENV LANG C.UTF-8
ENV TZ Asia/Tokyo
ENV RAILS_ENV=development
RUN apt-get update -qq && apt-get install -y \
build-essential \
libpq-dev \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY Gemfile Gemfile.lock ./
RUN bundle install
COPY . .
Dockerfile.devの説明
FROM ruby:3.4.7 # ベースイメージのバージョンを指定
ENV LANG C.UTF-8 # 日本語の文字化け防止
ENV TZ Asia/Tokyo # コンテナ内のタイムゾーンをJSTに設定して、デバッグ時のログの時刻をわかりやすくする
ENV RAILS_ENV=development # 開発環境であることを明示
RUN apt-get update -qq && apt-get install -y \ # installする前にupdateする、-qqでログの出力を抑制する
build-essential \ # 必須
libpq-dev \ # PostgreSQLを使う場合は必須
&& rm -rf /var/lib/apt/lists/* # クリーンアップ処理
WORKDIR /app # 作業ディレクトリの指定
COPY Gemfile Gemfile.lock ./ # Gemfileだけ先にコピー(キャッシュ効率化)
RUN bundle install # Gemに関連するファイルだけインストール
COPY . . # ローカルのディレクトリを丸ごと作業ディレクトリにコピー
Bootstrapを使う場合
esbuildというJavaScriptのバンドラーを使用します。そのため、Node.jsやYarnのインストールが必要となります。以下のように編集します。
FROM ruby:3.4.7
ENV LANG C.UTF-8
ENV TZ Asia/Tokyo
ENV RAILS_ENV=development
RUN curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - \
&& apt-get update -qq \
&& apt-get install -y \
build-essential \
libpq-dev \
nodejs \
&& npm install --global yarn \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY Gemfile Gemfile.lock ./
RUN bundle install
COPY . .
Dockerfile.devの説明(1つ前の説明との差異のみ)
FROM ruby:3.4.7
ENV LANG C.UTF-8
ENV TZ Asia/Tokyo
ENV RAILS_ENV=development
# Node.jsは公式リポジトリを追加してからインストール、Yarnはnpm経由でインストール
RUN curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - \
&& apt-get update -qq \
&& apt-get install -y \
build-essential \
libpq-dev \
nodejs \
&& npm install --global yarn \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY Gemfile Gemfile.lock ./
RUN bundle install
COPY . .
compose.yaml
以下のように編集します。
services:
web:
build:
context: .
dockerfile: "Dockerfile.dev"
ports:
- "3000:3000"
command: bash -c "rm -f tmp/pids/server.pid && ./bin/dev"
tty: true
stdin_open: true
environment:
- TZ=Asia/Tokyo
depends_on:
db:
condition: service_healthy
volumes:
- .:/app
- bundle_data:/usr/local/bundle
db:
image: postgres:16
ports:
- "5432:5432"
environment:
POSTGRES_PASSWORD: password
restart: always
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
bundle_data:
postgres_data:
compose.yamlの説明
services:
web:
# 開発環境では ./Dockerfile.dev からビルドする
build:
context: .
dockerfile: "Dockerfile.dev"
ports:
- "3000:3000" # 開発環境では3000番ポートでアプリケーションにアクセス
# クリーンアップ処理&Procfile.devを起動
command: bash -c "rm -f tmp/pids/server.pid && ./bin/dev"
tty: true # デバッグコマンドを使えるようにする
stdin_open: true # デバッグコマンドを使えるようにする
environment:
- TZ=Asia/Tokyo # デバッグ時に時間を見やすくする
# 接続エラーを防ぐためにdbコンテナが起動確認後にwebコンテナを起動する
depends_on:
db:
condition: service_healthy
volumes:
- .:/app # バインドマウント
- bundle_data:/usr/local/bundle # bundleキャッシュ
db:
image: postgres:16 # PostgeSQLイメージのバージョンを指定
ports:
- "5432:5432" # 開発環境ではポート公開
# POSTGRES_PASSWORDは必須
environment:
POSTGRES_PASSWORD: password
restart: always # DBは安定稼働させる
healthcheck: # restartとセットで使う
test: ["CMD-SHELL", "pg_isready -U postgres"] # PostgreSQLの接続確認コマンド
interval: 10s # チェック間隔
timeout: 5s # コマンドのタイムアウト時間
retries: 5 # unhealthyになるまでのリトライ回数
start_period: 30s # 初回起動時の猶予期間
volumes:
- postgres_data:/var/lib/postgresql/data # ボリュームマウント
volumes:
bundle_data:
postgres_data:
補足:PostgreSQL 18以降のボリュームマウント先について
今回の記事のようにPostgreSQL 17以前の場合は/var/lib/postgresql/dataとなりますが、PostgreSQL 18以降を使う場合は/var/lib/postgresqlとしてください。
参考:Docker Hubの公式ページ
compose.yamlとこの後のDatabase.yamlでは、開発環境のための簡易的な設定として平文のパスワードを使っています。
3. rails new
こちらも使いたいCSSフレームワークに合わせてコマンドを実行します。
rails newのオプションについて
rails newする際に、使用するデータベースやJavaScriptのバンドラー、CSSフレームワークを指定します。
データベース
既定値はSQLite。PostgreSQLを使用したい場合は -d postgresql と指定します。
JavaScriptのバンドラー
既定値はimportmap。TypeScriptやReact、VueなどのUIライブラリを使いたい場合はesbuildなどのバンドラーを指定します( -j esbuild)。importmap以外を使う場合はDockerfileでNode.jsとYarnのインストールが必要です。
CSSフレームワーク
Tailwind CSSを使用したい場合は--css=tailwind、Bootstrapを使用したい場合は--css=bootstrapのオプションをつけます。
Tailwind CSSを使う場合
docker compose run --rm web rails new . --force --database=postgresql --css=tailwind
Bootstrapを使う場合
docker compose run --rm web rails new . --force --database=postgresql -j esbuild --css=bootstrap
rails newした後に出てくる警告について
Bootstrapを使う場合は、rails new後にSassの警告が大量に出てきます。一応そのままでも動きますが、気になる方は修正しましょう。
4. config/database.yamlを編集
# 以下3行を追加しますとコメントしている以下の部分を追加してください。
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 } %>
# 以下3行を追加します
host: db
username: postgres
password: password
development:
<<: *default
database: app_development
test:
<<: *default
database: app_test
production:
<<: *default
# Renderでは環境変数DATABASE_URLが優先されるため、以下の設定は使用されません
database: app_production
username: app
password: <%= ENV["APP_DATABASE_PASSWORD"] %>
5. Procfile.dev
Procfileはforemanというgemを使っています。compose.yamlのcommandで./bin/devと実行させることで、Procfileがjsやcssもまとめてビルドしてくれて、開発中にファイルの変更内容が自動反映されます。
Tailwind CSSを使う場合
importmapの場合、jsのビルドは不要です。
web: bin/rails server -b 0.0.0.0 -p 3000
css: bin/rails tailwindcss:watch
Bootstrapを使う場合
web: bin/rails server -b 0.0.0.0 -p 3000
js: yarn build --watch
css: yarn watch:css
6. ビルド&データベース準備
ビルドとデータベースの準備を行います。
docker compose build
docker compose run --rm web bundle exec rails db:prepare
7. docker compose upを実行
docker compose up
これで開発環境ができました。http://localhost:3000にアクセスするといつもの画面が表示されるはずです。
デプロイ手順
これからRenderでのデプロイ手順を紹介していきます。開発環境ができたばかりの方は確認画面をscaffoldでも大丈夫なので作成しておいてください。
以下の流れで進めていきます。
- bin/render-build.shを作成&編集
- GitHubにpush
- 本番環境用のPostgreSQLを作成
- Web Serviceを作成
1. bin/render-build.shを作成&編集
ビルド時に実行するシェルスクリプトを作成します。
touch bin/render-build.sh
デフォルトでは実行権限が無いので追加しておきます。
chmod a+x bin/render-build.sh
以下のように編集します。
#!/usr/bin/env bash
set -o errexit
bundle install
bundle exec rails assets:precompile
bundle exec rails assets:clean
bundle exec rails db:migrate
初期データを入れたい場合
bundle exec rails db:seedを追加する。
#!/usr/bin/env bash
set -o errexit
bundle install
bundle exec rails assets:precompile
bundle exec rails assets:clean
bundle exec rails db:migrate
bundle exec rails db:seed
2. GitHubにpush
1が終わったらリモートリポジトリにpushしておきます。
3. 本番環境用のPostgreSQLを作成
これからはRenderで作業をしていきます。
Renderにアクセスして、Add newボタンからPostgresを選択を選択します。作成画面を開いたら以下を設定します。
| 設定項目 | 設定内容 |
|---|---|
| Region | Singapore |
| PostgreSQL Version | 使用するバージョン(今回は16) |
| Instance Type | Free(無料プラン) |
その他はお好みで大丈夫です。設定できたらCreate Databaseボタンを押しましょう。
しばらく待つとできあがります。できあがったら表示されるinternal database URLをこのあと使用します。
4. Web Serviceを作成
最後にRailsアプリをデプロイするためのWeb Serviceを作成します。
Add newボタンを押して、今度はWeb Serviceを選択します。Source Codeを選ぶ画面が出るので、今回デプロイするリポジトリを選択します。設定画面が出てくるので以下のように設定します。
| 設定項目 | 設定内容 |
|---|---|
| Language | Ruby |
| Branch | デプロイしたいブランチ |
| Region | Singapore |
| Instance Type | Free(無料プラン) |
| Build Command | ./bin/render-build.sh |
| Start Command | bundle exec puma -C config/puma.rb |
Languageの設定について
LanguageにはデフォルトでDockerと入っていますが、今回はマネージドなRuby環境にデプロイするため、チェックボックスからRubyと選択します。
このため、今回は自動生成された本番環境向けのDockerfileとそこから実行されるbin/docker-entrypointは使用しません。これらはRenderのDockerモードやその他コンテナサービスにデプロイする場合に使用します。
ちなみにDockerと設定したままだとBuild CommandとStart Commandが表示されません。
上記の設定が終わったら、Environment Variablesで環境変数を設定します。
| NAME_OF_VARIABLE | value |
|---|---|
| WEB_CONCURRENCY | (デフォルトで入っているものでOK) |
| RAILS_MASTER_KEY | (ローカルのconfig/master.keyの値) |
| RAILS_ENV | production |
| DATABASE_URL | (PostgreSQLのInternal Database URLの値) |
環境変数の入力が終わったら、すぐ下のAdvancedをクリックして展開します。Health Check Pathを設定しておきましょう。デフォルトでは/upなのでそのまま入れます(Railsのルーティングで設定変更できます)。
全ての設定ができたらDeploy Web Serviceボタンをクリックします。
あとはLogを見守りましょう。ビルドやデプロイができているか確認できます。デプロイが成功したら、RenderのダッシュボードからアプリのURLにアクセスして動作確認をしましょう。開発した通りに表示されていれば成功です!細かいミスをしていてデプロイが失敗していても、修正してデプロイし直せばOKです。お疲れ様でした。
参考