以前、個人でRailsプロジェクトを作成したことはありましたが、ローカルMacにパッケージやMySQLをインストールしたりと、プロジェクト作成前の面倒な工程の印象がありました。
今では、Dockerを使うとローカルマシーンにインストールすることなく、仮想環境でアプリケーションを作れるので、現時点(2024年4月)の最新バージョンでRailsプロジェクトを作ってみました。
また、なるべくDockerfileやcompose.yml(docker-compose.yml)ファイル内の記述をシンプルに書いています。
使用環境・バージョン
- Mac
- Ruby 3.3
- Rails 7.1.3
- MySQL 8.3
完成形
後述の、環境構築の進め方記載の2ステップで進めた結果、完成形のディレクトリ構成、Dockerfile、compose.ymlは以下になります。
ディレクトリ構成
|- service # Railsプロジェクトを格納するディレクトリ
|- db_data # MySQLのボリュームディレクトリ
|- compose.yml
|- Dockerfile
|- Gemfile # Railsのパッケージバージョンを記載
|- Gemfile.lock
Dockerfile
FROM ruby:3.3
WORKDIR /service
COPY Gemfile* /service/
RUN bundle install
EXPOSE 3000
CMD ["rails", "server", "-b", "0.0.0.0"]
compose.yml
version: '3.8'
services:
web:
build: .
environment:
MYSQL_HOST: db
MYSQL_USER: root
MYSQL_PASSWORD: password
ports:
- '3000:3000'
volumes:
- type: bind
source: ./service
target: /service
depends_on:
- db
db:
image: mysql:8.3
environment:
MYSQL_ROOT_PASSWORD: password
ports:
- '3306:3306'
volumes:
- type: bind
source: ./db_data
target: /var/lib/mysql
ディレクトリは、他の記事ではDockerfile/compose.ymlと同階層にプロジェクトファイルが混在するのを見かけたりしましたが、個人的に整理しておきたいなと考え、Docker関連のファイルと同階層に、プロジェクトディレクトリを配置するようにしています。
環境構築の進め方
ステップ1: コンテナセットアップ・Railsプロジェクト作成
準備
以下のディレクトリ構成、Dockerfile、compose.yml、Gemfileファイルの中身を以下のようにします。
ディレクトリ構成
|- service # 空ディレクトリを用意
|- compose.yml
|- Dockerfile
|- Gemfile
Gemfile
source 'https://rubygems.org'
gem 'rails', '~> 7.1.3'
Dockerfile
FROM ruby:3.3
WORKDIR /service
# GemfileとGemfile.lockファイルを
# イメージのserviceディレクトリ内にコピー
COPY Gemfile* /service/
RUN bundle install
EXPOSE 3000
CMD ["rails", "server", "-b", "0.0.0.0"]
compose.yml
version: '3.8'
services:
web:
build: .
ports:
- '3000:3000'
volumes:
- type: bind
source: ./service
target: /service
compose.ymlのvolumesは、他の記事では1行に書いているのを見ますが、docker-compose の bind mount を1行で書くなという記事を参考に、long syntaxで書いています。シンプルな記述ならshort syntaxが良いのかもしれないけど、このくらいならシンプルの範疇だし厄介ごとはできれば減らしたいという意図でした。
手順
-
docker compose build
でDockerfileのイメージをビルド -
docker compose run web rails new . --database=mysql
のコマンドを実行して、serviceディレクトリ配下をRailsプロジェクトにする - serviceディレクトリ内にあるGemfile, Gemfile.lockファイルをserviceディレクトリと同じ階層にコピー *元々あるGemfileをそのまま上書きする
- 再度
docker compose build
を実行 -
docker compose up
でコンテナを起動
ここまで終わったら、webコンテナが起動した状態で、ブラウザから http://localhost:3000 のURLでアクセスすると、以下の画面が表示されます。
エラーメッセージ
ActiveRecord::ConnectionNotEstablished
Can't connect to local server through socket '/run/mysqld/mysqld.sock' (2)
Railsプロジェクトは起動したのですが、MySQLのデータベース環境を準備する必要があります。
ステップ2: MySQL環境のセットアップ・データベースの接続設定
ステップ1でコンテナを起動していたら、docker compose down
コマンドで一度コンテナを終了しましょう。
準備
ステップ1から、以下のように変更します。
ディレクトリ構成
|- service
|- db_data # 空ディレクトリを用意、DBのマウントに使用
|- compose.yml
|- Dockerfile
|- Gemfile
|- Gemfile.lock # ステップ1で追加された
compose.yml
version: '3.8'
services:
web:
build: .
ports:
- '3000:3000'
# ステップ2で追記、database.ymlで参照するため
environment:
MYSQL_HOST: db
MYSQL_USER: root
MYSQL_PASSWORD: password
volumes:
- type: bind
source: ./service
target: /service
# ステップ2で追記、dbサービスと依存関係があり指定
depends_on:
- db
# ステップ2で追記、MySQLのイメージを使用
db:
image: mysql:8.3
environment:
MYSQL_ROOT_PASSWORD: password
ports:
- '3306:3306'
volumes:
- type: bind
source: ./db_data
target: /var/lib/mysql
また、serviceディレクトリ内にある config/database.yml
も該当箇所を以下のように更新します。
config/database.yml
# AS-IS
default: &default
adapter: mysql2
encoding: utf8mb4
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: root
password:
host: localhost
# TO-BE
default: &default
adapter: mysql2
encoding: utf8mb4
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: <%= ENV['MYSQL_USER'] %> # 変更
password: <%= ENV['MYSQL_PASSWORD'] %> #変更
host: <%= ENV['MYSQL_HOST'] %> # 変更
手順
-
docker compose build
で再度イメージをビルド -
docker compose up
でコンテナ起動 (*) -
docker compose run web rails db:create
で、データベースを作成 - 再度画面をリロードで読み込み直したら正しく表示されるようになります
*この時、http://localhost:3000 にアクセスすると、以下のようなエラー画面が表示されます。
エラーメッセージ
We could not find your database: service_development. Available database configurations can be found in config/database.yml.
To resolve this error:
- Did you not create the database, or did you delete it? To create the database, run:
bin/rails db:create
- Has the database name changed? Verify that config/database.yml contains the correct database name.
さいごに
RailsとDockerを組み合わせた環境構築の記事をみつつ、自分なりにDocker周りの記述をシンプルにしようと整理してみました。ただ、わたし自身バックエンドの実経験がなく、この手順だと考慮するべきポイントもあるかと思います。
今回は、最初つまづきそうな環境構築にフォーカスして書いてみましたが、
ここからはまったポイントとか、コントローラ、データベース疎通の進め方含め知見がたまったら記事にしていこうと思います。