彼らは例を挙げれば私にとって最も理にかなっています...
docker diffを使用して独自のビルドのレイヤーを調べる
不自然な例のDockerfileを見てみましょう:
FROM busybox
RUN mkdir /data
# imagine this is downloading source code
RUN dd if=/dev/zero bs=1024 count=1024 of=/data/one
RUN chmod -R 0777 /data
# imagine this is compiling the app
RUN dd if=/dev/zero bs=1024 count=1024 of=/data/two
RUN chmod -R 0777 /data
# and now this cleans up that downloaded source code
RUN rm /data/one
CMD ls -alh /data
これらの各dd
コマンドは、1Mファイルをディスクに出力します。一時的なコンテナを保存するために追加のフラグを使用してイメージを構築してみましょう:
docker image build --rm=false .
出力では、実行中の各コマンドが、自動的に削除するのではなく、現在保持している一時コンテナーで発生することがわかります。
...
Step 2/7 : RUN mkdir /data
---> Running in 04c5fa1360b0
---> 9b4368667b8c
Step 3/7 : RUN dd if=/dev/zero bs=1024 count=1024 of=/data/one
---> Running in f1b72db3bfaa
1024+0 records in
1024+0 records out
1048576 bytes (1.0MB) copied, 0.006002 seconds, 166.6MB/s
---> ea2506fc6e11
docker diff
これらのコンテナーIDのそれぞれでを実行すると、それらのコンテナーで作成されたファイルが表示されます。
$ docker diff 04c5fa1360b0 # mkdir /data
A /data
$ docker diff f1b72db3bfaa # dd if=/dev/zero bs=1024 count=1024 of=/data/one
C /data
A /data/one
$ docker diff 81c607555a7d # chmod -R 0777 /data
C /data
C /data/one
$ docker diff 1bd249e1a47b # dd if=/dev/zero bs=1024 count=1024 of=/data/two
C /data
A /data/two
$ docker diff 038bd2bc5aea # chmod -R 0777 /data
C /data/one
C /data/two
$ docker diff 504c6e9b6637 # rm /data/one
C /data
D /data/one
接頭辞が付いた各行A
はファイルを追加し、はC
既存のファイルへの変更をD
示し、は削除を示します。
これがTL; DRの部分です
上記のこれらのコンテナファイルシステムの差分はそれぞれ、イメージをコンテナとして実行するときに組み立てられる1つの「レイヤー」に入ります。追加または変更がある場合、ファイル全体が各レイヤーにあるため、これらの各chmod
コマンドは、許可ビットを変更するだけで、ファイル全体が次のレイヤーにコピーされます。削除された/ data / oneファイルは、実際には前のレイヤーに3回あります。イメージをプルすると、ネットワーク経由でコピーされ、ディスクに保存されます。
既存の画像を調べる
コマンドを使用して、既存の画像のレイヤーを作成するためのコマンドを確認できますdocker history
。docker image inspect
イメージでを実行して、RootFSセクションの下にあるレイヤーのリストを表示することもできます。
上記の画像の履歴は次のとおりです。
IMAGE CREATED CREATED BY SIZE COMMENT
a81cfb93008c 4 seconds ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "ls -… 0B
f36265598aef 5 seconds ago /bin/sh -c rm /data/one 0B
c79aff033b1c 7 seconds ago /bin/sh -c chmod -R 0777 /data 2.1MB
b821dfe9ea38 10 seconds ago /bin/sh -c dd if=/dev/zero bs=1024 count=102… 1.05MB
a5602b8e8c69 13 seconds ago /bin/sh -c chmod -R 0777 /data 1.05MB
08ec3c707b11 15 seconds ago /bin/sh -c dd if=/dev/zero bs=1024 count=102… 1.05MB
ed27832cb6c7 18 seconds ago /bin/sh -c mkdir /data 0B
22c2dd5ee85d 2 weeks ago /bin/sh -c #(nop) CMD ["sh"] 0B
<missing> 2 weeks ago /bin/sh -c #(nop) ADD file:2a4c44bdcb743a52f… 1.16MB
最新のレイヤーが上に表示されます。注目すべきは、かなり古い2つの層が下部にあることです。これらは、busyboxイメージ自体から取得されます。1つのイメージを作成するとき、FROM
ラインで指定するイメージのすべてのレイヤーを継承します。CMD
ラインのように、画像メタデータの変更のために追加されるレイヤーもあります。それらはほとんどスペースをとらず、実行しているイメージに適用される設定を記録しておくためのものです。
なぜレイヤーなのか?
層にはいくつかの利点があります。まず、それらは不変です。作成されると、sha256ハッシュによって識別されるそのレイヤーは決して変更されません。その不変性により、イメージを安全に構築し、互いから分岐させることができます。2つのdockerfileが同じ最初の行のセットを持ち、同じサーバー上に構築されている場合、それらは同じ最初のレイヤーのセットを共有し、ディスク領域を節約します。つまり、Dockerfileの最後の数行だけが変更された状態でイメージを再構築した場合、それらのレイヤーのみを再構築する必要があり、残りはレイヤーキャッシュから再利用できます。これにより、Dockerイメージの再構築が非常に高速になります。
コンテナー内には、イメージファイルシステムが表示されますが、そのファイルシステムはコピーされません。これらのイメージレイヤーの上に、コンテナーは独自の読み取り/書き込みファイルシステムレイヤーをマウントします。ファイルのすべての読み取りは、ファイルに削除のマークが付けられたレイヤーに到達するか、そのレイヤーにファイルのコピーがあるか、または読み取りのためにレイヤーが不足して検索するまで、レイヤーを通過します。すべての書き込みは、コンテナ固有の読み書きレイヤーで変更を行います。
層膨張を減らす
レイヤーの1つの欠点は、後のレイヤーで削除されたファイルを複製したりファイルを出荷したりする画像を作成することです。多くの場合、解決策は、複数のコマンドを1つのRUN
コマンドにマージすることです。特に、既存のファイルを変更したりファイルを削除したりする場合は、それらのステップを最初に作成したときと同じコマンドで実行する必要があります。上記のDockerfileを書き換えると、次のようになります。
FROM busybox
RUN mkdir /data \
&& dd if=/dev/zero bs=1024 count=1024 of=/data/one \
&& chmod -R 0777 /data \
&& dd if=/dev/zero bs=1024 count=1024 of=/data/two \
&& chmod -R 0777 /data \
&& rm /data/one
CMD ls -alh /data
そして、結果の画像を比較すると:
- busybox:〜1MB
- 最初の画像:〜6MB
- 2番目の画像:〜2MB
考案された例のいくつかの行をマージするだけで、同じ結果のコンテンツが画像に含まれ、画像が5MBから最終的な画像に表示される1MBのファイルに縮小されました。