Red Hatでソリューションアーキテクトをしている田中司恩(@tnk4on)です。 前回記事の続きになります。前回記事ではOpenJDKのコンテナイメージでjarファイルが実行される仕組みなどを深掘りしました。 今回はOpenJDKのコンテナイメージのサイズの確認やコンテナイメージを自作した場合との比較などを行います。
(前回記事はこちら) rheb.hatenablog.com
-目次-
OpenJDKのコンテナイメージとベースイメージとの差分を確認する
前回の記事でOpenJDKのコンテナイメージはUBI-minimalがベースイメージに使用されていることが分かりました。
では、元のUBI-minimalとの差分を確認してみましょう。UBI-minimalをダウンロードしpodman image tree
を使ってレイヤーの差分を確認します。
今回もOpenJDKのコンテナイメージはregistry.access.redhat.com/ubi9/openjdk-21
を使用します。手元にない方はpodman pull
でコンテナイメージを入手してください。
$ podman pull registry.access.redhat.com/ubi9/openjdk-21 $ podman pull registry.access.redhat.com/ubi9/ubi-minimal $ podman images REPOSITORY TAG IMAGE ID CREATED SIZE registry.access.redhat.com/ubi9/openjdk-21 latest 985daf3b31fb 10 days ago 422 MB registry.access.redhat.com/ubi9/ubi-minimal latest d254c4a73500 11 days ago 104 MB $ podman image tree openjdk-21:latest Image ID: 985daf3b31fb Tags: [registry.access.redhat.com/ubi9/openjdk-21:latest] Size: 422.4MB Image Layers ├── ID: 256cf40975c5 Size: 104.3MB └── ID: 25d8d0ec0c6b Size: 318.1MB Top Layer of: [registry.access.redhat.com/ubi9/openjdk-21:latest]
ベースとなるUBI-minimalが104MB、その差分の318MB程がOpenJDK用として追加されたとわかります。
podman diff
コマンドで2つのコンテナイメージを比較します。
$ podman diff openjdk-21 ubi-minimal A /help.1 C /home A /home/default A /home/default/.bash_logout A /home/default/.bash_profile A /home/default/.bashrc A /home/default/.m2 A /home/default/.m2/settings.xml C /var C /var/run C /var/cache A /var/cache/ldconfig A /var/cache/ldconfig/aux-cache A /var/cache/libX11 A /var/cache/libX11/compose C /var/lib C /var/lib/rpm C /var/lib/rpm/.rpm.lock C /var/lib/rpm/rpmdb.sqlite C /var/lib/rpm/rpmdb.sqlite-shm C /var/lib/rpm/rpmdb.sqlite-wal C /var/lib/alternatives A /var/lib/alternatives/java_sdk_21 A /var/lib/alternatives/java_sdk_21_openjdk A /var/lib/alternatives/java_sdk_openjdk A /var/lib/alternatives/javac A /var/lib/alternatives/jre_21 A /var/lib/alternatives/jre_21_openjdk A /var/lib/alternatives/jre_openjdk C /var/lib/alternatives/libnssckbi.so A /var/lib/alternatives/java A /var/lib/alternatives/mvn ...
すごい量のログが出力されます。7,000行以上の差分があるようです。
$ podman diff openjdk-21 ubi-minimal | wc -l 7096
Red Hatが作成したコンテナイメージではありますが、UBI-minimalのベースイメージに対してかなりの追加ファイルがあるようです。 Javaを動かすだけなのにここまでの追加が必要なのか?とちょっと疑ってしまいます。 そこで、OpenJDK入りのコンテナイメージを自作してできる限りスリムにしたものと、Red Hat提供のものとを比較してみようと思います。
OpenJDK入りの自作コンテナイメージを作成する
Red Hatが提供するOpenJDKのコンテナイメージではなく、自分でビルドしたOpenJDK入りのコンテナイメージの作成を行います。
まず、UBI-minimalをベースイメージとして使用し、OpenJDKのみをインストールするContainerfileを作成します。
UBI-minimalのパッケージマネージャーはdnf
コマンドではなくmicrodnf
コマンドを使用します。
$ cat > Containerfile <<EOF FROM registry.access.redhat.com/ubi9/ubi-minimal RUN microdnf install java-21-openjdk --setopt install_weak_deps=0 --nodocs -y \ && microdnf clean all EOF
- OpenJDKはUBIリポジトリで配布されているパッケージのためサブスクライブされたRHELホスト以外でもインストール可能です
- 可能な限りサイズを小さくしたいので、依存関係の少ないパッケージを除外する
--setopt install_weak_deps=0
オプションと、ドキュメント類のインストールを行わない--nodocs
オプションを追加します
ubi-openjdk
というタグを指定して新しいコンテナイメージをビルドします。ビルド後にイメージのリストを表示します。OpenJDKのコンテナイメージよりもサイズを減らすことができました。
$ podman build -t ubi-openjdk . $ podman images REPOSITORY TAG IMAGE ID CREATED SIZE localhost/ubi-openjdk latest 4e2b302567f1 16 seconds ago 394 MB registry.access.redhat.com/ubi9/openjdk-21 latest 985daf3b31fb 10 days ago 422 MB registry.access.redhat.com/ubi9/ubi-minimal latest d254c4a73500 11 days ago 104 MB
作成したコンテナイメージのレイヤーを確認するとレイヤーが2つあります。
$ podman image tree ubi-openjdk Image ID: 4e2b302567f1 Tags: [localhost/ubi-openjdk:latest] Size: 394.1MB Image Layers ├── ID: 69d96fccdf6f Size: 104.3MB Top Layer of: [registry.access.redhat.com/ubi9/ubi-minimal:latest] └── ID: 3a36d880c1ec Size: 289.9MB Top Layer of: [localhost/ubi-openjdk:latest]
これらを1つにまとめてさらに容量を減らしてみます。ビルド時に--squash-all
を追加します。
$ podman build --squash-all -t ubi-openjdk-squash . $ podman images REPOSITORY TAG IMAGE ID CREATED SIZE localhost/ubi-openjdk-squash latest 70909257c076 4 seconds ago 384 MB localhost/ubi-openjdk latest 4e2b302567f1 About a minute ago 394 MB registry.access.redhat.com/ubi9/openjdk-21 latest 985daf3b31fb 10 days ago 422 MB registry.access.redhat.com/ubi9/ubi-minimal latest d254c4a73500 11 days ago 104 MB
先ほど作ったコンテナイメージより容量を減らすことができました。 さらにベースイメージを変更して容量の削減を目指してみます。
UBI-microを使ってOpenJDKのコンテナイメージを作成する
UBI-minimalよりサイズの小さいUBI-microを使ってみます。
UBI-microについては以前書いた記事がありますので、こちらを参考にしてください。 【UBI】Red Hatの新しい最軽量コンテナーイメージ:UBI Microの紹介 - 赤帽エンジニアブログ
なお、ここからはローカルホストにRHELを使用します。PodmanとBuildahが導入された環境を用意ください。
UBI-microを入手しサイズを確認します。UBI-minimalよりも小さいサイズであることが分かります。
$ cat /etc/redhat-release Red Hat Enterprise Linux release 9.4 (Plow) $ podman pull registry.access.redhat.com/ubi9/ubi-micro $ podman images REPOSITORY TAG IMAGE ID CREATED SIZE localhost/ubi-openjdk-squash latest 70909257c076 27 seconds ago 384 MB localhost/ubi-openjdk latest 4e2b302567f1 About a minute ago 394 MB registry.access.redhat.com/ubi9/openjdk-21 latest 985daf3b31fb 10 days ago 422 MB registry.access.redhat.com/ubi9/ubi-minimal latest d254c4a73500 11 days ago 104 MB registry.access.redhat.com/ubi9/ubi-micro latest 2d8598608a5d 2 weeks ago 24.7 MB
Buildahでマウントしたコンテナイメージに対話的にパッケージを追加します。ルートレスで実行する場合はユーザーネームスペースに入る必要があるためbuildah unshare
またはpodman unshare
を実行します。
$ buildah unshare # container=$(buildah from registry.access.redhat.com/ubi9/ubi-micro) # mnt=$(buildah mount $container) # dnf install --installroot $mnt --setopt install_weak_deps=false --nodocs java-21-openjdk -y # dnf clean all --installroot $mnt # buildah commit $container ubi-micro-openjdk
buildah from registry.access.redhat.com/ubi9/ubi-micro
:作業用コンテナの元イメージを指定しますbuildah mount $container
:作業用コンテナをファイルシステムにマウントしますdnf install --installroot $mnt
:マウントした領域に対してdnf
コマンドでパッケージのインストールを行いますbuildah commit $container
:buildah commit
コマンドを使ってコンテナイメージをコミットします。
作成したコンテナイメージを確認するとUBI-minimalベースの自作コンテナイメージよりも小さいイメージができました。
# podman images REPOSITORY TAG IMAGE ID CREATED SIZE localhost/ubi-micro-openjdk latest 0aef77730e2e 7 seconds ago 378 MB localhost/ubi-openjdk-squash latest 70909257c076 About a minute ago 384 MB localhost/ubi-openjdk latest 4e2b302567f1 2 minutes ago 394 MB registry.access.redhat.com/ubi9/openjdk-21 latest 985daf3b31fb 10 days ago 422 MB registry.access.redhat.com/ubi9/ubi-minimal latest d254c4a73500 11 days ago 104 MB registry.access.redhat.com/ubi9/ubi-micro latest 2d8598608a5d 2 weeks ago 24.7 MB
イメージレイヤーを確認すると2つのレイヤーがあります。これを1つにまとめて(squash)してさらに容量を削減します。
# podman image tree ubi-micro-openjdk:latest Image ID: 0aef77730e2e Tags: [localhost/ubi-micro-openjdk:latest] Size: 378.3MB Image Layers ├── ID: b7c370fe2e29 Size: 24.64MB Top Layer of: [registry.access.redhat.com/ubi9/ubi-micro:latest] └── ID: 7377f93815e2 Size: 353.7MB Top Layer of: [localhost/ubi-micro-openjdk:latest]
buildah commit
に--squash
オプションをつけて実行します。レイヤーが1つにまとめられ、さらに容量が減りました。
# buildah commit --squash $container ubi-micro-openjdk-squash # podman images REPOSITORY TAG IMAGE ID CREATED SIZE localhost/ubi-micro-openjdk-squash latest 507bfdf69b15 7 seconds ago 370 MB localhost/ubi-micro-openjdk latest 0aef77730e2e 39 seconds ago 378 MB localhost/ubi-openjdk-squash latest 70909257c076 2 minutes ago 384 MB localhost/ubi-openjdk latest 4e2b302567f1 3 minutes ago 394 MB registry.access.redhat.com/ubi9/openjdk-21 latest 985daf3b31fb 10 days ago 422 MB registry.access.redhat.com/ubi9/ubi-minimal latest d254c4a73500 11 days ago 104 MB registry.access.redhat.com/ubi9/ubi-micro latest 2d8598608a5d 2 weeks ago 24.7 MB # podman image tree ubi-micro-openjdk-squash Image ID: 507bfdf69b15 Tags: [localhost/ubi-micro-openjdk-squash:latest] Size: 369.7MB Image Layers └── ID: afb99d712887 Size: 369.7MB Top Layer of: [localhost/ubi-micro-openjdk-squash:latest]
ビルド作業が終わったので作業用コンテナを削除してユーザーネームスペースから抜けます。
# buildah rm -a # exit exit $
前回の記事と同様に、自作したコンテナイメージをベースイメージとして使ったjarファイルを実行するコンテナイメージをビルドします。
hello.jar
は前回作成したものを流用します。
$ cat > Containerfile <<EOF FROM ubi-micro-openjdk-squash COPY hello.jar /hello.jar EOF $ podman build -t java-test . $ podman images REPOSITORY TAG IMAGE ID CREATED SIZE localhost/java-test latest 8e82cd787a48 8 seconds ago 370 MB localhost/ubi-micro-openjdk-squash latest 507bfdf69b15 About a minute ago 370 MB localhost/ubi-micro-openjdk latest 0aef77730e2e About a minute ago 378 MB localhost/ubi-openjdk-squash latest 70909257c076 3 minutes ago 384 MB localhost/ubi-openjdk latest 4e2b302567f1 4 minutes ago 394 MB registry.access.redhat.com/ubi9/openjdk-21 latest 985daf3b31fb 10 days ago 422 MB registry.access.redhat.com/ubi9/ubi-minimal latest d254c4a73500 11 days ago 104 MB registry.access.redhat.com/ubi9/ubi-micro latest 2d8598608a5d 2 weeks ago 24.7 MB
作成したコンテナイメージを実行します。java
コマンドに続けて-jar
オプションと実行するファイル(コンテナ内のパスを指定)を指定してコンテナを実行します。
$ podman run --rm java-test java -jar /hello.jar Hello, World!
期待通りにHello Worldが実行されました。
このようにシンプルなjarファイルを1つ実行するだけなら自作のコンテナイメージを作るのとOpenJDKのコンテナイメージを使うのとでは大した差はありません。 むしろRed Hat提供のOpenJDKのコンテナイメージは決められたディレクトリに配置するだけでjarファイルを読み込んでくれたり、S2Iが実行できたり、チューニング用の環境変数がいろいろ使えたりなど、より実務で使うために必要な機能が豊富に盛り込まれています。 その機能の豊富さとコンテナイメージを自作しメンテナンスする手間を比べた場合のメリットがどれほどのものかをよく考える必要があります。
まとめ
OpenJDKのコンテナイメージについて、使用されているベースイメージやイメージのレイヤー、イメージのサイズという観点で深堀りしてみました。 イメージのサイズが小さいということはコンテナのライフサイクルにおけるPushやPull(それらに伴う圧縮解凍)といった作業時間の軽減に寄与します。 また、コンテナレジストリやローカルストレージの保存領域の観点でも容量削減が見込めますが、昨今のストレージの規模から考えたらそこまで気にする点でもありません。 さらに、コンテナプロセスのリソース消費やコンテナの起動速度は実行するアプリに依存するため、コンテナサイズが直接的に影響するものではありません。
コンテナのサイズは利便性とのバランスになります。UBI-microはサイズが小さく、またパッケージの追加更新作業は手間がかかりますが、静的リンクでコンパイルされた実行バイナリをコピーするだけの用途ではとても有用です。Red Hatが提供するOpenJDKのコンテナイメージはS2IやJavaアプリの自動実行に対応し、さらにRed Hatがコンテナイメージのメンテナンスもして容量もそこそこ小さいです。 自作のコンテナイメージと比較するとRed Hatが提供するOpenJDKのコンテナイメージを活用する利点は十分あると考えます。
Red Hatが提供するOpenJDKのコンテナイメージはよく考えられて作られているので、みなさんどんどん活用しましょう!