Dockerイメージは、実際にはファイルシステムレイヤーのリンクリストです。Dockerfileの各命令は、対応する命令の実行前後のファイルシステムの違いを記述するファイルシステム層を作成します。docker inspect
サブコマンドは、ファイルシステム層のリンクされたリストであることの性質を明らかにするためにドッカー画像に使用することができます。
画像で使用されるレイヤーの数は重要です
- 同時に発生するアップロードまたはダウンロードの数に影響するため、画像をプッシュまたはプルするとき。
- コンテナを開始するとき、レイヤーが一緒に組み合わされて、コンテナで使用されるファイルシステムが生成されます。レイヤーが多くなるほどパフォーマンスは低下しますが、これにより異なるファイルシステムバックエンドが異なる影響を受けます。
これには、イメージの構築方法にいくつかの影響があります。私ができる最初で最も重要なアドバイスは:
アドバイス#1ソースコードが関係するビルドステップがDockerfileでできる限り遅くなり、a &&
またはa を使用する以前のコマンドに関連付けられていないことを確認します;
。
これは、前のステップがすべてキャッシュされ、対応するレイヤーを何度もダウンロードする必要がないためです。これは、ビルドとリリースの高速化を意味します。これはおそらくあなたが望むものです。興味深いことに、Dockerキャッシュを最適に使用することは驚くほど困難です。
2番目のアドバイスはそれほど重要ではありませんが、メンテナンスの観点からは非常に役立ちます。
アドバイス#2 Dockerfileに複雑なコマンドを書くのではなく、コピーして実行するスクリプトを使用します。
A Dockerfileようになり、このアドバイスを、次の
COPY apt_setup.sh /root/
RUN sh -x /root/apt_setup.sh
COPY install_pacakges.sh /root/
RUN sh -x /root/install_packages.sh
等々。いくつかのコマンドをバインドするアドバイスの&&
範囲は限られています。スクリプトを使用すると、冗長性を回避したり、ドキュメント化のために関数などを使用したりするのがはるかに簡単になります。
プリプロセッサとによって引き起こされる小さなオーバーヘッドを回避するために喜んでいる人達COPY
の手順を、実際にオンザフライ生成されDockerfile場所
COPY apt_setup.sh /root/
RUN sh -x /root/apt_setup.sh
シーケンスは
RUN base64 --decode … | sh -x
ここ…
で、はのbase64エンコードバージョンですapt_setup.sh
。
3番目のアドバイスは、ビルドの長さを犠牲にして、サイズとレイヤー数を制限したい人向けです。
アドバイス#3with
-idiomを使用して、中間層には存在するが、結果のファイルシステムには存在しないファイルを回避します。
いくつかのdocker命令によって追加され、後の命令によって削除されたファイルは、結果のファイルシステムには存在しませんが、構築中のdockerイメージを構成するdockerレイヤーで2回言及されます。1回は、命令を追加した結果のレイヤー内の名前と完全なコンテンツ、1回は命令を削除した結果のレイヤー内の削除通知として。
たとえば、一時的にCコンパイラと何らかのイメージが必要であると仮定し、
# !!! THIS DISPLAYS SOME PROBLEM --- DO NOT USE !!!
RUN apt-get install -y gcc
RUN gcc --version
RUN apt-get --purge autoremove -y gcc
(より現実的な例では、単に--version
フラグでその存在をアサートするのではなく、コンパイラーでいくつかのソフトウェアをビルドします。)
Dockerfileスニペットは3つのレイヤーを作成します。最初のレイヤーには完全なgccスイートが含まれているため、最終的なファイルシステムに存在しない場合でも、対応するデータは同じ方法で画像の一部であり、ダウンロード、アップロード、アンパックする必要があります最終画像です。
with
-idiom単離リソースの所有権およびリソースを使用して、ロジックから解放する関数型プログラミングにおける一般的な形態です。このイディオムをシェルスクリプトに置き換えるのは簡単です。以前のコマンドを次のスクリプトに言い換えCOPY & RUN
て、アドバイス#2のように使用できます。
# with_c_compiler SIMPLE-COMMAND
# Execute SIMPLE-COMMAND in a sub-shell with gcc being available.
with_c_compiler()
(
set -e
apt-get install -y gcc
"$@"
trap 'apt-get --purge autoremove -y gcc' EXIT
)
with_c_compiler\
gcc --version
複雑なコマンドを機能に変換して、に送ることができますwith_c_compiler
。いくつかのwith_whatever
関数の呼び出しを連鎖させることも可能ですが、おそらくあまり望ましくありません。(シェルのより難解な機能を使用して、with_c_compiler
複雑なコマンドを受け入れることは確かに可能ですが、これらの複雑なコマンドを関数にラップすることはすべての面で望ましいです。)
アドバイス#2を無視したい場合、結果のDockerfileスニペットは
RUN apt-get install -y gcc\
&& gcc --version\
&& apt-get --purge autoremove -y gcc
難読化のため、読みやすく保守が容易ではありません。シェルスクリプトバリアントが重要な部分に重点を置いているのgcc --version
に対して、チェーン&&
バリアントはノイズの中でその部分を埋めています。