LoginSignup
14
7

More than 5 years have passed since last update.

OpenJDK11のdokcerイメージ(1GB)が大きいのでalpine linux+ jlinkで小さいイメージ(85MB)を作成する

Last updated at Posted at 2018-08-14

はじめに

openjdk 11のdocker imageは、docker hubのofficial respoitoryで公開されています。

ただ・・・これを使う上でちょっと気になるのが、

  • イメージサイズがそもそも大きい。約1GBもあります。
  • jlinkを使っても、300MB以上ある

という問題があります。もっと小さくしたいな。という所で、どれくらい小さくできるか試してみました!

前提

  • Java Flight Recorderが動くこと
  • Spring Boot アプリケーションが動くこと

結果

1GB→85MBと1/10以下に圧縮できました:grinning:
個人的には大満足です。

docker images でサイズを確認した結果は下記の通りです。

imageの種類 jlink使用 size
openjdk:11-jdk しない 1GB
openjdk:11-jdk する 468MB
独自alpinelinux しない 336MB
独自alpinelinux する 84.6MB

jdk11はea版です。そのうちちゃんとopenjdk 11のofficial imageでも小さいイメージが作れるようになると思います。
独自alpinelinuxは、
 https://hub.docker.com/r/hirokimatsumoto/alpine-openjdk-11/
です。

問題

OpenJDK 11のofficial imageの問題を詳細に記載します。

イメージサイズが大きい

$ sudo docker images |grep jdk
docker.io/openjdk                            11-jdk   f684efd78557  2 weeks ago         979 MB
$

jreではちょっとflightrecorderが動かないので、jdkを使いたいのに・・・ちょっと大きすぎます。
参考:Qiita - OpenJDK11-JRE-SLIMじゃFlightRecorderは動きません。

openjdk 11(official)ではjlink使っても小さくならない。

下記issueでも同じ問題を取り上げています。
https://github.com/docker-library/openjdk/issues/217

試しにやると・・・下記のようになぜか400MBほどになり、imageサイズも450MBくらいになってしまいます。

$ docker run -it --rm openjdk:11-jdk /bin/sh
# ls -l /usr/lib/jvm/java-11-openjdk-amd64/lib/server/
total 34944
-rw-r--r-- 1 root root     1322 Jul 27 03:41 Xusage.txt
-r--r--r-- 1 root root 18210816 Jul 27 22:22 classes.jsa
-rw-r--r-- 1 root root    14440 Jul 27 03:41 libjsig.so
-rw-r--r-- 1 root root 17551048 Jul 27 03:41 libjvm.so  #まだ小さい
圧縮してみる
# jlink \
     --module-path /opt/java/jmods \
     --compress=2 \
     --add-modules java.base,java.logging,jdk.jfr  \
     --no-header-files \
     --no-man-pages \
     --output /opt/jdk-11-mini-runtime
#  ls -l /opt/jdk-11-mini-runtime/lib/server/
total 414452
-rw-r--r-- 1 root root      1322 Aug 14 09:41 Xusage.txt
-rw-r--r-- 1 root root     25384 Aug 14 09:41 libjsig.so
-rw-r--r-- 1 root root 424362808 Aug 14 09:41 libjvm.so #なんでや・・・
#

イメージサイズ小さくするぞ!

alpine linuxを使う、そしてjlinkを使って小さくするというアプローチをとってみます。

alpine linuxのベースのbuild用イメージを作成する。

他の人でも約に立つかな?と思って公開してます。

image: https://hub.docker.com/r/hirokimatsumoto/alpine-openjdk-11/
docker file: https://hub.docker.com/r/hirokimatsumoto/alpine-openjdk-11/~/dockerfile/

checksumしてなくてすみません…。

jlinkを使って小さい実行イメージを作る。

multi stageを使ってビルドします。

  1. 上記で作ったalpine linux + openjdk 11のimageをベースに、jlinkで小さいjava runtime moduleを作成します。
  2. runtime module、jar moduleをコピーしたalphine linuxのimageを作成します。
FROM hirokimatsumoto/alpine-openjdk-11:latest as jlink-package
# First: generate java runtime module by jlink.

RUN jlink \
     --module-path /opt/java/jmods \
     --compress=2 \
     --add-modules jdk.jfr,jdk.management.agent,java.base,java.logging,java.xml,jdk.unsupported,java.sql,java.naming,java.desktop,java.management,java.security.jgss,java.instrument \
     --no-header-files \
     --no-man-pages \
     --output /opt/jdk-11-mini-runtime

# Second: generate run image.
FROM alpine:3.8

ENV JAVA_HOME=/opt/jdk-11-mini-runtime
ENV PATH="$PATH:$JAVA_HOME/bin"

COPY --from=jlink-package /opt/jdk-11-mini-runtime /opt/jdk-11-mini-runtime
COPY target/k8s-jmc-sample-0.1.0-SNAPSHOT.jar /opt/spring-boot/

EXPOSE 30001 7199
CMD java \
    -XX:StartFlightRecording=name=sample,filename=/spring-boot/jfr/sample.jfr,delay=30s,maxage=2h,maxsize=10m,dumponexit=true,settings=/spring-boot/config/profile.jfc \
    -Dcom.sun.management.jmxremote.port=7199 \
    -Dcom.sun.management.jmxremote.rmi.port=7199 \
    -Dcom.sun.management.jmxremote.authenticate=false \
    -Dcom.sun.management.jmxremote.ssl=false \
    -jar /opt/spring-boot/k8s-jmc-sample-0.1.0-SNAPSHOT.jar \
    --server.port=${SPRING_SERVER_PORT} \
    --spring.config.location=/spring-boot/config/application.yaml

実行アプリケーションは、
https://github.com/h-r-k-matsumoto/k8s-jmc-sample
です。

ハマったこと

Spring Bootアプリケーションをjdepsで依存関係見ても正確ではない

最初jdepsを使い、下記のように必要なmoduleを確認してました。

> jdeps --list-deps .\target\k8s-jmc-sample-0.1.0-SNAPSHOT.jar
   java.base
   java.logging
>

これでruntime作っても・・・実行時に、下記のようにエラーになります。

Caused by: java.lang.ClassNotFoundException: java.sql.SQLException
        at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:471)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:588)
        at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:93)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)

うーん、spring boot内部でauto configurationしている箇所は上手く追跡できないのかな・・・。
めんどくさかったので、
 https://dev.solita.fi/2018/01/24/Java9-modules-Spring-Boot-2-Docker.html
みて適当に追加しました。

参考

14
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
7