docker
Posted:
リファレンス
Dockerfile の見直す時に参考にする場所
Dockerfile のベストプラクティス その 1 ) 下記以外にもあるが私が忘れやすいポイントだけ
- .dockerignore ファイルを使う
- レイヤの数を最小に
- 複数行の引数 <= 引数はアルファベット順に
- 構築キャッシュ <= docker build で –no-cache=true とすると既存キャッシュを使わない
- CMD <= 常に CMD [“executable”, “param1”, “param2”…] のような形式で使うべきです。
- WORKDIR <= 明確さと信頼性のため、常に WORKDIR からの絶対パスを使うべきです。
- Distroless が使えないか検討する
- LABEL <= ロジェクト内でのイメージ管理をしやすくしたり、ライセンス情報の記録や自動化の助けとするなど、さまざまな目的があります。
レイヤー削減の考え方
Dockerfile の layer を減らす時は、単純に RUN や COPY を結合すればよい、という話ではない。
layer 数を減らすと見た目はきれいになるが、巨大な layer にまとまると push/pull 時の差分再利用や、docker history での原因調査が悪くなることがある。
特に日常利用の CLI image のように、apt package、language runtime、npm global tool、クラウド CLI などを大量に含む image では、layer 数と image size は別の問題として扱う。
忘れやすい実務上のポイント:
COPY --chmod=0755 file /path/fileで済む場合は、COPY後のRUN chmodlayer を作らない。- 一時ファイルや cache は、生成した同じ
RUNの末尾で消す。後続のRUN rm -rf ...では過去 layer の bytes は消えない。 WORKDIR /tmp/foo、RUN ...、WORKDIR /、RUN rm -rf /tmp/fooのような空に近い cleanup layer は作らず、mktemp -dとtrapで同じRUNに閉じ込める。- multi-stage build では、builder stage から runtime に必要な成果物だけを
/outなどへ集めて final stage にコピーする。toolchain や package manager の cache を final に持ち込まない。 - 複数の builder stage から成果物を final stage へ個別に
COPYしている場合は、FROM scratch AS artifactsのような集約 stage に一度まとめ、final stage ではCOPY --from=artifacts / /の 1 layer にする選択肢がある。 - 同じ CLI を apt、aqua、手動 download など複数経路で入れない。PATH 上で shadow される実体は、容量と layer の両方で無駄になりやすい。
FROM scratchに rootfs を丸ごとCOPYする squash 風の構成は layer 数を大きく減らせるが、差分配布と調査性が悪くなるので最後の手段と考える。
実例: cli-tool-docker のイメージサイズ調査
参考
マルチステージビルドの利用
現実に効果的な Dockerfile を書くためには、
いつもながらトリッキーなシェルのテクニックや、
レイヤーができる限り小さくなるようなロジックを考えたりすることが必要でした。
つまり各レイヤーは、それ以前のレイヤーから受け継ぐべき生成物のみを持ち、
他のものは一切持たないようにすることが必要であったわけです。
本来 2 つあるRUNコマンドを Bash の&&オペレーターによって連結しています。
これを行うことで、イメージ内に不要なレイヤーが生成されることを防いでいます。
ただこれでは間違いを起こしやすく、保守もやりづらくなります。
保守がやりづらくなる、という認識は docker にもあるようだ。