📅 ⏰ 9 分で読めます
Rails7.1で自動生成されるDockerfileを開発環境でも使えるようにする

Rails7.1からDockerfileも生成される
Rails7.1からRails new
した際にDockerfileも自動生成されるようになりました。 しかし自動生成されるDockerfileは本番環境用で、そのままでは開発環境で使用することはできません。
今回は本番用のDockerfileから開発環境に必要な部分だけ抜き出して、Dockerfile.development
として開発環境用のDockerfileを作成したいと思います。
なお、Rails7.1の開発環境の構築はホストのRubyを使ってrails new
する記事も見かけますが、本記事で紹介する方法はdockerとdocker composeがあれば可能です。 つまりホストにRubyをインストールする必要がありません。 また今回はdatabaseにpostgresqlを使用します。 (mysqlを使う場合でも大きくやり方は変わらないと思います)
プロジェクトディレクトリの作成
適当にプロジェクトのディレクトリを作成しましょう。 今回はrails_sample
とします。
mkdir rails_sample
作成したディレクトリに移動します。
cd rails_sample
Gemfile
Gemfileを作成します。 このファイルをもとにRailsをinstallします。
$ touch Gemfile
Gemfile
が生成されたので以下を記述します。
source 'https://rubygems.org'
gem 'rails', '~>7'
次に空のGemfile.lock
を作成します
$ touch Gemfile.lock
docker
Dockerfileを作ります。
FROM ruby:3.3.1
RUN apt-get update -qq && apt-get install -y nodejs npm postgresql-client
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
色々と記述が足りないのでは?と思った方もいらっしゃると思いますが、rails new
すると上書きされてしまうので、rails new
ができる最低限の記述にとどめます。 ポイントはnpm
をinstallすることです。 npm
をインストールしておけば、後でrails new
するときにjavascriptが必要なオプションを渡した場合でもエラーを発生させることなく実行することができます。
次にcompose.yml
を作成します。この名前で作成するとdocker composeコマンド時にオプション無しで自動で読み込まれます。 以前はdocker-compose.yml
という名称でしたが現在はcompose.yml
が推奨されているようです。(docker-compose.ymlでもまだ動きます)
services:
db:
image: postgres:14-alpine
volumes:
- db:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: password
web:
build: .
command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
volumes:
- .:/myapp
ports:
- "3000:3000"
depends_on:
- db
volumes:
db:
コミットする
rails newの差分を確認するためにこのあたりでgit commitしておくとよいでしょう。
git add .
git commit -m "setup"
プロジェクトのビルド
セットアップが完了したのでプロジェクトをビルドします。
docker-compose run --no-deps web rails new . --force --database=postgresql
完了するとproduction用のDockerfileが生成されます。
# syntax = docker/dockerfile:1
# Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile
ARG RUBY_VERSION=3.3.1
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 git libpq-dev 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/
# Precompiling assets for production without requiring secret RAILS_MASTER_KEY
RUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile
# 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 libvips postgresql-client && \
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"]
db接続情報をdocker用に修正
compose.ymlで定義したdbサービスにrailsが接続できるように修正します。 ポイントはhostにcompose.ymlで定義したservice名を指定することです。 service名だけでdockerが名前解決してくれます。
default: &default
adapter: postgresql
encoding: unicode
+ host: db
+ username: postgres
+ password: password
# For details on connection pooling, see Rails configuration guide
# https://guides.rubyonrails.org/configuring.html#database-pooling
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
開発環境用のDockerfile作成
本番環境用のDockerfileから開発環境に必要な部分だけ抜き出し、Dockerfile.developmentを作成します。
# syntax = docker/dockerfile:1
# Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile
ARG RUBY_VERSION=3.3.1
FROM registry.docker.com/library/ruby:$RUBY_VERSION-slim as base
WORKDIR /myapp
# Install packages needed to build gems and node modules
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y build-essential curl git libpq-dev libvips node-gyp pkg-config python-is-python3 && \
rm -rf /var/lib/apt/lists /var/cache/apt/archives
# Install JavaScript dependencies
ARG NODE_VERSION=18.19.0
ARG YARN_VERSION=latest
ENV PATH=/usr/local/node/bin:$PATH
RUN curl -sL https://github.com/nodenv/node-build/archive/master.tar.gz | tar xz -C /tmp/ && \
/tmp/node-build-master/bin/node-build "${NODE_VERSION}" /usr/local/node && \
npm install -g yarn@$YARN_VERSION && \
rm -rf /tmp/node-build-master
# Install application gems
COPY Gemfile Gemfile.lock ./
RUN bundle install
# Install node modules
COPY package.json yarn.lock ./
RUN yarn install
# Copy application code
COPY . .
yarn.lockがコピーされていない状態なので、作成しておきます。
touch yarn.lock
docker composeでDockerfile.developmentを使用するように修正します。 またgemのキャッシュを利用できるようにvolumeを指定します。
environment:
POSTGRES_PASSWORD: password
web:
- build: .
+ build:
+ context: .
+ dockerfile: Dockerfile.development
command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
volumes:
- .:/myapp
+ - bundle:/usr/local/bundle
ports:
- "3000:3000"
depends_on:
- db
volumes:
db:
+ bundle:
css,jsをbuildするプロセスも起動する
開発環境でesbuildを使う場合、railsのサーバーのほかにcssとjsをbuildするプロセスも起動するため、compose.yml
で起動コマンドを修正します。 bin/dev
で起動するように修正します。 またttyを指定してプロセスが落ちないように修正します。
build:
context: .
dockerfile: Dockerfile.development
- command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
+ command: bash -c "rm -f tmp/pids/server.pid && bin/dev"
+ tty: true
bin/dev
を見てみましょう。 foremanというプロセス管理のgemを使って、Procfile.devを使って起動しています。 Procfile.devを見てみましょう。 js,cssをyarnを使ってbuildしています。 このbuildコマンドはpackage.jsonのscriptsで定義されています。 jsはesbuild,cssはtailwindcssを使っています。
"scripts": {
"build": "esbuild app/javascript/*.* --bundle --sourcemap --format=esm --outdir=app/assets/builds --public-path=/assets",
"build:css": "tailwindcss -i ./app/assets/stylesheets/application.tailwind.css -o ./app/assets/builds/application.css --minify"
}
bindingを指定する
Dockerを使っている場合、bindingを0.0.0.0に指定する必要があるので環境変数を指定します。
command: bash -c "rm -f tmp/pids/server.pid && bin/dev"
+ environment:
+ - BINDING=0.0.0.0
起動する
これで準備がすべて整いました。 ではrailsを起動してみましょう。
docker compose up
データベースを作成してくださいとエラーが発生しますが、create database
ボタンを押してください。
railsのwelcomeページが表示されれば成功です。