Buildpackでjavaのバージョンエラーにハマる

先日SpringBootで作成したコードをBuildpackを使用しコンテナイメージ化したのですが、その際にちょっとしたエラーにハマったのでこちらで紹介させて頂きます。

環境およびソースコード
=
今回は開発用環境とビルド用環境を別に作成しています。
それぞれ以下の通りです。

**■環境：開発環境**
* IDE：Spring Tool Suite 4 (Version: 4.13.0.RELEASE)
* java：java version "17" 2021-09-14 LTS

**■環境：ビルド環境**
* Docker：Docker version 20.10.17, build 100c701
* java：なし

**■プロジェクト構成**
```xml:pom.xml(修正前)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.6.2</version>
		<relativePath/>
	</parent>
	<groupId>com.api</groupId>
	<artifactId>apiProject</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>apiProject</name>
	<description>MicroService Demo project for Spring Boot</description>

	<properties>
		<java.version>17</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jdbc</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jdbc</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.postgresql</groupId>
			<artifactId>postgresql</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>io.projectreactor</groupId>
			<artifactId>reactor-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>
```


STS上でMavenビルド
=
まずはMavenで問題なくビルドできるか、STSで試してみます。
「Run as」＞「Maven Build」でいざ実行。
![結果.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3036138/91aff011-61f5-d045-3622-6c1540fe4b4d.png)
問題なくビルドが完了しました。
ではここからが本番です。コンテナイメージ化していきます。

Buildpack実行
=
packコマンドをインストールした端末にコードを持っていき、いざ実行！！！

```filename:エラー内容(抜粋)
[root@dev-docker-01 apiProject]# pack build tmc-devops/api-project:latest --builder paketobuildpacks/builder:base

//省略

Paketo Buildpack for CA Certificates 3.5.1
  https://github.com/paketo-buildpacks/ca-certificates
  Launch Helper: Reusing cached layer

Paketo Buildpack for BellSoft Liberica 9.10.1
  https://github.com/paketo-buildpacks/bellsoft-liberica
  Build Configuration:
    $BP_JVM_JLINK_ARGS           --no-man-pages --no-header-files --strip-debug --compress=1  configure custom link arguments (--output must be omitted)
    $BP_JVM_JLINK_ENABLED        false                                                        enables running jlink tool to generate custom JRE
    $BP_JVM_TYPE                 JRE                                                          the JVM type - JDK or JRE
    $BP_JVM_VERSION              11                                                           the Java version
  Launch Configuration:
    $BPL_DEBUG_ENABLED           false                                                        enables Java remote debugging support
    $BPL_DEBUG_PORT              8000                                                         configure the remote debugging port
    $BPL_DEBUG_SUSPEND           false                                                        configure whether to suspend execution until a debugger has attached
    $BPL_HEAP_DUMP_PATH                                                                       write heap dumps on error to this path
    $BPL_JAVA_NMT_ENABLED        true                                                         enables Java Native Memory Tracking (NMT)
    $BPL_JAVA_NMT_LEVEL          summary                                                      configure level of NMT, summary or detail
    $BPL_JFR_ARGS                                                                             configure custom Java Flight Recording (JFR) arguments
    $BPL_JFR_ENABLED             false                                                        enables Java Flight Recording (JFR)
    $BPL_JMX_ENABLED             false   
                                                   
//省略

  Compiled Application: Contributing to layer
    Executing mvnw --batch-mode -Dmaven.test.skip=true --no-transfer-progress package
      [INFO] Scanning for projects...
      [INFO]
      [INFO] -------------------------< com.api:apiProject >-------------------------
      [INFO] Building apiProject 0.0.1-SNAPSHOT
      [INFO] --------------------------------[ jar ]---------------------------------
      [INFO]
      [INFO] --- maven-resources-plugin:3.2.0:resources (default-resources) @ apiProject ---
      [INFO] Using 'UTF-8' encoding to copy filtered resources.
      [INFO] Using 'UTF-8' encoding to copy filtered properties files.
      [INFO] Copying 1 resource
      [INFO] Copying 0 resource
      [INFO]
      [INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ apiProject ---
      [INFO] Changes detected - recompiling the module!
      [INFO] Compiling 4 source files to /workspace/target/classes
      [INFO] ------------------------------------------------------------------------
      [INFO] BUILD FAILURE
      [INFO] ------------------------------------------------------------------------
      [INFO] Total time:  1.889 s
      [INFO] Finished at: 2022-12-13T07:27:10Z
      [INFO] ------------------------------------------------------------------------
      [ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project apiProject: Fatal error compiling: error: invalid target release: 17 -> [Help 1]
      [ERROR]
      [ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
      [ERROR] Re-run Maven using the -X switch to enable full debug logging.
      [ERROR]
      [ERROR] For more information about the errors and possible solutions, please read the following articles:
      [ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException
      unable to invoke layer creator
unable to contribute application layer
error running build
exit status 1
ERROR: failed to build: exit status 1
ERROR: failed to build: executing lifecycle: failed with status code: 51
[root@dev-docker-01 apiProject]#
```

結果：**なぜかエラーに…**

なぜだろうと内心はうろたえつつ、ログを見つめなおします。
すると気になる一文が…
```
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project apiProject: Fatal error compiling: error: invalid target release: 17 -> [Help 1]
```
→**17はターゲットではない？？？**

pom.xmlを確認すると、
```
	<properties>
		<java.version>17</java.version>
	</properties>
```
17が指定されています。
恐らくここの指定javaバージョンととビルドマシンのjavaバージョンが異なるが故に発生しているようです。

そこでふと思う。
**「あれ？ビルド用マシンってjavaのバージョンなんだっけ？？
　…そもそもjavaって入ってたっけ？？」**
```
-bash: java: コマンドが見つかりません
```
入ってませんでした。

こういう時は落ち着いて、再度ログを見てみます。
すると答えに近づく出力が。
```
Paketo Buildpack for BellSoft Liberica 9.10.1
  https://github.com/paketo-buildpacks/bellsoft-liberica
  Build Configuration:
    $BP_JVM_JLINK_ARGS           --no-man-pages --no-header-files --strip-debug --compress=1  configure custom link arguments (--output must be omitted)
    $BP_JVM_JLINK_ENABLED        false                                                        enables running jlink tool to generate custom JRE
    $BP_JVM_TYPE                 JRE                                                          the JVM type - JDK or JRE
    $BP_JVM_VERSION              11                                                           the Java version
```
**【$BP_JVM_VERSION 　11】**
どうやら「bellsoft-liberica」がJVMをダウンロードし、それに合うJDKやJREも併せてダウンロードしてくれるらしいです。
そして今回の実行でダウンロードされたバージョンが「11」だったようです。

bellsoft-libericaについてGitHubで確認してみましょう。
[paketo-buildpacks/bellsoft-liberica](https://github.com/paketo-buildpacks/bellsoft-liberica)　(GitHubリンク)

README.mdの「$BP_JVM_VERSION」を確認すると、以下の記述がありました。
> Configure the JVM version (e.g. 8, 11, 16). The buildpack will download JDK and JRE assets that are compatible with this version of the JVM specification. Since the buildpack only ships a single version of each supported line, updates to the buildpack can change the exact version of the JDK or JRE. In order to hold the JDK and JRE versions stable, the buildpack version itself must be stable.
Buildpack releases (and the dependency versions for each release) can be found here. Few users will use this buildpack directly, instead consuming a language buildpack like paketo-buildpacks/java who's releases (and the individual buildpack versions and dependency versions for each release) can be found here. Finally, some users will will consume builders like paketobuildpacks/builder:base who's releases can be found here. To determine the individual buildpack versions and dependency versions for each builder release use the pack inspect-builder <image> functionality.

また、構成情報が記述されている[buildpack.toml](https://github.com/paketo-buildpacks/bellsoft-liberica/blob/main/buildpack.toml)には以下の記述が。
>  [[metadata.configurations]]
    build = true
    default = "11"
    description = "the Java version"
    name = "BP_JVM_VERSION"

どうやら安定しているバージョンが指摘可能で、デフォルトは11のようです。
ですが説明を読む限りその他のバージョンも「$BP_JVM_VERSION」で指定出来そうなので、アップデート情報を確認してみると以下のような記述が。

[Paketo Buildpack for BellSoft Liberica 9.10.1](https://github.com/paketo-buildpacks/bellsoft-liberica/releases)
>BellSoft Liberica JDK	17.0.5

**対応している！**
buildpack.tomlも確認してみましたが、ちゃんと17の記述がありました。

>  [[metadata.dependencies]]
    cpes = ["cpe:2.3:a:oracle:jdk:17.0.5:*:*:*:*:*:*:*"]
    id = "jdk"
    name = "BellSoft Liberica JDK"
    purl = "pkg:generic/bellsoft-jdk@17.0.5?arch=amd64"
    sha256 = "6155654311ca0f7dbdba0571aec0633ab9de2a7a20941f2c959d8413df5b2cdc"
    stacks = ["io.buildpacks.stacks.bionic", "io.paketo.stacks.tiny", "*"]
    uri = "https://github.com/bell-sw/Liberica/releases/download/17.0.5+8/bellsoft-jdk17.0.5+8-linux-amd64.tar.gz"
    version = "17.0.5"

では、これらの情報を元に解決していこうと思います。

解決方法①：引数でバージョン指定
=
コマンドに「**-e BP_JVM_VERSION=17**」を追加することで指定可能です。
```
[root@dev-docker-01 apiProject]# pack build tmc-devops/api-project:latest -e BP_JVM_VERSION=17 --builder paketobuildpacks/builder:base
base: Pulling from paketobuildpacks/builder

~省略~

10 of 24 buildpacks participating
paketo-buildpacks/ca-certificates   3.5.1
paketo-buildpacks/bellsoft-liberica 9.10.1
paketo-buildpacks/syft              1.23.0
paketo-buildpacks/maven             6.11.0
paketo-buildpacks/executable-jar    6.5.0
paketo-buildpacks/apache-tomcat     7.9.1
paketo-buildpacks/apache-tomee      1.4.0
paketo-buildpacks/liberty           3.1.0
paketo-buildpacks/dist-zip          5.4.0
paketo-buildpacks/spring-boot       5.20.0

//省略

Paketo Buildpack for CA Certificates 3.5.1
  https://github.com/paketo-buildpacks/ca-certificates
  Launch Helper: Reusing cached layer

Paketo Buildpack for BellSoft Liberica 9.10.1
  https://github.com/paketo-buildpacks/bellsoft-liberica
  Build Configuration:
    $BP_JVM_JLINK_ARGS           --no-man-pages --no-header-files --strip-debug --compress=1  configure custom link arguments (--output must be omitted)
    $BP_JVM_JLINK_ENABLED        false                                                        enables running jlink tool to generate custom JRE
    $BP_JVM_TYPE                 JRE                                                          the JVM type - JDK or JRE
    $BP_JVM_VERSION              17                                                           the Java version
  Launch Configuration:
    $BPL_DEBUG_ENABLED           false                                                        enables Java remote debugging support
    $BPL_DEBUG_PORT              8000                                                         configure the remote debugging port
    $BPL_DEBUG_SUSPEND           false       

//省略

  Compiled Application: Contributing to layer
    Executing mvnw --batch-mode -Dmaven.test.skip=true --no-transfer-progress package
      [INFO] Scanning for projects...
      [INFO]
      [INFO] -------------------------< com.api:apiProject >-------------------------
      [INFO] Building apiProject 0.0.1-SNAPSHOT
      [INFO] --------------------------------[ jar ]---------------------------------
      [INFO]
      [INFO] --- maven-resources-plugin:3.2.0:resources (default-resources) @ apiProject ---
      [INFO] Using 'UTF-8' encoding to copy filtered resources.
      [INFO] Using 'UTF-8' encoding to copy filtered properties files.
      [INFO] Copying 1 resource
      [INFO] Copying 0 resource
      [INFO]
      [INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ apiProject ---
      [INFO] Changes detected - recompiling the module!
      [INFO] Compiling 4 source files to /workspace/target/classes
      [INFO]
      [INFO] --- maven-resources-plugin:3.2.0:testResources (default-testResources) @ apiProject ---
      [INFO] Not copying test resources
      [INFO]
      [INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ apiProject ---
      [INFO] Not compiling test sources
      [INFO]
      [INFO] --- maven-surefire-plugin:2.22.2:test (default-test) @ apiProject ---
      [INFO] Tests are skipped.
      [INFO]
      [INFO] --- maven-jar-plugin:3.2.0:jar (default-jar) @ apiProject ---
      [INFO] Building jar: /workspace/target/apiProject-0.0.1-SNAPSHOT.jar
      [INFO]
      [INFO] --- spring-boot-maven-plugin:2.6.2:repackage (repackage) @ apiProject ---
      [INFO] Replacing main artifact with repackaged archive
      [INFO] ------------------------------------------------------------------------
      [INFO] BUILD SUCCESS
      [INFO] ------------------------------------------------------------------------
      [INFO] Total time:  6.892 s
      [INFO] Finished at: 2022-12-16T04:22:41Z
      [INFO] ------------------------------------------------------------------------

  Removing source code
  Restoring application artifact

//省略
Successfully built image tmc-devops/api-project:latest
```
無事に成功しました！
ログからも17が使用されているのが確認できます。



解決方法②：pom.xmlを修正
=
根本的な解決にはなりませんが、Buildpackが対応していないバージョンの場合等はプロジェクトのjavaレベルを修正する必要もあるかもしれません。
というわけで、javaのバージョンを以下の通り修正する方法でもエラーにならず処理が完了します。
```filename:pom.xml
	<properties>
		<java.version>11</java.version>
	</properties>
```


感想
=

エラーに一瞬焦りましたが、Buildpackはログと公式の情報が充実していたため比較的早い段階で原因と解決策にたどり着くことが出来ました。
とくに設定を変えなくてもイメージ化は可能ですが、こうやってデフォルト設定から色々と変更して最適な状態でビルドするのが大切だなと改めて感じられて良かったです。