Dockerイメージの「レイヤー」とは何ですか?


165

私はDockerを初めて使用し、Docker イメージとは何かを正確に理解しようとしています。Dockerイメージのすべての定義では「レイヤー」という用語を使用していますが、レイヤーの意味を定義しているようには見えません。

公式のDockerドキュメントから

Dockerイメージは、Dockerコンテナーが起動される読み取り専用テンプレートであることは既に確認しました。各画像は一連のレイヤーで構成されています。Dockerは、ユニオンファイルシステムを使用して、これらのレイヤーを1つのイメージに結合します。ユニオンファイルシステムでは、ブランチと呼ばれる個別のファイルシステムのファイルとディレクトリを透過的にオーバーレイして、単一の一貫したファイルシステムを形成できます。

だから私は、レイヤーとは(正確に)何ですか?誰かがそれらのいくつかの具体的な例を示すことができますか?そして、これらのレイヤーはどのように「スナップ」して画像を形成しますか?

回答:


132

私は遅れているかもしれませんが、これが私の10セントです(アシシュジャインの答えを補完するもの):

基本的に、レイヤーまたは画像レイヤーは、画像または中間画像の変更です。指定したすべてのコマンド(FROMRUNCOPYあなたのDockerfile中など)はこのように新しいレイヤーを作成し、変更する前の画像が発生します。gitを使用している場合は、ステージングの変更と考えることができます。ファイルの変更を追加し、次に別の変更を追加します。

次のDockerfileを検討してください。

FROM rails:onbuild
ENV RAILS_ENV production
ENTRYPOINT ["bundle", "exec", "puma"]

まず、開始画像を選択します。rails:onbuildこれには、多くのレイヤーがあります。開始画像の上に別のレイヤーを追加RAILS_ENVし、ENVコマンドで環境変数を設定します。次に、Dockerに実行を指示しますbundle exec puma(これによりRailsサーバーが起動します)。それは別のレイヤーです。

レイヤーの概念は、イメージを構築するときに役立ちます。レイヤーは中間イメージであるため、Dockerfileに変更を加えると、Docker は変更されたレイヤーとその後のレイヤーのみをビルドします。これはレイヤーキャッシングと呼ばれます。

詳細については、こちらをご覧ください


13
レイヤーを変更または追加すると、変更の影響を受ける可能性があるため、Dockerはその後に続くレイヤーも構築します。
アダム

レイヤーの概念の背後にある、他の回答にはない理由を説明していただきありがとうございます。
Seeta Somagani 2017年

@David、上記の例では、いくつのレイヤーが追加されますか?2?または1?
Gourav Singla

1
@GouravSingla 2である必要があります。変更ENVも変更です。レイヤーはgitのコミットのようです。
PokerFace 2017年

最後のウェブリンク(https://labs.ctl.io/caching-docker-images/)は壊れています。誰かが交換の提案をしましたか?
ジョニーUtahh

72

dockerコンテナイメージはdockerfileを使用して作成されます。dockerfileのすべての行でレイヤーが作成されます。次のダミーの例を考えてみます。

FROM ubuntu             #This has its own number of layers say "X"
MAINTAINER FOO          #This is one layer 
RUN mkdir /tmp/foo      #This is one layer 
RUN apt-get install vim #This is one layer 

これにより、レイヤーの総数がX + 3になる最終的な画像が作成されます


32
私は反対票を投じませんでしたが、これはレイヤーの作成方法を説明していると思いますが、レイヤーとは何かについての質問には決して答えません。
Lasse V. Karlsen、2015

2
私は@ LasseV.Karlsen、ashishjainに同意します。私はあなたに反対票を投じなかったし、実際に私を助けようとした(つまり+1)ことに賛成票を投じている-しかし、私がグリーンチェックを提供できるようにするには、レイヤーが実際に何であるかを理解する必要がある!今後ともよろしくお願いいたします。
smeeb 2015

3
最高の答えはイモ。「Dockerの使用」に移行する多くの私たちにとって、レイヤーがどのように機能するかの要点がわかります。
dtc 2017

6
「dockerfileのすべての行でレイヤーが作成されます」-これは私が知るのに非常に役立ちました
akirekadu 2017

2
@akirekaduそれだけではありません。ほとんどの行はレイヤーを作成しますが、ADD、COPY、またはRUN命令のみが、作成されるコンテナーイメージのサイズを増やすレイヤーを作成します。ほとんどの行を言ったのは、コマンドをチェーンするか、バックスラッシュで改行をエスケープすると、チェーンされたコマンド/エスケープされた改行のシーケンスが単一のコマンドを形成するためです。
Scott Simontis

41

彼らは例を挙げれば私にとって最も理にかなっています...

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 historydocker 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のファイルに縮小されました。


ファイルの読み取り中にレイヤーをトラバースすると、オーバーヘッドが発生しますよね?そのオーバーヘッドを節約するために、1つのRUNで(とにかく一緒に実行する必要がある)複数のコマンドを組み合わせることは意味がありますか?
SergiyKolesnikov

@SergiyKolesnikovは、最適化の時期尚早に費やす時間によって異なります。リスクは、何時間もの開発者時間、追加の帯域幅とストレージのギグを費やして、数ミリ秒のランタイムを節約することです。パフォーマンスに関連する多くのことと同様に、極端な問題があり、修正に力を入れる前に問題を測定する必要があります。
BMitch

19

Docker v1.10以降、コンテンツアドレス可能なストレージが導入されたことで、「レイヤー」の概念はまったく異なります。レイヤーには、イメージやイメージに属するという概念はありません。レイヤーは、イメージ間で共有できるファイルとディレクトリのコレクションになります。レイヤーと画像が分離しました。

たとえば、ベースイメージからローカルにビルドされたイメージubuntu:14.04で、docker historyコマンドがイメージチェーンを生成するとしますが、ビルド履歴がロードされなくなったため、一部のイメージIDが「欠落」として表示されます。そして、これらの画像を構成するレイヤーは、

docker inspect <image_id> | jq -r '.[].RootFS'

レイヤーコンテンツは/var/lib/docker/aufs/diff、ストレージドライバーの選択がの場合に保存されaufsます。しかし、レイヤーはランダムに生成されたキャッシュIDで名前が付けられています。レイヤーとそのキャッシュIDの間のリンクは、セキュリティ上の理由からDocker Engineだけが知っているようです。私はまだ見つける方法を探しています

  1. 画像とその構成レイヤーの間の対応する関係
  2. ディスク上のレイヤーの実際の場所とサイズ

このブログは多くの洞察を提供しました。


このSOエントリでは、投稿した2つの質問に答える素朴な方法を投稿しました。
Ruifeng Ma

13

The Moby Projectを介したDockerのイメージ仕様

画像はレイヤーで構成されています。各層は、ファイルシステムの変更のセットです。レイヤーには、環境変数やデフォルト引数などの構成メタデータはありません。これらは、特定のレイヤーというよりも、全体としての画像のプロパティです。

したがって、本質的に、レイヤーはファイルシステムに加えられた一連の変更です。


それを見つけるのに数時間しかかかりませんでしたが、このエレガントでシンプルな答えで、最終的にレイヤーが何であるかを理解しました:("Each [Docker] layer is a set of filesystem changes."これが真実であると仮定して)。 blogs / Q + A's / etc、そして私は制限が私のものではないのではないかと思います。とにかく、問題の核心に到達するための勇敢なAditya。
ジョニーUtahh

12

公式ドキュメントはかなり詳細な説明を提供していると思います:https : //docs.docker.com/engine/userguide/storagedriver/imagesandcontainers/


(ソース:docker.com

画像は通常Dockerfileから生成される多くのレイヤーで構成され、Dockerfileの各行が新しいレイヤーを作成し、結果はのrepo:tagような形式で表される画像になりubuntu:15.04ます。

詳細については、上記の公式ドキュメントを読むことを検討してください。


2

有益な情報を提供してくれた@David Castilloに感謝します。レイヤーは、簡単に実行または元に戻すことができる画像のバイナリ変更または指示であると思います。レイヤー上のレイヤーと同じように段階的に行われるため、「レイヤー」と呼びます。

詳細については、次のような「ドッカー履歴」を参照してください。

Dockerイメージ-ツリー
警告: '--tree'は非推奨です。間もなく削除されます。使用法を参照してください。
└─511136ea3c5a仮想サイズ:0 Bタグ:scratch:latest
  └─59e359cb35ef仮想サイズ:85.18 MB
    └─e8d37d9e3476仮想サイズ:85.18 MBタグ:debian:wheezy
      └─c58b36b8f285仮想サイズ:85.18 MB
        └─90ea6e05b074仮想サイズ:118.6 MB
          └─5dc74cffc471仮想サイズ:118.6 MBタグ:vim:latest


5
レイヤーに関する新しい情報が見つかりました:Dockerがrootfsをマウントすると、従来のLinuxブートと同様に読み取り専用で起動しますが、ファイルシステムを読み書きモードに変更する代わりに、ユニオンマウントを利用して追加します読み取り専用ファイルシステム上の読み取り/書き込みファイルシステム。実際、複数の読み取り専用ファイルシステムが互いに積み重ねられている場合があります。これらのファイルシステムはそれぞれ1つのレイヤーと見なされます
Hiproz 2016

1

私の個人的な理解は、Dockerレイヤーをgithub commitと比較できるということです。ベースイメージ(新しいマスターリポジトリ)の場合、いくつかのコミットを行います。各コミットはマスターステータスを変更します。Dockerでも同じです。すべてのレイヤーが前の中間レイヤーに基づいて何らかの操作を行っています。そして、この層は次の層への新しい中間層になります。


0

以前のレイヤーの差分のようなものだと思っていました。ここでいくつかの答えを読んだ後、私は確信が持てませんでした。これらは、ファイルシステムに対する一連の変更として説明されています。私はいくつかのDockerfilesを記述して、それらがより差分のようであること、つまり、以前のレイヤーに本当に依存していることを示しました。

これら2つのDockerfileを考えると

FROM bash
RUN mkdir /data
RUN dd if=/dev/zero bs=1024 count=1024 of=/data/one
RUN dd if=/dev/zero bs=1024 count=1024 of=/data/two
RUN dd if=/dev/zero bs=1024 count=1024 of=/data/three

そして

FROM bash
RUN mkdir /data
RUN dd if=/dev/zero bs=1024 count=1024 of=/data/three
RUN dd if=/dev/zero bs=1024 count=1024 of=/data/two
RUN dd if=/dev/zero bs=1024 count=1024 of=/data/one

ファイルシステムの変更に関するものであれば、同じレイヤーのセットを期待できますが、そうではありません。

$ docker history img_1
IMAGE               CREATED             CREATED BY                                      SIZE
30daa166a9c5        6 minutes ago       /bin/sh -c dd if=/dev/zero bs=1024 count=102…   1.05MB
4467d16e79f5        6 minutes ago       /bin/sh -c dd if=/dev/zero bs=1024 count=102…   1.05MB
c299561fd031        6 minutes ago       /bin/sh -c dd if=/dev/zero bs=1024 count=102…   1.05MB
646feb178431        6 minutes ago       /bin/sh -c mkdir /data                          0B
78664daf24f4        2 weeks ago         /bin/sh -c #(nop)  CMD ["bash"]                 0B
<missing>           2 weeks ago         /bin/sh -c #(nop)  ENTRYPOINT ["docker-entry…   0B
<more missing...>

そして

$ docker history img_2
IMAGE               CREATED             CREATED BY                                      SIZE
f55c91305f8c        6 minutes ago       /bin/sh -c dd if=/dev/zero bs=1024 count=102…   1.05MB
29b3b627c76f        6 minutes ago       /bin/sh -c dd if=/dev/zero bs=1024 count=102…   1.05MB
18360be603aa        6 minutes ago       /bin/sh -c dd if=/dev/zero bs=1024 count=102…   1.05MB
646feb178431        6 minutes ago       /bin/sh -c mkdir /data                          0B
78664daf24f4        2 weeks ago         /bin/sh -c #(nop)  CMD ["bash"]                 0B
<missing>           2 weeks ago         /bin/sh -c #(nop)  ENTRYPOINT ["docker-entry…   0B
<more missing...>

ファイルシステムへ変更がどちらの場合も同じである場合でも、順序が重要であることがわかります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.