[docker][locale][JDK] とあるコンテナの Java 実行環境

Java アプリの docker イメージが、ある時期から倍程度にサイズが膨らんでいるのに気づきました。

## 現象

ベースは `openjdk:13-jdk` で、以下の Dockerfile を利用していました。
★印は、アプリで日本語が表示されない問題に対応するため、locale 設定を追加したものです。

この時点でベースのと、ビルドしたイメージのサイズは以下のとおり。

- `openjdk:13-jdk` → 491 MB
- ビルド結果    → 1.04 GB


```Dockerfile
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
```

```Dockerfile
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 を以下のように変更。

```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 からキャッシュ削除、不要言語の削除までを１行にまとめました。

```Dockerfile
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