先日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 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」でいざ実行。
問題なくビルドが完了しました。
ではここからが本番です。コンテナイメージ化していきます。
Buildpack実行
packコマンドをインストールした端末にコードを持っていき、いざ実行!!!
[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 (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 functionality.
また、構成情報が記述されている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
BellSoft Liberica JDK 17.0.5
対応している!
buildpack.tomlも確認してみましたが、ちゃんと17の記述がありました。
[[metadata.dependencies]]
cpes = ["cpe:2.3oracle: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のバージョンを以下の通り修正する方法でもエラーにならず処理が完了します。
<properties>
<java.version>11</java.version>
</properties>
感想
エラーに一瞬焦りましたが、Buildpackはログと公式の情報が充実していたため比較的早い段階で原因と解決策にたどり着くことが出来ました。
とくに設定を変えなくてもイメージ化は可能ですが、こうやってデフォルト設定から色々と変更して最適な状態でビルドするのが大切だなと改めて感じられて良かったです。