5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Dockerfileで先にGemfileとGemfile.lockだけをコピーするのって何がうれしいの?

Posted at

疑問

以下はRails7.2でRailsプロジェクトを作成した時のデフォルトのDockerfileの内容の一部です。

# 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 my_app .

この部分、何も考えず自分で作成するとしたら以下のように書きたくなります。

COPY my_app .
RUN bundle install && \
    rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \
    bundle exec bootsnap precompile --gemfile

なぜこのように段階を踏んで記述するのでしょうか?
今回はその理由調べてまとめました。

理由 1: キャッシュの活用によるビルドの高速化

Dockerではコマンド毎にCOPYやRUNコマンド毎にレイヤーとして情報をキャッシュする仕組みがあります。
キャッシュを利用するかどうかの判定はその時点で差分があるかどうかです。
もし私が書きたいように記述したとするとソースファイルの変更があるたびにキャッシュを利用せずに、bundle installをやり直すことになり、ビルドにかなりの時間を割くことになります。
しかし、GemfileとGemfile.lockのみをコピーすることでこれらのファイルに変更がない限りビルド時にbundle installを行うことになり効率よくビルドすることができるようになります。

理由 2: 依存関係とソースコードの分離

依存関係とソースコードを分離することでデバッグがやりやすくなります。
もし私が書きたいように記述するとソースファイルに問題がある場合のエラー時に原因をGemの依存関係に問題があるのか、それともソースコードに問題があるのかといった原因を切り分けることができます。
また、ソースコードに原因があった場合に、ソースコードを修正しただけでも再びbundle installを実行することになります。

今回のことで学んだこと

  • Dockerfileではコマンド毎にその時点でのレイヤーをキャッシュして差分がない場合はキャッシュしているレイヤーを利用してビルドを行う
  • Dockerfileで生成したイメージは全てのレイヤーの情報を保持しているためレイヤーが増えるとイメージが大きくなるのでコマンドはまとめる方がいい
5
1
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
5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?