Dockerfile での複数の RUN と単一のチェーン RUN のどちらが優れていますか? 質問する

Dockerfile での複数の RUN と単一のチェーン RUN のどちらが優れていますか? 質問する

Dockerfile.1複数実行RUN:

FROM busybox
RUN echo This is the A > a
RUN echo This is the B > b
RUN echo This is the C > c

Dockerfile.2彼らに加わる:

FROM busybox
RUN echo This is the A > a &&\
    echo This is the B > b &&\
    echo This is the C > c

それぞれがRUNレイヤーを作成するので、レイヤーが少ないほど良いと常に考えていましたDockerfile.2

これは、 がRUN前の によって追加されたものを削除する場合RUN(つまりyum install nano && yum clean all) には明らかに当てはまりますが、 がそれぞれ何かを追加する場合にはRUN、考慮する必要がある点がいくつかあります。

  1. レイヤーは前のレイヤーの上に差分を追加するだけなので、後のレイヤーが前のレイヤーで追加されたものを削除しない場合は、両方の方法の間にディスク容量節約の利点はあまりないはずです。

  2. レイヤーは Docker Hub から並行してプルされるため、Dockerfile.1おそらく少し大きくなりますが、理論的にはダウンロードが速くなります。

  3. 4 番目の文 (つまりecho This is the D > d) を追加してローカルで再構築すると、Dockerfile.1キャッシュのおかげでビルドが速くなりますが、Dockerfile.24 つのコマンドすべてを再度実行する必要があります。

それで、質問です: Dockerfile を実行するより良い方法はどれでしょうか?

ベストアンサー1

可能な場合は、ファイルを作成するコマンドと、同じファイルを削除するコマンドを 1 行にまとめます。これは、各行がイメージにレイヤーを追加するRUNためです。出力は文字通り、作成される一時コンテナーで表示できるファイルシステムの変更です。別のレイヤーで作成されたファイルを削除した場合、ユニオン ファイルシステムは新しいレイヤーにファイルシステムの変更を登録するだけで、ファイルは前のレイヤーに存在し、ネットワーク経由で送信され、ディスクに保存されます。したがって、ソース コードをダウンロードして抽出し、バイナリにコンパイルしてから、最後に tgz ファイルとソース ファイルを削除する場合は、イメージ サイズを縮小するために、これらすべてを 1 つのレイヤーで実行する必要があります。RUNdocker diff

次に、私は個人的に、他のイメージでの再利用の可能性と予想されるキャッシュの使用に基づいてレイヤーを分割します。 すべて同じベース イメージ (例: debian) を持つ 4 つのイメージがある場合、それらのイメージのほとんどに共通するユーティリティのコレクションを最初の実行コマンドに取り込んで、他のイメージがキャッシュの恩恵を受けられるようにします。

イメージ キャッシュの再利用を検討する場合、Dockerfile 内の順序が重要です。私は、ベース イメージが更新されたときのみなど、めったに更新されないコンポーネントを検討し、それらを Dockerfile の上位に配置します。Dockerfile の最後のほうには、ホスト固有の UID を持つユーザーの追加や、フォルダーの作成と権限の変更など、すばやく実行され、頻繁に変更される可能性のあるコマンドを含めます。コンテナーに、現在開発中の解釈済みコード (JavaScript など) が含まれている場合は、できるだけ遅く追加して、再構築でその変更のみが実行されるようにします。

これらの変更のグループごとに、レイヤーを最小限に抑えるためにできる限り統合します。したがって、4 つの異なるソース コード フォルダーがある場合、それらは 1 つのフォルダー内に配置され、1 つのコマンドで追加できます。apt-get などからのパッケージのインストールは、パッケージ マネージャーのオーバーヘッド (更新とクリーンアップ) の量を最小限に抑えるために、可能な場合は 1 つの RUN にマージされます。


マルチステージビルドの更新:

マルチステージ ビルドの最終段階以外の段階では、イメージ サイズの縮小についてはあまり心配する必要がありません。これらのステージがタグ付けされず、他のノードに送られる場合、各コマンドを別々のRUN行に分割することで、キャッシュの再利用の可能性を最大限に高めることができます。

ただし、ステージ間でコピーするのはファイルのみであり、環境変数設定、エントリポイント、コマンドなどのイメージのメタデータの残りはコピーされないため、これはレイヤーを圧縮するための完璧なソリューションではありません。また、Linux ディストリビューションにパッケージをインストールすると、ライブラリやその他の依存関係がファイルシステム全体に分散され、すべての依存関係のコピーが困難になる場合があります。

このため、CI/CD サーバーでバイナリをビルドする代わりに、マルチステージ ビルドを使用します。これにより、CI/CD サーバーには を実行するためのツールのみが必要になりdocker build、jdk、nodejs、go、およびその他のコンパイル ツールはインストールされなくなります。

おすすめ記事