--- title: Tanzu Application Platformに古いバージョンのSpring Bootを使ったアプリをデプロイする際のWorkaround tags: ["Kubernetes", "Tanzu", "TAP", "Tanzu Build Service", "kpack", "Maven"] categories: ["Dev", "CaaS", "Kubernetes", "TAP"] date: 2022-12-22T04:11:48Z updated: 2022-12-22T04:16:26Z --- TAPに古いバージョンのSpring Bootを使ったアプリをデプロイする際にいくつか問題が起きるので、回避策をメモします。 今回は https://github.com/making/demo-download-view をデプロイしてみます。 このアプリはSpring Boot **1.3** を使用して、7年前に作成されました。 このアプリをそのままTAPにデプロイしてみましょう。 ``` tanzu apps workload apply demo-download-view \ --app demo-download-view \ --git-repo https://github.com/making/demo-download-view \ --git-branch master \ --type web \ --annotation autoscaling.knative.dev/minScale=1 \ --build-env BP_JVM_VERSION=8 \ -n demo \ -y ``` 発生するエラーを1つ1つ対処していきます。 **目次** ### Mavenが古いことによるビルドエラー Build Serviceによるイメージ作成時に、まず次のエラーが発生しました。 ``` Compiled Application: Contributing to layer Executing mvnw --settings=/platform/bindings/settings-xml/settings.xml --batch-mode -Dmaven.test.skip=true --no-transfer-progress package Downloading https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.3/apache-maven-3.3.3-bin.zip ........................................................................................................................................................................................................................................................................................................................................................................................................................ Unzipping /home/cnb/.m2/wrapper/dists/apache-maven-3.3.3-bin/3opbjp6rgl6qp7k2a6tljcpvgp/apache-maven-3.3.3-bin.zip to /home/cnb/.m2/wrapper/dists/apache-maven-3.3.3-bin/3opbjp6rgl6qp7k2a6tljcpvgp Set executable permissions for: /home/cnb/.m2/wrapper/dists/apache-maven-3.3.3-bin/3opbjp6rgl6qp7k2a6tljcpvgp/apache-maven-3.3.3/bin/mvn Unable to parse command line options: Unrecognized option: --no-transfer-progress ``` Maven Buildpackはmavenビルドを実行時に `--no-transfer-progress` オプションをつけてログの出力を抑制するのですが、 このオプションはMaven 3.6.1で導入されました。今回のアプリに含まれるMaven WrapperはMavenを3.3.3を使用しており、このオプションが存在しないためにエラーが発生しました。 ソースコードのディレクトリで次のコマンドを実行すると、Maven Wrapperが使用するMavenのバージョンを最新にすることができます。 ``` mvn wrapper:wrapper ``` 次のように特定のバージョンを指定することもできます ``` mvn wrapper:wrapper -Dmaven=3.8.6 ``` 今回は次のコミットでMaven Wrapperを更新しました。 https://github.com/making/demo-download-view/commit/25eac90254d3c728ec1c4b90740aff51495e434c もしくは次のビルド環境変数を設定し、 `--no-transfer-progress` オプションをつけないようにしても良いでしょう。 ``` --build-env BP_MAVEN_BUILD_ARGUMENTS='-Dmaven.test.skip=true package' \ ``` ### Spring-Boot-LibがMANIFEST.MFに存在しないことによるビルドエラー Git上のソースコードを更新すると、再度イメージのビルドが実行されます。今度は次のエラーが発生しました。 ``` Paketo Buildpack for Spring Boot 5.19.0 https://github.com/paketo-buildpacks/spring-boot Build Configuration: $BP_SPRING_CLOUD_BINDINGS_DISABLED false whether to contribute Spring Boot cloud bindings support Launch Configuration: $BPL_SPRING_CLOUD_BINDINGS_DISABLED false whether to auto-configure Spring Boot environment properties from bindings $BPL_SPRING_CLOUD_BINDINGS_ENABLED true Deprecated - whether to auto-configure Spring Boot environment properties from bindings Paketo Buildpack for Spring Boot 5.19.0 manifest does not container Spring-Boot-Lib ERROR: failed to build: exit status 1 ``` jarファイルの中のMANIFEST.MFに`Spring-Boot-Lib`がないというエラーです。 次のBuildpackのソースコードを読むと、BuildpackはBOMにdependenciesを追加するためにこの項目に設定されたディレクトリを見ているようです。 * https://github.com/paketo-buildpacks/spring-boot/blob/v5.19.0/boot/build.go#L89 この`Spring-Boot-Lib`はMavenの場合はSpring Boot 1.4.0、Gradleの場合は2.0.9から含まれたようです。 * https://github.com/spring-projects/spring-boot/issues/5183 * https://github.com/spring-projects/spring-boot/issues/16068 サポートされたバージョンでは次のような値がMANIFEST.MFに設定されます。 * https://github.com/spring-projects/spring-boot/blob/main/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/resources/org/springframework/boot/jarmode/layertools/test-manifest.MF#L10 (jarの場合) * https://github.com/spring-projects/spring-boot/blob/main/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/resources/org/springframework/boot/jarmode/layertools/test-war-manifest.MF#L10 (warの場合) サポートされていないバージョンでは何らかの方法で、MANIFEST.MFにこの値を設定する必要があります。 MANIFST.MFに対してはMavenではmaven-jar-pluginを使って次のように任意の項目を追加できます。 ```xml org.apache.maven.plugins maven-jar-plugin lib/ ``` warファイルを作成している場合はmaven-jar-pluginをmaven-war-pluginに変えてください。 設定すべき内容はSpring Bootのバージョンによって異なります。jarのレイアウトが変わるからです。 jarやwarのレイアウトを確認したい場合は`zipinfo`コマンドを使ってください。 ``` $ zipinfo target/demo-0.0.1-SNAPSHOT.jar Archive: target/demo-0.0.1-SNAPSHOT.jar Zip file size: 20306425 bytes, number of entries: 122 -rw---- 2.0 fat 0 bX defN 22-Dec-22 11:25 META-INF/ -rw---- 2.0 fat 477 bl defN 22-Dec-22 11:25 META-INF/MANIFEST.MF drwxr-xr-x 1.0 unx 0 b- stor 22-Dec-22 11:25 templates/ drwxr-xr-x 1.0 unx 0 b- stor 22-Dec-22 11:25 com/ drwxr-xr-x 1.0 unx 0 b- stor 22-Dec-22 11:25 com/example/ -rw-r--r-- 2.0 unx 419 bl defN 22-Dec-22 11:25 templates/index.html -rw-r--r-- 2.0 unx 15 bl defN 22-Dec-22 11:25 hello.txt -rw-r--r-- 2.0 unx 730 bl defN 22-Dec-22 11:25 com/example/DemoDownloadViewApplication.class -rw-r--r-- 2.0 unx 701 bl defN 22-Dec-22 11:25 com/example/HelloForm.class -rw-r--r-- 2.0 unx 1586 bl defN 22-Dec-22 11:25 com/example/HelloController.class -rw-r--r-- 2.0 unx 2112 bl defN 22-Dec-22 11:25 com/example/DownloadView.class -rw-r--r-- 2.0 unx 0 bl defN 22-Dec-22 11:25 application.properties drwxr-xr-x 1.0 unx 0 b- stor 22-Dec-22 11:25 META-INF/maven/ drwxr-xr-x 1.0 unx 0 b- stor 22-Dec-22 11:25 META-INF/maven/com.example/ drwxr-xr-x 1.0 unx 0 b- stor 22-Dec-22 11:25 META-INF/maven/com.example/demo/ -rw-r--r-- 2.0 unx 1913 bl defN 22-Dec-22 11:24 META-INF/maven/com.example/demo/pom.xml -rw-r--r-- 2.0 unx 109 bl defN 22-Dec-22 11:25 META-INF/maven/com.example/demo/pom.properties -rw---- 2.0 fat 0 bl defN 22-Dec-22 11:25 lib/ -rw---- 1.0 fat 193581 b- stor 15-Nov-16 02:45 lib/spring-boot-devtools-1.3.0.RELEASE.jar -rw---- 1.0 fat 533592 b- stor 15-Nov-16 02:34 lib/spring-boot-1.3.0.RELEASE.jar ... -rw---- 1.0 fat 1077165 b- stor 15-Nov-15 08:03 lib/spring-core-4.2.3.RELEASE.jar -rw---- 2.0 fat 0 bl defN 22-Dec-22 11:25 org/ -rw---- 2.0 fat 0 bl defN 22-Dec-22 11:25 org/springframework/ -rw---- 2.0 fat 0 bl defN 22-Dec-22 11:25 org/springframework/boot/ -rw---- 2.0 fat 0 bl defN 22-Dec-22 11:25 org/springframework/boot/loader/ -rw---- 2.0 fat 1257 bl defN 15-Nov-16 02:31 org/springframework/boot/loader/LaunchedURLClassLoader$Java7LockProvider.class ... -rw---- 2.0 fat 884 bl defN 15-Nov-16 02:31 org/springframework/boot/loader/archive/ExplodedArchive$FileNotFoundURLConnection.class -rw---- 2.0 fat 192 bl defN 15-Nov-16 02:31 org/springframework/boot/loader/JavaAgentDetector.class 122 files, 20382587 bytes uncompressed, 20285023 bytes compressed: 0.5% ``` 今回は次のコミットでpom.xmlを更新しました。 https://github.com/making/demo-download-view/commit/e13e75a10560721e9f2c86563494bafb94dae8d1 ### Spring-Boot-ClassesがMANIFEST.MFに存在しないことによるビルドエラー Git上のソースコードを更新すると、再度イメージのビルドが実行されます。今度は次のエラーが発生しました。 ``` Paketo Buildpack for Spring Boot 5.19.0 https://github.com/paketo-buildpacks/spring-boot Build Configuration: $BP_SPRING_CLOUD_BINDINGS_DISABLED false whether to contribute Spring Boot cloud bindings support Launch Configuration: $BPL_SPRING_CLOUD_BINDINGS_DISABLED false whether to auto-configure Spring Boot environment properties from bindings $BPL_SPRING_CLOUD_BINDINGS_ENABLED true Deprecated - whether to auto-configure Spring Boot environment properties from bindings Paketo Buildpack for Spring Boot 5.19.0 manifest does not contain Spring-Boot-Classes ERROR: failed to build: exit status 1 ``` 先ほどと同様にjarファイルの中のMANIFEST.MFに`Spring-Boot-Classes`がないというエラーです。 次のBuildpackのソースコードを読むと、アプリケーションのタイプを検出するためにこの項目に設定されたディレクトリを見ているようです。 * https://github.com/paketo-buildpacks/spring-boot/blob/v5.19.0/boot/build.go#L152 サポートされたバージョンでは次のような値がMANIFEST.MFに設定されます。 * https://github.com/spring-projects/spring-boot/blob/main/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/resources/org/springframework/boot/jarmode/layertools/test-manifest.MF#L9 (jarの場合) * https://github.com/spring-projects/spring-boot/blob/main/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/resources/org/springframework/boot/jarmode/layertools/test-war-manifest.MF#L9 (warの場合) 今回もmaven-jar-plugin or maven-war-pluginでこの項目を設定します。 ```xml org.apache.maven.plugins maven-jar-plugin lib/ . ``` 今回は次のコミットでpom.xmlを更新しました。 https://github.com/making/demo-download-view/commit/ae127b2bbad58f663573489cbe95f24ff165129e ### Spring Cloud Bindingsに関するランタイムエラー Git上のソースコードを更新すると、再度イメージのビルドが実行されます。今度はイメージのビルドが成功し、アプリの起動が始まりました。 しかし、起動時に次のようなエラーが発生し、アプリは起動しません。 ``` java.lang.reflect.InvocationTargetException at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:53) at java.lang.Thread.run(Thread.java:750) Caused by: java.lang.IllegalArgumentException: Cannot instantiate interface org.springframework.context.ApplicationListener : org.springframework.cloud.bindings.boot.BindingSpecificEnvironmentPostProcessor at org.springframework.boot.SpringApplication.getSpringFactoriesInstances(SpringApplication.java:396) at org.springframework.boot.SpringApplication.getSpringFactoriesInstances(SpringApplication.java:373) at org.springframework.boot.SpringApplication.initialize(SpringApplication.java:253) at org.springframework.boot.SpringApplication.(SpringApplication.java:227) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1112) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1101) at com.example.DemoDownloadViewApplication.main(DemoDownloadViewApplication.java:10) ... 6 more Caused by: java.lang.ClassNotFoundException: org.springframework.cloud.bindings.boot.BindingSpecificEnvironmentPostProcessor at java.net.URLClassLoader.findClass(URLClassLoader.java:387) at java.lang.ClassLoader.loadClass(ClassLoader.java:418) at org.springframework.boot.loader.LaunchedURLClassLoader.doLoadClass(LaunchedURLClassLoader.java:166) at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:130) at java.lang.ClassLoader.loadClass(ClassLoader.java:351) at org.springframework.util.ClassUtils.forName(ClassUtils.java:250) at org.springframework.boot.SpringApplication.getSpringFactoriesInstances(SpringApplication.java:389) ... 12 more ``` Spring Cloud Bindingsに関連するエラーです。このライブラリはイメージビルド時に自動で追加されるライブラリですが、Spring Bootのバージョンのせいか、ClassNotFoundExceptionが発生してしまいます。 Service Binidngを使わない場合は、Spring Cloud Bindingsはなくても良いので、`--build-env BP_SPRING_CLOUD_BINDINGS_DISABLED=true`オプションをつけて、ビルド時にSpring Cloud Bindingsを無効にします。 最終的に実行したコマンドは次です。 ``` tanzu apps workload apply demo-download-view \ --app demo-download-view \ --git-repo https://github.com/making/demo-download-view \ --git-branch tap \ --type web \ --annotation autoscaling.knative.dev/minScale=1 \ --build-env BP_JVM_VERSION=8 \ --build-env BP_SPRING_CLOUD_BINDINGS_DISABLED=true \ -n demo \ -y ``` ``` $ tanzu apps workload get -n demo demo-download-view 📡 Overview name: demo-download-view type: web 💾 Source type: git url: https://github.com/making/demo-download-view branch: tap 📦 Supply Chain name: source-to-url RESOURCE READY HEALTHY TIME OUTPUT source-provider True True 42m GitRepository/demo-download-view image-provider True True 101s Image/demo-download-view config-provider True True 12m PodIntent/demo-download-view app-config True True 12m ConfigMap/demo-download-view service-bindings True True 12m ConfigMap/demo-download-view-with-claims api-descriptors True True 12m ConfigMap/demo-download-view-with-api-descriptors config-writer True True 81s Runnable/demo-download-view-config-writer 🚚 Delivery name: delivery-basic RESOURCE READY HEALTHY TIME OUTPUT source-provider True True 11m ImageRepository/demo-download-view-delivery deployer True True 69s App/demo-download-view 💬 Messages No messages found. 🛶 Pods NAME READY STATUS RESTARTS AGE demo-download-view-00001-deployment-76b5cc876c-t9clq 0/2 Terminating 7 (5m19s ago) 11m demo-download-view-00002-deployment-76dbf5f776-z7qvj 2/2 Running 0 71s demo-download-view-build-1-build-pod 0/1 Init:Error 0 47m demo-download-view-build-2-build-pod 0/1 Init:Error 0 42m demo-download-view-build-3-build-pod 0/1 Init:Error 0 26m demo-download-view-build-4-build-pod 0/1 Init:Error 0 16m demo-download-view-build-5-build-pod 0/1 Completed 0 14m demo-download-view-build-6-build-pod 0/1 Completed 0 2m29s demo-download-view-config-writer-d9l79-pod 0/1 Completed 0 92s demo-download-view-config-writer-f9kvp-pod 0/1 Completed 0 12m 🚢 Knative Services NAME READY URL demo-download-view Ready https://demo-download-view-demo.127-0-0-1.sslip.io To see logs: "tanzu apps workload tail demo-download-view --namespace demo" ``` これでアプリが起動し、アプリにアクセできました。 ``` $ curl -k "https://demo-download-view-demo.127-0-0-1.sslip.io/download?fileName=tap" Hello Download! ``` ### Tanzu Build Service単体の場合 Tanzu Build Serviceのみを使用している場合は、次のコマンドが等価です。 ``` kp image save demo-download-view \ --git https://github.com/making/demo-download-view \ --git-revision tap \ --tag ghcr.io/making/demo-download-view \ --env BP_JVM_VERSION=8 \ --env BP_SPRING_CLOUD_BINDINGS_DISABLED=true \ -n demo ``` --- 古いSpring Bootのバージョンに起因するbuildpackの問題を回避しました。 この回避策を使うのではなく、できればSpring Bootをバージョンアップしてください。