3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Ruby on Rails 7.1 で自動生成された Dockerfile を確認してみよう!

Last updated at Posted at 2023-10-31

はじめに

前回は、Dockerfile の自動生成そのものについて、rails new を実行する際のオプションや実行環境による違いを確認してみましたが、

今回は、実際に生成されたファイルの中身を見ていきたいと思います。

というか、前回の記事は、もともと書くつもりのなかった( 単一の記事にする予定ではなかった )ものなので、実は、ここからが本番です。

Dockerfile の生成方法について

詳しくは、上の記事を見てみて欲しいのですが、今回は、次のようなコマンドで生成された Dockerfile を確認していきます。

rails new . --database=postgresql --css=bootstrap

つまり、データベースに PostgreSQL を、CSS フレームワークとして Bootstrap を、それぞれオプションで指定した場合に生成される Dockerfile が対象となります。1

ちなみに、前回の記事で説明した通り、Node と Yarn のバージョンについては、実行環境に依存するようですが、Dockerfile としては、単に環境変数の値が変わるだけですね。

syntax の確認

さて、まずは、1行目から見ていきましょう。

と言っても、もちろん、丁寧に説明しすぎてもアレなので、ものによっては、簡単に触れるだけに留めておきます。

# syntax = docker/dockerfile:1

これは、Dockerfile の構文の「 バージョン1 」の、最新の安定リリースを、常に指すようになっているそうです。2

もし「 バージョン2 」がリリースされたりしたら、この辺の事情も変わってくるかもしれませんが、とりあえずは、そっとしておけばいいでしょう。

ベース環境の確認

次に、後で説明するビルド用の環境と、最終的に利用することとなるイメージを作成するためのファイナルステージ環境の、両方で base となる環境を構築しているのが、3~14行目になります。

まぁ、そんなに大袈裟なものでもなくて、親イメージ( すなわち Ruby 3 のバージョン )や、その他、共通する設定などを指定しているだけですね。

# 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"

ただ、ここで、作業ディレクトリ( WORKDIR )が /rails に設定されているのは、最低限、覚えておいた方がいいでしょう。

また、本番環境用に、いくつか Bundler 関連の環境変数も指定されています。4

  • BUNDLE_DEPLOYMENTGemfile の変更を禁止に
  • BUNDLE_PATH:gem が配置される場所
  • BUNDLE_WITHOUT:インストールしない gem( グループで指定 )

そのため、この Dockerfile を参考にして、開発環境も作ろうと思っている場合などには、ご注意ください。

ビルド環境の確認

ここからは、最終的に生成される Docker イメージのサイズを小さくするために切り離されている、build 環境を見ていきましょう。5

まずは、17~22行目ですが、base 環境を元に、後でビルドに必要となるパッケージを、色々とインストールしていますね。

# Throw-away build stage to reduce size of final image
FROM base as build

# 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

というか、主に gem と Node のインストールに必要な環境を整えてくれていて、以降、24~41行目で、実際にそれらのインストールが行われることとなります。

# Install JavaScript dependencies
ARG NODE_VERSION=18.15.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 && \
    rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \
    bundle exec bootsnap precompile --gemfile

# Install node modules
COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile

ちなみに、Node モジュールのインストール手順が含まれているのは、rails new する際に css オプションを加えたからです。6

一応、本番環境らしいものとしては、yarn install 時に --frozen-lockfile オプションが指定されていることが挙げられますかね。7

ともかく、これで、ビルドの実行環境は整ったので、43~50行目では、ローカルのファイルをコピーしてきて、Bootsnap 8 とアセットのプリコンパイルを実行しています。

# 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

特に、本番環境のためのアセットのプリコンパイルについては、重要ですね。

詳細は、ぜひ Rails ガイドなどを参照してください。

ファイナルステージ環境の確認

それでは、いよいよファイナルステージに突入です。

まず、53~59行目ですが、ビルド環境の時と同じ流れで、base 環境を元に、必要なパッケージをインストールしています。

# 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

ここで、postgresql-client パッケージがインストールされているのは、rails new を実行する際に、database オプションで postgresql を選択したからですね。

そして、61行目から最終行までで、上で構築した build 環境の中から、必要なファイルをコピーしてきて、non-root ユーザーを作成するなど、起動のための準備を行います。

# 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 の中身でした。

ちなみに、データベースの準備をしてくれるという /rails/bin/docker-entrypoint ファイルの中身は、こんな感じです。

/rails/bin/docker-entrypoint
#!/bin/bash -e

# If running the rails server then create or migrate existing database
if [ "${1}" == "./bin/rails" ] && [ "${2}" == "server" ]; then
  ./bin/rails db:prepare
fi

exec "${@}"

おわりに

果たして、何かしら参考になりましたでしょうか?

正直な感想を言えば「 思ったより普通だったな 」という感じかもしれませんが、

まぁ、デフォルトとして自動生成してくれるだけで、なんとなく安心感があるというか、

少なくとも、どこからコピペしてきたのか分からないようなものと比べれば、断然マシですし、これだけ簡潔な内容だというのは、むしろ、評価すべきところかもしれません。

また、具体例をもとに、Dockerfile のベストプラクティスについて学ぶのにも、ちょうど良い機会となるのではないでしょうか?

とは言え、今回は Dockerfile の内容を確認してみただけなので、これで、実際にコンテナが起動できるかどうかについては、実は、未知数です。

そして、とりあえず、次は、開発環境についても、Docker Compose の利用も含めて、考えてみたいところですね。9

  1. 要するに、前回の記事 で作成した Dockerfile を、そのまま利用するということです。

  2. https://docs.docker.com/build/dockerfile/frontend/

  3. https://hub.docker.com/_/ruby

  4. https://bundler.io/v2.5/man/bundle-config.1.html

  5. https://docs.docker.com/build/building/multi-stage/

  6. 他にも、Node 環境が必要となることが明らかなオプションを指定すると、同じような Dockerfile が生成されると考えられます。オプションを指定しなかった場合との差分については、前回の記事 もご参照ください。

  7. https://classic.yarnpkg.com/lang/en/docs/cli/install/

  8. https://github.com/Shopify/bootsnap

  9. 次回の記事 で、方法を紹介しています。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?