👻

rails7.1で生成されるDockerfileを覗いてみる

2023/10/11に公開

はじめに

https://www.publickey1.jp/blog/23/rails_71dockerfile.html
この記事を見て、「Dockerfile自動生成」で作られるDockerfileにとても興味がわいたので、備忘録としてのメモです

ディレクトリ構成

compose.yml
api(ディレクトリ)
 ├ Dockerfile
 ├ Gemfile
 └ Gemfile.lock

準備

ファイル生成
touch compose.yml
mkdir api/
touch api/Dockerfile
touch api/Gemfile
touch api/Gemfile.lock
compose.yml
services:
  api:
    build:
      context: ./api
    container_name: api
    ports:
      - 3000:3000
    environment:
      RAILS_ENV: development
      DB_HOST: mysql
      DB_NAME: root
      DB_PASSWORD: password
    depends_on:
      - mysql
    volumes:
      - ./api:/api

  mysql:
    image: public.ecr.aws/docker/library/mysql:8.1
    container_name: mysql
    volumes:
      - mysql_data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: password
      TZ: "Asia/Tokyo"

volumes:
  mysql_data:
Dockerfile
FROM public.ecr.aws/docker/library/ruby:3.2.2
RUN apt-get update -qq
RUN apt-get install -y build-essential nodejs

WORKDIR /api
COPY Gemfile Gemfile.lock /api/
RUN bundle install
Gemfile
source 'https://rubygems.org'
gem 'rails'
コマンド
docker compose build

rails new のオプションを確認

docker compose run --rm api rails new -h

dockerfile用のオプションが追加されてるのが分かります

表示内容
Usage:
  rails new APP_PATH [options]

Options:
                 [--skip-namespace], [--no-skip-namespace]              # Skip namespace (affects only isolated engines)
                 [--skip-collision-check], [--no-skip-collision-check]  # Skip collision check
  -r,            [--ruby=PATH]                                          # Path to the Ruby binary of your choice
                                                                        # Default: /usr/local/bin/ruby
  -n,            [--name=NAME]                                          # Name of the app
  -m,            [--template=TEMPLATE]                                  # Path to some application template (can be a filesystem path or URL)
  -d,            [--database=DATABASE]                                  # Preconfigure for selected database (options: mysql/trilogy/postgresql/sqlite3/oracle/sqlserver/jdbcmysql/jdbcsqlite3/jdbcpostgresql/jdbc)
                                                                        # Default: sqlite3
  -G,            [--skip-git], [--no-skip-git]                          # Skip git init, .gitignore and .gitattributes
+                [--skip-docker], [--no-skip-docker]                    # Skip Dockerfile, .dockerignore and bin/docker-entrypoint
                 [--skip-keeps], [--no-skip-keeps]                      # Skip source control .keep files
  -M,            [--skip-action-mailer], [--no-skip-action-mailer]      # Skip Action Mailer files
                 [--skip-action-mailbox], [--no-skip-action-mailbox]    # Skip Action Mailbox gem
                 [--skip-action-text], [--no-skip-action-text]          # Skip Action Text gem
  -O,            [--skip-active-record], [--no-skip-active-record]      # Skip Active Record files
                 [--skip-active-job], [--no-skip-active-job]            # Skip Active Job
                 [--skip-active-storage], [--no-skip-active-storage]    # Skip Active Storage files
  -C,            [--skip-action-cable], [--no-skip-action-cable]        # Skip Action Cable files
  -A,            [--skip-asset-pipeline], [--no-skip-asset-pipeline]    # Indicates when to generate skip asset pipeline
  -a,            [--asset-pipeline=ASSET_PIPELINE]                      # Choose your asset pipeline [options: sprockets (default), propshaft]
                                                                        # Default: sprockets
  -J, --skip-js, [--skip-javascript], [--no-skip-javascript]            # Skip JavaScript files
                 [--skip-hotwire], [--no-skip-hotwire]                  # Skip Hotwire integration
                 [--skip-jbuilder], [--no-skip-jbuilder]                # Skip jbuilder gem
  -T,            [--skip-test], [--no-skip-test]                        # Skip test files
                 [--skip-system-test], [--no-skip-system-test]          # Skip system test files
                 [--skip-bootsnap], [--no-skip-bootsnap]                # Skip bootsnap gem
                 [--skip-dev-gems], [--no-skip-dev-gems]                # Skip development gems (e.g., web-console)
                 [--dev], [--no-dev]                                    # Set up the application with Gemfile pointing to your Rails checkout
                 [--edge], [--no-edge]                                  # Set up the application with a Gemfile pointing to the 7-1-stable branch on the Rails repository
  --master,      [--main], [--no-main]                                  # Set up the application with Gemfile pointing to Rails repository main branch
                 [--rc=RC]                                              # Path to file containing extra configuration options for rails command
                 [--no-rc], [--no-no-rc]                                # Skip loading of extra configuration options from .railsrc file
                 [--api], [--no-api]                                    # Preconfigure smaller stack for API only apps
                 [--minimal], [--no-minimal]                            # Preconfigure a minimal rails app
  -j, --js,      [--javascript=JAVASCRIPT]                              # Choose JavaScript approach [options: importmap (default), bun, webpack, esbuild, rollup]
                                                                        # Default: importmap
  -c,            [--css=CSS]                                            # Choose CSS processor [options: tailwind, bootstrap, bulma, postcss, sass] check https://github.com/rails/cssbundling-rails for more options
  -B,            [--skip-bundle], [--no-skip-bundle]                    # Don't run bundle install
                 [--skip-decrypted-diffs], [--no-skip-decrypted-diffs]  # Don't configure git to show decrypted diffs of encrypted credentials

Runtime options:
  -f, [--force]                    # Overwrite files that already exist
  -p, [--pretend], [--no-pretend]  # Run but do not make any changes
  -q, [--quiet], [--no-quiet]      # Suppress status output
  -s, [--skip], [--no-skip]        # Skip files that already exist

Rails options:
  -h, [--help], [--no-help]        # Show this help message and quit
  -v, [--version], [--no-version]  # Show Rails version number and quit

Description:
    The `rails new` command creates a new Rails application with a default
    directory structure and configuration at the path you specify.

    You can specify extra command-line arguments to be used every time
    `rails new` runs in the .railsrc configuration file in your home directory,
    or in $XDG_CONFIG_HOME/rails/railsrc if XDG_CONFIG_HOME is set.

    Note that the arguments specified in the .railsrc file don't affect the
    default values shown above in this help message.

    You can specify which version to use when creating a new rails application
    using `rails _<version>_ new`.

Examples:
    `rails new ~/Code/Ruby/weblog`

    This generates a new Rails app in ~/Code/Ruby/weblog.

    `rails _<version>_ new weblog`

    This generates a new Rails app with the provided version in ./weblog.

    `rails new weblog --api`

    This generates a new Rails app in API mode in ./weblog.

    `rails new weblog --skip-action-mailer`

    This generates a new Rails app without Action Mailer in ./weblog.
    Any part of Rails can be skipped during app generation.

プロジェクト構築

rails newのコマンド
docker compose run --rm api rails new . --force --database=mysql --api --minimal --skip-git

生成されたDockerfileを確認

api/Dockerfile
# 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 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

# Copy application code
COPY . .


# 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 && \
    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 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"]

とりあえず、そのまま利用してみる

api/config/database.yml
  ・・・省略・・・
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: <%= ENV.fetch("DB_NAME") { 'root' } %>
  password: <%= ENV.fetch("DB_PASSWORD") { 'password' } %>
  host: <%= ENV.fetch("DB_HOST") { 'localhost' } %>
  ・・・省略・・・
コマンド
docker compose build
docker compose run --rm api rake db:drop db:create db:migrate db:seed
docker compose up

問題なく稼働できました!
Alt text

さいごに

まさかrails newでDockerfileまで作ってくれるとは思っていませんでした。
今回、Dockerfileの自動生成に期待して、Dockerfileを質素な作りで実施しましたが、予想以上にしっかりしたものが作られたので感激です。
オワコンとも言われてますが、常に進化し続けるのもrailsの強みでもあると思っています。
今後にも期待です。

Discussion