IK.AM

@making's tech note


Workaround for deploying apps with older versions of Spring Boot to Tanzu Application Platform

🗃 {Dev/CaaS/Kubernetes/TAP}
🏷 Kubernetes 🏷 Maven 🏷 TAP 🏷 Tanzu 🏷 Tanzu Build Service 🏷 kpack 
🗓 Updated at 2022-12-22T04:36:10Z  🗓 Created at 2022-12-22T04:36:10Z {✒️️ Edit  ⏰ History  🗑 Delete}  🇯🇵 Original entry

⚠️ The content of this article is not supported by VMware. Any issues arising from the content of this article are your responsibility and please do not contact VMware Support.

There are some problems when deploying apps using older versions of Spring Boot on TAP, so I will make a note of the workaround.

This time, I will deploy https://github.com/making/demo-download-view.

This app was created 7 years ago using Spring Boot 1.3.

Let's deploy this app as-is to 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

We will deal with the errors that occur one by one.

table of contents

Build error due to old Maven

When creating an image with the Build Service, I first got the following error:

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 suppresses log output with the --no-transfer-progress option when running maven build. This option was introduced in Maven 3.6.1. The Maven Wrapper included in this app uses Maven 3.3.3 and the error occurred because this option does not exist.

You can update the Maven version used by the Maven Wrapper by running the following command in your source code directory:

mvn wrapper:wrapper

You can also specify a specific version like:

mvn wrapper:wrapper -Dmaven=3.8.6

This time I updated the Maven Wrapper with the following commits:

https://github.com/making/demo-download-view/commit/25eac90254d3c728ec1c4b90740aff51495e434c

Alternatively, you can set the following build environment variables without the --no-transfer-progress option.

--build-env BP_MAVEN_BUILD_ARGUMENTS='-Dmaven.test.skip=true package' \

Build error due to Spring-Boot-Lib not present in MANIFEST.MF

If you update the source code on Git, the image will be built again. Now I got the following error:

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

The error is that there is no Spring-Boot-Lib in the MANIFEST.MF in the jar file.

Reading the following buildpack source code, it seems that the buildpack looks at the directory set in this entry to add dependencies to the BOM.

This Spring-Boot-Lib seems to have been included since Spring Boot 1.4.0 for Maven and 2.0.9 for Gradle.

The following values are set in MANIFEST.MF for supported versions:

Unsupported versions must somehow set this value in the MANIFEST.MF. Any entry can be added to MANIFST.MF using maven-jar-plugin as follows.

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifestEntries>
                            <Spring-Boot-Lib>lib/</Spring-Boot-Lib>
                        </manifestEntries>
                    </archive>
                </configuration>
            </plugin>

If you are creating a war file, change maven-jar-plugin to maven-war-plugin. The content to be set depends on the version of Spring Boot. Because it changes the layout of the jar.

If you want to check the layout of a jar or war, use zipinfo command.

$ 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%

This time I updated the pom.xml with the following commits:

https://github.com/making/demo-download-view/commit/e13e75a10560721e9f2c86563494bafb94dae8d1

Build error due to Spring-Boot-Classes not present in MANIFEST.MF

If you update the source code on Git, the image will be built again. Now I got the following error:

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

As before, the error is that there is no Spring-Boot-Classes in the MANIFEST.MF in the jar file.

Reading the buildpack source code below, it seems to look at the directory set in this entry to detect the application type.

The following values are set in MANIFEST.MF for supported versions:

This time also set this item with maven-jar-plugin or maven-war-plugin.

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifestEntries>
                            <Spring-Boot-Lib>lib/</Spring-Boot-Lib>
                            <Spring-Boot-Classes>.</Spring-Boot-Classes>							
                        </manifestEntries>
                    </archive>
                </configuration>
            </plugin>

This time I updated the pom.xml with the following commits:

https://github.com/making/demo-download-view/commit/ae127b2bbad58f663573489cbe95f24ff165129e

Runtime error regarding Spring Cloud Bindings

If you update the source code on Git, the image will be built again. This time the image build succeeded and the app started to run. But on startup I get the following error and the app did't start.

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.<init>(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

It's an error related to Spring Cloud Bindings. This library is automatically added when building the image, but due to the version of Spring Boot, a ClassNotFoundException occurs.

If you don't use Service Binding, you don't need Spring Cloud Bindings, so add --build-env BP_SPRING_CLOUD_BINDINGS_DISABLED=true option to disable Spring Cloud Bindings when building.

The final command I ran was:

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"

Now the app has started and I have access to the app.

$ curl -k "https://demo-download-view-demo.127-0-0-1.sslip.io/download?fileName=tap"    
Hello Download!

For the standalone Tanzu Build Service

If you are using only the Tanzu Build Service, the following commands are equivalent.

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

Worked around buildpack issues caused by older Spring Boot versions.

Please upgrade Spring Boot if possible instead of using this workaround.