Dockerイメージのサイズを縮小する6つの方法

Dockerイメージのサイズを縮小する6つの方法

2017 年に Vulhub に取り組み始めてから、私は厄介な問題に悩まされてきました。Dockerfile を書くときに、 docker buildによって生成されるイメージのサイズを縮小するにはどうすればよいでしょうか?この記事では、画像のサイズを縮小するために私が使用した 6 つの方法をまとめます。

1. Alpine Linuxの使用

Alpine Linux は、BusyBox と Musl Libc をベースにした Linux ディストリビューションです。最大の利点はサイズが小さいことです。純粋なベースの Alpine Docker イメージは、圧縮するとわずか 2.67 MB になります。

多くの公式 Docker イメージには、PHP などの Alpine バージョンがあります。

比較してみると、アルパインバージョンの画像の大きさは通常バージョンの約1/5であることがわかります。

しかし、Docker Hub では、Mysql や PHP-Apache など、ほとんどのイメージに Alpine バージョンがありません。これらの環境をベースに開発する必要がある場合は、自分で Alpine バージョンを作成するか、サードパーティのイメージを探す必要があります。

さらに、Alpine のもう 1 つの欠点は、従来の glibc の代わりに Musl Libc を使用していることです。ソフトウェアをコンパイルするときに、予期しない問題が発生する可能性があり、多くの無駄な時間を費やすことになります。

2. 最小限の依存関係のみをインストールする

apt-get、yum、apk などのパッケージ マネージャーは、イメージをコンパイルするときに使用する必要があるツールです。純粋な Docker ベースのイメージには通常、wget、curl、git、gcc などのツールがないため、手動でインストールする必要があります。

apt を例に挙げてみましょう。ソフトウェアをインストールするときに、apt-get はオプション--no-install-recommendsを指定できます。このパラメータを指定すると、必須でない依存関係の一部は一緒にインストールされなくなります。たとえば、wget をインストールするときにこのオプションを追加すると、インストールされるパッケージの数は 6 から 3 に減ります。

これにより、イメージのサイズはある程度縮小されますが、その副作用として、対象ソフトウェアの一部の機能が不足する可能性があります。

たとえば、この時点で wget はサーバー証明書の信頼性を検証できず、コマンド エラーが発生します。

したがって、私たちの一般的なやり方は、apt を使用するときに--no-install-recommendsを追加し、後でエラーが発生した場合にすぐに修正することです。 wget のような既知の問題は事前に予測して対処できます。

apt-get install --no-install-recommends wget ca-certificates

3. aptの混乱を解消する

一部のツールはコンパイル段階でのみ使用されます。貴重なイメージ容量を占有させたくありません。イメージのコンパイルが完了したら、これらの中間依存関係を削除できます。

apt を例に挙げてみましょう。apt を使用した後は、次の操作を行う必要があります。

  • 不要な依存関係を削除します: apt-get pruge --autoremove ...
  • ローカルパッケージリストを削除します: rm -rf /var/lib/apt/lists/*

このプロセスでは、どの依存関係が「不要」なのかという非常に難しい問題に遭遇します。

たとえば、PHP をコンパイルする場合、wget、libxml、gcc の 3 つのツールを使用できます。 PHP をコンパイルする前に、これら 3 つのツールをインストールする必要があります。しかし、コンパイルが完了した後、wget と gcc はアンインストールできますが、libxml はアンインストールできません。

その理由は、libxml は PHP が依存するダイナミック リンク ライブラリだからです。これをアンインストールすると、共有リンク ライブラリが見つからないというエラーが発生します。

ルート@8eab53da8d5b:/#php -v
php: 共有ライブラリのロード中にエラーが発生しました: libxml2.so.2: 共有オブジェクトファイルを開けません: そのようなファイルまたはディレクトリはありません

では、「共有リンク ライブラリ」ではない依存関係のみを自動的に検出して削除する、より便利な方法はありますか?

もちろんあります。もっと簡単な方法は、新しくコンパイルされた実行可能ファイルを走査し、ldd コマンドを使用してそれが依存する共有リンク ライブラリ ファイル名を一覧表示し、ソース内でこのファイル名に対応するパッケージ名を検索することです。

これらのパッケージはすべて、PHP が依存するダイナミック リンク ライブラリです。次に、 apt-markを使用してこれらのパッケージを「手動でインストールされたパッケージ」として宣言し、 apt purgeによって自動的にアンインストールされるのを防ぎます。

その後、残りの未使用のパッケージを自動的にアンインストールできます。完全なシェル スクリプトは次のとおりです。

/usr/local を見つけます -type f -executable -exec ldd '{}' ';' \
 | awk '/=>/ { $(NF-1) を印刷 }' \
 | ソート -u \
 | xargs -r dpkg-query --search \
 | カット -d: -f1 \
 | ソート -u \
 | xargs -r apt-mark マニュアル \
; \
apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false;

4. 中間依存関係を1ステップでインストールおよびアンインストールする

Docker イメージは、レイヤーで構成された階層化されたケーキです。docker docker history <image name>コマンドを使用すると、イメージがどのレイヤーで構成されているか、および各レイヤーのサイズを確認できます。

Dockerfile の場合、後者のレイヤーが前のレイヤーに保存されたファイルを削除したとしても、これらのレイヤーのデータはイメージに保存されます。

たとえば、次の Dockerfile があります。

アルパインより:3.12
実行 truncate -s 50M /sample.dat
rm -rf /sample.dat を実行します。

このコンパイルされたイメージの大きさは 58 MB です。

比較すると、通常の alpine:3.12 はわずか 5.57 MB です。つまり、 /sample.datファイルを削除しても、最終イメージにはそのようなコンテンツは存在しませんが、イメージ履歴には常に残ります。

そのため、前述の「中間依存関係」を削除する際には、確実に領域を解放するために、インストール、使用、アンインストールの 3 つの部分を 1 つのステップで記述する必要があります。例えば:

debian:buster より

apt-get update を実行する\
 && apt-get install gcc \
 && gcc ... \
 && apt-get purge --autoremove gcc \
 && rm -rf /var/lib/apt/lists/*

5. 多段階コンパイル

Docker バージョン 17.05 以降では、マルチステージ ビルドの概念が導入され、上記のすべての操作が大幅に簡素化されます。

簡単に言えば、マルチステージ ビルドを使用すると、Docker イメージのコンパイルを複数の「ステージ」に分割できます。たとえば、一般的なソフトウェアのコンパイルの場合、コンパイル段階を分離し、ソフトウェアのコンパイルが完了した後にバイナリファイルを新しいベースイメージに直接コピーすることができます。これの最大の利点は、2 番目のイメージにはコンパイル段階で使用される中間依存関係が含まれなくなり、クリーンで明確になることです。

最も一般的な Java プロジェクトを例にとると、Jar パッケージをコンパイルするときには JDK や Maven などのツールを使用する必要がありますが、実際の運用段階では JRE 環境のみが必要になります。 2 つのイメージ ( maven:3-openjdk-8openjdk:8-jreのサイズを比較してみましょう。

その差は2倍以上です。

Vulhub の Shiro 1.2.4 環境を例にとると、Dockerfile には 2 つのFROMコマンドがあります。

maven:3-jdk-8 AS ビルダーから

ラベル MAINTAINER="phithon <[email protected]>"

./code/ /usr/src/ をコピー

ワークディレクトリ /usr/src

実行cd /usr/src; \
 mvn -U クリーンパッケージ -Dmaven.test.skip=true

openjdk:8u102-jre から

ラベル MAINTAINER="phithon <[email protected]>"

コピー --from=builder /usr/src/target/shirodemo-1.0-SNAPSHOT.jar /shirodemo-1.0-SNAPSHOT.jar

エクスポーズ8080

CMD ["java", "-jar", "/shirodemo-1.0-SNAPSHOT.jar"]

最初のFROMmaven:3-jdk-8環境に入り、Maven を使用してソース コードをコンパイルするために使用されます。2 番目のFROM 、より小さいopenjdk:8u102-jre環境に入り、 COPY --from=構文を使用して、前のステージのコンパイル結果から jar ファイルを jre 環境にコピーします。

最終的に、マシン上に 2 つのイメージが残ります。1 つはビルダーで、もう 1 つは最終的に必要となる shiro 1.2.4 環境です。後者は他のユーザーが独立して使用できますが、前者は直接削除できます。

ユーザーは、ソフトウェアをコンパイルしてイメージを小さくするときに、中間依存関係をどのように削除するかを心配する必要がなくなりました。いずれにしても、最初の段階で使用された依存関係は、正式な本番環境に残されません。

しかし、マルチステージコンパイルでは、ダイナミックリンクライブラリに依存するという前述の問題が依然として残ります。コンパイル結果をコピーするときに実行可能ファイルのみをコピーすると、新しい環境で実行したときに共有リンクライブラリが見つからないというエラーが依然として発生します。そのため、個人的には、マルチステージコンパイルは、Java や golang などのクロスプラットフォームまたは静的コンパイルが可能な言語にのみ適しており、C や Python などの依存関係が多いプロジェクトにはまだ適していないと感じています。

6. 画像のスリムバージョンを使用する

注意深い学生なら、公式の Docker Debian イメージに、デフォルト バージョンの 2 倍以上のサイズのスリム バージョンがあることに気付いたかもしれません。

slim の中国語の意味は「スリム」です。名前が示すように、 debian:stretch-slimコンテナで使用されない man ドキュメントなどの多くのファイルを削除するため、実際にははるかにスリムです。

一部の上位レベルのイメージは、Python など、Debian のスリム バージョンに基づいて作成されています。 Python プロジェクトを開発する場合は、 python:slimベースイメージを使用できます。

まとめると、6 つの方法は互いに影響を及ぼさず、同時に使用できます。しかし、5番目の多段階コンパイルは、将来的には主流の方法になるでしょう。

以上で、Docker イメージのサイズを小さくする 6 つの方法についての説明は終了です。Docker イメージのサイズを小さくする方法の詳細については、123WORDPRESS.COM の過去の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • Alibaba Cloud イメージリポジトリの Docker 構成変更の実装
  • SpringBootでDockerイメージを構築する3つの方法の詳しい説明
  • Springboot docker jenkins でイメージを自動的にデプロイしてアップロードするための詳細な手順
  • Dockerイメージ内のファイルを表示する方法
  • Dockerとイメージの操作方法

<<:  MySQL NULLがピットを引き起こした

>>:  階段を転がす特殊効果を実現する JavaScript (jQuery 実装)

推薦する

jQueryで劇場の座席選択と予約の効果を実現

jQueryは劇場の座席選択と予約の効果を実現します。参考までに、具体的な内容は次のとおりです。効果...

異なるデータベースで DROP TABLE を書く方法

異なるデータベースで DROP TABLE を書く方法1.MySQL 存在する場合はテーブルを削除 ...

MySQLをシンプルに学ぶ

序文データベースは常に私の弱点でした。自分の経験 (python+sqlalchemy) を組み合わ...

Vue で配列パラメータを渡すための get / delete メソッド

フロントエンドとバックエンドがやり取りする場合、get または delete を介してバックエンドに...

CSS3+JavaScript を使用したクールな呼吸効果のサンプル コード

CSS3 アニメーションで実現したシンプルでクールな効果。最終的な効果は次のようになります。 ページ...

Tomcat9 Windows サービスのインストールに関する詳細なチュートリアル

1. 準備1.1 service.bat を含む tomcat 圧縮パッケージをダウンロードします。...

CentOS 7 で RPM を使用して mysql5.7.13 をインストールする

0. 環境この記事のオペレーティング システム: CentOS 7.2.1511 x86_64 My...

Tomcatはスレッドプールを使用してリモート同時リクエストを処理します。

Tomcatが同時リクエストを処理する方法を理解することで、スレッドプール、ロック、キュー、および...

jQueryは居住地を選択するためのドロップダウンボックスを実装します

居住地を選択するためのドロップダウンボックスをjQueryで実装するための具体的なコードは参考までに...

CSS で雨滴アニメーション効果を実装するサンプルコード

ガラス窓今日実現するのは雨滴効果です。ただし、雨滴効果を実現する前に、まずは曇りガラス効果を作成しま...

さまざまなHTTPリターンステータスコードの詳細な説明

サイト上のページを表示するためのリクエストがサーバーに送信されると(たとえば、ユーザーがブラウザでペ...

Linux運用保守ツールSupervisor(プロセス管理ツール)のインストールと使用

1. はじめにSupervisor は Python で開発された汎用プロセス管理プログラムです。通...

VS2022 リモート デバッグ ツールの使い方

WeChat 関連サービスをデバッグする場合など、職場のサーバー環境でリモートデバッグを行う必要があ...

Docker で SVN サーバーを構築するチュートリアル

SVN は Subversion の略称で、ブランチ管理システムを使用して効率的に管理するオープンソ...

JavaScript で簡単なモグラ叩きゲームを実装する

この記事では、モグラ叩きゲームを実装するためのJavaScriptの具体的なコードを参考までに紹介し...