Rails7.1 APIモード + MySQL + Dockerの環境構築

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の設定が残っているので対応が必要です。

詳しくは以下の記事をどうぞ。

あわせて読みたい
【Rails7.1 API】uninitialized constant Rack::Cors (NameError)の対処法 Rails7.1のAPIモードでuninitialized constant Rack::Cors (NameError)というエラーが出た時の解決方法を探していませんか?この記事ではエラーの原因と対処法をまとめています。エラーに苦しんでいる方はぜひご一読ください。

また、以下の記事ではワンランク上のRailsエンジニアになりたいと考えている方向けにおすすめの技術書を紹介しています。

こちらの記事もぜひ読んでみてください。

あわせて読みたい
【実務経験1年以上向け】Rubyで設計を学べる技術書3選 Rubyで設計を学べる技術書を知りたくないですか?この記事ではRubyエンジニア向けにサンプルコードがRubyで書かれていて設計を学べる技術書を3つ紹介しています。自分に必要なのはどの1冊なのか、ぜひ考えてみてください。
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

未経験でSESから従業員300名以上の自社開発企業に転職しました。業務や個人開発で直面した問題や、転職・学習の経験を発信していきます。

コメント

コメントする

目次