最小の作業ドッカーイメージを毎回作成する方法は?


19

目的:常に最小の作業用ドッカー画像を作成する

現在

REPOSITORY          TAG       IMAGE ID            CREATED             SIZE
a-docker-image      latest    x                   42 minutes ago       1.92 GB

試行

Dockerfileの最後にクリーンアップステップを追加します。

#clean
RUN apt-get purge -y wget
RUN rm -r a-build-dir
RUN apt-get purge -y a-package

画像サイズを少し縮小しました:

REPOSITORY          TAG       IMAGE ID            CREATED             SIZE
a-docker-image      latest    y                   2 minutes ago       1.86 GB

討論

さまざまなdockerイメージを作成しました。作成する画像のサイズを小さくしようとするたびに、常に大きすぎると感じます。githubの誰かによって既に作成されているスクリプトを探しています。このスクリプトは、作成されたイメージのサイズが可能な限り小さくなるように、イメージからすべての余分なパッケージを削除します。

私が言ったように、私は常に画像のサイズを小さくしようとしますが、これから作成するすべての画像が可能な限り小さくなるように、この一貫性を適用したいと思います。

質問

最小の作業ドッカーイメージを毎回作成する方法は?

回答:


1

単一のソリューションではなく、さまざまな手法が関係しています。次のいくつかの操作を行うことをお勧めします。


最初に、再利用のために画像レイヤーを最適化します。頻繁に変更する手順を後でDockerfileに入れて、以前のビルドから初期のレイヤーがキャッシュされる可能性を増やします。再利用されたレイヤーは、でより多くのディスク容量として表示されdocker image lsますが、基礎となるファイルシステムを調べると、各レイヤーのコピーが1つだけディスクに保存されます。つまり、それぞれが2 GBの3つのイメージですが、ビルドの最後のいくつかのレイヤーで50 MBしか異なるものではないため、2.1 GBのディスク容量しか占有しません。再利用された各レイヤーをダブルカウントします。

レイヤーの再利用により、ビルドの依存関係がめったに変更されないイメージが表示されるのは、コードをコピーする前にそれらを最初にインストールするためです。次のようなパターンを持つPythonの例を参照してください。

FROM python
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
# note how the code is copied only after the pip install
# since code changes but requirements.txt doesn't
COPY . .
CMD ["gunicorn", "app:app"]

最小限の基本画像を選択します。あなたは、人々が行くから見るのはこのためですubuntudebian:slim(スリムな変異体は、より少ないツールで出荷し、小さい)、あるいはalpine。これにより、開始点のサイズが小さくなり、ベースイメージの新しいバージョンを常にプルする場合に非常に役立ちます。ただし、ベースイメージがめったに変更されない場合、レイヤーを再利用すると、最小限のベースイメージの利点の多くが失われます。

選択できる最小のベースイメージはですscratch。これは、シェルやライブラリではなく、静的にコンパイルされたバイナリでのみ有用です。それ以外の場合は、必要のない多くのツールを使用せずに、必要なツールを含むベースイメージを選択します。


次に、ファイルを変更または削除するステップは、そのファイルを作成する前のステップと組み合わせる必要があります。そうしないと、ファイル許可の変更などでもコピーオンライトを使用する階層化ファイルシステムは、前のレイヤーに元のファイルを保持し、ファイルを削除しても画像サイズは縮小しません。これが、rmコマンドが結果のディスク容量に影響を与えない理由です。代わりに、次のようにコマンドを連鎖できます。

RUN apt-get update \
 && apt-get install -y \
      a-package \
      wget \
 && ... \
 && apt-get purge -y wget \
 && rm -r a-build-dir \
 && apt-get purge -y a-package

コマンドチェーンの過剰使用は、前提条件が変更されるたびに同じツールセットを再インストールする必要があるため(たとえば、wgetでプルされるコード)、ビルドの速度が低下する可能性があることに注意してください。より良い代替案については、以下のマルチステージを参照してください。


作成したイメージで必要のないファイルは、作成するステップで削除する必要があります。これには、パッケージキャッシュ、ログ、マニュアルページなどが含まれます。各レイヤーで作成されているファイルを見つけるには、wagoodman / diveなどのツールを使用できます(完全にルートアクセスで実行されるため、私は個人的に吟味しておらず、注意を表明します)または、中間コンテナを削除せずにDockerイメージを構築し、次のようにして差分を表示できます:

# first create and leave containers from any RUN step using options on build
docker image build --rm=false --no-cache -t image_name . 
# review which layers use an unexpectedly large amount of space
docker image history image_name
# list all containers, particularly the exited ones from above
docker container ps -a 
# examine any of those containers
docker container diff ${container_id} 
# ... repeat the diff for other build steps
# then cleanup exited containers
docker container prune

それらの中間のコンテナのそれぞれと、diffはファイルを追加、変更、またはそのステップで削除されているものが表示されます(これらはで表示されACまたはD各ファイル名の前に)。diffが示しているのは、コンテナ固有の読み取り/書き込みファイルシステムです。これは、コピーオンライトを使用してイメージ状態からコンテナによって変更されたファイルです。


画像サイズを縮小する最良の方法は、出荷された画像からコンパイラなどの不要なコンポーネントを削除することです。そのために、マルチステージビルドを使用すると、1つのステージでコンパイルし、結果のアーティファクトのみをビルドステージから、アプリケーションの実行に最低限必要なランタイムイメージにコピーできます。これにより、結果のイメージとともに出荷されないため、ビルドステップを最適化する必要がなくなります。

FROM debian:9 as build
# still chain update with install to prevent stale cache issues
RUN apt-get update \
 && apt-get install -y \
      a-package \
      wget \
RUN ... # perform any download/compile steps

FROM debian:9-slim as release
COPY --from=build /usr/local/bin/app /usr/local/bin/app
CMD [ "/usr/local/bin/app" ]

マルチステージは、静的にコンパイルされたバイナリで理想的です。これをベースイメージとしてスクラッチで実行したり、JDKのようなコンパイル環境からJREのようなランタイムに移行したりできます。これは、高速なビルドを維持しながら、イメージサイズを劇的に削減する最も簡単な方法です。以前のステップで作成されたファイルを変更または削除するステップがある場合、リリースステージでステップのチェーンを実行できますが、ほとんどの場合、COPY別のステージからリリースステージを以前のビルドステージで経験したレイヤーの膨張から分離します。


レイヤーの再利用を排除することで1つの画像のサイズを縮小するため、画像を潰すことはお勧めしません。つまり、同じイメージの今後のビルドでは、更新を送信するためにより多くのディスクとネットワークトラフィックが必要になります。最初の例に戻ると、スカッシュによりイメージが2 GBから1 GBに削減される場合がありますが、3つのイメージではなく2.1 GBの代わりに3 GBが使用される場合があります。


25

A Dockerfileは、ファイル内のコマンドごとに新しいレイヤーを作成します。レイヤーは適切であるため、互いに重ねられます-前のレイヤーが追加したファイルを削除することはできません。これが、パッケージをインストールするとき、ファイルをダウンロードするとき、またはそれぞれ個別のコマンドでビルドを作成するとき-将来のレイヤーでそれらを削除した場合でも、これらはイメージ内に残っている理由です。

したがって、これを変更するだけの場合:

RUN apt-get update -y
RUN apt-get install -y wget a-package
# ...
RUN apt-get purge -y wget
RUN rm -r a-build-dir
RUN apt-get purge -y a-package

これに:

RUN apt-get update -y \
    && apt-get install -y wget a-package \
    && mkdir a-build-dir \
    && wget http://some-site/very-big-source-code.tar.gz \
    && tar xzvf very-big-source-code.tar.gz \
    && do-some-compilation \
    && apt-get purge -y wget \
    && cd .. \
    && rm -rf a-build-dir \
    && apt-get purge -y a-package

はるかに小さな画像が得られます。


もう1つのオプションは、イメージを構築した後に潰すことです。 Q:新しいdocker --squash機能はどのように機能しますか?


さらに別のオプションは、スリムなベース画像を選択することです。たとえば、Debianの代わりにAlpine Linuxをベースとして使用するイメージは、180〜250 MBではなく10〜15 MBしか使用しません。これは、独自のアプリケーションとデータを追加する前です。Docker Hubの公式ベースイメージの多くには、高山バージョンがあります。


3
2.37vs.1.47 GB
030

4

おそらく正確な答えではありませんが、選択肢を与える価値があります。

Chefの生息地はこれを念頭に置いて作成されており、不要なディストリビューション/ベースイメージのロードが不要な、必要なすべての依存関係を持つパッケージを作成します。

ここで重要なこと、この単純なnodejsアプリを使用したこのブログ投稿からコンテナーサイズを抽出します。

michael@ricardo-2:plans_pkg_part_2$ docker images
REPOSITORY           TAG                 IMAGE ID            CREATED             SIZE
mfdii/node-example   latest              36c6568c606b        40 minutes ago      655.9 MB
node                 latest              04c0ca2a8dad        16 hours ago        654.6 MB
mfdii/mytutorialapp  latest              534afd80d74d        2 minutes ago       182.1 MB

mdfii/node-exampleは、従来のdockerfileからのdocker mfdii/mytutorialappイメージですが、生息地で作成されたdocker イメージです。

サイズが主な関心事であり、ハビタット計画の学習曲線を採用するなら、これはあなたのための解決策かもしれません。


0

ダイビングを使用することもできます

docker run --rm -it \
    -v /var/run/docker.sock:/var/run/docker.sock \
    wagoodman/dive:latest <dive arguments...>

サイズを縮小するために、Dockerイメージから削除できる廃棄物に関するレポートを取得します。


0

再利用可能な開発レイヤーを持ちたいが、配信のためのディスク使用量を減らしたい場合は、次のようにマージされた「配信レイヤー」を作成できます。

  1. イメージを使用するコンテナがあることを確認してください(持っていないdocker run IMAGE echo場合は、echoコマンドが利用可能な場合、のようなものを使用することもできます)
  2. コンテナIDを検索します(おそらくを使用docker container ls -l
  3. にパイプdocker exportdocker importてマージされたレイヤー(のようなものdocker export 20f192c6530a | docker import - project:merged)を作成します

これにより、開発レイヤーが維持されますが、配信可能なより小さなマージされたイメージが提供されます。


0

マルチステージビルド。すべてのビルドコンポーネントを含むイメージを使用して、アプリケーションをビルドし、より軽いランタイムイメージを使用します。ビルドアーティファクトだけをランタイムイメージにコピーします。何も削除する必要はありません。

https://docs.docker.com/develop/develop-images/multistage-build/


0

simple .. docker psは、現在実行中の画像を確認します。以下の簡単なファイルの例については..

ubuntu16から

MAINTAINER sreeni(メール/ドメイン)

apt-get updateを実行する

apt-get install -y nginxを実行します

ENTRYPOINT [“ / usr / sbin / nginx”、”-g”、” daemon off;”]

EXPOSE 80(ポート)

シンプルなdockerファイル...

以下のdockerコマンドを使用

docker run -d -p 80:80 --name web server ubuntu16(image name)その後、localhostまたはIPアドレスをチェックします:80(ブラウザーを開いて確認)


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