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

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

https://kazuya-engineer.com/2024/01/07/rails-7-1-api-fix-uninitialized-constant-rack-cors/

Railsエンジニアにおすすめの記事

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

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

コメント

コメントする

目次