Rails7.1 APIモード + MySQL + Dockerの構成で環境構築をしたので、備忘録としてまとめます。
最後まで読めば、Rails7.1のAPIモードでサーバー立ち上げまで成功するはずです。
1. ファイルの準備
準備するファイルは次の6つです。
- Gemfile
- Gemfile.lock
- Dockerfile
- Dockerfile.dev
- entrypoint.sh
- compose.yaml
順番に説明します。
Gemfile
rails
のバージョンは現時点での最新安定版の7.1.2
を指定します。
source 'https://rubygems.org'
gem 'rails', '7.1.2'
Gemfile.lock
Gemfile.lockは空のままでOKです。
# 空ファイルを用意
Dockerfile
Dockerfile
の実装は次のとおりです。なおRubyのバージョンは現時点で最新安定版の3.2.2
を指定しています。
FROM ruby:3.2.2
WORKDIR /sample-api
COPY Gemfile /sample-api/Gemfile
COPY Gemfile.lock /sample-api/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"]
Dockerfile.dev
Dockerfile
と全く同じものをDockerfile.dev
として別途作成しておきます。
これはrails new
コマンドの実行によりDockerfile
がproduction環境用に書き変わってしまうためです。
詳しくは後述します。
FROM ruby:3.2.2
WORKDIR /sample-api
COPY Gemfile /sample-api/Gemfile
COPY Gemfile.lock /sample-api/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"]
entrypoint.sh
entrypoint.sh
はコンテナ起動時に実行されるよう、Dockerfile内でENTRYPOINT ["entrypoint.sh"]
と定義したスクリプトの中身です。
#!/bin/sh
set -e
rm -f /sample-api/tmp/pids/server.pid
exec "$@"
compose.yaml
compose.yaml
の記述は以下のとおりです。なおQiitaなどではよくdocker-compose.yaml
と命名されている記事を見かけますが、Dockerの公式ドキュメントではcompose.yaml
というファイル名が推奨されているため、それに倣っています。
services:
db:
image: mysql:8.0
volumes:
- db-data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: password
ports:
- "3306:3306"
web:
build: .
volumes:
- .:/sample-api
ports:
- "3000:3000"
depends_on:
- db
volumes:
db-data:
2. Rails newコマンドの実行
ファイルを作成したらrails new
コマンドを実行してRailsアプリケーションの雛形を作成します。
$ docker compose run --rm --no-deps web rails new . --force --database=mysql --api
各オプションの意味は次のとおりです。
- –no-deps:リンクされたコンテナを起動させない
- –force:Gemfileの上書きを行う
- –database=mysql:DBとしてMySQLを指定
- –api:APIモードでRailsを使う
3. 開発環境用と本番環境用のファイルを作る
Rails7.1のリリースノートにあるように、rails new
をするとDockerfile
はproduction用の内容に上書きされてしまいます!
# syntax = docker/dockerfile:1
# Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile
ARG RUBY_VERSION=3.2.2
FROM registry.docker.com/library/ruby:$RUBY_VERSION-slim as base
# Rails app lives here
WORKDIR /rails
# Set production environment
ENV RAILS_ENV="production" \
BUNDLE_DEPLOYMENT="1" \
BUNDLE_PATH="/usr/local/bundle" \
BUNDLE_WITHOUT="development"
# Throw-away build stage to reduce size of final image
FROM base as build
# Install packages needed to build gems
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y build-essential default-libmysqlclient-dev git libvips pkg-config
# Install application gems
COPY Gemfile Gemfile.lock ./
RUN bundle install && \
rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \
bundle exec bootsnap precompile --gemfile
# Copy application code
COPY . .
# Precompile bootsnap code for faster boot times
RUN bundle exec bootsnap precompile app/ lib/
# Final stage for app image
FROM base
# Install packages needed for deployment
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y curl default-mysql-client libvips && \
rm -rf /var/lib/apt/lists /var/cache/apt/archives
# Copy built artifacts: gems, application
COPY --from=build /usr/local/bundle /usr/local/bundle
COPY --from=build /rails /rails
# Run and own only the runtime files as a non-root user for security
RUN useradd rails --create-home --shell /bin/bash && \
chown -R rails:rails db log storage tmp
USER rails:rails
# Entrypoint prepares the database.
ENTRYPOINT ["/rails/bin/docker-entrypoint"]
# Start the server by default, this can be overwritten at runtime
EXPOSE 3000
CMD ["./bin/rails", "server"]
なのでこのDockerfileは開発環境には使えない、、でもせっかく上書きされたならproduction用のDockerfileもこれはこれで使いたい、、
というわけでDockerfileを開発環境用とproduction用に2つ作ります。
3.1 Dockerfileを開発環境・productionに分ける
最初にDockerfileと全く同じDockerfile.dev
を作成してあるのでこれを開発環境用に、そしてrails new
で上書きされたDockerfileはproduction環境用となるため名称をDockerfile.prod
に変更します。
3.2 compose.yamlを開発環境・productionに分ける
合わせてcompose.yamlファイルも開発環境・production用の2つを作成する必要があります。
まずcompose.yamlのファイル名をcompose-dev.yaml
に変更し、Dockerfile.dev
をビルドに使用するよう修正します。
services:
db:
image: mysql:8.0
volumes:
- db-data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: password
ports:
- "3306:3306"
web:
build:
context: .
dockerfile: Dockerfile.dev
volumes:
- .:/sample-api
ports:
- "3000:3000"
depends_on:
- db
volumes:
db-data:
続いてproduction用にcompose-prod.yaml
を作成し、こちらのビルドにはDockerfile.prod
を使わせます。
services:
db:
image: mysql:8.0
volumes:
- db-data:/var/lib/mysql/data
environment:
MYSQL_ROOT_PASSWORD: password
web:
build:
context: .
dockerfile: Dockerfile.prod
command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
volumes:
- .:/sample-api
ports:
- "3000:3000"
depends_on:
- db
volumes:
db-data:
4. buildコマンドの実行
開発環境用とProduction用にファイルを分けたらbuildコマンドを実行します。
$ docker compose -f compose-dev.yaml build
5. database.ymlの修正
ビルドが完了したらconfig/database.yml
にdbコンテナとの接続情報を追記してください。
passwordとhostをcompose-dev.yaml
に合わせましょう。
default: &default
adapter: mysql2
encoding: utf8mb4
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: root
password: password
host: db
development:
<<: *default
database: sample_api_development
test:
<<: *default
database: sample_api_test
production:
<<: *default
database: sample_api_production
username: sample_api
password: <%= ENV["SAMPLE_API_DATABASE_PASSWORD"] %>
6. DB作成コマンドを実行
config/database.yml
への追記が完了したらDB作成コマンドを実行しましょう。
$ docker compose -f compose-dev.yaml run --rm web rake db:create
[+] Running 1/1
✔ Container sample-api-db-1 Created 0.1s
[+] Running 1/1
✔ Container sample-api-db-1 Started 0.4s
Created database 'sample_api_development'
Created database 'sample_api_test'
7. コンテナを起動
DBの作成が確認できたらコンテナを起動してください。
$ docker compose -f compose-dev.yaml up
web-1 | => Booting Puma
web-1 | => Rails 7.1.2 application starting in development
web-1 | => Run `bin/rails server --help` for more startup options
web-1 | Puma starting in single mode...
web-1 | * Puma version: 6.4.0 (ruby 3.2.2-p53) ("The Eagle of Durango")
web-1 | * Min threads: 5
web-1 | * Max threads: 5
web-1 | * Environment: development
web-1 | * PID: 1
web-1 | * Listening on http://0.0.0.0:3000
web-1 | Use Ctrl-C to stop
8. http://0.0.0.0:3000 にアクセスすると…
以下の画面が表示されていれば無事成功です!
おわりに
ここまでで終わり!と言いたいところですが、CORSの設定が残っているので対応が必要です。
詳しくは以下の記事をどうぞ。
また、以下の記事ではワンランク上のRailsエンジニアになりたいと考えている方向けにおすすめの技術書を紹介しています。
こちらの記事もぜひ読んでみてください。
コメント