docker-compose run web bundle installでGemをインストールした後に再度buildが必要な理由
前提
https://docs.docker.com/samples/rails/ を参考にDocker環境でRailsを起動
問題
fakerをGemfileに追記後、docker compose run web bundle install
, docker compose up
すると以下のエラーが出る。
docker-rails-sample-web-1 | /usr/local/lib/ruby/3.1.0/bundler/definition.rb:481:in `materialize': Could not find faker-2.19.0 in any of the sources (Bundler::GemNotFound)
https://docs.docker.com/samples/rails/#rebuild-the-application を読むとgemをGemfileに追記した後にdocker compose run web bundle install
,docker compose up --build
する必要がある。
なぜbuildする必要があるのか理解できなかったので整理する。
メモ
イメージとは -> コンテナの土台となる動作環境テンプレート
Dockerfileとは -> カスタムイメージを作るためのファイル
Buildとは -> Dockerファイルからイメージを作ること
docker compose run web bundle install
runコマンドについて
1 つのサービスに対して、1 コマンドだけ実行します。
run
によって指定したコマンドは、定義されたサービス設定に基づいて生成された新たなコンテナー内において実行されます。
https://matsuand.github.io/docs.docker.jp.onthefly/compose/reference/run/
ポイントは新たなコンテナー内において実行されるということ。
bundle installでgemが追加される環境はrunコマンドによって作成されたコンテナーに限定される。
docker compose up
コンテナの作成、起動を行う
docker compose build
DockerFileを元にサービスのビルドを実行する。
DockerホストのGemfile, Gemfile.lockを元にbundle installを実行する
# 一部抜粋 COPY Gemfile /myapp/Gemfile COPY Gemfile.lock /myapp/Gemfile.lock RUN bundle install
エラーが起きるまでの流れ
- Dockerホスト(Mac)のGemfileに追記すると、ボリューム先のGemfileも更新される
docker compose run web bundle install
を実行すると、コンテナが新たに作成され、そのコンテナでbundle install
が実行され、faker gemがインストールされる。 またコンテナー、Dockerホスト のGemfile.lockが更新されるdocker compose up
を実行すると、fakerをインストールしていないイメージを元にコンテナが作成されるが、Gemfile, Gemfile.lockにはfakerの記述あるので、エラーになる
結論
再度buildしイメージを更新しないとdocker compose up
で作成されるcontainerの環境にgemがインストールされない。
回避策としてgem用のvolumeを作って永続化すれば、再buildしなくて済みそうです。
https://qiita.com/neko-neko/items/abe912eba9c113fd527e
おまけ buildした時に必ずbundle installが走るわけではない
docker compose build
- 再度
docker compose build
するがgemのinstallのログは吐かれていない - コンテナのgemのフォルダに移動して作成日時を確認すると、1回目のbuildの時刻と一致する
キャッシュしていることが原因。docker compose build -no-cache
とすると上記手順の2でもgemがinstallされる。(インストールされるgemは変わらないので意味はないです。)