Dockerfileを書く過程で、共通して使う一部分を別ファイルに切り出す、という手法が有用だなと感じてきました。
問題となった状況
Dockerfileを書いているところで、「環境によって効率的なキャッシュのさせ方が違ってくるので、レイヤの順序を入れ替えたい」「複数のDockerfileに分割している1」などの事情があり、単純にレイヤを積み重ねるだけではなく、同じ動作をさせるレイヤを別々に書きたくなった、という状況が発生しました。
もちろん、そのまま複数箇所に書いても動作はするのですが、同じ設定を何度も行うというのは、あとあとの保守管理上を考えると好ましい選択肢ではありません。
ファイルに書き出したものを回収する
そこで、「必要な設定だけ別ファイルに書き出す」という手法が考えられます。書き出した設定を取り込む方法については、以下のような方法が考えられます。
- 実行するコマンドの行に
`cat path/to/file`
のように混ぜ込んで置き換えを行う(バージョン番号など値が1つの場合) -
xargs some_command < path/to/file
のようにxargs
を使ってファイルリストをコマンドリストに展開する(パッケージマネージャに与えるインストールするパッケージのリストなど) - シェルスクリプトを書いてそれを実行する
ファイルはどう導入する?
ファイルに書いたものの使い方はいいとして、そのファイルをどのようにDockerイメージ内から参照させればいいのでしょうか。
もちろん、COPY
で導入してもいいのですが、ファイルがレイヤとして残ることとなりますし、最終イメージにファイルが残るのを気にするなら改めて消す必要が出てきます。
ここで有用なのがRUN --mount=type=bind
です。このmount
を使ってRUN
に導入したファイルは、RUN
の作ったレイヤ内に残らないので、設定のみに使う一時ファイルを流すにはぴったりです。
RUN --mount=type=bind
の詳細について
- マウントできるものはフォルダに限られず、1ファイルだけマウントすることも可能です。
- 特に、この記事のように1ファイルを参照したい場合は、そのファイルだけマウントしたほうがいいです(余計なファイルまでマウントすると、そちらもキャッシュの有効判定に組み込まれて、キャッシュが無駄に無効化されることとなります)。
-
from
を明示すれば、ビルドコンテキストだけでなく、他のステージやイメージをマウントすることも可能です。 -
rw=true
として、マウント後に書き込みを許可することもできます。ただし、書き込んだ内容は次のステージに残らない、というのは同じです。
参照
- Dockerfile referenceのRUN --mount=type=bind節
- 2024年版のDockerfileの考え方&書き方
- RUN --mount=type=bind の動きを調べて COPY のオーバーヘッドを無くす
脚注
-
このような場合、少し前に正式リリースされた
docker bake
の利用についても考慮の余地はあります。 ↩