Spring Boot 2.3のDocker Supportを試す

[Spring Boot 2.3.0](https://spring.io/blog/2020/05/15/spring-boot-2-3-0-available-now)の新機能としてDocker Supportがあったので試してみました。
環境は

* Mac 10.15.4
* Docker 19.03.8

です。

## 使用方法

使い方としてはMavenだと以下を実行するだけです。

```
$ mvn spring-boot:build-image
[INFO] Scanning for projects...
[INFO] 
[INFO] ------------------------------------------------------------------------
[INFO] Building demo 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
︙
︙
︙
[INFO] --- spring-boot-maven-plugin:2.3.0.RELEASE:build-image (default-cli) @ demo ---
[INFO] Building image 'docker.io/library/demo:0.0.1-SNAPSHOT'
[INFO] 
[INFO]  > Pulling builder image 'gcr.io/paketo-buildpacks/builder:base-platform-api-0.3' 100%
[INFO]  > Pulled builder image 'gcr.io/paketo-buildpacks/builder@sha256:7996dd44d157f656bdea4f1063760ad8d4eae2dd41465f7fe6bf720f5b25ca4d'
[INFO]  > Pulling run image 'gcr.io/paketo-buildpacks/run:base-cnb' 100%
[INFO]  > Pulled run image 'gcr.io/paketo-buildpacks/run@sha256:15bccd9803f63b20a38a6834821a74d9c3949eb475cf759446047dc9586ca2a9'
[INFO]  > Executing lifecycle version v0.7.5
[INFO]  > Using build cache volume 'pack-cache-5cbe5692dbc4.build'
[INFO] 
[INFO]  > Running creator
[INFO]     [creator]     ---> DETECTING
[INFO]     [creator]     5 of 15 buildpacks participating
[INFO]     [creator]     paketo-buildpacks/bellsoft-liberica 2.5.3
[INFO]     [creator]     paketo-buildpacks/executable-jar    1.2.3
[INFO]     [creator]     paketo-buildpacks/apache-tomcat     1.1.3
[INFO]     [creator]     paketo-buildpacks/dist-zip          1.3.0
[INFO]     [creator]     paketo-buildpacks/spring-boot       1.5.3
[INFO]     [creator]     ---> ANALYZING
[INFO]     [creator]     Previous image with name "docker.io/library/demo:0.0.1-SNAPSHOT" not found
[INFO]     [creator]     ---> RESTORING
[INFO]     [creator]     ---> BUILDING
[INFO]     [creator]     
[INFO]     [creator]     Paketo BellSoft Liberica Buildpack 2.5.3
[INFO]     [creator]         Set $BPL_JVM_HEAD_ROOM to configure the headroom in memory calculation. Default 0.
[INFO]     [creator]         Set $BPL_JVM_LOADED_CLASS_COUNT to configure the number of loaded classes in memory calculation. Default 35% of classes.
[INFO]     [creator]         Set $BPL_JVM_THREAD_COUNT to configure the number of threads in memory calculation. Default 250.
[INFO]     [creator]         Set $BP_JVM_VERSION to configure the Java version. Default 11.*.
[INFO]     [creator]       BellSoft Liberica JRE 11.0.7: Contributing to layer
[INFO]     [creator]         Downloading from https://github.com/bell-sw/Liberica/releases/download/11.0.7+10/bellsoft-jre11.0.7+10-linux-amd64.tar.gz
[INFO]     [creator]         Verifying checksum
[INFO]     [creator]         Expanding to /layers/paketo-buildpacks_bellsoft-liberica/jre
[INFO]     [creator]         Writing env.launch/JAVA_HOME.override
[INFO]     [creator]         Writing env.launch/MALLOC_ARENA_MAX.override
[INFO]     [creator]         Writing profile.d/active-processor-count.sh
[INFO]     [creator]       Memory Calculator 4.0.0: Contributing to layer
[INFO]     [creator]         Downloading from https://github.com/cloudfoundry/java-buildpack-memory-calculator/releases/download/v4.0.0/memory-calculator-4.0.0.tgz
[INFO]     [creator]         Verifying checksum
[INFO]     [creator]         Expanding to /layers/paketo-buildpacks_bellsoft-liberica/memory-calculator
[INFO]     [creator]         Writing profile.d/memory-calculator.sh
[INFO]     [creator]       Class Counter: Contributing to layer
[INFO]     [creator]         Copying to /layers/paketo-buildpacks_bellsoft-liberica/class-counter
[INFO]     [creator]       JVMKill Agent 1.16.0: Contributing to layer
[INFO]     [creator]         Downloading from https://github.com/cloudfoundry/jvmkill/releases/download/v1.16.0.RELEASE/jvmkill-1.16.0-RELEASE.so
[INFO]     [creator]         Verifying checksum
[INFO]     [creator]         Copying to /layers/paketo-buildpacks_bellsoft-liberica/jvmkill
[INFO]     [creator]         Writing env.launch/JAVA_OPTS.append
[INFO]     [creator]       Link-Local DNS: Contributing to layer
[INFO]     [creator]         Copying to /layers/paketo-buildpacks_bellsoft-liberica/link-local-dns
[INFO]     [creator]         Writing profile.d/link-local-dns.sh
[INFO]     [creator]       Java Security Properties: Contributing to layer
[INFO]     [creator]         Writing env.launch/JAVA_OPTS.append
[INFO]     [creator]         Writing env.launch/JAVA_SECURITY_PROPERTIES.override
[INFO]     [creator]       Security Providers Configurer: Contributing to layer
[INFO]     [creator]         Copying to /layers/paketo-buildpacks_bellsoft-liberica/security-providers-configurer
[INFO]     [creator]         Writing profile.d/security-providers-classpath.sh
[INFO]     [creator]         Writing profile.d/security-providers-configurer.sh
[INFO]     [creator]       OpenSSL Security Provider 1.0.2: Contributing to layer
[INFO]     [creator]         Downloading from https://jitpack.io/com/github/paketo-buildpacks/openssl-security-provider/1.0.2/openssl-security-provider-1.0.2.jar
[INFO]     [creator]         Verifying checksum
[INFO]     [creator]         Copying to /layers/paketo-buildpacks_bellsoft-liberica/openssl-security-provider
[INFO]     [creator]         Writing env.launch/SECURITY_PROVIDERS.append
[INFO]     [creator]         Writing env.launch/SECURITY_PROVIDERS_CLASSPATH
[INFO]     [creator]         Writing profile.d/openssl-security-provider.sh
[INFO]     [creator]     
[INFO]     [creator]     Paketo Executable JAR Buildpack 1.2.3
[INFO]     [creator]         Writing env.launch/CLASSPATH
[INFO]     [creator]       Process types:
[INFO]     [creator]         executable-jar: java -cp "${CLASSPATH}" ${JAVA_OPTS} org.springframework.boot.loader.JarLauncher
[INFO]     [creator]         task:           java -cp "${CLASSPATH}" ${JAVA_OPTS} org.springframework.boot.loader.JarLauncher
[INFO]     [creator]         web:            java -cp "${CLASSPATH}" ${JAVA_OPTS} org.springframework.boot.loader.JarLauncher
[INFO]     [creator]     
[INFO]     [creator]     Paketo Spring Boot Buildpack 1.5.3
[INFO]     [creator]       Image labels:
[INFO]     [creator]         org.opencontainers.image.title
[INFO]     [creator]         org.opencontainers.image.version
[INFO]     [creator]         org.springframework.boot.spring-configuration-metadata.json
[INFO]     [creator]         org.springframework.boot.version
[INFO]     [creator]     ---> EXPORTING
[INFO]     [creator]     Adding layer 'launcher'
[INFO]     [creator]     Adding layer 'paketo-buildpacks/bellsoft-liberica:class-counter'
[INFO]     [creator]     Adding layer 'paketo-buildpacks/bellsoft-liberica:java-security-properties'
[INFO]     [creator]     Adding layer 'paketo-buildpacks/bellsoft-liberica:jre'
[INFO]     [creator]     Adding layer 'paketo-buildpacks/bellsoft-liberica:jvmkill'
[INFO]     [creator]     Adding layer 'paketo-buildpacks/bellsoft-liberica:link-local-dns'
[INFO]     [creator]     Adding layer 'paketo-buildpacks/bellsoft-liberica:memory-calculator'
[INFO]     [creator]     Adding layer 'paketo-buildpacks/bellsoft-liberica:openssl-security-provider'
[INFO]     [creator]     Adding layer 'paketo-buildpacks/bellsoft-liberica:security-providers-configurer'
[INFO]     [creator]     Adding layer 'paketo-buildpacks/executable-jar:class-path'
[INFO]     [creator]     Adding 1/1 app layer(s)
[INFO]     [creator]     Adding layer 'config'
[INFO]     [creator]     *** Images (3f95a912b231):
[INFO]     [creator]           docker.io/library/demo:0.0.1-SNAPSHOT
[INFO] 
[INFO] Successfully built image 'docker.io/library/demo:0.0.1-SNAPSHOT'
[INFO] 
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 05:06 min
[INFO] Finished at: 2020-05-16T06:00:03+09:00
[INFO] Final Memory: 47M/150M
[INFO] ------------------------------------------------------------------------
```

これでDockerイメージが出来上がるのですが、確認すると「あれ？無い」とちょっと焦りました。
新しく作成されたイメージが先頭に表示される筈なのが、よく見たら末尾にありました。
何故かCREATEDが40年前です。。。

```
$ sudo docker images
REPOSITORY                         TAG                     IMAGE ID            CREATED             SIZE
gcr.io/paketo-buildpacks/run       base-cnb                41080a961a76        31 hours ago        71.1MB
︙
demo                               0.0.1-SNAPSHOT          3f95a912b231        40 years ago        262MB
gcr.io/paketo-buildpacks/builder   base-platform-api-0.3   2ca41db2c654        40 years ago        894MB
```

作成されるDockerイメージのリポジトリ名はpom.xmlに書いたartifactIdが、バージョンはversionが使われるようです。

なお、

* gcr.io/paketo-buildpacks/builder:base-platform-api-0.3
    * Dockerイメージを作成するビルダーで、org.springframework.boot:spring-boot-maven-plugin:2.3.0.RELEASEに定義されているデフォルトのビルダーです。
* gcr.io/paketo-buildpacks/run:base-cnb
    * demo:0.0.1-SNAPSHOTのレイヤーのハッシュ値と照合した結果から、これが基底のイメージです。

でした。

あとはお好みのオプションで起動するだけです。

```
$ sudo docker run -d -p 8080:8080 demo:0.0.1-SNAPSHOT
```

## コンテナ内部
リリース通知にも書いてありましたが、このDocker Supportは[Paket Buildpacks](https://paketo.io/)を利用しています。
実行中のコンテナに入ってみます。

* OS
 
```
$ cat /etc/debian_version 
buster/sid
```
Debian 10でした。


* プロセス

```
＄ ps auxww
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
cnb          1  1.6  7.4 1150548 151396 ?      Ssl  02:47   0:16 java -cp /workspace:/layers/paketo-buildpacks_bellsoft-liberica/openssl-security-provider/openssl-security-provider-1.0.2.jar -Djava.security.properties=/layers/paketo-buildpacks_bellsoft-liberica/java-security-properties/java-security.properties -agentpath:/layers/paketo-buildpacks_bellsoft-liberica/jvmkill/jvmkill-1.16.0-RELEASE.so=printHeapHistogram=1 -XX:ActiveProcessorCount=4 -XX:MaxDirectMemorySize=10M -XX:MaxMetaspaceSize=88261K -XX:ReservedCodeCacheSize=240M -Xss1M -Xmx448314K -Dio.paketo.openssl.ca-certificates=/etc/ssl/certs/ca-certificates.crt org.springframework.boot.loader.JarLauncher
︙
$ ls /workspace
BOOT-INF  META-INF  org

```

workspaceフォルダにSpring Bootのjarが解凍された状態で格納されてました。


## Java VMオプションを指定する
今までは手動でDockerfileを書いていたので、-Dspring.profiles.active=productionでSpringのプロファイルを切り替えてました。
しかし、mvn spring-boot:build-imageではDockerfileが不要なのでプロファイルの変更方法が判りません。
[Spring Boot Maven Plugin Documentation](https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/html/#goals-build-image)にも、それらしきカスタマイズ方法が見つかりませんでした。

* [こちらを参考](https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/html/#build-image-example-builder-configuration)にJAVA_OPTSを指定してみたのですが、駄目でした。

試行錯誤の末、単に docker run時の環境変数オプションとして JAVA_OPTS を指定することで実現できることが判りました。

```
$ sudo docker run -d -p 8080:8080 -e JAVA_OPTS=-Dspring.profiles.active=production  demo:0.0.1-SNAPSHOT
b495ca243276a485317fd4b392cdf0f446224e62ed935cc745371cdd8c398d4c
$ sudo docker exec -it b495ca243276 bash
$ ps auxww
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
cnb          1 21.1  8.3 1153308 170592 ?      Ssl  07:01   0:11 java -cp /workspace:/layers/paketo-buildpacks_bellsoft-liberica/openssl-security-provider/openssl-security-provider-1.0.2.jar -Dspring.profiles.active=production -Djava.security.properties=/layers/paketo-buildpacks_bellsoft-liberica/java-security-properties/java-security.properties -agentpath:/layers/paketo-buildpacks_bellsoft-liberica/jvmkill/jvmkill-1.16.0-RELEASE.so=printHeapHistogram=1 -XX:ActiveProcessorCount=4 -XX:MaxDirectMemorySize=10M -XX:MaxMetaspaceSize=88261K -XX:ReservedCodeCacheSize=240M -Xss1M -Xmx448314K -Dio.paketo.openssl.ca-certificates=/etc/ssl/certs/ca-certificates.crt org.springframework.boot.loader.JarLauncher
```

他のオプションが上書きされずに -Dspring.profiles.active=production が追加されていることも確認できました。