docker-compose + Rails 7 + Postgres の環境構築
Rails 7 と Postgres を、docker-compose を用いてセットアップする方法です。
仕事で Rails を使う機会があり、自分でも1からセットアップしようと思ったらいくつかつまずいたポイントがあったため、n番煎じですが備忘録も兼ねて文章にしました。
基本的には Docker の公式チュートリアルに沿って進めていきますが、一部バージョンが古い部分等を補っています。
Rails や Postgres、 Docker 自体が何者かは分かる前提で書いていきますのでご了承ください。
今回のゴール
Docker Compose 上で以下のコンテナを動かし、 Rails アプリケーションを開発できる状態にする
- PostgreSQL
- Rails 7.0.4
- ruby 3.1
Docker Desktop のインストール
まだ Docker Desktop がインストールされていない場合はインストールします。
Docker の準備
プロジェクトを配置するフォルダを準備します。ここが Rails のルートフォルダになります。
mkdir rails-proj
続いて、 Rails を実行するための Ruby コンテナを作成する Dockerfile
を作成します。
今回 Ruby のバージョンは 3.1
を利用します。
FROM ruby:3.1
USER root
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs
RUN mkdir /webapp
WORKDIR /webapp
ADD Gemfile /webapp/Gemfile
ADD Gemfile.lock /webapp/Gemfile.lock
RUN bundle install
ADD . /webapp
さらに、上の Dockerfile で作成する Rails アプリケーションコンテナと、 Postgres データベースコンテナを起動するための docker-compose.yml
を作成します。
version: '3'
services:
db:
container_name: rails_db
image: postgres
web:
container_name: rails_web
build: .
command: bundle exec rails s -p 3000 -b '0.0.0.0'
volumes:
- .:/webapp
ports:
- 3000:3000
depends_on:
- db
Rails のインストール
Rails のインストールをするため Gemfile を記述します。
source 'https://rubygems.org'
gem 'rails', '~> 7.0.4'
また、空で良いので Gemfile.lock
も必要なので作成します。
touch Gemfile.lock
この時点で、ファイルが4つあるはずです。
ls
Dockerfile Gemfile Gemfile.lock docker-compose.yml
ここまできたら、コンテナ内で Rails のインストールを行うことで必要なファイルを Rails が自動で作成してくれます。
以下を実行すると、Dockerfile
の記述に従って bundle install
が走って Rails がインストールされた後、 Rails のアプリケーション作成コマンドが実行されます。
docker compose run --rm web rails new . --force --database=postgresql
実行後、大量のフォルダ・ファイルが作成されているはずです。
ログには Could not find gem ~
などのエラーが表示されているはずですが、今のうちは問題ありません。
ls
Dockerfile Gemfile Gemfile.lock README.md Rakefile app bin config config.ru db docker-compose.yml lib log public storage test tmp vendor
データベースの設定
config/database.yml
内の default: &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 } %>
+ host: db
+ username: postgres
+ password: admin
また、環境変数経由で Postgres のパスワードを設定するために docker-compose.yml
に追記します。
services:
db:
container_name: rails_db
image: postgres
+ environment:
+ - POSTGRES_PASSWORD=admin
Rails を起動する
rails new
を実行したことにより、 Gemfile
が変更されているはずです。
なので、新しい gem をインストールするために、コンテナを再ビルドして起動します。
docker compose up --build
ここまでくれば、 Rails と Postgres が正常に起動するはずです。
データベースの作成
お疲れ様です!ここまできたら後もう少しです。
Postgres 内にデータベースを作成します。
rails_web
コンテナ内で、rake db:create
を実行することでデータベースが作成できます。
docker exec rails_web rake db:create
以下が表示されれば成功です。
Created database 'webapp_development'
Created database 'webapp_test'
http://localhost:3000/ にアクセスしてみましょう。
Rails と Postgres の設定が正常にできていれば、下の画像のようなページが表示されます。
Yay! You’re on Rails!
お疲れ様でした。以降はローカルで開発するのと同様に Rails アプリケーションを作成できます。
Rails を実行するには docker compose up
、終了するには Ctrl+C
/Cmd+C
を押下します。
Rails による実際のアプリケーション作成がはじめての場合は、以下のサイトが参考になるかと思います。
おまけ
Postgres のデータがコンテナ再作成で消えないようにする
このままだと docker compose down
した際に、 rails_db
のコンテナが消えると同時にデータベース内のデータも消えてしまいます。
Docker の Volume 機能を活用して、データを永続化することができます。
version: "3"
services:
db:
container_name: rails_db
image: postgres
+ volumes:
+ - postgres-volume:/var/lib/postgresql/data
environment:
- POSTGRES_PASSWORD=admin
web:
container_name: rails_web
build: .
command: bundle exec rails s -p 3000 -b '0.0.0.0'
volumes:
- .:/webapp
ports:
- 3000:3000
depends_on:
- db
+volumes:
+ postgres-volume:
この設定を行うことで、データベースに書き込まれたデータが Volume に同期されるようになり、新しくコンテナを作ったときも Volume のデータをコンテナに同期してくれるようになります。
なお、変更した後はデータベースの再作成が必要です。
docker exec rails_web rake db:create
Gem がコンテナ再作成で消えないようにする
上の Postgres と同様に、コンテナ再作成ごとにインストールが走ってしまう Gem も永続化できます。
version: "3"
services:
db:
container_name: rails_db
image: postgres
volumes:
- postgres-volume:/var/lib/postgresql/data
environment:
- POSTGRES_PASSWORD=admin
web:
container_name: rails_web
build: .
command: bundle exec rails s -p 3000 -b '0.0.0.0'
volumes:
- .:/webapp
+ - gems-volume:/usr/local/bundle
ports:
- 3000:3000
depends_on:
- db
volumes:
postgres-volume:
+ gems-volume:
コンテナを再ビルドすることで Dockerfile 経由で bundle install
を実行します。
docker compose build
VSCode の Remote Container で開発する
VSCode の Remote Container 内で開発すると、ホスト側に Ruby や Gem をインストールせずとも rubocop
や solargraph
等を利用しながら開発ができるので、幸せになれるかもしれません。
.devcontainer
ディレクトリを作成し、以下の2ファイルを作成します。
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.245.2/containers/docker-existing-docker-compose
// If you want to run as a non-root user in the container, see .devcontainer/docker-compose.yml.
{
"name": "rails-webapp",
// Update the 'dockerComposeFile' list if you have more compose files or use different names.
// The .devcontainer/docker-compose.yml file contains any overrides you need/want to make.
"dockerComposeFile": ["../docker-compose.yml", "./docker-compose.yml"],
// The 'service' property is the name of the service for the container that VS Code should
// use. Update this value and .devcontainer/docker-compose.yml to the real service name.
"service": "web",
// The optional 'workspaceFolder' property is the path VS Code should open by default when
// connected. This is typically a file mount in .devcontainer/docker-compose.yml
"workspaceFolder": "/webapp"
}
また、ホストとの同期オプションで delegated
を指定するとファイル読み書きが高速化するかもしれないので指定しておきます。
version: "3"
services:
web:
volumes:
- .:/webapp:delegated
:delegated
と :cached
について詳しくは↓をご参照ください。
VSCode でプロジェクトを開き、 Dev Containers: Reopen in Container
を実行することでコンテナ内で開発できます。
参考
docker-compose.ymlで複数コマンドを実行する方法
docker-compose upしたときに「A server is already running.」って言われないようにする
Discussion