1

Jib を使用して Docker イメージを構築すると、リモートの Docker リポジトリ ストレージを最適化できますか?

Gradle を使用して Docker で Spring Boot を使用しています。現在、すべての依存関係が内部にパックされた標準のファット ブート jar を作成してから、次のようにイメージを作成しています。

FROM gcr.io/distroless/java:11
COPY ./build/libs/*.jar app.jar
CMD ["app.jar"]

これにより、実際にはコードがほとんど変更されていない場合でも、ビルドするたびに大きな (250 MB) 新しいイメージが作成されます。これは、fat jar に共有依存関係 (頻繁に変更されない) とコードの両方が含まれているためです。これは、プライベート リポジトリのストレージ スペースの非効率的な使用法であり、これを変更したいと考えています。

このためのアイデアは次のとおりです。

  • /opt/libs に依存関係のみを含む基本イメージを作成し、それを呼び出してspring-base:1.0.0、プライベート Docker レジストリにプッシュしましょう。

  • そのイメージを、コードのみを含むアプリケーション イメージの親/ベースとして使用します。Dockerfile は次のようになります (概念を提示するためだけにテストされていません)。

    FROM our-registry/spring-base:1.0.0
    COPY ./build/classes/kotlin/main/* /opt/classes
    COPY ./build/resources/main/* /opt/resources
    ENTRYPOINT ["java", "-cp", "/opt/libs/*:/opt/resources:/opt/classes", "com.example.MainKt"]
    

これらのイメージははるかに小さく、依存関係のある大きな基本イメージは一度だけ保存されるため、多くのストレージが節約されることが期待されます。

私たちの同僚は、Jib を調べて、まさにこれを行うと主張しましたが、ドキュメント全体と FAQ を読み、少しいじってみましたが、よくわかりません。私たちはそれを統合して使用./gradlew jibDockerBuildし、依存関係、リソース、およびクラスのレイヤーを作成しているように見えますが、まだ 1 つの大きなイメージしかありません。Jib はビルド時間の短縮 (Docker レイヤー キャッシュの利用による) と再現可能なビルドに重点を置いているようですが、そのイメージをリポジトリにアップロードしても、現在のソリューションと比べて何も変わらないと思います。「静的な」依存関係を引き続き保存します。何度も繰り返しますが、新しい画像ごとに 1 つだけではなく、複数のレイヤーを持つようになります。

Docker と Jib の経験が豊富な方で、Jib が私たちが求めているストレージ スペースの最適化を提供してくれるかどうか説明していただけますか?

編集:答えを待っている間、私はこれらすべてをいじってhttps://github.com/wagoodman/diveを使用しdocker system dfdocker imagesサイズを確認し、画像とレイヤーを調べました.Jibはまさに何をしているようです必要です。

4

1 に答える 1

3

Jib を使用して Docker イメージを構築すると、リモートの Docker リポジトリ ストレージを最適化できますか?

はい。確かに、画像レイヤーの再現性が高いため、これはかなりの程度に役立ちます。を使用するだけDockerfileでは、通常、ほとんどのレイヤーの再現性が完全に失われます。これは、ファイルのタイムスタンプがレイヤーが同一であるかどうかのチェックに組み込まれるためです。たとえば、ファイルのバイト.classがまったく変更されていない場合でも、ファイルを再生成すると、再現性が失われます。これは jar ではさらに悪いことです。タイムスタンプが変更される可能性があるだけでなく、jar メタデータ (たとえばMETA-INF/MANIFEST.MF

これにより、実際にはコードがほとんど変更されていない場合でも、ビルドするたびに大きな (250 MB) 新しいイメージが作成されます。これは、fat jar に共有依存関係 (頻繁に変更されない) とコードの両方が含まれているためです。

サイズが大きい (250MB) ことは部分的に修正しますが、jar が大きいためではありません。ビルドされたイメージのサイズは、それがファット jar ではなく、共有ライブラリ用に別のレイヤーを指定した場合でも、常に 250MB になります。gcr.io/distroless/java:11最終的なイメージのサイズ (250MB) には、イメージがどのツールでどのように構築されたかに関係なく、基本イメージのサイズ ( ) と共有ライブラリのサイズが常に含まれます。

ただし、Docker エンジンは、ストレージ内で既に認識しているレイヤーを複製しません。同様に、リモート レジストリは、リポジトリに既に存在するレイヤーを複製することもありません。さらに、多くの場合、レジストリは異なるリポジトリ間でレイヤーのコピーを 1 つだけ保存することさえあります。したがって、コード (つまり jar) のみを更新すると、その jar を含むレイヤーのみが新しいストレージ スペースを占有します。また、Docker と Jib は、新しいレイヤーのみをネットワーク経由でリモート レジストリに送信します。つまり、 のベース イメージ レイヤーはgcr.io/distroless/java:11送信されません。

/opt/libs に依存関係のみを含む基本イメージを作成し、それを呼び出してspring-base:1.0.0、プライベート Docker レジストリにプッシュしましょう。

共有ライブラリを含めるためだけに別のイメージを作成することは、前例のないことではなく、これを試みている人を見てきました。ただし、この特別な基本イメージを、組織内のさまざまな種類のイメージ間で共有するための独立したスタンドアロン イメージとして概念的に扱うつもりはないと思います。したがって、この状況でそうするのは型にはまらないと思います。ストレージスペース(およびネットワーク帯域幅)の節約に関して頭の中で思い浮かんだだけの場合、このトリックはおそらく不要です。読み続けてください。

これらの画像ははるかに小さいことが予想されます

いいえ。説明したとおり、何があっても同じサイズの 250MB のイメージを作成します。これには、共有ライブラリを含む基本イメージのサイズが含まれます。を実行するdocker imagesと、ローカルの Docker エンジンはイメージ サイズが 250MB であることを示します。しかし、私が言ったように、新しいイメージを構築するたびに、Docker エンジンが追加の 250 MB のスペースを占有するという意味ではありません。

依存関係のある大きな基本イメージは一度だけ保存されます

はい。ただし、これは、最初からFROM gcr.io/distroless/java:11. 共有ライブラリ用に独自の別のレイヤーを作成し、そのレイヤーを安定した (つまり、再現可能な) 状態に保つことができる限り、共有ライブラリを別の「ベース イメージ」に押し込むことは無意味です。そして、ジブはそのようなレイヤーを再現可能に構築することに非常に長けています。レジストリに保存されるビットの粒度はイメージではなくレイヤーであるため、ライブラリ レイヤーが何らかの「ベース イメージ」にあることを「マーク」する必要はありません (ライブラリ用に独自のレイヤーを作成する限り)。レジストリはレイヤーのみを認識し、「このイメージはレイヤー A、レイヤー B、レイヤー C とこのメタデータで構成される」と宣言するだけで「イメージ」の概念が形成されます。イメージにはベース イメージの概念さえありません。「この画像は、このベース画像の上にレイヤーAを置いたものです」とは言いません。

多くのストレージを節約します。

したがって、これは真実ではありません。結局のところ、Docker エンジンとレジストリは、正当な理由もなく同じレイヤーを複数回保存することはありません。

私たちはそれを統合して使用./gradlew jibDockerBuildし、依存関係、リソース、およびクラスのレイヤーを作成しているように見えますが、まだ 1 つの大きなイメージしかありません。

はい。画像サイズは250MBになります。Dockerfileこれは、またはその他のイメージ構築ツールを使用する場合にも当てはまります。ただし、Jib を使用する場合、アプリケーション.javaファイルのみを変更すると、再構築時に、Jib はネットワーク経由で小さなアプリケーション層 (共有ライブラリやリソースを含まない) のみをリモート レジストリに送信します。ジブは再現性が高いため、250MB のレイヤー全体を送信するわけではありません。同様に、共有ライブラリのみを更新する場合、Jib はライブラリ レイヤーのみを送信し、時間、帯域幅、およびストレージを節約します。

ただし、Docker エンジン API の機能が限られているため、Jib が特定のレイヤーが既に Docker エンジンに格納されているかどうかを確認する方法がないため、Jib は使用時に 250MB のレイヤー全体をロードする必要があります。jibDockerBuild. 読み込みはネットワークを経由せずにローカルで行われるため、これは通常は問題になりません。しかし、この API の制限により、驚くべきことに、Jib がイメージをリモート レジストリに直接プッシュする方が、ローカルの Docker エンジンにプッシュするよりも高速であることがよくあります。ジブは、変更されたレイヤーのみを送信する必要があります。ただし、何度も強調してきたように、Jib (または他のイメージ構築ツール) が 250MB のレイヤー全体を Docker エンジンにロードしたとしても、エンジンは必要なもの (つまり、見たことのない新しいレイヤー) のみを保存します。またはそう信じている)。ベース イメージまたは共有ライブラリ レイヤーは複製されません。新しい、異なるレイヤーのみがストレージを占有します。ではDockerfile、再現性が低いために実際には新しいレイヤーではありませんが、通常は「新しいレイヤー」を生成することになります。

于 2020-03-18T15:45:37.930 に答える