Java アプリの docker イメージが、ある時期から倍程度にサイズが膨らんでいるのに気づきました。
現象
ベースは openjdk:13-jdk で、以下の Dockerfile を利用していました。
★印は、アプリで日本語が表示されない問題に対応するため、locale 設定を追加したものです。
この時点でベースのと、ビルドしたイメージのサイズは以下のとおり。
-
openjdk:13-jdk→ 491 MB - ビルド結果 → 1.04 GB
FROM openjdk:13-jdk
RUN yum -y reinstall glibc-common ★glibc を入れ直し
RUN localedef -f UTF-8 -i ja_JP ja_JP.UTF-8 ★locale を設定
ENV LANG="ja_JP.UTF-8" \ ★言語設定
LANGUAGE="ja_JP:ja" \
LC_ALL="ja_JP.UTF-8"
...
以下、アプリ用設定。
解析
ビルドしたイメージを見てみると /var/cahce/yum の下の yum キャッシュが膨らんでいるようだったので、glibc インストール後にキャッシュを削除。
$ docker run --rm -it test-openjdk:latest bash
FROM openjdk:13-jdk
RUN yum -y reinstall glibc-common
RUN yum clean all ★キャッシュ削除
RUN localedef -f UTF-8 -i ja_JP ja_JP.UTF-8
ENV LANG="ja_JP.UTF-8" \
LANGUAGE="ja_JP:ja" \
LC_ALL="ja_JP.UTF-8"
...
以下、アプリ用設定。
でも、あまり変わらない。
さらにイメージ内のディレクトリサイズを見ていくと、/usr/lib、/usr/share で 100 MB ほど増加しています。
これらは locale 関連のファイルでした。
## ベース(openjdk:13-jdk)
# du -sm /*
0 /bin
:
463 /usr ★
11 /var
## ビルドイメージ
# du -sm /*
0 /bin
:
613 /usr ★
12 /var
## ベース(openjdk:13-jdk)
# du -sm /usr/*
27 /usr/bin
0 /usr/etc
0 /usr/games
1 /usr/include
316 /usr/java
9 /usr/lib ★
75 /usr/lib64
1 /usr/libexec
0 /usr/local
5 /usr/sbin
34 /usr/share ★
0 /usr/src
0 /usr/tmp
## ビルドイメージ
# du -sm /usr/*
27 /usr/bin
0 /usr/etc
0 /usr/games
1 /usr/include
316 /usr/java
107 /usr/lib ★
75 /usr/lib64
1 /usr/libexec
0 /usr/local
5 /usr/sbin
47 /usr/share ★
0 /usr/src
0 /usr/tmp
ちなみに glibc を入れ直すと、locale に多言語分の設定が入るようです。
必要なのは日本語、英語なので不要な言語の設定を除去できないか考えます。
以下のサイトを参考に locale のスリム化を図ります。
CentOS 7 の不要な言語(locale)を削除する
https://qiita.com/bezeklik/items/a8274bb230f2efa61ffa
locale情報のスリム化(locale-archiveとか)
http://blog.livedoor.jp/centosnotes/archives/3085708.html
# localedef --list-archive | egrep --invert-match --ignore-case '^(ja|en_US)' | xargs localedef --delete-from-archive
# localedef --list-archive
en_US
en_US.iso88591
en_US.iso885915
en_US.utf8
ja_JP
ja_JP.eucjp
ja_JP.ujis
ja_JP.utf8
japanese
japanese.euc
★英語、日本語以外が削除されている
# cp -p /usr/lib/locale/locale-archive /usr/lib/locale/locale-archive.tmpl
# build-locale-archive --verbose ★locale アーカイブを再作成
input archive file: /usr/lib/locale/locale-archive.tmpl
input alias file: /usr/share/locale/locale.alias
input locale directory prefix: /usr/lib/locale/
output archive file: /usr/lib/locale/locale-archive
# ( cd /usr/share/locale && ls -1 | egrep -v '^(default|en|ja|locale)' | xargs rm -rf ) ★/usr/share 以下をスリム化
# du -sm /usr/*
27 /usr/bin
:
316 /usr/java
10 /usr/lib ★107MB → 10MB へ削減
75 /usr/lib64
:
33 /usr/share ★47MB → 33MB へ削減
:
これでサイズ減らせそうなので、Dockerfile を以下のように変更。
FROM openjdk:13-jdk
RUN yum -y reinstall glibc-common
RUN yum clean all
RUN localedef --list-archive | egrep --invert-match --ignore-case '^(ja|en_US)' | xargs localedef --delete-from-archive \
&& cp -p /usr/lib/locale/locale-archive /usr/lib/locale/locale-archive.tmpl \
&& build-locale-archive --verbose ★locale の不要言語削除
RUN cd /usr/share/locale && ls -1 | egrep -v '^(default|en|ja|locale)' | xargs rm -rf
★/usr/share 以下の不要言語削除
RUN localedef -f UTF-8 -i ja_JP ja_JP.UTF-8
ENV LANG="ja_JP.UTF-8" \
LANGUAGE="ja_JP:ja" \
LC_ALL="ja_JP.UTF-8"
...
以下、アプリ用設定。
あれ?
やっぱり、サイズがあまり変わらない。。
そもそも、イメージ内で du で計上したサイズでは 100MB 前後しか差がないのに、docker イメージで倍近くの差があるのがおかしいのでは?
対処
docker イメージは Dockerfile の各行(RUN など) の変更履歴が蓄積されるので、glibc インストールだけで完結させると中間状態も残ってしまうのを失念していました。。
なので、以下のように glibc からキャッシュ削除、不要言語の削除までを1行にまとめました。
FROM openjdk:13-jdk
RUN yum -y reinstall glibc-common \
&& yum clean all \
&& localedef --list-archive | egrep --invert-match --ignore-case '^(ja|en_US)' | xargs localedef --delete-from-archive \
&& cp -p /usr/lib/locale/locale-archive /usr/lib/locale/locale-archive.tmpl \
&& build-locale-archive --verbose \
&& cd /usr/share/locale \
&& ls -1 | egrep -v '^(default|en|ja|locale)' | xargs rm -rf
RUN localedef -f UTF-8 -i ja_JP ja_JP.UTF-8
ENV LANG="ja_JP.UTF-8" \
LANGUAGE="ja_JP:ja" \
LC_ALL="ja_JP.UTF-8"
...
以下、アプリ用設定。
docker history コマンドで各行の変更履歴が確認できるので、以下のように比較してみました。
glib インストールの差分を削減できていることが分かります。
## スリム化失敗のイメージ
$ docker history test-openjdk:latest
IMAGE CREATED CREATED BY SIZE COMMENT
32d236a955d3 20 hours ago /bin/sh -c #(nop) ENV LANG=ja_JP.UTF-8 LANG… 0B
45f72f6b6ff1 20 hours ago /bin/sh -c localedef -f UTF-8 -i ja_JP ja_JP… 106MB ★
95424705b975 20 hours ago /bin/sh -c yum clean all 8.55MB ★
5f2e315ac96c 20 hours ago /bin/sh -c yum -y reinstall glibc-common 397MB ★
ff31919fd91c 8 months ago /bin/sh -c #(nop) CMD ["jshell"] 0B
<missing> 8 months ago /bin/sh -c set -eux; curl -fL -o /openjdk.… 330MB
:
## スリム化したイメージ
$ docker history test-openjdk:slim
IMAGE CREATED CREATED BY SIZE COMMENT
f3de5895d121 19 hours ago /bin/sh -c #(nop) ENV LANG=ja_JP.UTF-8 LANG… 0B
a9b5dc6c04a7 19 hours ago /bin/sh -c localedef -f UTF-8 -i ja_JP ja_JP… 4MB ★
d2196a62443d 19 hours ago /bin/sh -c yum -y reinstall glibc-common … 23.3MB ★
ff31919fd91c 8 months ago /bin/sh -c #(nop) CMD ["jshell"] 0B
<missing> 8 months ago /bin/sh -c set -eux; curl -fL -o /openjdk.… 330MB
:
最終的に以下のように 520 MB くらいに抑えることができました。
(それでも Java のイメージはでかい。。)
$ docker image ls
test-openjdk latest 32d236a955d3 20 hours ago 1GB ★スリム化失敗
test-openjdk slim f3de5895d121 19 hours ago 518MB ★スリム化成功
openjdk 13-jdk ff31919fd91c 8 months ago 491MB
// EOF