bunty's blog

ググったこととか勉強したことのメモ

Dockerfile のベストプラクティスを読んだまとめ

有給消化でまとまった時間ができたので、雰囲気でやってた Docker 周りを復習。 ベストプラクティスに書いてある内容をまとめているだけなので、正しい情報はベストプラクティスを読むことをお勧めします。

docs.docker.jp

ここら辺は理解しているつもりだけど、ちょいちょいあやしい。

  • Docker イメージは各コマンドごとにレイヤーになっている
  • コンテナを生成すると、その上に書き込み可能なレイヤーが追加される
  • レイヤーごとにキャッシュが使用されるか判断される

ビルド・キャッシュの活用

そもそも処理内容によって、キャッシュを使用されるかどうかの判定方法が変わってくる。

ADD 命令や COPY 命令では、イメージに含まれるファイルの内容が検査され、個々のファイルについてチェックサムが計算されます

ADD と COPY 以外のコマンドの場合、キャッシュのチェックは、コンテナ内のファイル内容を見ることはなく、それによってキャッシュと一致しているかどうかが決定されるわけでありません。 コマンド文字列そのものが、キャッシュの一致判断に用いられます。

キャッシュが無効になった場合

キャッシュが無効になると、次に続く Dockerfile コマンドは新たなイメージを生成し、以降ではキャッシュを使いません。

たとえば、複数のレイヤが入った構築をする時には、(ビルド・キャッシュを再利用可能にしている場合)頻繁に変更しないものから順番に、より頻繁に変更するものへと並べます。

レイヤーごとに判定は行うものの、その手前で無効になった場合はその後はキャッシュは使用されない。
そのためなるべく変更の少ないものから順番に記載して行って、頻繁に変更するものは最後の方に記載をした方がキャッシュをうまく使うことができる。
すでにある Docker file をベースにどうするかを考えることが多くて、言われてみればそうだけど、全然意識してなかった。

RUN コマンドのキャッシュ・バスティング

上の書き方は非推奨で、同一の RUN コマンドで同時実行させる方が良い。
確かに書く時には下の書き方をするけど、ちゃんと説明ができないなと思ったのでメモ。

# 非推奨
FROM ubuntu:20.04
RUN apt-get update
RUN apt-get install -y curl nginx

# 推奨
RUN apt-get update && apt-get install -y

RUN コマンドを分けると update と install が別のレイヤーになる。
RUN コマンドはコマンド文字列そのものが、キャッシュの一致判断に用いられるため、apt-get update は実行されなくなる。
そのため、curl や nginx はずっと古いものを使い続ける可能性が出てきてしまうので、同じ RUN コマンドで実行させることによって install する際に update も毎回実行させることができる。
そうすると、勝手に新しいバージョンになってしまい問題が発生することもある。その場合には、キャッシュにどんなイメージがあっても指定したバージョンを使用させる方法があり、これをバージョン・ピニングと呼ぶ。

RUN apt-get update && apt-get install -y \
    package-bar \
    package-baz \
    package-foo=1.3.*

ADD と COPY の違い

一方 ADD には特定の機能(ローカルでの tar 展開やリモート URL サポート)があり、これはすぐにわかるものではありません。結局 ADD の最も適切な利用場面は、ローカルの tar ファイルを自動的に展開してイメージに書き込むときです。

COPY は基本的なコピーをする処理だとして、ADD の使い所は記載されていた。

異なるファイルをコピーするときには、一度にすべてをコピーするのではなく、 COPY を使って個別にコピーしてください。

これもキャッシュに関わることで、全部まとめて COPY をする場合、1つでも変更がある場合には全てキャッシュが無効化されるが、個別にコピーしていれば無効化されるのは最低限になると。