Real-world Cloud Native Buildpacks Part 1

Real-world Cloud Native Buildpacks Part 1

How to tackle real-world use cases with Cloud Native Buildpacks

Intro

Cloud Native Buildpacks is a CNCF specification that "helps you transform your application source code into images that can run on any cloud".

In simpler terms, it is an automated source-to-OCI-image solution that is designed to take the toil of writing Dockerfiles from the hands of developers or devops teams. More importantly - it allows for proactive CVE patching. Since CNB is responsible for building the image, it knows how that image was built - its various layers, including the underlying base OS, which is called a stack, as well as runtime layers such as OpenJDK, .NET Core runtime etc.

Working with our customers at VMware Tanzu, I began to notice some patterns around making sure CNB work well in the "real world" - that is, with real customer codebases, airgapped environments, and multi-module repositories. These are usually much different than your typical "Hello World" demo apps, so I figured I'd list some of the caveats and best practices that I find for the most common languages.

Choosing a platform

Cloud Native Buildpacks is a specification. It does not dictate the target runtime. As a result - there are various platforms it can run on, such as:

For this article, I'm going to use Tanzu Build Service since that is what I'm most comfortable with and also because it's probably the most feature-rich distribution. It's also included as part of Tanzu Application Platform . Since Tanzu Build Service is based on kpack, almost everything can be applied to kpack as well.

Buildpacks in review

Spring Boot "hello world!"

Let's start with a simple Spring Boot hello world app just to get into the mood:

Git repo

The repository is available at github.com/odedia/spring-on-k8s.git

Build command

This is as straigntforward as it gets. Our repository is based on maven, and Tanzu Build Service detects it automatically since a pom.xml is available at the root of the repository. The command to build the image is:

> kp image save spring-hello-world \
    --tag harbor.registry.com/apps/spring-hello-world \
    --git https://github.com/odedia/spring-on-k8s.git \
    --git-revision master

Build logs output

Let's check the build logs:

> kp build logs spring-hello-world
===> PREPARE
Build reason(s): CONFIG
CONFIG:
  resources: {}
  - source: {}
  + source:
  +   git:
  +     revision: 50c46f40baa6ac8a72498d516624fc78d95f0d2a
  +     url: https://github.com/odedia/spring-on-k8s.git
Loading secret for "harbor.registry.com" from secret "registry-credentials" at location "/var/build-secrets/registry-credentials"
Cloning "https://github.com/odedia/spring-on-k8s.git" @ "50c46f40baa6ac8a72498d516624fc78d95f0d2a"...
Successfully cloned "https://github.com/odedia/spring-on-k8s.git" @ "50c46f40baa6ac8a72498d516624fc78d95f0d2a" in path "/workspace"
===> ANALYZE
===> DETECT
8 of 35 buildpacks participating
paketo-buildpacks/ca-certificates   3.0.2
paketo-buildpacks/bellsoft-liberica 9.0.2
paketo-buildpacks/syft              1.3.1
paketo-buildpacks/maven             6.0.2
paketo-buildpacks/executable-jar    6.0.2
paketo-buildpacks/apache-tomcat     7.0.3
paketo-buildpacks/dist-zip          5.0.2
paketo-buildpacks/spring-boot       5.3.0
===> RESTORE
Restoring metadata for "paketo-buildpacks/ca-certificates:helper" from app image
Restoring metadata for "paketo-buildpacks/bellsoft-liberica:java-security-properties" from app image
Restoring metadata for "paketo-buildpacks/bellsoft-liberica:jre" from app image
Restoring metadata for "paketo-buildpacks/bellsoft-liberica:helper" from app image
Restoring metadata for "paketo-buildpacks/spring-boot:helper" from app image
Restoring metadata for "paketo-buildpacks/spring-boot:spring-cloud-bindings" from app image
Restoring metadata for "paketo-buildpacks/spring-boot:web-application-type" from app image
===> BUILD

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

Paketo BellSoft Liberica Buildpack 9.0.2
  https://github.com/paketo-buildpacks/bellsoft-liberica
  Build Configuration:
    $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           enables Java Management Extensions (JMX)
    $BPL_JMX_PORT                5000            configure the JMX port
    $BPL_JVM_HEAD_ROOM           0               the headroom in memory calculation
    $BPL_JVM_LOADED_CLASS_COUNT  35% of classes  the number of loaded classes in memory calculation
    $BPL_JVM_THREAD_COUNT        250             the number of threads in memory calculation
    $JAVA_TOOL_OPTIONS                           the JVM launch flags
  BellSoft Liberica JDK 11.0.13: Contributing to layer
    Reusing cached download from buildpack
    Expanding to /layers/paketo-buildpacks_bellsoft-liberica/jdk
    Adding 128 container CA certificates to JVM truststore
    Writing env.build/JAVA_HOME.override
    Writing env.build/JDK_HOME.override
  BellSoft Liberica JRE 11.0.13: Reusing cached layer
  Launch Helper: Reusing cached layer
  Java Security Properties: Reusing cached layer

Paketo Syft Buildpack 1.3.1
  https://github.com/paketo-buildpacks/syft
    Reusing cached download from buildpack
    Writing env.build/SYFT_CHECK_FOR_APP_UPDATE.default

Paketo Maven Buildpack 6.0.2
  https://github.com/paketo-buildpacks/maven
  Build Configuration:
    $BP_MAVEN_BUILD_ARGUMENTS  -Dmaven.test.skip=true package  the arguments to pass to Maven
    $BP_MAVEN_BUILT_ARTIFACT   target/*.[ejw]ar                the built application artifact explicitly.  Supersedes $BP_MAVEN_BUILT_MODULE
    $BP_MAVEN_BUILT_MODULE                                     the module to find application artifact in
    $BP_MAVEN_POM_FILE         pom.xml                         the location of the main pom.xml file, relative to the application root
    Creating cache directory /home/cnb/.m2
  Compiled Application: Contributing to layer
    Executing mvnw --batch-mode -Dmaven.test.skip=true package
      [INFO] Scanning for projects...
      [INFO] Downloading from central: https://repo.maven.apache.org/maven2/org/springframework/boot/spring-boot-starter-parent/2.4.3/spring-boot-starter-parent-2.4.3.pom
...
...
...
      [INFO] Downloaded from central: https://repo.maven.apache.org/maven2/org/eclipse/sisu/org.eclipse.sisu.inject/0.3.4/org.eclipse.sisu.inject-0.3.4.jar (379 kB at 2.9 MB/s)
      [INFO] Downloaded from central: https://repo.maven.apache.org/maven2/org/eclipse/sisu/org.eclipse.sisu.plexus/0.3.4/org.eclipse.sisu.plexus-0.3.4.jar (205 kB at 1.5 MB/s)
      [INFO] Replacing main artifact with repackaged archive
      [INFO] ------------------------------------------------------------------------
      [INFO] BUILD SUCCESS
      [INFO] ------------------------------------------------------------------------
      [INFO] Total time:  10.232 s
      [INFO] Finished at: 2022-01-16T10:02:48Z
      [INFO] ------------------------------------------------------------------------
  Removing source code

Paketo Executable JAR Buildpack 6.0.2
  https://github.com/paketo-buildpacks/executable-jar
  Class Path: Contributing to layer
    Writing env/CLASSPATH.delim
    Writing env/CLASSPATH.prepend
  Process types:
    executable-jar: java org.springframework.boot.loader.JarLauncher (direct)
    task:           java org.springframework.boot.loader.JarLauncher (direct)
    web:            java org.springframework.boot.loader.JarLauncher (direct)

Paketo Spring Boot Buildpack 5.3.0
  https://github.com/paketo-buildpacks/spring-boot
  Creating slices from layers index
    dependencies
    spring-boot-loader
    snapshot-dependencies
    application
  Launch Helper: Reusing cached layer
  Spring Cloud Bindings 1.8.0: Reusing cached layer
  Web Application Type: Reusing cached layer
  4 application slices
  Image labels:
    org.opencontainers.image.title
    org.opencontainers.image.version
    org.springframework.boot.version
===> EXPORT
Reusing layers from image 'harbor.registry.com/apps/spring-hello-world@sha256:e135f066c71524c6dc8343d4c803c417240c1ffc1563daa0224c865e45900d53'
Reusing layer 'paketo-buildpacks/ca-certificates:helper'
Reusing layer 'paketo-buildpacks/bellsoft-liberica:helper'
Reusing layer 'paketo-buildpacks/bellsoft-liberica:java-security-properties'
Reusing layer 'paketo-buildpacks/bellsoft-liberica:jre'
Reusing layer 'paketo-buildpacks/executable-jar:classpath'
Reusing layer 'paketo-buildpacks/spring-boot:helper'
Reusing layer 'paketo-buildpacks/spring-boot:spring-cloud-bindings'
Reusing layer 'paketo-buildpacks/spring-boot:web-application-type'
Adding layer 'launch.sbom'
Reusing 5/5 app layer(s)
Reusing layer 'launcher'
Reusing layer 'config'
Reusing layer 'process-types'
Adding label 'io.buildpacks.lifecycle.metadata'
Adding label 'io.buildpacks.build.metadata'
Adding label 'io.buildpacks.project.metadata'
Adding label 'org.opencontainers.image.title'
Adding label 'org.opencontainers.image.version'
Adding label 'org.springframework.boot.version'
Setting default process type 'web'
Saving harbor.registry.com/apps/spring-hello-world...
*** Images (sha256:792fee75f5627daed9e8731971d134a28112cc952359d983ea901fca5cf7f522):
      harbor.registry.com/apps/spring-hello-world
      harbor.registry.com/apps/spring-hello-world:b1.20220116.100212
Adding cache layer 'paketo-buildpacks/bellsoft-liberica:jdk'
Adding cache layer 'paketo-buildpacks/syft:syft'
Adding cache layer 'paketo-buildpacks/maven:application'
Adding cache layer 'paketo-buildpacks/maven:cache'
Adding cache layer 'cache.sbom'
===> COMPLETION
Build successful

Running the image

Let's see if our OCI image runs as expected:

> docker run -p 8080:8080 harbor.registry.com/apps/spring-hello-world:b1.20220116.100212

Unable to find image 'harbor.registry.com/apps/spring-hello-world:b1.20220116.100212' locally
b1.20220116.100212: Pulling from apps/spring-hello-world
bf99a8b93828: Already exists
1da1131b1360: Pull complete
48bde579d8cc: Pull complete
1929d0623312: Pull complete
1fea93ec33be: Pull complete
fed2bcb93d83: Pull complete
d06e3ac07eba: Pull complete
a8090bf3b91d: Pull complete
204c9b3ef04c: Pull complete
95d9537f4e2e: Pull complete
40cbb147917e: Pull complete
b8e5cf599c18: Pull complete
bd74081a3b16: Pull complete
1d17a9810ba3: Pull complete
be14b062b309: Pull complete
33a1d27f7a3f: Pull complete
89732bc75041: Pull complete
96580d31d7e3: Pull complete
40d17e1b116e: Pull complete
02d76976a806: Pull complete
b39b18afe74e: Pull complete
Digest: sha256:792fee75f5627daed9e8731971d134a28112cc952359d983ea901fca5cf7f522
Status: Downloaded newer image for harbor.registry.com/apps/spring-hello-world:b1.20220116.100212
Setting Active Processor Count to 4
WARNING: Unable to convert memory limit "max" from path "/sys/fs/cgroup/memory.max" as int: memory size "max" does not match pattern "^([\\d]+)([kmgtKMGT]?)$"
Calculating JVM memory based on 1284376K available memory
Calculated JVM Memory Configuration: -XX:MaxDirectMemorySize=10M -Xmx687495K -XX:MaxMetaspaceSize=84880K -XX:ReservedCodeCacheSize=240M -Xss1M (Total Memory: 1284376K, Thread Count: 250, Loaded Class Count: 12572, Headroom: 0%)
Enabling Java Native Memory Tracking
Adding 128 container CA certificates to JVM truststore
Spring Cloud Bindings Enabled
Picked up JAVA_TOOL_OPTIONS: -Djava.security.properties=/layers/paketo-buildpacks_bellsoft-liberica/java-security-properties/java-security.properties -XX:+ExitOnOutOfMemoryError -XX:ActiveProcessorCount=4 -XX:MaxDirectMemorySize=10M -Xmx687495K -XX:MaxMetaspaceSize=84880K -XX:ReservedCodeCacheSize=240M -Xss1M -XX:+UnlockDiagnosticVMOptions -XX:NativeMemoryTracking=summary -XX:+PrintNMTStatistics -Dorg.springframework.cloud.bindings.boot.enable=true

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.4.3)

2022-01-16 10:08:34.050  INFO 1 --- [           main] c.vmware.demos.springonk8s.Application   : Starting Application v1.0.0-SNAPSHOT using Java 11.0.13 on 3b4ec7e4ed92 with PID 1 (/workspace/BOOT-INF/classes started by cnb in /workspace)
2022-01-16 10:08:34.055  INFO 1 --- [           main] c.vmware.demos.springonk8s.Application   : No active profile set, falling back to default profiles: default
2022-01-16 10:08:35.541  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2022-01-16 10:08:35.560  INFO 1 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2022-01-16 10:08:35.560  INFO 1 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.43]
2022-01-16 10:08:35.640  INFO 1 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2022-01-16 10:08:35.641  INFO 1 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1499 ms
2022-01-16 10:08:36.079  INFO 1 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2022-01-16 10:08:36.433  INFO 1 --- [           main] o.s.b.a.e.web.EndpointLinksResolver      : Exposing 2 endpoint(s) beneath base path '/actuator'
2022-01-16 10:08:36.494  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2022-01-16 10:08:36.517  INFO 1 --- [           main] c.vmware.demos.springonk8s.Application   : Started Application in 3.032 seconds (JVM running for 3.479)
2022-01-16 10:08:42.024  INFO 1 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2022-01-16 10:08:42.026  INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2022-01-16 10:08:42.028  INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 2 ms

Let's check the application:

image.png

Looking good! Let's move to a more robust application.

Spring Boot Pet Clinic backend application

This is the classic demo application for Spring Boot. I'm going to use a version of this app that only runs the backend, since I find it quite rare to run HTML+Javascript in a Spring Boot container - you'd usually run an Angular/React/VueVS application in a static code server such as NGINX. For now, lets build our REST APIs backend:

Git Repo

This application is located in github.com/spring-petclinic/spring-petclini..

Build command

The Java Buildpack (and Spring), is probably the most robust, so building the OCI image is still quite straightforward. Just point to the git repo:

> kp image save spring-petclinic-backend \
    --tag harbor.registry.com/apps/spring-petclinic-backend \
    --git https://github.com/spring-petclinic/spring-petclinic-rest.git \
    --git-revision master
Creating Image Resource...
Image Resource "spring-petclinic-backend" created

Build logs output

> kp image save spring-petclinic-backend \
    --tag harbor.registry.com/apps/spring-petclinic-backend \
    --git https://github.com/spring-petclinic/spring-petclinic-rest.git \
    --git-revision master
Creating Image Resource...
Image Resource "spring-petclinic-backend" created
(⎈ |tap:default)➜  ~
> kp build logs spring-petclinic-backend
===> PREPARE
Build reason(s): CONFIG
CONFIG:
  resources: {}
  - source: {}
  + source:
  +   git:
  +     revision: 8da34240a5a9a04809f714a76cee82c6e27bea14
  +     url: https://github.com/spring-petclinic/spring-petclinic-rest.git
Loading secret for "harbor.registry.com" from secret "registry-credentials" at location "/var/build-secrets/registry-credentials"
Cloning "https://github.com/spring-petclinic/spring-petclinic-rest.git" @ "8da34240a5a9a04809f714a76cee82c6e27bea14"...
Successfully cloned "https://github.com/spring-petclinic/spring-petclinic-rest.git" @ "8da34240a5a9a04809f714a76cee82c6e27bea14" in path "/workspace"
===> ANALYZE
Previous image with name "harbor.registry.com/apps/spring-petclinic-backend" not found
===> DETECT
8 of 35 buildpacks participating
paketo-buildpacks/ca-certificates   3.0.2
paketo-buildpacks/bellsoft-liberica 9.0.2
paketo-buildpacks/syft              1.3.1
paketo-buildpacks/maven             6.0.2
paketo-buildpacks/executable-jar    6.0.2
paketo-buildpacks/apache-tomcat     7.0.3
paketo-buildpacks/dist-zip          5.0.2
paketo-buildpacks/spring-boot       5.3.0
===> RESTORE
===> BUILD

Paketo CA Certificates Buildpack 3.0.2
  https://github.com/paketo-buildpacks/ca-certificates
  Launch Helper: Contributing to layer
    Creating /layers/paketo-buildpacks_ca-certificates/helper/exec.d/ca-certificates-helper

Paketo BellSoft Liberica Buildpack 9.0.2
  https://github.com/paketo-buildpacks/bellsoft-liberica
  Build Configuration:
    $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           enables Java Management Extensions (JMX)
    $BPL_JMX_PORT                5000            configure the JMX port
    $BPL_JVM_HEAD_ROOM           0               the headroom in memory calculation
    $BPL_JVM_LOADED_CLASS_COUNT  35% of classes  the number of loaded classes in memory calculation
    $BPL_JVM_THREAD_COUNT        250             the number of threads in memory calculation
    $JAVA_TOOL_OPTIONS                           the JVM launch flags
  BellSoft Liberica JDK 11.0.13: Contributing to layer
    Reusing cached download from buildpack
    Expanding to /layers/paketo-buildpacks_bellsoft-liberica/jdk
    Adding 128 container CA certificates to JVM truststore
    Writing env.build/JAVA_HOME.override
    Writing env.build/JDK_HOME.override
  BellSoft Liberica JRE 11.0.13: Contributing to layer
    Reusing cached download from buildpack
    Expanding to /layers/paketo-buildpacks_bellsoft-liberica/jre
    Adding 128 container CA certificates to JVM truststore
    Writing env.launch/BPI_APPLICATION_PATH.default
    Writing env.launch/BPI_JVM_CACERTS.default
    Writing env.launch/BPI_JVM_CLASS_COUNT.default
    Writing env.launch/BPI_JVM_SECURITY_PROVIDERS.default
    Writing env.launch/JAVA_HOME.default
    Writing env.launch/JAVA_TOOL_OPTIONS.append
    Writing env.launch/JAVA_TOOL_OPTIONS.delim
    Writing env.launch/MALLOC_ARENA_MAX.default
  Launch Helper: Contributing to layer
    Creating /layers/paketo-buildpacks_bellsoft-liberica/helper/exec.d/active-processor-count
    Creating /layers/paketo-buildpacks_bellsoft-liberica/helper/exec.d/java-opts
    Creating /layers/paketo-buildpacks_bellsoft-liberica/helper/exec.d/jvm-heap
    Creating /layers/paketo-buildpacks_bellsoft-liberica/helper/exec.d/link-local-dns
    Creating /layers/paketo-buildpacks_bellsoft-liberica/helper/exec.d/memory-calculator
    Creating /layers/paketo-buildpacks_bellsoft-liberica/helper/exec.d/openssl-certificate-loader
    Creating /layers/paketo-buildpacks_bellsoft-liberica/helper/exec.d/security-providers-configurer
    Creating /layers/paketo-buildpacks_bellsoft-liberica/helper/exec.d/jmx
    Creating /layers/paketo-buildpacks_bellsoft-liberica/helper/exec.d/jfr
    Creating /layers/paketo-buildpacks_bellsoft-liberica/helper/exec.d/nmt
    Creating /layers/paketo-buildpacks_bellsoft-liberica/helper/exec.d/security-providers-classpath-9
    Creating /layers/paketo-buildpacks_bellsoft-liberica/helper/exec.d/debug-9
  Java Security Properties: Contributing to layer
    Writing env.launch/JAVA_SECURITY_PROPERTIES.default
    Writing env.launch/JAVA_TOOL_OPTIONS.append
    Writing env.launch/JAVA_TOOL_OPTIONS.delim

Paketo Syft Buildpack 1.3.1
  https://github.com/paketo-buildpacks/syft
    Reusing cached download from buildpack
    Writing env.build/SYFT_CHECK_FOR_APP_UPDATE.default

Paketo Maven Buildpack 6.0.2
  https://github.com/paketo-buildpacks/maven
  Build Configuration:
    $BP_MAVEN_BUILD_ARGUMENTS  -Dmaven.test.skip=true package  the arguments to pass to Maven
    $BP_MAVEN_BUILT_ARTIFACT   target/*.[ejw]ar                the built application artifact explicitly.  Supersedes $BP_MAVEN_BUILT_MODULE
    $BP_MAVEN_BUILT_MODULE                                     the module to find application artifact in
    $BP_MAVEN_POM_FILE         pom.xml                         the location of the main pom.xml file, relative to the application root
    Creating cache directory /home/cnb/.m2
  Compiled Application: Contributing to layer
    Executing mvnw --batch-mode -Dmaven.test.skip=true package
      [INFO] Scanning for projects...
      [INFO] Downloading from central: https://repo.maven.apache.org/maven2/org/springframework/boot/spring-boot-starter-parent/2.6.2/spring-boot-starter-parent-2.6.2.pom
...
...
...
      [INFO] Downloaded from central: https://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-utils/3.3.0/plexus-utils-3.3.0.jar (263 kB at 16 MB/s)
      [INFO] Downloaded from central: https://repo.maven.apache.org/maven2/org/apache/commons/commons-compress/1.19/commons-compress-1.19.jar (615 kB at 23 MB/s)
      [INFO] Building jar: /workspace/target/spring-petclinic-rest-2.6.2.jar
      [INFO]
      [INFO] --- spring-boot-maven-plugin:2.6.2:repackage (repackage) @ spring-petclinic-rest ---
      [INFO] Replacing main artifact with repackaged archive
      [INFO] ------------------------------------------------------------------------
      [INFO] BUILD SUCCESS
      [INFO] ------------------------------------------------------------------------
      [INFO] Total time:  23.587 s
      [INFO] Finished at: 2022-01-16T10:31:48Z
      [INFO] ------------------------------------------------------------------------
  Removing source code

Paketo Executable JAR Buildpack 6.0.2
  https://github.com/paketo-buildpacks/executable-jar
  Class Path: Contributing to layer
    Writing env/CLASSPATH.delim
    Writing env/CLASSPATH.prepend
  Process types:
    executable-jar: java org.springframework.boot.loader.JarLauncher (direct)
    task:           java org.springframework.boot.loader.JarLauncher (direct)
    web:            java org.springframework.boot.loader.JarLauncher (direct)

Paketo Spring Boot Buildpack 5.3.0
  https://github.com/paketo-buildpacks/spring-boot
  Creating slices from layers index
    dependencies
    spring-boot-loader
    snapshot-dependencies
    application
  Launch Helper: Contributing to layer
    Creating /layers/paketo-buildpacks_spring-boot/helper/exec.d/spring-cloud-bindings
  Spring Cloud Bindings 1.8.0: Contributing to layer
    Reusing cached download from buildpack
    Copying to /layers/paketo-buildpacks_spring-boot/spring-cloud-bindings
  Web Application Type: Contributing to layer
    Servlet web application detected
    Writing env.launch/BPL_JVM_THREAD_COUNT.default
  4 application slices
  Image labels:
    org.opencontainers.image.title
    org.opencontainers.image.version
    org.springframework.boot.version
===> EXPORT
Adding layer 'paketo-buildpacks/ca-certificates:helper'
Adding layer 'paketo-buildpacks/bellsoft-liberica:helper'
Adding layer 'paketo-buildpacks/bellsoft-liberica:java-security-properties'
Adding layer 'paketo-buildpacks/bellsoft-liberica:jre'
Adding layer 'paketo-buildpacks/executable-jar:classpath'
Adding layer 'paketo-buildpacks/spring-boot:helper'
Adding layer 'paketo-buildpacks/spring-boot:spring-cloud-bindings'
Adding layer 'paketo-buildpacks/spring-boot:web-application-type'
Adding layer 'launch.sbom'
Adding 5/5 app layer(s)
Adding layer 'launcher'
Adding layer 'config'
Adding layer 'process-types'
Adding label 'io.buildpacks.lifecycle.metadata'
Adding label 'io.buildpacks.build.metadata'
Adding label 'io.buildpacks.project.metadata'
Adding label 'org.opencontainers.image.title'
Adding label 'org.opencontainers.image.version'
Adding label 'org.springframework.boot.version'
Setting default process type 'web'
Saving harbor.registry.com/apps/spring-petclinic-backend...
*** Images (sha256:6cf16c4573c95f5e66e40740d9f6238377b3aaab38176e7986310c21bdd6094a):
      harbor.registry.com/apps/spring-petclinic-backend
      harbor.registry.com/apps/spring-petclinic-backend:b1.20220116.103057
Adding cache layer 'paketo-buildpacks/bellsoft-liberica:jdk'
Adding cache layer 'paketo-buildpacks/syft:syft'
Adding cache layer 'paketo-buildpacks/maven:application'
Adding cache layer 'paketo-buildpacks/maven:cache'
Adding cache layer 'cache.sbom'
===> COMPLETION
Build successful

Running the image

> docker run -p 8080:8080 harbor.registry.com/apps/spring-petclinic-backend:b1.20220116.103057
Unable to find image 'harbor.registry.com/apps/spring-petclinic-backend:b1.20220116.103057' locally
b1.20220116.103057: Pulling from apps/spring-petclinic-backend
bf99a8b93828: Already exists
1da1131b1360: Already exists
48bde579d8cc: Already exists
1929d0623312: Already exists
1fea93ec33be: Already exists
fed2bcb93d83: Already exists
d06e3ac07eba: Already exists
a8090bf3b91d: Already exists
204c9b3ef04c: Already exists
95d9537f4e2e: Already exists
40cbb147917e: Already exists
b8e5cf599c18: Already exists
bd74081a3b16: Already exists
50105f4a3af9: Pull complete
b218c24b76da: Pull complete
afd258a43f9e: Pull complete
89732bc75041: Pull complete
428c2ea77ec0: Pull complete
40d17e1b116e: Pull complete
c3e95d93d7ac: Pull complete
b39b18afe74e: Pull complete
Digest: sha256:6cf16c4573c95f5e66e40740d9f6238377b3aaab38176e7986310c21bdd6094a
Status: Downloaded newer image for harbor.registry.com/apps/spring-petclinic-backend:b1.20220116.103057
Setting Active Processor Count to 4
WARNING: Unable to convert memory limit "max" from path "/sys/fs/cgroup/memory.max" as int: memory size "max" does not match pattern "^([\\d]+)([kmgtKMGT]?)$"
Calculating JVM memory based on 1280440K available memory
Calculated JVM Memory Configuration: -XX:MaxDirectMemorySize=10M -Xmx644437K -XX:MaxMetaspaceSize=124002K -XX:ReservedCodeCacheSize=240M -Xss1M (Total Memory: 1280440K, Thread Count: 250, Loaded Class Count: 19479, Headroom: 0%)
Enabling Java Native Memory Tracking
Adding 128 container CA certificates to JVM truststore
Spring Cloud Bindings Enabled
Picked up JAVA_TOOL_OPTIONS: -Djava.security.properties=/layers/paketo-buildpacks_bellsoft-liberica/java-security-properties/java-security.properties -XX:+ExitOnOutOfMemoryError -XX:ActiveProcessorCount=4 -XX:MaxDirectMemorySize=10M -Xmx644437K -XX:MaxMetaspaceSize=124002K -XX:ReservedCodeCacheSize=240M -Xss1M -XX:+UnlockDiagnosticVMOptions -XX:NativeMemoryTracking=summary -XX:+PrintNMTStatistics -Dorg.springframework.cloud.bindings.boot.enable=true

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.6.2)

INFO  PetClinicApplication - Starting PetClinicApplication v2.6.2 using Java 11.0.13 on 0b6241f0c523 with PID 1 (/workspace/BOOT-INF/classes started by cnb in /workspace)
DEBUG PetClinicApplication - Running with Spring Boot v2.6.2, Spring v5.3.14
INFO  PetClinicApplication - The following profiles are active: hsqldb,spring-data-jpa
INFO  Version - HV000001: Hibernate Validator 6.2.0.Final
INFO  RepositoryConfigurationDelegate - Bootstrapping Spring Data JPA repositories in DEFAULT mode.
INFO  RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 97 ms. Found 7 JPA repository interfaces.
INFO  TomcatWebServer - Tomcat initialized with port(s): 9966 (http)
INFO  Http11NioProtocol - Initializing ProtocolHandler ["http-nio-9966"]
INFO  StandardService - Starting service [Tomcat]
INFO  StandardEngine - Starting Servlet engine: [Apache Tomcat/9.0.56]
INFO  [/petclinic] - Initializing Spring embedded WebApplicationContext
INFO  ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 2210 ms
INFO  HikariDataSource - HikariPool-1 - Starting...
INFO  PoolBase - HikariPool-1 - Driver does not support get/set network timeout for connections. (feature not supported)
INFO  HikariDataSource - HikariPool-1 - Start completed.
INFO  LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
INFO  Version - HHH000412: Hibernate ORM core version 5.6.3.Final
INFO  Version - HCANN000001: Hibernate Commons Annotations {5.1.2.Final}
INFO  Dialect - HHH000400: Using dialect: org.hibernate.dialect.HSQLDialect
INFO  JtaPlatformInitiator - HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
INFO  LocalContainerEntityManagerFactoryBean - Initialized JPA EntityManagerFactory for persistence unit 'default'
INFO  EndpointLinksResolver - Exposing 1 endpoint(s) beneath base path '/actuator'
INFO  UserDetailsServiceAutoConfiguration -

Using generated security password: 5b765681-8357-403d-8e73-7edc4554cccc

INFO  DefaultSecurityFilterChain - Will secure any request with [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@4f1072ee, org.springframework.security.web.context.SecurityContextPersistenceFilter@3fe33c59, org.springframework.security.web.header.HeaderWriterFilter@60eb9c29, org.springframework.security.web.authentication.logout.LogoutFilter@293988dc, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@34e700f4, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@3bbab2c9, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@7b0a69b9, org.springframework.security.web.session.SessionManagementFilter@2f0a29f7, org.springframework.security.web.access.ExceptionTranslationFilter@63019596, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@5a513627]
INFO  Http11NioProtocol - Starting ProtocolHandler ["http-nio-9966"]
INFO  TomcatWebServer - Tomcat started on port(s): 9966 (http) with context path '/petclinic'
INFO  PetClinicApplication - Started PetClinicApplication in 6.817 seconds (JVM running for 7.35)

Let's check the output by running one of the APIs at localhost:8080/petclinic/swagger-ui/index.h..:

image.png

Hmm.... what happened here? If we check the logs above, it seems that our sample code starts at port 9966. It is considered a common practice (but definitely not required) to run user-facing containers such as these on port 8080, and map to whatever port we want outside the container. We could simple run the below command and it would work fine:

> docker run -p 8080:9966 harbor.registry.com/apps/spring-petclinic-backend:b1.20220116.103057

However, I like to have repeatable practices. So, let's fork the repo and fix the server.port setting in application.properties.

Making changes

The forked repo is located at github.com/odedia/spring-petclinic-rest. Let's update github.com/odedia/spring-petclinic-rest/blo.. and change server.port=9966 to server.port=8080.

To update our build to point to the updated repo, we simply need to update the kp image save command with the updated git URL:

> kp image save spring-petclinic-backend \
    --tag harbor.registry.com/apps/spring-petclinic-backend \
    --git https://github.com/odedia/spring-petclinic-rest.git \
    --git-revision master
Patching Image Resource...
Image Resource "spring-petclinic-backend" patched

If we'll check the build logs now, we'll find that the build is a lot faster and doesn't download all the maven dependencies again. That's because Tanzu Build Service caches layers as needed, and the maven cache layer did not change:

> kp build logs spring-petclinic-backend
===> PREPARE
Build reason(s): COMMIT,CONFIG
COMMIT:
  - 8da34240a5a9a04809f714a76cee82c6e27bea14
  + c31f00af9fae5ef63c323cfbf5f890f252d8669a
CONFIG:
  resources: {}
  source:
    git:
  -     revision: 8da34240a5a9a04809f714a76cee82c6e27bea14
  -     url: https://github.com/spring-petclinic/spring-petclinic-rest.git
  +     revision: c31f00af9fae5ef63c323cfbf5f890f252d8669a
  +     url: https://github.com/odedia/spring-petclinic-rest.git
Loading secret for "harbor.registry.com" from secret "registry-credentials" at location "/var/build-secrets/registry-credentials"
Cloning "https://github.com/odedia/spring-petclinic-rest.git" @ "c31f00af9fae5ef63c323cfbf5f890f252d8669a"...
Successfully cloned "https://github.com/odedia/spring-petclinic-rest.git" @ "c31f00af9fae5ef63c323cfbf5f890f252d8669a" in path "/workspace"
===> ANALYZE
===> DETECT
8 of 35 buildpacks participating
paketo-buildpacks/ca-certificates   3.0.2
paketo-buildpacks/bellsoft-liberica 9.0.2
paketo-buildpacks/syft              1.3.1
paketo-buildpacks/maven             6.0.2
paketo-buildpacks/executable-jar    6.0.2
paketo-buildpacks/apache-tomcat     7.0.3
paketo-buildpacks/dist-zip          5.0.2
paketo-buildpacks/spring-boot       5.3.0
===> RESTORE
Restoring metadata for "paketo-buildpacks/ca-certificates:helper" from app image
Restoring metadata for "paketo-buildpacks/bellsoft-liberica:java-security-properties" from app image
Restoring metadata for "paketo-buildpacks/bellsoft-liberica:jre" from app image
Restoring metadata for "paketo-buildpacks/bellsoft-liberica:helper" from app image
Restoring metadata for "paketo-buildpacks/bellsoft-liberica:jdk" from cache
Restoring metadata for "paketo-buildpacks/syft:syft" from cache
Restoring metadata for "paketo-buildpacks/maven:cache" from cache
Restoring metadata for "paketo-buildpacks/maven:application" from cache
Restoring metadata for "paketo-buildpacks/spring-boot:spring-cloud-bindings" from app image
Restoring metadata for "paketo-buildpacks/spring-boot:web-application-type" from app image
Restoring metadata for "paketo-buildpacks/spring-boot:helper" from app image
Restoring data for "paketo-buildpacks/bellsoft-liberica:jdk" from cache
Restoring data for "paketo-buildpacks/syft:syft" from cache
Restoring data for "paketo-buildpacks/maven:application" from cache
Restoring data for "paketo-buildpacks/maven:cache" from cache
===> BUILD

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

Paketo BellSoft Liberica Buildpack 9.0.2
  https://github.com/paketo-buildpacks/bellsoft-liberica
  Build Configuration:
    $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           enables Java Management Extensions (JMX)
    $BPL_JMX_PORT                5000            configure the JMX port
    $BPL_JVM_HEAD_ROOM           0               the headroom in memory calculation
    $BPL_JVM_LOADED_CLASS_COUNT  35% of classes  the number of loaded classes in memory calculation
    $BPL_JVM_THREAD_COUNT        250             the number of threads in memory calculation
    $JAVA_TOOL_OPTIONS                           the JVM launch flags
  BellSoft Liberica JDK 11.0.13: Reusing cached layer
  BellSoft Liberica JRE 11.0.13: Reusing cached layer
  Launch Helper: Reusing cached layer
  Java Security Properties: Reusing cached layer

Paketo Syft Buildpack 1.3.1
  https://github.com/paketo-buildpacks/syft

Paketo Maven Buildpack 6.0.2
  https://github.com/paketo-buildpacks/maven
  Build Configuration:
    $BP_MAVEN_BUILD_ARGUMENTS  -Dmaven.test.skip=true package  the arguments to pass to Maven
    $BP_MAVEN_BUILT_ARTIFACT   target/*.[ejw]ar                the built application artifact explicitly.  Supersedes $BP_MAVEN_BUILT_MODULE
    $BP_MAVEN_BUILT_MODULE                                     the module to find application artifact in
    $BP_MAVEN_POM_FILE         pom.xml                         the location of the main pom.xml file, relative to the application root
    Creating cache directory /home/cnb/.m2
  Compiled Application: Contributing to layer
    Executing mvnw --batch-mode -Dmaven.test.skip=true package
      [INFO] Scanning for projects...
      [INFO]
      [INFO] ---------< org.springframework.samples:spring-petclinic-rest >----------
      [INFO] Building spring-petclinic-rest 2.6.2
      [INFO] --------------------------------[ jar ]---------------------------------
      [INFO]
      [INFO] --- jacoco-maven-plugin:0.8.7:prepare-agent (default) @ spring-petclinic-rest ---
      [INFO] argLine set to -javaagent:/home/cnb/.m2/repository/org/jacoco/org.jacoco.agent/0.8.7/org.jacoco.agent-0.8.7-runtime.jar=destfile=/workspace/target/jacoco.exec,excludes=**/org/springframework/samples/petclinic/rest/dto/**:**/org/springframework/samples/petclinic/rest/api/**
      [INFO]
      [INFO] --- openapi-generator-maven-plugin:5.2.1:generate (default) @ spring-petclinic-rest ---
      [INFO] Generating with dryRun=false
      [INFO] Output directory (/workspace/target/generated-sources/openapi) does not exist, or is inaccessible. No file (.openapi-generator-ignore) will be evaluated.
      [INFO] OpenAPI Generator: spring (server)
      [INFO] Generator 'spring' is considered stable.
      [INFO] ----------------------------------
      [WARNING] java8 option has been deprecated as it's set to true by default (JDK7 support has been deprecated)
      [INFO] Environment variable JAVA_POST_PROCESS_FILE not defined so the Java code may not be properly formatted. To define it, try 'export JAVA_POST_PROCESS_FILE="/usr/local/bin/clang-format -i"' (Linux/Mac)
      [INFO] NOTE: To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI).
      [INFO] Invoker Package Name, originally not set, is now derived from api package name: org.springframework.samples.petclinic.rest
      [INFO] Processing operation failingRequest
      [INFO] Processing operation listOwners
      [INFO] Processing operation addOwner
      [INFO] Processing operation getOwner
      [INFO] Processing operation updateOwner
      [INFO] Processing operation addPet
      [INFO] Processing operation getPet
      [INFO] Processing operation updatePet
      [INFO] Processing operation addVisit
      [INFO] Processing operation listPetTypes
      [INFO] Processing operation listVets
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/OwnerAllOfDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/OwnerDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/OwnerFieldsDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/PetAllOfDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/PetDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/PetFieldsDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/PetTypeAllOfDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/PetTypeDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/PetTypeFieldsDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/RestErrorDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/RoleDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/SpecialtyDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/UserDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/ValidationMessageDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/VetAllOfDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/VetDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/VetFieldsDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/VisitAllOfDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/VisitDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/VisitFieldsDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/api/OopsApi.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/api/OwnersApi.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/api/PettypesApi.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/api/VetsApi.java
      [INFO] Skipped /workspace/target/generated-sources/openapi/pom.xml (Skipped by supportingFiles options supplied by user.)
      [INFO] Skipped /workspace/target/generated-sources/openapi/README.md (Skipped by supportingFiles options supplied by user.)
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/api/ApiUtil.java
      [INFO] Skipped /workspace/target/generated-sources/openapi/.openapi-generator-ignore (Skipped by supportingFiles options supplied by user.)
      [INFO] writing file /workspace/target/generated-sources/openapi/.openapi-generator/VERSION
      [INFO] writing file /workspace/target/generated-sources/openapi/.openapi-generator/FILES
      ################################################################################
      # Thanks for using OpenAPI Generator.                                          #
      # Please consider donation to help us maintain this project ?                 #
      # https://opencollective.com/openapi_generator/donate                          #
      ################################################################################
      [INFO]
      [INFO] --- build-helper-maven-plugin:3.2.0:add-source (add-source) @ spring-petclinic-rest ---
      [INFO] Source directory: /workspace/target/generated-sources/openapi/src/main/java added.
      [INFO]
      [INFO] --- spring-boot-maven-plugin:2.6.2:build-info (default) @ spring-petclinic-rest ---
      [INFO]
      [INFO] --- maven-resources-plugin:3.2.0:resources (default-resources) @ spring-petclinic-rest ---
      [INFO] Using 'UTF-8' encoding to copy filtered resources.
      [INFO] Using 'UTF-8' encoding to copy filtered properties files.
      [INFO] Copying 4 resources
      [INFO] Copying 13 resources
      [INFO]
      [INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ spring-petclinic-rest ---
      [INFO] Changes detected - recompiling the module!
      [INFO] Compiling 108 source files to /workspace/target/classes
      [INFO]
      [INFO] --- maven-resources-plugin:3.2.0:testResources (default-testResources) @ spring-petclinic-rest ---
      [INFO] Not copying test resources
      [INFO]
      [INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ spring-petclinic-rest ---
      [INFO] Not compiling test sources
      [INFO]
      [INFO] --- maven-surefire-plugin:2.22.2:test (default-test) @ spring-petclinic-rest ---
      [INFO] Tests are skipped.
      [INFO]
      [INFO] --- jacoco-maven-plugin:0.8.7:report (report) @ spring-petclinic-rest ---
      [INFO] Skipping JaCoCo execution due to missing execution data file.
      [INFO]
      [INFO] --- maven-jar-plugin:3.2.0:jar (default-jar) @ spring-petclinic-rest ---
      [INFO] Building jar: /workspace/target/spring-petclinic-rest-2.6.2.jar
      [INFO]
      [INFO] --- spring-boot-maven-plugin:2.6.2:repackage (repackage) @ spring-petclinic-rest ---
      [INFO] Replacing main artifact with repackaged archive
      [INFO] ------------------------------------------------------------------------
      [INFO] BUILD SUCCESS
      [INFO] ------------------------------------------------------------------------
      [INFO] Total time:  7.741 s
      [INFO] Finished at: 2022-01-16T10:43:45Z
      [INFO] ------------------------------------------------------------------------
  Removing source code

Paketo Executable JAR Buildpack 6.0.2
  https://github.com/paketo-buildpacks/executable-jar
  Class Path: Contributing to layer
    Writing env/CLASSPATH.delim
    Writing env/CLASSPATH.prepend
  Process types:
    executable-jar: java org.springframework.boot.loader.JarLauncher (direct)
    task:           java org.springframework.boot.loader.JarLauncher (direct)
    web:            java org.springframework.boot.loader.JarLauncher (direct)

Paketo Spring Boot Buildpack 5.3.0
  https://github.com/paketo-buildpacks/spring-boot
  Creating slices from layers index
    dependencies
    spring-boot-loader
    snapshot-dependencies
    application
  Launch Helper: Reusing cached layer
  Spring Cloud Bindings 1.8.0: Reusing cached layer
  Web Application Type: Contributing to layer
    Servlet web application detected
    Writing env.launch/BPL_JVM_THREAD_COUNT.default
  4 application slices
  Image labels:
    org.opencontainers.image.title
    org.opencontainers.image.version
    org.springframework.boot.version
===> EXPORT
Reusing layers from image 'harbor.registry.com/apps/spring-petclinic-backend@sha256:6cf16c4573c95f5e66e40740d9f6238377b3aaab38176e7986310c21bdd6094a'
Reusing layer 'paketo-buildpacks/ca-certificates:helper'
Reusing layer 'paketo-buildpacks/bellsoft-liberica:helper'
Reusing layer 'paketo-buildpacks/bellsoft-liberica:java-security-properties'
Reusing layer 'paketo-buildpacks/bellsoft-liberica:jre'
Reusing layer 'paketo-buildpacks/executable-jar:classpath'
Reusing layer 'paketo-buildpacks/spring-boot:helper'
Reusing layer 'paketo-buildpacks/spring-boot:spring-cloud-bindings'
Reusing layer 'paketo-buildpacks/spring-boot:web-application-type'
Adding layer 'launch.sbom'
Reusing 4/5 app layer(s)
Adding 1/5 app layer(s)
Reusing layer 'launcher'
Reusing layer 'config'
Reusing layer 'process-types'
Adding label 'io.buildpacks.lifecycle.metadata'
Adding label 'io.buildpacks.build.metadata'
Adding label 'io.buildpacks.project.metadata'
Adding label 'org.opencontainers.image.title'
Adding label 'org.opencontainers.image.version'
Adding label 'org.springframework.boot.version'
Setting default process type 'web'
Saving harbor.registry.com/apps/spring-petclinic-backend...
*** Images (sha256:d55635a51867aa722318fd405b288d865c42604ad758804bb20ef913e88e111e):
      harbor.registry.com/apps/spring-petclinic-backend
      harbor.registry.com/apps/spring-petclinic-backend:b2.20220116.104312
Reusing cache layer 'paketo-buildpacks/bellsoft-liberica:jdk'
Reusing cache layer 'paketo-buildpacks/syft:syft'
Adding cache layer 'paketo-buildpacks/maven:application'
Reusing cache layer 'paketo-buildpacks/maven:cache'
Reusing cache layer 'cache.sbom'
===> COMPLETION
Build successful

Let's run the image again:

> docker run -p 8080:8080 harbor.registry.com/apps/spring-petclinic-backend:b2.20220116.104312
Unable to find image 'harbor.registry.com/apps/spring-petclinic-backend:b2.20220116.104312' locally
b2.20220116.104312: Pulling from apps/spring-petclinic-backend
bf99a8b93828: Already exists
1da1131b1360: Already exists
48bde579d8cc: Already exists
1929d0623312: Already exists
1fea93ec33be: Already exists
fed2bcb93d83: Already exists
d06e3ac07eba: Already exists
a8090bf3b91d: Already exists
204c9b3ef04c: Already exists
95d9537f4e2e: Already exists
40cbb147917e: Already exists
b8e5cf599c18: Already exists
bd74081a3b16: Already exists
1eeff7ac260d: Pull complete
b218c24b76da: Pull complete
afd258a43f9e: Pull complete
89732bc75041: Pull complete
ee556fcb0298: Pull complete
40d17e1b116e: Pull complete
c3e95d93d7ac: Pull complete
b39b18afe74e: Pull complete
Digest: sha256:d55635a51867aa722318fd405b288d865c42604ad758804bb20ef913e88e111e
Status: Downloaded newer image for harbor.registry.com/apps/spring-petclinic-backend:b2.20220116.104312
Setting Active Processor Count to 4
WARNING: Unable to convert memory limit "max" from path "/sys/fs/cgroup/memory.max" as int: memory size "max" does not match pattern "^([\\d]+)([kmgtKMGT]?)$"
Calculating JVM memory based on 1279512K available memory
Calculated JVM Memory Configuration: -XX:MaxDirectMemorySize=10M -Xmx643509K -XX:MaxMetaspaceSize=124002K -XX:ReservedCodeCacheSize=240M -Xss1M (Total Memory: 1279512K, Thread Count: 250, Loaded Class Count: 19479, Headroom: 0%)
Enabling Java Native Memory Tracking
Adding 128 container CA certificates to JVM truststore
Spring Cloud Bindings Enabled
Picked up JAVA_TOOL_OPTIONS: -Djava.security.properties=/layers/paketo-buildpacks_bellsoft-liberica/java-security-properties/java-security.properties -XX:+ExitOnOutOfMemoryError -XX:ActiveProcessorCount=4 -XX:MaxDirectMemorySize=10M -Xmx643509K -XX:MaxMetaspaceSize=124002K -XX:ReservedCodeCacheSize=240M -Xss1M -XX:+UnlockDiagnosticVMOptions -XX:NativeMemoryTracking=summary -XX:+PrintNMTStatistics -Dorg.springframework.cloud.bindings.boot.enable=true

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.6.2)

INFO  PetClinicApplication - Starting PetClinicApplication v2.6.2 using Java 11.0.13 on 8c17a9943dd9 with PID 1 (/workspace/BOOT-INF/classes started by cnb in /workspace)
DEBUG PetClinicApplication - Running with Spring Boot v2.6.2, Spring v5.3.14
INFO  PetClinicApplication - The following profiles are active: hsqldb,spring-data-jpa
INFO  Version - HV000001: Hibernate Validator 6.2.0.Final
INFO  RepositoryConfigurationDelegate - Bootstrapping Spring Data JPA repositories in DEFAULT mode.
INFO  RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 81 ms. Found 7 JPA repository interfaces.
INFO  TomcatWebServer - Tomcat initialized with port(s): 8080 (http)
INFO  Http11NioProtocol - Initializing ProtocolHandler ["http-nio-8080"]
INFO  StandardService - Starting service [Tomcat]
INFO  StandardEngine - Starting Servlet engine: [Apache Tomcat/9.0.56]
INFO  [/petclinic] - Initializing Spring embedded WebApplicationContext
INFO  ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 2294 ms
INFO  HikariDataSource - HikariPool-1 - Starting...
INFO  PoolBase - HikariPool-1 - Driver does not support get/set network timeout for connections. (feature not supported)
INFO  HikariDataSource - HikariPool-1 - Start completed.
INFO  LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
INFO  Version - HHH000412: Hibernate ORM core version 5.6.3.Final
INFO  Version - HCANN000001: Hibernate Commons Annotations {5.1.2.Final}
INFO  Dialect - HHH000400: Using dialect: org.hibernate.dialect.HSQLDialect
INFO  JtaPlatformInitiator - HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
INFO  LocalContainerEntityManagerFactoryBean - Initialized JPA EntityManagerFactory for persistence unit 'default'
INFO  EndpointLinksResolver - Exposing 1 endpoint(s) beneath base path '/actuator'
INFO  UserDetailsServiceAutoConfiguration -

Using generated security password: 73e3ef49-bc5c-4922-a168-570d4d8c048e

INFO  DefaultSecurityFilterChain - Will secure any request with [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@62cbe18c, org.springframework.security.web.context.SecurityContextPersistenceFilter@490b8f1e, org.springframework.security.web.header.HeaderWriterFilter@dc6a186, org.springframework.security.web.authentication.logout.LogoutFilter@35ef158f, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@4eb43d2f, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@5c70eda4, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@377b7798, org.springframework.security.web.session.SessionManagementFilter@27b9d5b7, org.springframework.security.web.access.ExceptionTranslationFilter@71cdde0c, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@6d398b6c]
INFO  Http11NioProtocol - Starting ProtocolHandler ["http-nio-8080"]
INFO  TomcatWebServer - Tomcat started on port(s): 8080 (http) with context path '/petclinic'
INFO  PetClinicApplication - Started PetClinicApplication in 7.167 seconds (JVM running for 7.718)

The result looks much better now:

image.png

Changing the defaults

If we'll take a closer look at each buildpack stage in the logs, we'll see that there are certain defaults that are being applied to our image. For example:

  Build Configuration:
    $BP_JVM_TYPE                 JRE             the JVM type - JDK or JRE
    $BP_JVM_VERSION              11              the Java version
  Build Configuration:
    $BP_MAVEN_BUILD_ARGUMENTS  -Dmaven.test.skip=true package  the arguments to pass to Maven

Each one of these parameters can be changed in order to customize our build. For example - I may want to use Java 17 since it's 2022. I may also opt to run all unit tests as part of my build. In that case, I could change the parameters as follows:

  • BP_JVM_VERSION=17
  • BP_MAVEN_BUILD_ARGUMENTS="-Dmaven.test.skip=false package" Let's update our build accordingly:
> kp image save spring-petclinic-backend \
    --tag harbor.registry.com/apps/spring-petclinic-backend \
    --git https://github.com/odedia/spring-petclinic-rest.git \
    --git-revision master \
    --env BP_JVM_VERSION=17 \
    --env BP_MAVEN_BUILD_ARGUMENTS="-Dmaven.test.skip=false package"

If we'll check the updated logs, we'll see that we now use Java 17 and that we are now running all unit tests (logs truncated due to many lines of unit testing...):

> kp build logs spring-petclinic-backend
===> PREPARE
Build reason(s): CONFIG
CONFIG:
  + env:
  + - name: BP_JVM_VERSION
  +   value: "17"
  + - name: BP_MAVEN_BUILD_ARGUMENTS
  +   value: -Dmaven.test.skip=false package
  resources: {}
  source:
    git:
      revision: c31f00af9fae5ef63c323cfbf5f890f252d8669a
      url: https://github.com/odedia/spring-petclinic-rest.git
Loading secret for "harbor.registry.com" from secret "registry-credentials" at location "/var/build-secrets/registry-credentials"
Cloning "https://github.com/odedia/spring-petclinic-rest.git" @ "c31f00af9fae5ef63c323cfbf5f890f252d8669a"...
Successfully cloned "https://github.com/odedia/spring-petclinic-rest.git" @ "c31f00af9fae5ef63c323cfbf5f890f252d8669a" in path "/workspace"
===> ANALYZE
===> DETECT
8 of 35 buildpacks participating
paketo-buildpacks/ca-certificates   3.0.2
paketo-buildpacks/bellsoft-liberica 9.0.2
paketo-buildpacks/syft              1.3.1
paketo-buildpacks/maven             6.0.2
paketo-buildpacks/executable-jar    6.0.2
paketo-buildpacks/apache-tomcat     7.0.3
paketo-buildpacks/dist-zip          5.0.2
paketo-buildpacks/spring-boot       5.3.0
===> RESTORE
Restoring metadata for "paketo-buildpacks/ca-certificates:helper" from app image
Restoring metadata for "paketo-buildpacks/bellsoft-liberica:helper" from app image
Restoring metadata for "paketo-buildpacks/bellsoft-liberica:java-security-properties" from app image
Restoring metadata for "paketo-buildpacks/bellsoft-liberica:jre" from app image
Restoring metadata for "paketo-buildpacks/bellsoft-liberica:jdk" from cache
Restoring metadata for "paketo-buildpacks/syft:syft" from cache
Restoring metadata for "paketo-buildpacks/maven:application" from cache
Restoring metadata for "paketo-buildpacks/maven:cache" from cache
Restoring metadata for "paketo-buildpacks/spring-boot:web-application-type" from app image
Restoring metadata for "paketo-buildpacks/spring-boot:helper" from app image
Restoring metadata for "paketo-buildpacks/spring-boot:spring-cloud-bindings" from app image
Restoring data for "paketo-buildpacks/bellsoft-liberica:jdk" from cache
Restoring data for "paketo-buildpacks/syft:syft" from cache
Restoring data for "paketo-buildpacks/maven:application" from cache
Restoring data for "paketo-buildpacks/maven:cache" from cache
===> BUILD

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

Paketo BellSoft Liberica Buildpack 9.0.2
  https://github.com/paketo-buildpacks/bellsoft-liberica
  Build Configuration:
    $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           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           enables Java Management Extensions (JMX)
    $BPL_JMX_PORT                5000            configure the JMX port
    $BPL_JVM_HEAD_ROOM           0               the headroom in memory calculation
    $BPL_JVM_LOADED_CLASS_COUNT  35% of classes  the number of loaded classes in memory calculation
    $BPL_JVM_THREAD_COUNT        250             the number of threads in memory calculation
    $JAVA_TOOL_OPTIONS                           the JVM launch flags
  BellSoft Liberica JDK 17.0.1: Contributing to layer
    Reusing cached download from buildpack
    Expanding to /layers/paketo-buildpacks_bellsoft-liberica/jdk
    Adding 128 container CA certificates to JVM truststore
    Writing env.build/JAVA_HOME.override
    Writing env.build/JDK_HOME.override
  BellSoft Liberica JRE 17.0.1: Contributing to layer
    Reusing cached download from buildpack
    Expanding to /layers/paketo-buildpacks_bellsoft-liberica/jre
    Adding 128 container CA certificates to JVM truststore
    Writing env.launch/BPI_APPLICATION_PATH.default
    Writing env.launch/BPI_JVM_CACERTS.default
    Writing env.launch/BPI_JVM_CLASS_COUNT.default
    Writing env.launch/BPI_JVM_SECURITY_PROVIDERS.default
    Writing env.launch/JAVA_HOME.default
    Writing env.launch/JAVA_TOOL_OPTIONS.append
    Writing env.launch/JAVA_TOOL_OPTIONS.delim
    Writing env.launch/MALLOC_ARENA_MAX.default
  Launch Helper: Reusing cached layer
  Java Security Properties: Reusing cached layer

Paketo Syft Buildpack 1.3.1
  https://github.com/paketo-buildpacks/syft

Paketo Maven Buildpack 6.0.2
  https://github.com/paketo-buildpacks/maven
  Build Configuration:
    $BP_MAVEN_BUILD_ARGUMENTS  -Dmaven.test.skip=false package  the arguments to pass to Maven
    $BP_MAVEN_BUILT_ARTIFACT   target/*.[ejw]ar                 the built application artifact explicitly.  Supersedes $BP_MAVEN_BUILT_MODULE
    $BP_MAVEN_BUILT_MODULE                                      the module to find application artifact in
    $BP_MAVEN_POM_FILE         pom.xml                          the location of the main pom.xml file, relative to the application root
    Creating cache directory /home/cnb/.m2
  Compiled Application: Contributing to layer
    Executing mvnw --batch-mode -Dmaven.test.skip=false package
      [INFO] Scanning for projects...
      [INFO]
      [INFO] ---------< org.springframework.samples:spring-petclinic-rest >----------
      [INFO] Building spring-petclinic-rest 2.6.2
      [INFO] --------------------------------[ jar ]---------------------------------
      [INFO]
      [INFO] --- jacoco-maven-plugin:0.8.7:prepare-agent (default) @ spring-petclinic-rest ---
      [INFO] argLine set to -javaagent:/home/cnb/.m2/repository/org/jacoco/org.jacoco.agent/0.8.7/org.jacoco.agent-0.8.7-runtime.jar=destfile=/workspace/target/jacoco.exec,excludes=**/org/springframework/samples/petclinic/rest/dto/**:**/org/springframework/samples/petclinic/rest/api/**
      [INFO]
      [INFO] --- openapi-generator-maven-plugin:5.2.1:generate (default) @ spring-petclinic-rest ---
      [INFO] Generating with dryRun=false
      [INFO] Output directory (/workspace/target/generated-sources/openapi) does not exist, or is inaccessible. No file (.openapi-generator-ignore) will be evaluated.
      [INFO] OpenAPI Generator: spring (server)
      [INFO] Generator 'spring' is considered stable.
      [INFO] ----------------------------------
      [WARNING] java8 option has been deprecated as it's set to true by default (JDK7 support has been deprecated)
      [INFO] Environment variable JAVA_POST_PROCESS_FILE not defined so the Java code may not be properly formatted. To define it, try 'export JAVA_POST_PROCESS_FILE="/usr/local/bin/clang-format -i"' (Linux/Mac)
      [INFO] NOTE: To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI).
      [INFO] Invoker Package Name, originally not set, is now derived from api package name: org.springframework.samples.petclinic.rest
      [INFO] Processing operation failingRequest
      [INFO] Processing operation listOwners
      [INFO] Processing operation addOwner
      [INFO] Processing operation getOwner
      [INFO] Processing operation updateOwner
      [INFO] Processing operation addPet
      [INFO] Processing operation getPet
      [INFO] Processing operation updatePet
      [INFO] Processing operation addVisit
      [INFO] Processing operation listPetTypes
      [INFO] Processing operation listVets
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/OwnerAllOfDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/OwnerDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/OwnerFieldsDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/PetAllOfDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/PetDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/PetFieldsDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/PetTypeAllOfDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/PetTypeDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/PetTypeFieldsDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/RestErrorDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/RoleDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/SpecialtyDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/UserDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/ValidationMessageDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/VetAllOfDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/VetDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/VetFieldsDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/VisitAllOfDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/VisitDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/dto/VisitFieldsDto.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/api/OopsApi.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/api/OwnersApi.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/api/PettypesApi.java
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/api/VetsApi.java
      [INFO] Skipped /workspace/target/generated-sources/openapi/pom.xml (Skipped by supportingFiles options supplied by user.)
      [INFO] Skipped /workspace/target/generated-sources/openapi/README.md (Skipped by supportingFiles options supplied by user.)
      [INFO] writing file /workspace/target/generated-sources/openapi/src/main/java/org/springframework/samples/petclinic/rest/api/ApiUtil.java
      [INFO] Skipped /workspace/target/generated-sources/openapi/.openapi-generator-ignore (Skipped by supportingFiles options supplied by user.)
      [INFO] writing file /workspace/target/generated-sources/openapi/.openapi-generator/VERSION
      [INFO] writing file /workspace/target/generated-sources/openapi/.openapi-generator/FILES
      ################################################################################
      # Thanks for using OpenAPI Generator.                                          #
      # Please consider donation to help us maintain this project ?                 #
      # https://opencollective.com/openapi_generator/donate                          #
      ################################################################################
      [INFO]
      [INFO] --- build-helper-maven-plugin:3.2.0:add-source (add-source) @ spring-petclinic-rest ---
      [INFO] Source directory: /workspace/target/generated-sources/openapi/src/main/java added.
      [INFO]
      [INFO] --- spring-boot-maven-plugin:2.6.2:build-info (default) @ spring-petclinic-rest ---
      [INFO]
      [INFO] --- maven-resources-plugin:3.2.0:resources (default-resources) @ spring-petclinic-rest ---
      [INFO] Using 'UTF-8' encoding to copy filtered resources.
      [INFO] Using 'UTF-8' encoding to copy filtered properties files.
      [INFO] Copying 4 resources
      [INFO] Copying 13 resources
      [INFO]
      [INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ spring-petclinic-rest ---
      [INFO] Changes detected - recompiling the module!
      [INFO] Compiling 108 source files to /workspace/target/classes
      [INFO]
      [INFO] --- maven-resources-plugin:3.2.0:testResources (default-testResources) @ spring-petclinic-rest ---
      [INFO] Using 'UTF-8' encoding to copy filtered resources.
      [INFO] Using 'UTF-8' encoding to copy filtered properties files.
      [INFO] Copying 1 resource
      [INFO]
      [INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ spring-petclinic-rest ---
      [INFO] Changes detected - recompiling the module!
      [INFO] Compiling 18 source files to /workspace/target/test-classes
      [INFO]
      [INFO] --- maven-surefire-plugin:2.22.2:test (default-test) @ spring-petclinic-rest ---
      [INFO] Downloading from central: https://repo.maven.apache.org/maven2/org/apache/maven/surefire/surefire-junit-platform/2.22.2/surefire-junit-platform-2.22.2.pom
      [INFO] Downloaded from central: https://repo.maven.apache.org/maven2/org/apache/maven/surefire/surefire-junit-platform/2.22.2/surefire-junit-platform-2.22.2.pom (7.0 kB at 28 kB/s)
      [INFO] Downloading from central: https://repo.maven.apache.org/maven2/org/apache/maven/surefire/surefire-providers/2.22.2/surefire-providers-2.22.2.pom
      [INFO] Downloaded from central: https://repo.maven.apache.org/maven2/org/apache/maven/surefire/surefire-providers/2.22.2/surefire-providers-2.22.2.pom (2.5 kB at 113 kB/s)
      [INFO] Downloading from central: https://repo.maven.apache.org/maven2/org/junit/platform/junit-platform-launcher/1.3.1/junit-platform-launcher-1.3.1.pom
      [INFO] Downloaded from central: https://repo.maven.apache.org/maven2/org/junit/platform/junit-platform-launcher/1.3.1/junit-platform-launcher-1.3.1.pom (2.2 kB at 222 kB/s)
      [INFO] Downloading from central: https://repo.maven.apache.org/maven2/org/apiguardian/apiguardian-api/1.0.0/apiguardian-api-1.0.0.pom
      [INFO] Downloaded from central: https://repo.maven.apache.org/maven2/org/apiguardian/apiguardian-api/1.0.0/apiguardian-api-1.0.0.pom (1.2 kB at 146 kB/s)
      [INFO] Downloading from central: https://repo.maven.apache.org/maven2/org/junit/platform/junit-platform-engine/1.3.1/junit-platform-engine-1.3.1.pom
      [INFO] Downloaded from central: https://repo.maven.apache.org/maven2/org/junit/platform/junit-platform-engine/1.3.1/junit-platform-engine-1.3.1.pom (2.4 kB at 126 kB/s)
      [INFO] Downloading from central: https://repo.maven.apache.org/maven2/org/junit/platform/junit-platform-commons/1.3.1/junit-platform-commons-1.3.1.pom
      [INFO] Downloaded from central: https://repo.maven.apache.org/maven2/org/junit/platform/junit-platform-commons/1.3.1/junit-platform-commons-1.3.1.pom (2.0 kB at 202 kB/s)
      [INFO] Downloading from central: https://repo.maven.apache.org/maven2/org/opentest4j/opentest4j/1.1.1/opentest4j-1.1.1.pom
      [INFO] Downloaded from central: https://repo.maven.apache.org/maven2/org/opentest4j/opentest4j/1.1.1/opentest4j-1.1.1.pom (1.7 kB at 129 kB/s)
      [INFO] Downloading from central: https://repo.maven.apache.org/maven2/org/apache/maven/surefire/surefire-junit-platform/2.22.2/surefire-junit-platform-2.22.2.jar
      [INFO] Downloading from central: https://repo.maven.apache.org/maven2/org/junit/platform/junit-platform-launcher/1.3.1/junit-platform-launcher-1.3.1.jar
      [INFO] Downloading from central: https://repo.maven.apache.org/maven2/org/junit/platform/junit-platform-commons/1.3.1/junit-platform-commons-1.3.1.jar
      [INFO] Downloading from central: https://repo.maven.apache.org/maven2/org/apiguardian/apiguardian-api/1.0.0/apiguardian-api-1.0.0.jar
      [INFO] Downloading from central: https://repo.maven.apache.org/maven2/org/junit/platform/junit-platform-engine/1.3.1/junit-platform-engine-1.3.1.jar
      [INFO] Downloaded from central: https://repo.maven.apache.org/maven2/org/apiguardian/apiguardian-api/1.0.0/apiguardian-api-1.0.0.jar (2.2 kB at 37 kB/s)
      [INFO] Downloaded from central: https://repo.maven.apache.org/maven2/org/apache/maven/surefire/surefire-junit-platform/2.22.2/surefire-junit-platform-2.22.2.jar (66 kB at 1.0 MB/s)
      [INFO] Downloading from central: https://repo.maven.apache.org/maven2/org/opentest4j/opentest4j/1.1.1/opentest4j-1.1.1.jar
      [INFO] Downloaded from central: https://repo.maven.apache.org/maven2/org/opentest4j/opentest4j/1.1.1/opentest4j-1.1.1.jar (7.1 kB at 647 kB/s)
      [INFO] Downloaded from central: https://repo.maven.apache.org/maven2/org/junit/platform/junit-platform-launcher/1.3.1/junit-platform-launcher-1.3.1.jar (95 kB at 1.1 MB/s)
      [INFO] Downloaded from central: https://repo.maven.apache.org/maven2/org/junit/platform/junit-platform-commons/1.3.1/junit-platform-commons-1.3.1.jar (78 kB at 771 kB/s)
      [INFO] Downloaded from central: https://repo.maven.apache.org/maven2/org/junit/platform/junit-platform-engine/1.3.1/junit-platform-engine-1.3.1.jar (135 kB at 1.3 MB/s)
      [INFO]
      [INFO] -------------------------------------------------------
      [INFO]  T E S T S
      [INFO] -------------------------------------------------------
      [INFO] Running org.springframework.samples.petclinic.rest.controller.OwnerRestControllerTests
      INFO  AbstractContextLoader - Could not detect default resource locations for test class [org.springframework.samples.petclinic.rest.controller.OwnerRestControllerTests]: no resource found for suffixes {-context.xml, Context.groovy}.
      INFO  SpringBootTestContextBootstrapper - Found @SpringBootConfiguration org.springframework.samples.petclinic.PetClinicApplication for test class org.springframework.samples.petclinic.rest.controller.OwnerRestControllerTests
      INFO  SpringBootTestContextBootstrapper - Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener, org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener, org.springframework.boot.test.autoconfigure.restdocs.RestDocsTestExecutionListener, org.springframework.boot.test.autoconfigure.web.client.MockRestServiceServerResetTestExecutionListener, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcPrintOnlyOnFailureTestExecutionListener, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverTestExecutionListener, org.springframework.boot.test.autoconfigure.webservices.client.MockWebServiceServerTestExecutionListener, org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener, org.springframework.test.context.event.ApplicationEventsTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener, org.springframework.test.context.event.EventPublishingTestExecutionListener, org.springframework.security.test.context.support.WithSecurityContextTestExecutionListener, org.springframework.security.test.context.support.ReactorContextTestExecutionListener]
      INFO  SpringBootTestContextBootstrapper - Using TestExecutionListeners: [org.springframework.test.context.web.ServletTestExecutionListener@ea52184, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener@3e7b65d7, org.springframework.test.context.event.ApplicationEventsTestExecutionListener@3c854752, org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener@3ddeaa5f, org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener@1a500561, org.springframework.test.context.support.DirtiesContextTestExecutionListener@7f608e21, org.springframework.test.context.transaction.TransactionalTestExecutionListener@6949e948, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener@210d2a6c, org.springframework.test.context.event.EventPublishingTestExecutionListener@3bec5821, org.springframework.security.test.context.support.WithSecurityContextTestExecutionListener@4086d8fb, org.springframework.security.test.context.support.ReactorContextTestExecutionListener@66236a0a, org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener@2e3572e8, org.springframework.boot.test.autoconfigure.restdocs.RestDocsTestExecutionListener@77c10a5f, org.springframework.boot.test.autoconfigure.web.client.MockRestServiceServerResetTestExecutionListener@176555c, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcPrintOnlyOnFailureTestExecutionListener@7c781c42, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverTestExecutionListener@795f8317, org.springframework.boot.test.autoconfigure.webservices.client.MockWebServiceServerTestExecutionListener@633fd91]

        .   ____          _            __ _ _
       /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
      ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
       \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
        '  |____| .__|_| |_|_| |_\__, | / / / /
       =========|_|==============|___/=/_/_/_/
       :: Spring Boot ::                (v2.6.2)

      INFO  OwnerRestControllerTests - Starting OwnerRestControllerTests using Java 17.0.1 on spring-petclinic-backend-build-3-build-pod with PID 82 (started by cnb in /workspace)
      DEBUG OwnerRestControllerTests - Running with Spring Boot v2.6.2, Spring v5.3.14
      INFO  OwnerRestControllerTests - The following profiles are active: hsqldb,spring-data-jpa
      INFO  RepositoryConfigurationDelegate - Bootstrapping Spring Data JPA repositories in DEFAULT mode.
      INFO  RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 108 ms. Found 7 JPA repository interfaces.
      INFO  HikariDataSource - HikariPool-1 - Starting...
      INFO  PoolBase - HikariPool-1 - Driver does not support get/set network timeout for connections. (feature not supported)
      INFO  HikariDataSource - HikariPool-1 - Start completed.
      INFO  LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
      INFO  Version - HHH000412: Hibernate ORM core version 5.6.3.Final
      INFO  Version - HCANN000001: Hibernate Commons Annotations {5.1.2.Final}
      INFO  Dialect - HHH000400: Using dialect: org.hibernate.dialect.HSQLDialect
      INFO  Version - HV000001: Hibernate Validator 6.2.0.Final
      INFO  JtaPlatformInitiator - HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
      INFO  LocalContainerEntityManagerFactoryBean - Initialized JPA EntityManagerFactory for persistence unit 'default'
      INFO  EndpointLinksResolver - Exposing 1 endpoint(s) beneath base path '/actuator'
      INFO  DefaultSecurityFilterChain - Will secure any request with [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@4195e7fb, org.springframework.security.web.context.SecurityContextPersistenceFilter@3999f490, org.springframework.security.web.header.HeaderWriterFilter@152a8948, org.springframework.security.web.authentication.logout.LogoutFilter@20df4edc, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@191323f5, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@47ac1aa0, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@4fe30669, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@187ed1ef, org.springframework.security.web.session.SessionManagementFilter@7472bba0, org.springframework.security.web.access.ExceptionTranslationFilter@2104e947, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@7a4f9db7]
      INFO  OwnerRestControllerTests - Started OwnerRestControllerTests in 10.988 seconds (JVM running for 13.299)
      INFO  MockServletContext - Initializing Spring TestDispatcherServlet ''
      INFO  TestDispatcherServlet - Initializing Servlet ''
      INFO  TestDispatcherServlet - Completed initialization in 0 ms
      INFO  MockServletContext - Initializing Spring TestDispatcherServlet ''
      INFO  TestDispatcherServlet - Initializing Servlet ''
      INFO  TestDispatcherServlet - Completed initialization in 0 ms
      INFO  MockServletContext - Initializing Spring TestDispatcherServlet ''
      INFO  TestDispatcherServlet - Initializing Servlet ''
      INFO  TestDispatcherServlet - Completed initialization in 0 ms
      INFO  MockServletContext - Initializing Spring TestDispatcherServlet ''
      INFO  TestDispatcherServlet - Initializing Servlet ''
      INFO  TestDispatcherServlet - Completed initialization in 0 ms
      --> newPetAsJSON={"name":"Rosy","birthDate":"2022-01-16","type":{"name":"dog","id":2},"id":999,"ownerId":null,"visits":[]}
      INFO  MockServletContext - Initializing Spring TestDispatcherServlet ''
      INFO  TestDispatcherServlet - Initializing Servlet ''
      INFO  TestDispatcherServlet - Completed initialization in 0 ms
      INFO  MockServletContext - Initializing Spring TestDispatcherServlet ''
      INFO  TestDispatcherServlet - Initializing Servlet ''
      INFO  TestDispatcherServlet - Completed initialization in 0 ms
      INFO  MockServletContext - Initializing Spring TestDispatcherServlet ''
      INFO  TestDispatcherServlet - Initializing Servlet ''
      INFO  TestDispatcherServlet - Completed initialization in 0 ms
      INFO  MockServletContext - Initializing Spring TestDispatcherServlet ''
      INFO  TestDispatcherServlet - Initializing Servlet ''
      INFO  TestDispatcherServlet - Completed initialization in 1 ms
      INFO  MockServletContext - Initializing Spring TestDispatcherServlet ''
      INFO  TestDispatcherServlet - Initializing Servlet ''
      INFO  TestDispatcherServlet - Completed initialization in 0 ms

      MockHttpServletRequest:
            HTTP Method = POST
            Request URI = /api/owners/1/pets/
             Parameters = {}
                Headers = [Content-Type:"application/json", Accept:"application/json", Content-Length:"104"]
                   Body = <no character encoding set>
          Session Attrs = {}

      Handler:
                   Type = org.springframework.samples.petclinic.rest.controller.OwnerRestController
                 Method = org.springframework.samples.petclinic.rest.controller.OwnerRestController#addPet(Integer, PetFieldsDto)

      Async:
          Async started = false
           Async result = null

      Resolved Exception:
                   Type = org.springframework.web.bind.MethodArgumentNotValidException

      ModelAndView:
              View name = null
                   View = null
                  Model = null

      FlashMap:
             Attributes = null

      MockHttpServletResponse:
                 Status = 400
          Error message = null
                Headers = [Vary:"Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers", Content-Type:"application/json", Content-Length:"737"]
           Content type = application/json
                   Body = {"className":"org.springframework.web.bind.MethodArgumentNotValidException","exMessage":"Validation failed for argument [1] in public org.springframework.http.ResponseEntity<org.springframework.samples.petclinic.rest.dto.PetDto> org.springframework.samples.petclinic.rest.controller.OwnerRestController.addPet(java.lang.Integer,org.springframework.samples.petclinic.rest.dto.PetFieldsDto): [Field error in object 'petFieldsDto' on field 'name': rejected value [null]; codes [NotNull.petFieldsDto.name,NotNull.name,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [petFieldsDto.name,name]; arguments []; default message [name]]; default message [must not be null]] "}
          Forwarded URL = null
         Redirected URL = null
                Cookies = []
      INFO  MockServletContext - Initializing Spring TestDispatcherServlet ''
      INFO  TestDispatcherServlet - Initializing Servlet ''
      INFO  TestDispatcherServlet - Completed initialization in 5 ms
      INFO  MockServletContext - Initializing Spring TestDispatcherServlet ''
      INFO  TestDispatcherServlet - Initializing Servlet ''
      INFO  TestDispatcherServlet - Completed initialization in 0 ms
      INFO  MockServletContext - Initializing Spring TestDispatcherServlet ''
      INFO  TestDispatcherServlet - Initializing Servlet ''
      INFO  TestDispatcherServlet - Completed initialization in 0 ms
      INFO  MockServletContext - Initializing Spring TestDispatcherServlet ''
      INFO  TestDispatcherServlet - Initializing Servlet ''
      INFO  TestDispatcherServlet - Completed initialization in 0 ms
      INFO  MockServletContext - Initializing Spring TestDispatcherServlet ''
      INFO  TestDispatcherServlet - Initializing Servlet ''
      INFO  TestDispatcherServlet - Completed initialization in 0 ms
      newVisitAsJSON {"id":999,"date":"2022-01-16","description":"rabies shot","pet":null}
      INFO  MockServletContext - Initializing Spring TestDispatcherServlet ''
      INFO  TestDispatcherServlet - Initializing Servlet ''
      INFO  TestDispatcherServlet - Completed initialization in 1 ms
      INFO  MockServletContext - Initializing Spring TestDispatcherServlet ''
      INFO  TestDispatcherServlet - Initializing Servlet ''
      INFO  TestDispatcherServlet - Completed initialization in 0 ms
      [INFO] Tests run: 16, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 13.43 s - in org.springframework.samples.petclinic.rest.controller.OwnerRestControllerTests
      [INFO] Running org.springframework.samples.petclinic.rest.controller.SpecialtyRestControllerTests
      INFO  AbstractContextLoader - Could not detect default resource locations for test class [org.springframework.samples.petclinic.rest.controller.SpecialtyRestControllerTests]: no resource found for suffixes {-context.xml, Context.groovy}.
      INFO  SpringBootTestContextBootstrapper - Found @SpringBootConfiguration org.springframework.samples.petclinic.PetClinicApplication for test class org.springframework.samples.petclinic.rest.controller.SpecialtyRestControllerTests
...
...
      INFO  DefaultSecurityFilterChain - Will secure any request with [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@4af026c6, org.springframework.security.web.context.SecurityContextPersistenceFilter@2ce17213, org.springframework.security.web.header.HeaderWriterFilter@29d76031, org.springframework.security.web.authentication.logout.LogoutFilter@2a97b5a2, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@72b927c6, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@5295b114, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@40d1859f, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@268433c9, org.springframework.security.web.session.SessionManagementFilter@64653709, org.springframework.security.web.access.ExceptionTranslationFilter@1dac64c7, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@a53b06d]
      INFO  SpringConfigTests - Started SpringConfigTests in 1.855 seconds (JVM running for 29.56)
      [INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.845 s - in org.springframework.samples.petclinic.SpringConfigTests
      INFO  LocalContainerEntityManagerFactoryBean - Closing JPA EntityManagerFactory for persistence unit 'default'
      INFO  HikariDataSource - HikariPool-1 - Shutdown initiated...
      INFO  HikariDataSource - HikariPool-1 - Shutdown completed.
      INFO  LocalContainerEntityManagerFactoryBean - Closing JPA EntityManagerFactory for persistence unit 'default'
      INFO  HikariDataSource - HikariPool-2 - Shutdown initiated...
      INFO  HikariDataSource - HikariPool-2 - Shutdown completed.
      INFO  LocalContainerEntityManagerFactoryBean - Closing JPA EntityManagerFactory for persistence unit 'default'
      INFO  HikariDataSource - HikariPool-3 - Shutdown initiated...
      INFO  HikariDataSource - HikariPool-3 - Shutdown completed.
      INFO  LocalContainerEntityManagerFactoryBean - Closing JPA EntityManagerFactory for persistence unit 'default'
      INFO  HikariDataSource - HikariPool-4 - Shutdown initiated...
      INFO  HikariDataSource - HikariPool-4 - Shutdown completed.
      INFO  LocalContainerEntityManagerFactoryBean - Closing JPA EntityManagerFactory for persistence unit 'default'
      INFO  HikariDataSource - HikariPool-5 - Shutdown initiated...
      INFO  HikariDataSource - HikariPool-5 - Shutdown completed.
      INFO  LocalContainerEntityManagerFactoryBean - Closing JPA EntityManagerFactory for persistence unit 'default'
      INFO  HikariDataSource - HikariPool-6 - Shutdown initiated...
      INFO  HikariDataSource - HikariPool-6 - Shutdown completed.
      [INFO]
      [INFO] Results:
      [INFO]
      [INFO] Tests run: 172, Failures: 0, Errors: 0, Skipped: 0
      [INFO]
      [INFO]
      [INFO] --- jacoco-maven-plugin:0.8.7:report (report) @ spring-petclinic-rest ---
      [INFO] Loading execution data file /workspace/target/jacoco.exec
      [INFO] Analyzed bundle 'spring-petclinic-rest' with 65 classes
      [INFO]
      [INFO] --- maven-jar-plugin:3.2.0:jar (default-jar) @ spring-petclinic-rest ---
      [INFO] Building jar: /workspace/target/spring-petclinic-rest-2.6.2.jar
      [INFO]
      [INFO] --- spring-boot-maven-plugin:2.6.2:repackage (repackage) @ spring-petclinic-rest ---
      [INFO] Replacing main artifact with repackaged archive
      [INFO] ------------------------------------------------------------------------
      [INFO] BUILD SUCCESS
      [INFO] ------------------------------------------------------------------------
      [INFO] Total time:  39.657 s
      [INFO] Finished at: 2022-01-16T10:58:22Z
      [INFO] ------------------------------------------------------------------------
  Removing source code

Paketo Executable JAR Buildpack 6.0.2
  https://github.com/paketo-buildpacks/executable-jar
  Class Path: Contributing to layer
    Writing env/CLASSPATH.delim
    Writing env/CLASSPATH.prepend
  Process types:
    executable-jar: java org.springframework.boot.loader.JarLauncher (direct)
    task:           java org.springframework.boot.loader.JarLauncher (direct)
    web:            java org.springframework.boot.loader.JarLauncher (direct)

Paketo Spring Boot Buildpack 5.3.0
  https://github.com/paketo-buildpacks/spring-boot
  Creating slices from layers index
    dependencies
    spring-boot-loader
    snapshot-dependencies
    application
  Launch Helper: Reusing cached layer
  Spring Cloud Bindings 1.8.0: Reusing cached layer
  Web Application Type: Contributing to layer
    Servlet web application detected
    Writing env.launch/BPL_JVM_THREAD_COUNT.default
  4 application slices
  Image labels:
    org.opencontainers.image.title
    org.opencontainers.image.version
    org.springframework.boot.version
===> EXPORT
Reusing layers from image 'harbor.registry.com/apps/spring-petclinic-backend@sha256:d55635a51867aa722318fd405b288d865c42604ad758804bb20ef913e88e111e'
Reusing layer 'paketo-buildpacks/ca-certificates:helper'
Reusing layer 'paketo-buildpacks/bellsoft-liberica:helper'
Reusing layer 'paketo-buildpacks/bellsoft-liberica:java-security-properties'
Adding layer 'paketo-buildpacks/bellsoft-liberica:jre'
Reusing layer 'paketo-buildpacks/executable-jar:classpath'
Reusing layer 'paketo-buildpacks/spring-boot:helper'
Reusing layer 'paketo-buildpacks/spring-boot:spring-cloud-bindings'
Reusing layer 'paketo-buildpacks/spring-boot:web-application-type'
Adding layer 'launch.sbom'
Reusing 4/5 app layer(s)
Adding 1/5 app layer(s)
Reusing layer 'launcher'
Reusing layer 'config'
Reusing layer 'process-types'
Adding label 'io.buildpacks.lifecycle.metadata'
Adding label 'io.buildpacks.build.metadata'
Adding label 'io.buildpacks.project.metadata'
Adding label 'org.opencontainers.image.title'
Adding label 'org.opencontainers.image.version'
Adding label 'org.springframework.boot.version'
Setting default process type 'web'
Saving harbor.registry.com/apps/spring-petclinic-backend...
*** Images (sha256:8096781a5d7236c037ef39a128a99eae397ba733d80600c515df09b93228067b):
      harbor.registry.com/apps/spring-petclinic-backend
      harbor.registry.com/apps/spring-petclinic-backend:b3.20220116.105703
Adding cache layer 'paketo-buildpacks/bellsoft-liberica:jdk'
Reusing cache layer 'paketo-buildpacks/syft:syft'
Adding cache layer 'paketo-buildpacks/maven:application'
Adding cache layer 'paketo-buildpacks/maven:cache'
Adding cache layer 'cache.sbom'
===> COMPLETION
Build successful

Let's run the updated image:

> docker run -p 8080:8080 harbor.registry.com/apps/spring-petclinic-backend:b3.20220116.105703
Setting Active Processor Count to 4
WARNING: Unable to convert memory limit "max" from path "/sys/fs/cgroup/memory.max" as int: memory size "max" does not match pattern "^([\\d]+)([kmgtKMGT]?)$"
Calculating JVM memory based on 1283900K available memory
Calculated JVM Memory Configuration: -XX:MaxDirectMemorySize=10M -Xmx655838K -XX:MaxMetaspaceSize=116061K -XX:ReservedCodeCacheSize=240M -Xss1M (Total Memory: 1283900K, Thread Count: 250, Loaded Class Count: 18077, Headroom: 0%)
Enabling Java Native Memory Tracking
Adding 128 container CA certificates to JVM truststore
Spring Cloud Bindings Enabled
Picked up JAVA_TOOL_OPTIONS: -Djava.security.properties=/layers/paketo-buildpacks_bellsoft-liberica/java-security-properties/java-security.properties -XX:+ExitOnOutOfMemoryError -XX:ActiveProcessorCount=4 -XX:MaxDirectMemorySize=10M -Xmx655838K -XX:MaxMetaspaceSize=116061K -XX:ReservedCodeCacheSize=240M -Xss1M -XX:+UnlockDiagnosticVMOptions -XX:NativeMemoryTracking=summary -XX:+PrintNMTStatistics -Dorg.springframework.cloud.bindings.boot.enable=true

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.6.2)

INFO  Version - HV000001: Hibernate Validator 6.2.0.Final
INFO  PetClinicApplication - Starting PetClinicApplication v2.6.2 using Java 17.0.1 on de3b2736ea60 with PID 1 (/workspace/BOOT-INF/classes started by cnb in /workspace)
DEBUG PetClinicApplication - Running with Spring Boot v2.6.2, Spring v5.3.14
INFO  PetClinicApplication - The following profiles are active: hsqldb,spring-data-jpa
INFO  RepositoryConfigurationDelegate - Bootstrapping Spring Data JPA repositories in DEFAULT mode.
INFO  RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 80 ms. Found 7 JPA repository interfaces.
INFO  TomcatWebServer - Tomcat initialized with port(s): 8080 (http)
INFO  Http11NioProtocol - Initializing ProtocolHandler ["http-nio-8080"]
INFO  StandardService - Starting service [Tomcat]
INFO  StandardEngine - Starting Servlet engine: [Apache Tomcat/9.0.56]
INFO  [/petclinic] - Initializing Spring embedded WebApplicationContext
INFO  ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 2020 ms
INFO  HikariDataSource - HikariPool-1 - Starting...
INFO  PoolBase - HikariPool-1 - Driver does not support get/set network timeout for connections. (feature not supported)
INFO  HikariDataSource - HikariPool-1 - Start completed.
INFO  LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
INFO  Version - HHH000412: Hibernate ORM core version 5.6.3.Final
INFO  Version - HCANN000001: Hibernate Commons Annotations {5.1.2.Final}
INFO  Dialect - HHH000400: Using dialect: org.hibernate.dialect.HSQLDialect
INFO  JtaPlatformInitiator - HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
INFO  LocalContainerEntityManagerFactoryBean - Initialized JPA EntityManagerFactory for persistence unit 'default'
INFO  EndpointLinksResolver - Exposing 1 endpoint(s) beneath base path '/actuator'
INFO  UserDetailsServiceAutoConfiguration -

Using generated security password: 86095fd7-2e96-4455-bf12-c85a821c51b0

INFO  DefaultSecurityFilterChain - Will secure any request with [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@18206382, org.springframework.security.web.context.SecurityContextPersistenceFilter@6030eff1, org.springframework.security.web.header.HeaderWriterFilter@cec1ce2, org.springframework.security.web.authentication.logout.LogoutFilter@311eb725, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@5a02fca5, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@309ac89e, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@3e8c9981, org.springframework.security.web.session.SessionManagementFilter@730611a0, org.springframework.security.web.access.ExceptionTranslationFilter@38320819, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@38816a6c]
INFO  Http11NioProtocol - Starting ProtocolHandler ["http-nio-8080"]
INFO  TomcatWebServer - Tomcat started on port(s): 8080 (http) with context path '/petclinic'
INFO  PetClinicApplication - Started PetClinicApplication in 6.352 seconds (JVM running for 6.824)

We can see from the logs that the JRE is now version 17, and also that our startup time has improved from 7.5 seconds to just under 6 seconds. The application still works as expected:

image.png

Some more tips and tricks

  • If you have multiple microservices in a single git repo, use the --sub-path parameter to point Build Service to the relevant sub-path.
  • The buildpack will honor any maven repo setting you may have in your source code. So, if you are running in an airgapped environment and target a local Nexus or Jfrog Artifactory repo, make sure your maven pom.xml or gradle build.settings are set with the correct local repo.
  • If you don't want Build Service to kick off a new image automatically on each git commit, set the --git-revision parameter to the current git commit id and not the desired git branch. Then, as part of your pipeline, you can update the commit ID to kick off a new build. Here is a snippet you can include in your CI pipeline:
export COMMIT_ID=`git rev-parse HEAD`
echo Commit ID is: $COMMIT_ID
kp image save spring-petclinic-backend \
    --tag harbor.registry.com/apps/spring-petclinic-backend \
    --git https://github.com/odedia/spring-petclinic-rest.git \
    --git-revision $COMMIT_ID \
    --env BP_JVM_VERSION=17 \
    --env BP_MAVEN_BUILD_ARGUMENTS="-Dmaven.test.skip=false package"
  • If you want to extract the SHA256 of the last build image, you can use the below kubectl command:
    export LATEST_IMAGE_SHA=`kubectl get images.kpack.io spring-petclinic-backend -o json | jq .status.latestImage`
    echo Latest image sha256 is: $LATEST_IMAGE_SHA
    

.NET Core eShopWeb

.NET Core is the second most popular language I see in the field. It had its share of changes and turmoils with the move from .NET Framework to .NET Core 3, and now "Just .NET 5" and .NET 6. Let's try to build the popular eShopWeb .NET Core sample application.

Git repo

The git repository is available at github.com/dotnet-architecture/eShopOnWeb.git

Build command

Let's build the image:

> kp image save dotnet-eshopweb \
> --tag harbor.registry.com/apps/dotnet-eshopweb \
> --git https://github.com/dotnet-architecture/eShopOnWeb.git \
> --git-revision main
Creating Image Resource...
Image Resource "dotnet-eshopweb" created

Build logs output

Let's check the logs:

> kp build logs dotnet-eshopweb
===> PREPARE
Build reason(s): CONFIG
CONFIG:
  resources: {}
  - source: {}
  + source:
  +   git:
  +     revision: 896fae150fbcec5de8a1fb923eab5dfafe09422a
  +     url: https://github.com/dotnet-architecture/eShopOnWeb.git
Loading secret for "harbor.registry.com" from secret "registry-credentials" at location "/var/build-secrets/registry-credentials"
Cloning "https://github.com/dotnet-architecture/eShopOnWeb.git" @ "896fae150fbcec5de8a1fb923eab5dfafe09422a"...
Successfully cloned "https://github.com/dotnet-architecture/eShopOnWeb.git" @ "896fae150fbcec5de8a1fb923eab5dfafe09422a" in path "/workspace"
===> ANALYZE
Previous image with name "harbor.registry.com/apps/dotnet-eshopweb" not found
===> DETECT
ERROR: No buildpack groups passed detection.
ERROR: Please check that you are running against the correct path.
ERROR: failed to detect: no buildpacks participating

Well that didn't work... What happened here?

It seems that, like many .NET Core projects, the source code is nested inside our main repo. Let's try to build the ApplicationCore module by pointing at the sub path:

> kp image save dotnet-eshopweb \
--tag harbor.registry.com/apps/dotnet-eshopweb \
--git https://github.com/dotnet-architecture/eShopOnWeb.git \
--git-revision main \
--sub-path ./src/Web

Let's check the updated logs:

> kp build logs dotnet-eshopweb
===> PREPARE
Build reason(s): CONFIG
CONFIG:
  resources: {}
  - source: {}
  + source:
  +   git:
  +     revision: 896fae150fbcec5de8a1fb923eab5dfafe09422a
  +     url: https://github.com/dotnet-architecture/eShopOnWeb.git
  +   subPath: ./src/Web
Loading secret for "harbor.registry.com" from secret "registry-credentials" at location "/var/build-secrets/registry-credentials"
Cloning "https://github.com/dotnet-architecture/eShopOnWeb.git" @ "896fae150fbcec5de8a1fb923eab5dfafe09422a"...
Successfully cloned "https://github.com/dotnet-architecture/eShopOnWeb.git" @ "896fae150fbcec5de8a1fb923eab5dfafe09422a" in path "/workspace"
===> ANALYZE
Previous image with name "harbor.registry.com/apps/dotnet-eshopweb" not found
===> DETECT
7 of 13 buildpacks participating
paketo-buildpacks/ca-certificates    3.0.2
tanzu-buildpacks/dotnet-core-runtime 0.3.1
tanzu-buildpacks/dotnet-core-aspnet  0.3.2
tanzu-buildpacks/dotnet-core-sdk     0.3.1
tanzu-buildpacks/icu                 0.0.13
tanzu-buildpacks/dotnet-publish      0.5.1
tanzu-buildpacks/dotnet-execute      0.4.1
===> RESTORE
===> BUILD

Paketo CA Certificates Buildpack 3.0.2
  https://github.com/paketo-buildpacks/ca-certificates
  Launch Helper: Contributing to layer
    Creating /layers/paketo-buildpacks_ca-certificates/helper/exec.d/ca-certificates-helper
Tanzu .NET Core Runtime Buildpack 0.3.1
  Resolving Dotnet Core Runtime version
    Candidate version sources (in priority order):
      Web.csproj -> "6.0.0"
      <unknown>  -> ""

    Selected dotnet-runtime version (using Web.csproj): 6.0.0

  Executing build process
    Installing Dotnet Core Runtime 6.0.0
      Completed in 4.228s

  Configuring environment for build and launch
    DOTNET_ROOT -> "/workspace/.dotnet_root"

  Configuring environment for build
    RUNTIME_VERSION -> "6.0.0"

Tanzu ASP.NET Core Buildpack 0.3.2
  Resolving Dotnet Core ASPNet version
    Candidate version sources (in priority order):
      RUNTIME_VERSION -> "6.0.0"
      Web.csproj      -> "6.0.0"
      <unknown>       -> ""

    Selected dotnet-aspnetcore version (using RUNTIME_VERSION): 6.0.0

  Executing build process
    Installing Dotnet Core ASPNet 6.0.0
      Completed in 1.292s

  Configuring environment
    DOTNET_ROOT -> "/workspace/.dotnet_root"

Tanzu .NET Core SDK Buildpack 0.3.1
  Resolving .NET Core SDK version
    Candidate version sources (in priority order):
      RUNTIME_VERSION -> "6.0.100"
      <unknown>       -> "*"
      Web.csproj      -> "6.0.*"

    Selected .NET Core SDK version (using RUNTIME_VERSION): 6.0.100

  Executing build process
    Installing .NET Core SDK 6.0.100
      Completed in 16.038s

  Configuring environment
    DOTNET_ROOT -> "/workspace/.dotnet_root"
    PATH        -> "/workspace/.dotnet_root:$PATH"

Tanzu ICU Buildpack 0.0.13
  Executing build process
    Installing ICU
      Completed in 480ms

Tanzu .Net Publish Buildpack 0.5.1
  Executing build process
    Running 'dotnet publish /workspace --configuration Release --runtime ubuntu.18.04-x64 --self-contained false --output /tmp/dotnet-publish-output2505033169'
      Failed after 20.780801107s
failed to execute 'dotnet publish': exit status 1

        Welcome to .NET 6.0!
        ---------------------
        SDK Version: 6.0.100

        Telemetry
        ---------
        The .NET tools collect usage data in order to help us improve your experience. It is collected by Microsoft and shared with the community. You can opt-out of telemetry by setting the DOTNET_CLI_TELEMETRY_OPTOUT environment variable to '1' or 'true' using your favorite shell.

        Read more about .NET CLI Tools telemetry: https://aka.ms/dotnet-cli-telemetry

        ----------------
        Installed an ASP.NET Core HTTPS development certificate.
        To trust the certificate run 'dotnet dev-certs https --trust' (Windows and macOS only).
        Learn about HTTPS: https://aka.ms/dotnet-https
        ----------------
        Write your first app: https://aka.ms/dotnet-hello-world
        Find out what's new: https://aka.ms/dotnet-whats-new
        Explore documentation: https://aka.ms/dotnet-docs
        Report issues and find source on GitHub: https://github.com/dotnet/core
        Use 'dotnet --help' to see available commands or visit: https://aka.ms/dotnet-cli
        --------------------------------------------------------------------------------------
        Microsoft (R) Build Engine version 17.0.0+c9eb9dd64 for .NET
        Copyright (C) Microsoft Corporation. All rights reserved.

          Determining projects to restore...
          Skipping project "/ApplicationCore/ApplicationCore.csproj" because it was not found.
          Skipping project "/BlazorAdmin/BlazorAdmin.csproj" because it was not found.
          Skipping project "/BlazorShared/BlazorShared.csproj" because it was not found.
          Skipping project "/Infrastructure/Infrastructure.csproj" because it was not found.
          Skipping project "/ApplicationCore/ApplicationCore.csproj" because it was not found.
          Skipping project "/BlazorAdmin/BlazorAdmin.csproj" because it was not found.
          Skipping project "/BlazorShared/BlazorShared.csproj" because it was not found.
          Skipping project "/Infrastructure/Infrastructure.csproj" because it was not found.
          Restored /workspace/Web.csproj (in 14.4 sec).

          Restore operation started...

          6 libraries restored in 0.56 seconds

        /layers/tanzu-buildpacks_dotnet-core-sdk/dotnet-core-sdk/sdk/6.0.100/Microsoft.Common.CurrentVersion.targets(2068,5): warning : The referenced project '../ApplicationCore/ApplicationCore.csproj' does not exist. [/workspace/Web.csproj]
        /layers/tanzu-buildpacks_dotnet-core-sdk/dotnet-core-sdk/sdk/6.0.100/Microsoft.Common.CurrentVersion.targets(2068,5): warning : The referenced project '../BlazorAdmin/BlazorAdmin.csproj' does not exist. [/workspace/Web.csproj]
        /layers/tanzu-buildpacks_dotnet-core-sdk/dotnet-core-sdk/sdk/6.0.100/Microsoft.Common.CurrentVersion.targets(2068,5): warning : The referenced project '../BlazorShared/BlazorShared.csproj' does not exist. [/workspace/Web.csproj]
        /layers/tanzu-buildpacks_dotnet-core-sdk/dotnet-core-sdk/sdk/6.0.100/Microsoft.Common.CurrentVersion.targets(2068,5): warning : The referenced project '../Infrastructure/Infrastructure.csproj' does not exist. [/workspace/Web.csproj]

          Bundler: Begin processing bundleconfig.json
          Bundler: Done processing bundleconfig.json
        /workspace/Areas/Identity/Pages/Account/ConfirmEmail.cshtml.cs(9,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Areas/Identity/Pages/Account/Login.cshtml.cs(12,26): error CS0234: The type or namespace name 'ApplicationCore' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Areas/Identity/Pages/Account/Login.cshtml.cs(13,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Areas/Identity/Pages/Account/Logout.cshtml.cs(10,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Areas/Identity/Pages/Account/Register.cshtml.cs(11,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Configuration/ConfigureCoreServices.cs(1,26): error CS0234: The type or namespace name 'ApplicationCore' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Configuration/ConfigureCoreServices.cs(2,26): error CS0234: The type or namespace name 'ApplicationCore' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Configuration/ConfigureCoreServices.cs(3,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Configuration/ConfigureCoreServices.cs(4,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Configuration/ConfigureCoreServices.cs(5,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Configuration/ConfigureCoreServices.cs(6,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Controllers/ManageController.cs(10,26): error CS0234: The type or namespace name 'ApplicationCore' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Controllers/ManageController.cs(11,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Controllers/UserController.cs(5,7): error CS0246: The type or namespace name 'BlazorShared' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Controllers/UserController.cs(8,26): error CS0234: The type or namespace name 'ApplicationCore' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Extensions/EmailSenderExtensions.cs(3,26): error CS0234: The type or namespace name 'ApplicationCore' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Features/MyOrders/GetMyOrdersHandler.cs(6,26): error CS0234: The type or namespace name 'ApplicationCore' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Features/MyOrders/GetMyOrdersHandler.cs(7,26): error CS0234: The type or namespace name 'ApplicationCore' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Features/MyOrders/GetMyOrdersHandler.cs(8,26): error CS0234: The type or namespace name 'ApplicationCore' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Features/OrderDetails/GetOrderDetailsHandler.cs(5,26): error CS0234: The type or namespace name 'ApplicationCore' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Features/OrderDetails/GetOrderDetailsHandler.cs(6,26): error CS0234: The type or namespace name 'ApplicationCore' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Features/OrderDetails/GetOrderDetailsHandler.cs(7,26): error CS0234: The type or namespace name 'ApplicationCore' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/HealthChecks/ApiHealthCheck.cs(4,7): error CS0246: The type or namespace name 'BlazorShared' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Interfaces/IBasketViewModelService.cs(1,26): error CS0234: The type or namespace name 'ApplicationCore' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Pages/Admin/EditCatalogItem.cshtml.cs(5,26): error CS0234: The type or namespace name 'ApplicationCore' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Pages/Admin/Index.cshtml.cs(4,26): error CS0234: The type or namespace name 'ApplicationCore' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Pages/Basket/Checkout.cshtml.cs(11,26): error CS0234: The type or namespace name 'ApplicationCore' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Pages/Basket/Checkout.cshtml.cs(12,26): error CS0234: The type or namespace name 'ApplicationCore' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Pages/Basket/Checkout.cshtml.cs(13,26): error CS0234: The type or namespace name 'ApplicationCore' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Pages/Basket/Checkout.cshtml.cs(14,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Pages/Basket/Index.cshtml.cs(8,26): error CS0234: The type or namespace name 'ApplicationCore' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Pages/Shared/Components/BasketComponent/Basket.cs(5,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Program.cs(3,7): error CS0246: The type or namespace name 'BlazorAdmin' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Program.cs(4,7): error CS0246: The type or namespace name 'BlazorAdmin' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Program.cs(5,7): error CS0246: The type or namespace name 'Blazored' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Program.cs(6,7): error CS0246: The type or namespace name 'BlazorShared' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Program.cs(13,26): error CS0234: The type or namespace name 'ApplicationCore' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Program.cs(14,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Program.cs(15,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Services/BasketViewModelService.cs(4,26): error CS0234: The type or namespace name 'ApplicationCore' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Services/BasketViewModelService.cs(5,26): error CS0234: The type or namespace name 'ApplicationCore' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Services/BasketViewModelService.cs(6,26): error CS0234: The type or namespace name 'ApplicationCore' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Services/BasketViewModelService.cs(7,26): error CS0234: The type or namespace name 'ApplicationCore' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Services/CatalogItemViewModelService.cs(2,26): error CS0234: The type or namespace name 'ApplicationCore' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Services/CatalogItemViewModelService.cs(3,26): error CS0234: The type or namespace name 'ApplicationCore' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Services/CatalogViewModelService.cs(6,26): error CS0234: The type or namespace name 'ApplicationCore' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Services/CatalogViewModelService.cs(7,26): error CS0234: The type or namespace name 'ApplicationCore' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Services/CatalogViewModelService.cs(8,26): error CS0234: The type or namespace name 'ApplicationCore' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/ViewModels/OrderViewModel.cs(3,26): error CS0234: The type or namespace name 'ApplicationCore' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Areas/Identity/Pages/_ViewImports.cshtml(3,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Areas/Identity/Pages/_ViewImports.cshtml(3,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Areas/Identity/Pages/_ViewImports.cshtml(3,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Areas/Identity/Pages/_ViewImports.cshtml(3,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Areas/Identity/Pages/_ViewImports.cshtml(3,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Areas/Identity/Pages/_ViewImports.cshtml(3,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Areas/Identity/Pages/_ViewImports.cshtml(3,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Areas/Identity/Pages/_ViewImports.cshtml(3,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Areas/Identity/Pages/Account/ConfirmEmail.cshtml.cs(16,34): error CS0246: The type or namespace name 'ApplicationUser' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Areas/Identity/Pages/Account/ConfirmEmail.cshtml.cs(18,42): error CS0246: The type or namespace name 'ApplicationUser' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Controllers/ManageController.cs(528,55): error CS0246: The type or namespace name 'ApplicationUser' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Controllers/ManageController.cs(22,34): error CS0246: The type or namespace name 'ApplicationUser' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Controllers/ManageController.cs(23,36): error CS0246: The type or namespace name 'ApplicationUser' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Controllers/ManageController.cs(24,22): error CS0246: The type or namespace name 'IEmailSender' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Controllers/ManageController.cs(25,22): error CS0246: The type or namespace name 'IAppLogger<>' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Controllers/ManageController.cs(32,19): error CS0246: The type or namespace name 'ApplicationUser' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Controllers/ManageController.cs(33,21): error CS0246: The type or namespace name 'ApplicationUser' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Controllers/ManageController.cs(34,7): error CS0246: The type or namespace name 'IEmailSender' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Controllers/ManageController.cs(35,7): error CS0246: The type or namespace name 'IAppLogger<>' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Features/MyOrders/GetMyOrdersHandler.cs(15,22): error CS0246: The type or namespace name 'IReadRepository<>' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Features/MyOrders/GetMyOrdersHandler.cs(15,38): error CS0246: The type or namespace name 'Order' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Features/MyOrders/GetMyOrdersHandler.cs(17,31): error CS0246: The type or namespace name 'IReadRepository<>' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Features/MyOrders/GetMyOrdersHandler.cs(17,47): error CS0246: The type or namespace name 'Order' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Features/OrderDetails/GetOrderDetailsHandler.cs(14,22): error CS0246: The type or namespace name 'IReadRepository<>' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Features/OrderDetails/GetOrderDetailsHandler.cs(14,38): error CS0246: The type or namespace name 'Order' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Areas/Identity/Pages/Account/Login.cshtml.cs(21,36): error CS0246: The type or namespace name 'ApplicationUser' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Controllers/UserController.cs(29,24): error CS0246: The type or namespace name 'UserInfo' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Features/OrderDetails/GetOrderDetailsHandler.cs(16,35): error CS0246: The type or namespace name 'IReadRepository<>' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Features/OrderDetails/GetOrderDetailsHandler.cs(16,51): error CS0246: The type or namespace name 'Order' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Controllers/UserController.cs(16,22): error CS0246: The type or namespace name 'ITokenClaimsService' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Areas/Identity/Pages/Account/Login.cshtml.cs(23,22): error CS0246: The type or namespace name 'IBasketService' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Controllers/UserController.cs(18,27): error CS0246: The type or namespace name 'ITokenClaimsService' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/HealthChecks/ApiHealthCheck.cs(12,22): error CS0246: The type or namespace name 'BaseUrlConfiguration' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/HealthChecks/ApiHealthCheck.cs(14,36): error CS0246: The type or namespace name 'BaseUrlConfiguration' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Extensions/EmailSenderExtensions.cs(9,56): error CS0246: The type or namespace name 'IEmailSender' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Areas/Identity/Pages/Account/Login.cshtml.cs(25,37): error CS0246: The type or namespace name 'ApplicationUser' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Areas/Identity/Pages/Account/Login.cshtml.cs(25,97): error CS0246: The type or namespace name 'IBasketService' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Services/BasketViewModelService.cs(56,86): error CS0246: The type or namespace name 'BasketItem' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Services/BasketViewModelService.cs(80,44): error CS0246: The type or namespace name 'Basket' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Interfaces/IBasketViewModelService.cs(10,31): error CS0246: The type or namespace name 'Basket' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Pages/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Areas/Identity/Pages/Account/Logout.cshtml.cs(20,36): error CS0246: The type or namespace name 'ApplicationUser' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Pages/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Pages/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Pages/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Pages/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Views/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Views/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Services/BasketViewModelService.cs(15,22): error CS0246: The type or namespace name 'IRepository<>' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Services/BasketViewModelService.cs(15,34): error CS0246: The type or namespace name 'Basket' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Pages/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Areas/Identity/Pages/Account/Logout.cshtml.cs(24,38): error CS0246: The type or namespace name 'ApplicationUser' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Areas/Identity/Pages/Account/Logout.cshtml.cs(35,64): warning CS8625: Cannot convert null literal to non-nullable reference type. [/workspace/Web.csproj]
        /workspace/Services/BasketViewModelService.cs(16,22): error CS0246: The type or namespace name 'IUriComposer' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Pages/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Pages/Admin/Index.cshtml(2,7): error CS0246: The type or namespace name 'BlazorAdmin' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Pages/Admin/EditCatalogItem.cshtml.cs(11,20): error CS0103: The name 'BlazorShared' does not exist in the current context [/workspace/Web.csproj]
        /workspace/Services/BasketViewModelService.cs(17,22): error CS0246: The type or namespace name 'IBasketQueryService' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Pages/Admin/Index.cshtml.cs(12,20): error CS0103: The name 'BlazorShared' does not exist in the current context [/workspace/Web.csproj]
        /workspace/Areas/Identity/Pages/Account/Register.cshtml.cs(19,36): error CS0246: The type or namespace name 'ApplicationUser' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Services/BasketViewModelService.cs(18,22): error CS0246: The type or namespace name 'IRepository<>' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Services/BasketViewModelService.cs(18,34): error CS0246: The type or namespace name 'CatalogItem' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Areas/Identity/Pages/Account/Register.cshtml.cs(20,34): error CS0246: The type or namespace name 'ApplicationUser' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Pages/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Pages/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Pages/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Areas/Identity/Pages/Account/Register.cshtml.cs(25,21): error CS0246: The type or namespace name 'ApplicationUser' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Areas/Identity/Pages/Account/Register.cshtml.cs(26,23): error CS0246: The type or namespace name 'ApplicationUser' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Areas/Identity/Pages/Account/Register.cshtml.cs(60,42): warning CS8625: Cannot convert null literal to non-nullable reference type. [/workspace/Web.csproj]
        /workspace/Areas/Identity/Pages/Account/Register.cshtml.cs(65,69): warning CS8625: Cannot convert null literal to non-nullable reference type. [/workspace/Web.csproj]
        /workspace/Services/BasketViewModelService.cs(20,35): error CS0246: The type or namespace name 'IRepository<>' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Services/BasketViewModelService.cs(20,47): error CS0246: The type or namespace name 'Basket' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Services/BasketViewModelService.cs(21,9): error CS0246: The type or namespace name 'IRepository<>' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Services/BasketViewModelService.cs(21,21): error CS0246: The type or namespace name 'CatalogItem' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Services/BasketViewModelService.cs(22,9): error CS0246: The type or namespace name 'IUriComposer' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Services/BasketViewModelService.cs(23,9): error CS0246: The type or namespace name 'IBasketQueryService' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Pages/Basket/Checkout.cshtml.cs(22,22): error CS0246: The type or namespace name 'IBasketService' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Pages/Basket/Checkout.cshtml.cs(23,36): error CS0246: The type or namespace name 'ApplicationUser' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Pages/Basket/Checkout.cshtml.cs(24,22): error CS0246: The type or namespace name 'IOrderService' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Services/CatalogItemViewModelService.cs(11,22): error CS0246: The type or namespace name 'IRepository<>' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Services/CatalogItemViewModelService.cs(11,34): error CS0246: The type or namespace name 'CatalogItem' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Pages/Basket/Checkout.cshtml.cs(27,22): error CS0246: The type or namespace name 'IAppLogger<>' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Services/CatalogItemViewModelService.cs(13,40): error CS0246: The type or namespace name 'IRepository<>' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Services/CatalogItemViewModelService.cs(13,52): error CS0246: The type or namespace name 'CatalogItem' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Services/CatalogViewModelService.cs(21,22): error CS0246: The type or namespace name 'IRepository<>' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Services/CatalogViewModelService.cs(21,34): error CS0246: The type or namespace name 'CatalogItem' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Pages/Basket/Checkout.cshtml.cs(29,26): error CS0246: The type or namespace name 'IBasketService' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Pages/Basket/Checkout.cshtml.cs(31,23): error CS0246: The type or namespace name 'ApplicationUser' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Pages/Basket/Checkout.cshtml.cs(32,9): error CS0246: The type or namespace name 'IOrderService' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Pages/Basket/Checkout.cshtml.cs(33,9): error CS0246: The type or namespace name 'IAppLogger<>' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Services/CatalogViewModelService.cs(22,22): error CS0246: The type or namespace name 'IRepository<>' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Services/CatalogViewModelService.cs(22,34): error CS0246: The type or namespace name 'CatalogBrand' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Pages/Basket/Index.cshtml.cs(16,22): error CS0246: The type or namespace name 'IBasketService' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Pages/Basket/Index.cshtml.cs(19,23): error CS0246: The type or namespace name 'IBasketService' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Services/CatalogViewModelService.cs(23,22): error CS0246: The type or namespace name 'IRepository<>' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Services/CatalogViewModelService.cs(23,34): error CS0246: The type or namespace name 'CatalogType' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Services/CatalogViewModelService.cs(24,22): error CS0246: The type or namespace name 'IUriComposer' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Services/CatalogViewModelService.cs(28,9): error CS0246: The type or namespace name 'IRepository<>' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Services/CatalogViewModelService.cs(28,21): error CS0246: The type or namespace name 'CatalogItem' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Services/CatalogViewModelService.cs(29,9): error CS0246: The type or namespace name 'IRepository<>' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Services/CatalogViewModelService.cs(29,21): error CS0246: The type or namespace name 'CatalogBrand' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Services/CatalogViewModelService.cs(30,9): error CS0246: The type or namespace name 'IRepository<>' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Services/CatalogViewModelService.cs(30,21): error CS0246: The type or namespace name 'CatalogType' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Services/CatalogViewModelService.cs(31,9): error CS0246: The type or namespace name 'IUriComposer' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Pages/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Pages/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Pages/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Views/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Views/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Views/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Views/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Views/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Pages/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Pages/Shared/Components/BasketComponent/Basket.cs(14,36): error CS0246: The type or namespace name 'ApplicationUser' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Pages/Shared/Components/BasketComponent/Basket.cs(17,35): error CS0246: The type or namespace name 'ApplicationUser' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Views/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Views/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Views/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Views/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Views/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Views/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Views/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Views/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Views/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Views/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Views/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Views/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Views/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Views/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Views/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Views/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Views/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Microsoft.NET.Sdk.Razor.SourceGenerators/Microsoft.NET.Sdk.Razor.SourceGenerators.RazorSourceGenerator/Views_Manage__ManageNav_cshtml.g.cs(236,30): error CS0246: The type or namespace name 'ApplicationUser' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
        /workspace/Views/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/Views/_ViewImports.cshtml(7,26): error CS0234: The type or namespace name 'Infrastructure' does not exist in the namespace 'Microsoft.eShopWeb' (are you missing an assembly reference?) [/workspace/Web.csproj]
        /workspace/SlugifyParameterTransformer.cs(8,19): warning CS8767: Nullability of reference types in type of parameter 'value' of 'string SlugifyParameterTransformer.TransformOutbound(object value)' doesn't match implicitly implemented member 'string? IOutboundParameterTransformer.TransformOutbound(object? value)' (possibly because of nullability attributes). [/workspace/Web.csproj]
        /workspace/ViewModels/OrderViewModel.cs(15,12): error CS0246: The type or namespace name 'Address' could not be found (are you missing a using directive or an assembly reference?) [/workspace/Web.csproj]
ERROR: failed to build: exit status 1

It seems that we are building our project in the wrong context. .NET usually has multiple modules and a shared project root. We can tell Build Service to use the src folder as the project root (since it has our .cs_proj file), and also point to a specific .NET project path that we'd like to build:

> kp image save dotnet-eshopweb \
--tag harbor.registry.com/apps/dotnet-eshopweb \
--git https://github.com/dotnet-architecture/eShopOnWeb.git \
--git-revision main \
--sub-path=./src \
--env BP_DOTNET_PROJECT_PATH="./Web"
Patching Image Resource...
Image Resource "dotnet-eshopweb" patched

Let's check out the updated logs:

> kp build logs dotnet-eshopweb
===> PREPARE
Build reason(s): CONFIG
CONFIG:
  + env:
  + - name: BP_DOTNET_PROJECT_PATH
  +   value: ./Web
  resources: {}
  source:
    git:
      revision: 896fae150fbcec5de8a1fb923eab5dfafe09422a
      url: https://github.com/dotnet-architecture/eShopOnWeb.git
  -   subPath: ./src/Web
  +   subPath: ./src
Loading secret for "harbor.registry.com" from secret "registry-credentials" at location "/var/build-secrets/registry-credentials"
Cloning "https://github.com/dotnet-architecture/eShopOnWeb.git" @ "896fae150fbcec5de8a1fb923eab5dfafe09422a"...
Successfully cloned "https://github.com/dotnet-architecture/eShopOnWeb.git" @ "896fae150fbcec5de8a1fb923eab5dfafe09422a" in path "/workspace"
===> ANALYZE
Previous image with name "harbor.registry.com/apps/dotnet-eshopweb" not found
===> DETECT
7 of 13 buildpacks participating
paketo-buildpacks/ca-certificates    3.0.2
tanzu-buildpacks/dotnet-core-runtime 0.3.1
tanzu-buildpacks/dotnet-core-aspnet  0.3.2
tanzu-buildpacks/dotnet-core-sdk     0.3.1
tanzu-buildpacks/icu                 0.0.13
tanzu-buildpacks/dotnet-publish      0.5.1
tanzu-buildpacks/dotnet-execute      0.4.1
===> RESTORE
===> BUILD

Paketo CA Certificates Buildpack 3.0.2
  https://github.com/paketo-buildpacks/ca-certificates
  Launch Helper: Contributing to layer
    Creating /layers/paketo-buildpacks_ca-certificates/helper/exec.d/ca-certificates-helper
Tanzu .NET Core Runtime Buildpack 0.3.1
  Resolving Dotnet Core Runtime version
    Candidate version sources (in priority order):
      Web.csproj -> "6.0.0"
      <unknown>  -> ""

    Selected dotnet-runtime version (using Web.csproj): 6.0.0

  Executing build process
    Installing Dotnet Core Runtime 6.0.0
      Completed in 4.383s

  Configuring environment for build and launch
    DOTNET_ROOT -> "/workspace/.dotnet_root"

  Configuring environment for build
    RUNTIME_VERSION -> "6.0.0"

Tanzu ASP.NET Core Buildpack 0.3.2
  Resolving Dotnet Core ASPNet version
    Candidate version sources (in priority order):
      RUNTIME_VERSION -> "6.0.0"
      Web.csproj      -> "6.0.0"
      <unknown>       -> ""

    Selected dotnet-aspnetcore version (using RUNTIME_VERSION): 6.0.0

  Executing build process
    Installing Dotnet Core ASPNet 6.0.0
      Completed in 1.253s

  Configuring environment
    DOTNET_ROOT -> "/workspace/.dotnet_root"

Tanzu .NET Core SDK Buildpack 0.3.1
  Resolving .NET Core SDK version
    Candidate version sources (in priority order):
      RUNTIME_VERSION -> "6.0.100"
      <unknown>       -> "*"
      Web.csproj      -> "6.0.*"

    Selected .NET Core SDK version (using RUNTIME_VERSION): 6.0.100

  Executing build process
    Installing .NET Core SDK 6.0.100
      Completed in 16.334s

  Configuring environment
    DOTNET_ROOT -> "/workspace/.dotnet_root"
    PATH        -> "/workspace/.dotnet_root:$PATH"

Tanzu ICU Buildpack 0.0.13
  Executing build process
    Installing ICU
      Completed in 485ms

Tanzu .Net Publish Buildpack 0.5.1
  Executing build process
    Running 'dotnet publish /workspace/Web --configuration Release --runtime ubuntu.18.04-x64 --self-contained false --output /tmp/dotnet-publish-output4061578451'
failed to execute 'dotnet publish': exit status 1
      Failed after 37.399735604s

        Welcome to .NET 6.0!
        ---------------------
        SDK Version: 6.0.100

        Telemetry
        ---------
        The .NET tools collect usage data in order to help us improve your experience. It is collected by Microsoft and shared with the community. You can opt-out of telemetry by setting the DOTNET_CLI_TELEMETRY_OPTOUT environment variable to '1' or 'true' using your favorite shell.

        Read more about .NET CLI Tools telemetry: https://aka.ms/dotnet-cli-telemetry

        ----------------
        Installed an ASP.NET Core HTTPS development certificate.
        To trust the certificate run 'dotnet dev-certs https --trust' (Windows and macOS only).
        Learn about HTTPS: https://aka.ms/dotnet-https
        ----------------
        Write your first app: https://aka.ms/dotnet-hello-world
        Find out what's new: https://aka.ms/dotnet-whats-new
        Explore documentation: https://aka.ms/dotnet-docs
        Report issues and find source on GitHub: https://github.com/dotnet/core
        Use 'dotnet --help' to see available commands or visit: https://aka.ms/dotnet-cli
        --------------------------------------------------------------------------------------
        Microsoft (R) Build Engine version 17.0.0+c9eb9dd64 for .NET
        Copyright (C) Microsoft Corporation. All rights reserved.

          Determining projects to restore...
          Restored /workspace/BlazorShared/BlazorShared.csproj (in 2.82 sec).
          Restored /workspace/BlazorAdmin/BlazorAdmin.csproj (in 4.12 sec).
          Restored /workspace/ApplicationCore/ApplicationCore.csproj (in 7.8 sec).
          Restored /workspace/Infrastructure/Infrastructure.csproj (in 4.28 sec).
          Restored /workspace/Web/Web.csproj (in 17.21 sec).

          Restore operation started...

          6 libraries restored in 0.96 seconds

          BlazorShared -> /workspace/BlazorShared/bin/Release/net6.0/BlazorShared.dll
          ApplicationCore -> /workspace/ApplicationCore/bin/Release/net6.0/ApplicationCore.dll
          Infrastructure -> /workspace/Infrastructure/bin/Release/net6.0/Infrastructure.dll
          BlazorAdmin -> /workspace/BlazorAdmin/bin/Release/net6.0/BlazorAdmin.dll
          BlazorAdmin (Blazor output) -> /workspace/BlazorAdmin/bin/Release/net6.0/wwwroot

          Bundler: Begin processing bundleconfig.json
          Bundler: Done processing bundleconfig.json
        /workspace/Web/SlugifyParameterTransformer.cs(8,19): warning CS8767: Nullability of reference types in type of parameter 'value' of 'string SlugifyParameterTransformer.TransformOutbound(object value)' doesn't match implicitly implemented member 'string? IOutboundParameterTransformer.TransformOutbound(object? value)' (possibly because of nullability attributes). [/workspace/Web/Web.csproj]
        /workspace/Web/Areas/Identity/Pages/Account/Logout.cshtml.cs(35,64): warning CS8625: Cannot convert null literal to non-nullable reference type. [/workspace/Web/Web.csproj]
        /workspace/Web/Areas/Identity/Pages/Account/Register.cshtml.cs(60,42): warning CS8625: Cannot convert null literal to non-nullable reference type. [/workspace/Web/Web.csproj]
        /workspace/Web/Areas/Identity/Pages/Account/Register.cshtml.cs(65,69): warning CS8625: Cannot convert null literal to non-nullable reference type. [/workspace/Web/Web.csproj]
        /workspace/Web/Controllers/ManageController.cs(31,12): warning CS8618: Non-nullable property 'StatusMessage' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/Extensions/UrlHelperExtensions.cs(7,16): warning CS8603: Possible null reference return. [/workspace/Web/Web.csproj]
        /workspace/Web/Controllers/UserController.cs(27,12): warning CS8602: Dereference of a possibly null reference. [/workspace/Web/Web.csproj]
        /workspace/Web/HealthChecks/HomePageHealthCheck.cs(22,23): warning CS8602: Dereference of a possibly null reference. [/workspace/Web/Web.csproj]
        /workspace/Web/Views/Manage/ManageNavPages.cs(30,16): warning CS8603: Possible null reference return. [/workspace/Web/Web.csproj]
        /workspace/Web/Services/CatalogItemViewModelService.cs(21,9): warning CS8602: Dereference of a possibly null reference. [/workspace/Web/Web.csproj]
        /workspace/Web/Configuration/RevokeAuthenticationEvents.cs(25,22): warning CS8602: Dereference of a possibly null reference. [/workspace/Web/Web.csproj]
        /workspace/Web/Features/OrderDetails/GetOrderDetailsHandler.cs(29,20): warning CS8603: Possible null reference return. [/workspace/Web/Web.csproj]
        /workspace/Web/Features/MyOrders/GetMyOrdersHandler.cs(31,26): warning CS8601: Possible null reference assignment. [/workspace/Web/Web.csproj]
        /workspace/Web/Controllers/UserController.cs(31,14): warning CS8602: Dereference of a possibly null reference. [/workspace/Web/Web.csproj]
        /workspace/Web/Controllers/ManageController.cs(383,29): warning CS8600: Converting null literal or possible null value to non-nullable type. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/PaginationInfoViewModel.cs(9,19): warning CS8618: Non-nullable property 'Previous' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/PaginationInfoViewModel.cs(10,19): warning CS8618: Non-nullable property 'Next' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/OrderViewModel.cs(15,20): warning CS8618: Non-nullable property 'ShippingAddress' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/OrderItemViewModel.cs(6,19): warning CS8618: Non-nullable property 'ProductName' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/OrderItemViewModel.cs(10,19): warning CS8618: Non-nullable property 'PictureUrl' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/Manage/ShowRecoveryCodesViewModel.cs(5,21): warning CS8618: Non-nullable property 'RecoveryCodes' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/Manage/SetPasswordViewModel.cs(11,19): warning CS8618: Non-nullable property 'NewPassword' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/Manage/SetPasswordViewModel.cs(16,19): warning CS8618: Non-nullable property 'ConfirmPassword' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/Manage/SetPasswordViewModel.cs(18,19): warning CS8618: Non-nullable property 'StatusMessage' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/Manage/RemoveLoginViewModel.cs(5,19): warning CS8618: Non-nullable property 'LoginProvider' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/Manage/RemoveLoginViewModel.cs(6,19): warning CS8618: Non-nullable property 'ProviderKey' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/Manage/IndexViewModel.cs(7,19): warning CS8618: Non-nullable property 'Username' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/Manage/IndexViewModel.cs(13,19): warning CS8618: Non-nullable property 'Email' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/Manage/IndexViewModel.cs(17,19): warning CS8618: Non-nullable property 'PhoneNumber' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/Manage/IndexViewModel.cs(19,19): warning CS8618: Non-nullable property 'StatusMessage' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/SlugifyParameterTransformer.cs(10,37): warning CS8603: Possible null reference return. [/workspace/Web/Web.csproj]
        /workspace/Web/SlugifyParameterTransformer.cs(13,30): warning CS8604: Possible null reference argument for parameter 'input' in 'string Regex.Replace(string input, string pattern, string replacement)'. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/Manage/ExternalLoginsViewModel.cs(9,33): warning CS8618: Non-nullable property 'CurrentLogins' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/Manage/ExternalLoginsViewModel.cs(10,40): warning CS8618: Non-nullable property 'OtherLogins' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/Manage/ExternalLoginsViewModel.cs(12,19): warning CS8618: Non-nullable property 'StatusMessage' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/Manage/EnableAuthenticatorViewModel.cs(13,19): warning CS8618: Non-nullable property 'Code' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/Manage/EnableAuthenticatorViewModel.cs(16,19): warning CS8618: Non-nullable property 'SharedKey' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/Manage/EnableAuthenticatorViewModel.cs(19,19): warning CS8618: Non-nullable property 'AuthenticatorUri' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/Manage/ChangePasswordViewModel.cs(10,19): warning CS8618: Non-nullable property 'OldPassword' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/Manage/ChangePasswordViewModel.cs(16,19): warning CS8618: Non-nullable property 'NewPassword' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/Manage/ChangePasswordViewModel.cs(21,19): warning CS8618: Non-nullable property 'ConfirmPassword' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/Manage/ChangePasswordViewModel.cs(23,19): warning CS8618: Non-nullable property 'StatusMessage' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/File/FileViewModel.cs(5,19): warning CS8618: Non-nullable property 'FileName' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/File/FileViewModel.cs(6,19): warning CS8618: Non-nullable property 'Url' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/File/FileViewModel.cs(7,19): warning CS8618: Non-nullable property 'DataBase64' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/CatalogItemViewModel.cs(6,19): warning CS8618: Non-nullable property 'Name' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/CatalogItemViewModel.cs(7,19): warning CS8618: Non-nullable property 'PictureUri' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/CatalogIndexViewModel.cs(8,39): warning CS8618: Non-nullable property 'CatalogItems' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/CatalogIndexViewModel.cs(9,33): warning CS8618: Non-nullable property 'Brands' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/CatalogIndexViewModel.cs(10,33): warning CS8618: Non-nullable property 'Types' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/CatalogIndexViewModel.cs(13,36): warning CS8618: Non-nullable property 'PaginationInfo' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/Account/ResetPasswordViewModel.cs(9,19): warning CS8618: Non-nullable property 'Email' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/Account/ResetPasswordViewModel.cs(14,19): warning CS8618: Non-nullable property 'Password' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/Account/ResetPasswordViewModel.cs(19,19): warning CS8618: Non-nullable property 'ConfirmPassword' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/Account/ResetPasswordViewModel.cs(21,19): warning CS8618: Non-nullable property 'Code' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/Account/RegisterViewModel.cs(10,19): warning CS8618: Non-nullable property 'Email' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/Account/RegisterViewModel.cs(16,19): warning CS8618: Non-nullable property 'Password' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/Account/RegisterViewModel.cs(21,19): warning CS8618: Non-nullable property 'ConfirmPassword' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/Account/LoginWith2faViewModel.cs(11,19): warning CS8618: Non-nullable property 'TwoFactorCode' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/Controllers/OrderController.cs(25,62): warning CS8602: Dereference of a possibly null reference. [/workspace/Web/Web.csproj]
        /workspace/Web/Controllers/OrderController.cs(25,62): warning CS8604: Possible null reference argument for parameter 'userName' in 'GetMyOrders.GetMyOrders(string userName)'. [/workspace/Web/Web.csproj]
        /workspace/Web/Controllers/OrderController.cs(33,66): warning CS8602: Dereference of a possibly null reference. [/workspace/Web/Web.csproj]
        /workspace/Web/Controllers/OrderController.cs(33,66): warning CS8604: Possible null reference argument for parameter 'userName' in 'GetOrderDetails.GetOrderDetails(string userName, int orderId)'. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/Account/LoginViewModel.cs(9,19): warning CS8618: Non-nullable property 'Email' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/ViewModels/Account/LoginViewModel.cs(13,19): warning CS8618: Non-nullable property 'Password' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/Views/Order/Detail.cshtml(20,68): warning CS8602: Dereference of a possibly null reference. [/workspace/Web/Web.csproj]
        /workspace/Web/Areas/Identity/Pages/Account/Login.cshtml.cs(25,12): warning CS8618: Non-nullable property 'Input' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/Areas/Identity/Pages/Account/Login.cshtml.cs(25,12): warning CS8618: Non-nullable property 'ExternalLogins' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/Areas/Identity/Pages/Account/Login.cshtml.cs(25,12): warning CS8618: Non-nullable property 'ReturnUrl' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/Areas/Identity/Pages/Account/Login.cshtml.cs(25,12): warning CS8618: Non-nullable property 'ErrorMessage' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/Views/Manage/TwoFactorAuthentication.cshtml(8,6): warning CS8602: Dereference of a possibly null reference. [/workspace/Web/Web.csproj]
        /workspace/Web/Areas/Identity/Pages/Account/Login.cshtml.cs(46,23): warning CS8618: Non-nullable property 'Email' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/Areas/Identity/Pages/Account/Login.cshtml.cs(50,23): warning CS8618: Non-nullable property 'Password' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/Areas/Identity/Pages/Account/Register.cshtml.cs(24,12): warning CS8618: Non-nullable property 'Input' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/Areas/Identity/Pages/Account/Register.cshtml.cs(24,12): warning CS8618: Non-nullable property 'ReturnUrl' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/Pages/Basket/BasketItemViewModel.cs(9,19): warning CS8618: Non-nullable property 'ProductName' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/Pages/Basket/BasketItemViewModel.cs(16,19): warning CS8618: Non-nullable property 'PictureUrl' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/Pages/Basket/Checkout.cshtml.cs(25,32): warning CS8625: Cannot convert null literal to non-nullable reference type. [/workspace/Web/Web.csproj]
        /workspace/Web/Areas/Identity/Pages/Account/Register.cshtml.cs(46,23): warning CS8618: Non-nullable property 'Email' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/Areas/Identity/Pages/Account/Register.cshtml.cs(52,23): warning CS8618: Non-nullable property 'Password' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/Areas/Identity/Pages/Account/Register.cshtml.cs(57,23): warning CS8618: Non-nullable property 'ConfirmPassword' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/Pages/Error.cshtml.cs(10,19): warning CS8618: Non-nullable property 'RequestId' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/Pages/Basket/BasketViewModel.cs(11,19): warning CS8618: Non-nullable property 'BuyerId' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/workspace/Web/Web.csproj]
        /workspace/Web/Pages/Basket/Checkout.cshtml.cs(79,82): warning CS8602: Dereference of a possibly null reference. [/workspace/Web/Web.csproj]
        /workspace/Web/Pages/Basket/Checkout.cshtml.cs(79,82): warning CS8604: Possible null reference argument for parameter 'userName' in 'Task<BasketViewModel> IBasketViewModelService.GetOrCreateBasketForUser(string userName)'. [/workspace/Web/Web.csproj]
        /workspace/Web/Views/Shared/Components/Basket/Default.cshtml(12,15): warning CS8602: Dereference of a possibly null reference. [/workspace/Web/Web.csproj]
        /workspace/Web/Areas/Identity/Pages/Account/Register.cshtml.cs(84,91): warning CS8604: Possible null reference argument for parameter 'value' in 'string TextEncoder.Encode(string value)'. [/workspace/Web/Web.csproj]
        /workspace/Web/Views/Manage/ShowRecoverCodes.cshtml(19,34): warning CS8602: Dereference of a possibly null reference. [/workspace/Web/Web.csproj]
        /workspace/Web/Pages/Basket/Checkout.cshtml.cs(92,25): warning CS8601: Possible null reference assignment. [/workspace/Web/Web.csproj]
        /workspace/Web/Pages/Basket/Index.cshtml.cs(64,27): warning CS8600: Converting null literal or possible null value to non-nullable type. [/workspace/Web/Web.csproj]
        /workspace/Web/Pages/Basket/Index.cshtml.cs(66,13): warning CS8602: Dereference of a possibly null reference. [/workspace/Web/Web.csproj]
        /workspace/Web/Pages/Basket/Index.cshtml.cs(68,20): warning CS8603: Possible null reference return. [/workspace/Web/Web.csproj]
        /workspace/Web/Pages/Basket/Index.cshtml.cs(73,24): warning CS8600: Converting null literal or possible null value to non-nullable type. [/workspace/Web/Web.csproj]
        /workspace/Web/Pages/Basket/Index.cshtml.cs(79,32): warning CS8600: Converting null literal or possible null value to non-nullable type. [/workspace/Web/Web.csproj]
        /workspace/Web/Pages/Shared/Components/BasketComponent/Default.cshtml(11,11): warning CS8602: Dereference of a possibly null reference. [/workspace/Web/Web.csproj]
        /workspace/Web/Pages/Shared/_editCatalog.cshtml(5,50): warning CS8602: Dereference of a possibly null reference. [/workspace/Web/Web.csproj]
        /workspace/Web/Pages/Shared/Components/BasketComponent/Basket.cs(36,63): warning CS8602: Dereference of a possibly null reference. [/workspace/Web/Web.csproj]
        /workspace/Web/Pages/Shared/Components/BasketComponent/Basket.cs(36,63): warning CS8604: Possible null reference argument for parameter 'username' in 'Task<int> IBasketViewModelService.CountTotalBasketItems(string username)'. [/workspace/Web/Web.csproj]
        /workspace/Web/Pages/Shared/Components/BasketComponent/Basket.cs(57,16): warning CS8603: Possible null reference return. [/workspace/Web/Web.csproj]
        /workspace/Web/Views/Shared/_LoginPartial.cshtml(1,6): warning CS8602: Dereference of a possibly null reference. [/workspace/Web/Web.csproj]
        /workspace/Web/Views/Manage/EnableAuthenticator.cshtml(23,58): warning CS8602: Dereference of a possibly null reference. [/workspace/Web/Web.csproj]
        /workspace/Web/Views/Manage/ExternalLogins.cshtml(7,6): warning CS8602: Dereference of a possibly null reference. [/workspace/Web/Web.csproj]
        /workspace/Web/Pages/Shared/_pagination.cshtml(6,34): warning CS8602: Dereference of a possibly null reference. [/workspace/Web/Web.csproj]
        /workspace/Web/Pages/Shared/_product.cshtml(4,46): warning CS8602: Dereference of a possibly null reference. [/workspace/Web/Web.csproj]
        /workspace/Web/Views/Manage/MyAccount.cshtml(19,22): warning CS8602: Dereference of a possibly null reference. [/workspace/Web/Web.csproj]
          Web -> /workspace/Web/bin/Release/net6.0/ubuntu.18.04-x64/Web.dll
        /layers/tanzu-buildpacks_dotnet-core-sdk/dotnet-core-sdk/sdk/6.0.100/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.ILLink.targets(213,5): error NETSDK1102: Optimizing assemblies for size is not supported for the selected publish configuration. Please ensure that you are publishing a self-contained app. [/workspace/BlazorAdmin/BlazorAdmin.csproj]
ERROR: failed to build: exit status 1

Our build is still failing, but at least the dotnet publish command gives us a very clear hint as to what is going on. In this particular application, we need to set our application to be self-contained. Let's set the .NET build flags to the desired setting. While we're at it, we'll change the verbosity level to normal, so that we'll get more information during the build:

> kp image save dotnet-eshopweb \
--tag harbor.registry.com/apps/dotnet-eshopweb \
--git https://github.com/dotnet-architecture/eShopOnWeb.git \
--git-revision main \
--sub-path=./src \
--env BP_DOTNET_PROJECT_PATH="./Web" \
--env BP_DOTNET_PUBLISH_FLAGS="--verbosity=normal --self-contained=true"

Let's check the updated logs:

> kp build logs dotnet-eshopweb
===> PREPARE
Build reason(s): CONFIG
CONFIG:
  env:
  - name: BP_DOTNET_PROJECT_PATH
    value: ./Web
  + - name: BP_DOTNET_PUBLISH_FLAGS
  +   value: --verbosity=normal --self-contained=true
  resources: {}
  source:
    git:
      revision: 896fae150fbcec5de8a1fb923eab5dfafe09422a
      url: https://github.com/dotnet-architecture/eShopOnWeb.git
    subPath: ./src
Loading secret for "harbor.registry.com" from secret "registry-credentials" at location "/var/build-secrets/registry-credentials"
Cloning "https://github.com/dotnet-architecture/eShopOnWeb.git" @ "896fae150fbcec5de8a1fb923eab5dfafe09422a"...
Successfully cloned "https://github.com/dotnet-architecture/eShopOnWeb.git" @ "896fae150fbcec5de8a1fb923eab5dfafe09422a" in path "/workspace"
===> ANALYZE
Previous image with name "harbor.registry.com/apps/dotnet-eshopweb" not found
===> DETECT
7 of 13 buildpacks participating
paketo-buildpacks/ca-certificates    3.0.2
tanzu-buildpacks/dotnet-core-runtime 0.3.1
tanzu-buildpacks/dotnet-core-aspnet  0.3.2
tanzu-buildpacks/dotnet-core-sdk     0.3.1
tanzu-buildpacks/icu                 0.0.13
tanzu-buildpacks/dotnet-publish      0.5.1
tanzu-buildpacks/dotnet-execute      0.4.1
===> RESTORE
===> BUILD

Paketo CA Certificates Buildpack 3.0.2
  https://github.com/paketo-buildpacks/ca-certificates
  Launch Helper: Contributing to layer
    Creating /layers/paketo-buildpacks_ca-certificates/helper/exec.d/ca-certificates-helper
Tanzu .NET Core Runtime Buildpack 0.3.1
  Resolving Dotnet Core Runtime version
    Candidate version sources (in priority order):
      Web.csproj -> "6.0.0"
      <unknown>  -> ""

    Selected dotnet-runtime version (using Web.csproj): 6.0.0

  Executing build process
    Installing Dotnet Core Runtime 6.0.0
      Completed in 4.814s

  Configuring environment for build and launch
    DOTNET_ROOT -> "/workspace/.dotnet_root"

  Configuring environment for build
    RUNTIME_VERSION -> "6.0.0"

Tanzu ASP.NET Core Buildpack 0.3.2
  Resolving Dotnet Core ASPNet version
    Candidate version sources (in priority order):
      RUNTIME_VERSION -> "6.0.0"
      Web.csproj      -> "6.0.0"
      <unknown>       -> ""

    Selected dotnet-aspnetcore version (using RUNTIME_VERSION): 6.0.0

  Executing build process
    Installing Dotnet Core ASPNet 6.0.0
      Completed in 1.262s

  Configuring environment
    DOTNET_ROOT -> "/workspace/.dotnet_root"

Tanzu .NET Core SDK Buildpack 0.3.1
  Resolving .NET Core SDK version
    Candidate version sources (in priority order):
      RUNTIME_VERSION -> "6.0.100"
      <unknown>       -> "*"
      Web.csproj      -> "6.0.*"

    Selected .NET Core SDK version (using RUNTIME_VERSION): 6.0.100

  Executing build process
    Installing .NET Core SDK 6.0.100
      Completed in 16.227s

  Configuring environment
    DOTNET_ROOT -> "/workspace/.dotnet_root"
    PATH        -> "/workspace/.dotnet_root:$PATH"

Tanzu ICU Buildpack 0.0.13
  Executing build process
    Installing ICU
      Completed in 471ms

Tanzu .Net Publish Buildpack 0.5.1
  Executing build process
    Running 'dotnet publish /workspace/Web --configuration Release --runtime ubuntu.18.04-x64 --output /tmp/dotnet-publish-output1039265788 --verbosity=normal --self-contained=true'
      Completed in 1m3.68120334s

  Removing source code

Tanzu .NET Execute Buildpack 0.4.1
  Assigning launch processes
    web: /workspace/Web --urls http://0.0.0.0:${PORT:-8080}

===> EXPORT
Adding layer 'paketo-buildpacks/ca-certificates:helper'
Adding layer 'tanzu-buildpacks/dotnet-core-runtime:dotnet-core-runtime'
Adding layer 'tanzu-buildpacks/dotnet-core-aspnet:dotnet-core-aspnet'
Adding layer 'tanzu-buildpacks/dotnet-core-sdk:dotnet-env-var'
Adding layer 'tanzu-buildpacks/icu:icu'
Adding layer 'launch.sbom'
Adding 1/1 app layer(s)
Adding layer 'launcher'
Adding layer 'config'
Adding layer 'process-types'
Adding label 'io.buildpacks.lifecycle.metadata'
Adding label 'io.buildpacks.build.metadata'
Adding label 'io.buildpacks.project.metadata'
Setting default process type 'web'
Saving harbor.registry.com/apps/dotnet-eshopweb...
*** Images (sha256:48ac5c34be35b15589edb25a186978b19c70c397c08f618795799b3d65a454a0):
      harbor.registry.com/apps/dotnet-eshopweb
      harbor.registry.com/apps/dotnet-eshopweb:b3.20220116.122508
Adding cache layer 'tanzu-buildpacks/dotnet-core-runtime:dotnet-core-runtime'
Adding cache layer 'tanzu-buildpacks/dotnet-core-aspnet:dotnet-core-aspnet'
Adding cache layer 'tanzu-buildpacks/dotnet-core-sdk:dotnet-core-sdk'
Adding cache layer 'tanzu-buildpacks/icu:icu'
===> COMPLETION
Build successful

This looks A LOT better.

Running the image

Let's see if the image runs as expected:

image.png

We still see some errors, but if we'll enable the development mode as hinted on screen, we'll see that the error is as follows:

image.png

After some googling, we can see that SQL Server Express is only supported on Windows. This will require us to make some architectural code changes in our app to adapt to a linux world, but that's standard development effort and out of scope for Cloud Native Buildpacks themselves.

Additional tips and tricks

  • If your application fails on error NU1605, make sure you update your project file with the following XML entry to force it to use the correct runtime for your desired runtime:

    <PackageReference Include="Microsoft.NETCore.Targets" Version="5.0.0" PrivateAssets="all" />
    
  • If you're working at an airgapped environment, you may need to clear the default nuget repositories to force the build to use your private registry only. In your nuget.config:

    <configuration>
    <packageSources>
          <clear /> <!-- ensure only the sources defined below are used -->
          <add key="MyPrivateRepo - ES" value="https://MyPrivateRepo/ES/nuget" />
      </packageSources>
    </configuration>
    
  • If you need to set environment variables for the application runtime, add the env varible to the kp image save command, prefixed with BPE_. For example - --env BPE_MY_RUNTIME_VAR=value. Any env variable that starts with BPE will automatically add the environment variables buildpack to the image.

Frontend VueJS Application

We'll begin with a UI application that is using the popular VueJS library. This application presents a frontend for a Todo application. We won't be focusing on the backend so we'll see some "error loading details" in the UI, but the idea is just to see if the image works as expected.

Git repo

The git repo for this application is available at github.com/odedia/todo-ui.git

Build command

Let's try to build the code:

> kp image save todo-vuejs \
--tag harbor.registry.com/tap/todo-vuejs \
--git https://github.com/odedia/todo-ui \
--git-revision main
Creating Image Resource...
Image Resource "todo-vuejs" created

Build logs output

Here's the output from the build logs:

> kp build logs todo-vuejs
===> PREPARE
Build reason(s): CONFIG
CONFIG:
  resources: {}
  - source: {}
  + source:
  +   git:
  +     revision: 0236707eb0481fce9d3d292f0a1787a7ced5e706
  +     url: https://github.com/odedia/todo-ui
Loading secret for "harbor.registry.com" from secret "registry-credentials" at location "/var/build-secrets/registry-credentials"
Cloning "https://github.com/odedia/todo-ui" @ "0236707eb0481fce9d3d292f0a1787a7ced5e706"...
Successfully cloned "https://github.com/odedia/todo-ui" @ "0236707eb0481fce9d3d292f0a1787a7ced5e706" in path "/workspace"
===> ANALYZE
Previous image with name "harbor.registry.com/tap/todo-vuejs" not found
===> DETECT
5 of 17 buildpacks participating
paketo-buildpacks/ca-certificates 3.0.2
tanzu-buildpacks/node-engine      0.8.3
tanzu-buildpacks/npm-install      0.5.3
tanzu-buildpacks/node-module-bom  0.1.4
tanzu-buildpacks/npm-start        0.2.3
===> RESTORE
===> BUILD

Paketo CA Certificates Buildpack 3.0.2
  https://github.com/paketo-buildpacks/ca-certificates
  Launch Helper: Contributing to layer
    Creating /layers/paketo-buildpacks_ca-certificates/helper/exec.d/ca-certificates-helper
Tanzu Node Engine Buildpack 0.8.3
  Resolving Node Engine version
    Candidate version sources (in priority order):
      package.json -> ">=10.12.0"
      .nvmrc       -> "11.6.0"
      <unknown>    -> ""

    Selected Node Engine version (using package.json): 16.13.1

  Executing build process
    Installing Node Engine 16.13.1
      Completed in 1.043s

  Configuring build environment
    NODE_ENV     -> "production"
    NODE_HOME    -> "/layers/tanzu-buildpacks_node-engine/node"
    NODE_VERBOSE -> "false"

  Configuring launch environment
    NODE_ENV     -> "production"
    NODE_HOME    -> "/layers/tanzu-buildpacks_node-engine/node"
    NODE_VERBOSE -> "false"

    Writing profile.d/0_memory_available.sh
      Calculates available memory based on container limits at launch time.
      Made available in the MEMORY_AVAILABLE environment variable.

Tanzu NPM Install Buildpack 0.5.3
  Resolving installation process
    Process inputs:
      node_modules      -> "Not found"
      npm-cache         -> "Not found"
      package-lock.json -> "Found"

    Selected NPM build process: 'npm ci'

  Executing build process
    Running 'npm ci --unsafe-perm --cache /layers/tanzu-buildpacks_npm-install/npm-cache'
      Completed in 7.182s

  Configuring launch environment
    NPM_CONFIG_LOGLEVEL -> "error"

  Configuring environment shared by build and launch
    PATH -> "$PATH:/layers/tanzu-buildpacks_npm-install/modules/node_modules/.bin"


Tanzu Node Module Bill of Materials Generator Buildpack 0.1.4
  Resolving CycloneDX Node.js Module version
    Selected CycloneDX Node.js Module version: 3.0.7

  Executing build process
    Installing CycloneDX Node.js Module 3.0.7
      Completed in 42ms

  Configuring environment
    Appending CycloneDX Node.js Module onto PATH

  Running CycloneDX Node.js Module
    Running 'cyclonedx-bom -o bom.json'
      Completed in 501ms

Tanzu NPM Start Buildpack 0.2.3
  Assigning launch processes
    web: node server.js

===> EXPORT
Adding layer 'paketo-buildpacks/ca-certificates:helper'
Adding layer 'tanzu-buildpacks/node-engine:node'
Adding layer 'tanzu-buildpacks/npm-install:modules'
Adding layer 'tanzu-buildpacks/npm-install:npm-cache'
Adding layer 'launch.sbom'
Adding 1/1 app layer(s)
Adding layer 'launcher'
Adding layer 'config'
Adding layer 'process-types'
Adding label 'io.buildpacks.lifecycle.metadata'
Adding label 'io.buildpacks.build.metadata'
Adding label 'io.buildpacks.project.metadata'
Setting default process type 'web'
Saving harbor.registry.com/tap/todo-vuejs...
*** Images (sha256:493cb51b0cd480eb68228da37332a06112141284ee55266faca2047503b99cab):
      harbor.registry.com/tap/todo-vuejs
      harbor.registry.com/tap/todo-vuejs:b1.20220117.104712
Adding cache layer 'tanzu-buildpacks/node-engine:node'
Adding cache layer 'tanzu-buildpacks/npm-install:modules'
Adding cache layer 'tanzu-buildpacks/npm-install:npm-cache'
Adding cache layer 'tanzu-buildpacks/node-module-bom:cyclonedx-node-module'
===> COMPLETION
Build successful

Running the image

Here's the command to run the image:

> docker run -p 8080:8080 harbor.registry.com/tap/todo-vuejs:b1.20220117.104712
Unable to find image 'harbor.registry.com/tap/todo-vuejs:b1.20220117.104712' locally
b1.20220117.104712: Pulling from tap/todo-vuejs
bf99a8b93828: Already exists
1da1131b1360: Already exists
48bde579d8cc: Already exists
1929d0623312: Already exists
1fea93ec33be: Already exists
fed2bcb93d83: Already exists
eb2e57672edf: Already exists
03e598551527: Pull complete
00da406126de: Pull complete
841d6c40c392: Pull complete
b3e12a218902: Pull complete
40d17e1b116e: Pull complete
5baaabcf4fd8: Pull complete
5a44e4f7b58d: Pull complete
Digest: sha256:493cb51b0cd480eb68228da37332a06112141284ee55266faca2047503b99cab
Status: Downloaded newer image for harbor.registry.com/tap/todo-vuejs:b1.20220117.104712
cat: /sys/fs/cgroup/memory/memory.limit_in_bytes: No such file or directory
/layers/tanzu-buildpacks_node-engine/node/profile.d/0_memory_available.sh: line 3: / ( 1024 * 1024 ) : syntax error: operand expected (error token is "/ ( 1024 * 1024 ) ")
server started 5000

Oops - we immediatly see that the container boots on default node port of 5000. This means we can't access the application since nothing maps to 8080. We could just map intenral port 5000 to external port 8080, but conventions are good. We can change the source code, but it's possible we want to keep port 5000 as the default for local development and debugging. The alternative is to set the PORT env varible. The Node buildpack supports embedding launch-time environment varialbes by utilizing the Environment Variables buildpack. Following the documentation, it appears we need to set a value called BPE_PORT:

> kp image save todo-vuejs \
--tag harbor.registry.com/tap/todo-vuejs \
--git https://github.com/odedia/todo-ui \
--git-revision main \
> --env BPE_PORT=8080
Patching Image Resource...
Image Resource "todo-vuejs" patched

We can confirm in the logs that the DETECT phase now contributes the Environment Variables buildpack, which is a good sign:

===> DETECT
6 of 17 buildpacks participating
paketo-buildpacks/ca-certificates       3.0.2
tanzu-buildpacks/node-engine            0.8.3
tanzu-buildpacks/npm-install            0.5.3
tanzu-buildpacks/node-module-bom        0.1.4
tanzu-buildpacks/npm-start              0.2.3
paketo-buildpacks/environment-variables 4.0.1

And indeed, while running the image again, we see the application listening on port 8080:

> docker run -p 8080:8080 harbor.registry.com/tap/todo-vuejs:b2.20220117.105600
Unable to find image 'harbor.registry.com/tap/todo-vuejs:b2.20220117.105600' locally
b2.20220117.105600: Pulling from tap/todo-vuejs
bf99a8b93828: Already exists
1da1131b1360: Already exists
48bde579d8cc: Already exists
1929d0623312: Already exists
1fea93ec33be: Already exists
fed2bcb93d83: Already exists
eb2e57672edf: Already exists
03e598551527: Already exists
00da406126de: Already exists
f9724edbdfed: Pull complete
f4702cd992a7: Pull complete
40d17e1b116e: Pull complete
0dc2cd914cc8: Pull complete
5a44e4f7b58d: Pull complete
Digest: sha256:cdd54580ea9554927a80f7c4ccdbd97046624a6001c137f9c0cecc9487300389
Status: Downloaded newer image for harbor.registry.com/tap/todo-vuejs:b2.20220117.105600
cat: /sys/fs/cgroup/memory/memory.limit_in_bytes: No such file or directory
/layers/tanzu-buildpacks_node-engine/node/profile.d/0_memory_available.sh: line 3: / ( 1024 * 1024 ) : syntax error: operand expected (error token is "/ ( 1024 * 1024 ) ")
server started 8080

Our application is now shown as expected:

image.png

Changing the defaults

Does this buildpack really does what we want it to do? Node is a language that can run as a standard backend server, for example to host your APIs, but for frontend applications we really just use it to compile our libraries into standard HTML+Javascript or Typescript. We want Node when doing local development and debugging, but once that part is done - we really just want to take these artifacts and serve them over a web server such as HTTPD or Nginx. Let's see what really happens in our container at the moment:

> docker exec -it b4db4162a405 /bin/bash
cnb@b4db4162a405:/workspace$ ls -l
total 1308
-rwxr-xr-x 1 cnb cnb     521 Jan  1  1980 Dockerfile
-rwxr-xr-x 1 cnb cnb     364 Jan  1  1980 README.md
-rw-r--r-- 1 cnb cnb     716 Jan  1  1980 Tiltfile
-rwxr-xr-x 1 cnb cnb      53 Jan  1  1980 babel.config.js
-rwxr-xr-x 1 cnb cnb      86 Jan  1  1980 build.sh
-rwxr-xr-x 1 cnb cnb      97 Jan  1  1980 buildAndPush.sh
drwxr-sr-x 2 cnb cnb    4096 Jan  1  1980 ci
drwxr-sr-x 2 cnb cnb    4096 Jan  1  1980 config
drwxr-sr-x 4 cnb cnb    4096 Jan  1  1980 dist
-rwxr-xr-x 1 cnb cnb     310 Jan  1  1980 manifest-docker.yml
-rwxr-xr-x 1 cnb cnb     120 Jan  1  1980 manifest-tas4vms.yml
-rwxr-xr-x 1 cnb cnb     120 Jan  1  1980 manifest.yml
lrwxrwxrwx 1 cnb cnb      57 Jan  1  1980 node_modules -> /layers/tanzu-buildpacks_npm-install/modules/node_modules
-rwxr-xr-x 1 cnb cnb 1257671 Jan  1  1980 package-lock.json
-rwxr-xr-x 1 cnb cnb    2508 Jan  1  1980 package.json
drwxr-sr-x 2 cnb cnb    4096 Jan  1  1980 public
-rwxr-xr-x 1 cnb cnb     271 Jan  1  1980 server.js
drwxr-sr-x 3 cnb cnb    4096 Jan  1  1980 src
-rwxr-xr-x 1 cnb cnb      46 Jan  1  1980 vue.config.js

We seem to have a dist folder that contains our desired HTML+Javascript/Typescript, but that's not what the container is currently serving. Checking the package.json file, we can see that the available scripts are:

  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "start": "node server.js",
    "lint": "vue-cli-service lint"
  }

If we'll take a closer look at the build logs from above, the NPM start buildpack contributed the start command as listed in the json:

Tanzu NPM Start Buildpack 0.2.3
  Assigning launch processes
    web: node server.js

So, we're at an odd place - the application is running, but it's probably not optimized as we'd like.

What we really want to do is to take the artifacts in the dist folder and host that as a web server. Sadly, there is no OOTB solution for this yet with existing buildpacks. This is something that would probably change in the near future. In order to solve this issue, we can solve it in two approaches, both are not perfect at the moment:

Option 1: Compile NPM externally

This option would build the source code into the dist folder before building the final image witth TBS. In order to do that, we first need to create two files for NGINX: nginx.conf and mime.types. Both of these files should exist at the root of the repository. mime.types is a standard file that can be replicated wherever needed. A sample file is available here. You may want to tweak nginx.conf per your own use cases, but here's a good starting point:

worker_processes 1;
daemon off;

error_log stderr;
events { worker_connections 1024; }

http {
  charset utf-8;
  log_format cloudfoundry 'NginxLog "$request" $status $body_bytes_sent';
  access_log /dev/stdout cloudfoundry;
  default_type application/octet-stream;
  include mime.types;
  sendfile on;

  tcp_nopush on;
  keepalive_timeout 30;
  port_in_redirect off; # Ensure that redirects don't include the internal container PORT - 8080

  server {
    listen {{ 8080 }};
    root .;
    index index.html;
  }
}

Note that the root folder to serve is the root of the target workspace folder, since we only use the dist folder as the root of our container. Also, We again use port 8080 to host the application.

To get this working, we first need to update the build command in package.json to also copy the two NGINX files to the dist folder:

  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build && cp nginx.conf ./dist && cp mime.types ./dist",
    "start": "node server.js",
    "lint": "vue-cli-service lint"
  }

Let's try to run the flow:

npm install && npm run build && kp image save todo-vuejs --tag harbor.registry.com/tap/todo-vuejs --local-path ./dist

The build logs are a lot simpler now - they just server static content behind NGINX:

> kp build logs todo-vuejs
===> PREPARE
Build reason(s): CONFIG
CONFIG:
  resources: {}
  - source: {}
  + source:
  +   registry:
  +     image: harbor.registry.com/tap/todo-vuejs-source@sha256:772c0bb4faa607fde8f6139135dd27814cf0a38b4d27e8abdcb68d1f528ab1d5
Loading secret for "harbor.registry.com" from secret "registry-credentials" at location "/var/build-secrets/registry-credentials"
Pulling harbor.registry.com/tap/todo-vuejs-source@sha256:772c0bb4faa607fde8f6139135dd27814cf0a38b4d27e8abdcb68d1f528ab1d5...
Successfully pulled harbor.registry.com/tap/todo-vuejs-source@sha256:772c0bb4faa607fde8f6139135dd27814cf0a38b4d27e8abdcb68d1f528ab1d5 in path "/workspace"
===> ANALYZE
===> DETECT
tanzu-buildpacks/nginx 0.4.4
===> RESTORE
Restoring metadata for "tanzu-buildpacks/nginx:nginx" from app image
===> BUILD
Tanzu Nginx Server Buildpack 0.4.4
  Resolving Nginx Server version
    Candidate version sources (in priority order):
      buildpack.toml -> "1.21.*"

    Selected Nginx Server version (using buildpack.toml): 1.21.4

===> EXPORT
Reusing layers from image 'harbor.registry.com/tap/todo-vuejs@sha256:cc57796966f948dbec6531f399cdfbb5a2840730405810efd70eeb205f79a23a'
Reusing layer 'tanzu-buildpacks/nginx:nginx'
Reusing 1/1 app layer(s)
Reusing layer 'launcher'
Reusing layer 'config'
Reusing layer 'process-types'
Adding label 'io.buildpacks.lifecycle.metadata'
Adding label 'io.buildpacks.build.metadata'
Adding label 'io.buildpacks.project.metadata'
Setting default process type 'web'
Saving harbor.registry.com/tap/todo-vuejs...
*** Images (sha256:cc57796966f948dbec6531f399cdfbb5a2840730405810efd70eeb205f79a23a):
      harbor.registry.com/tap/todo-vuejs
      harbor.registry.com/tap/todo-vuejs:b1.20220117.112114
===> COMPLETION
Build successful

Let's see if the application is still running as expected:

> docker run -p 8080:8080 harbor.registry.com/tap/todo-vuejs:b1.20220117.112114
Unable to find image 'harbor.registry.com/tap/todo-vuejs:b1.20220117.112114' locally
b1.20220117.112114: Pulling from tap/todo-vuejs
bf99a8b93828: Already exists
1da1131b1360: Already exists
48bde579d8cc: Already exists
1929d0623312: Already exists
1fea93ec33be: Already exists
5ad05d7a8092: Pull complete
3499fa7eadde: Pull complete
40d17e1b116e: Pull complete
274f229843b4: Pull complete
5a44e4f7b58d: Pull complete
Digest: sha256:cc57796966f948dbec6531f399cdfbb5a2840730405810efd70eeb205f79a23a
Status: Downloaded newer image for harbor.registry.com/tap/todo-vuejs:b1.20220117.112114

Our application is exposed as expected:

image.png

So things work, great! But, is this a good practice? probably not.

  • We need to compile our code outside the container.
  • The NPM version that runs on the target system can impact our build. Changes to the hosted environment can produce different results.
  • We need to send source code from a local path to Build Service. This means that we are basically decoupled from our git repository. Changes in git will not be reflected in the build pipeline.
  • We create dependencies between Node buildpack and the NGINX buildpack - our build command needs to copy files to the dist folder.
  • In general, this feels very "scripty" and you might as well just revert to a Dockerfile at this point (although you always gain the benefits of proactive CVE patching for your base OS stack and middleware, even with this approach).

Option 2: Create a custom buildpack

We can take a different approach and just tell Build Service to run the Node Buildpack followed by the NGINX buildpack. This way we'll get better automation and can still target a git repository and not a local folder.

The first thing we need is to know how our buildpacks are named. We can use the following command to get information about our default clusterbuilder, which is the one we used up to this point:

> kp clusterbuilder status default
Status:       Ready
Image:        harbor.registry.com/build-service/tbs:clusterbuilder-default@sha256:e2f4db390a617d11a475a5ebbed4bd17ddd9375a5e1b9f489621480ae58dcc43
Stack ID:     io.buildpacks.stacks.bionic
Run Image:    harbor.registry.com/build-service/tbs@sha256:b69b4f654e6a2d2d69d1cca1a51638401127b6fb3556faa6304cab1575ef7c16

Stack Ref:
  Name:       base
  Kind:       ClusterStack
Store Ref:
  Name:       default
  Kind:       ClusterStore

BUILDPACK ID                                    VERSION    HOMEPAGE
paketo-buildpacks/bellsoft-liberica             9.0.2      https://github.com/paketo-buildpacks/bellsoft-liberica
tanzu-buildpacks/go-dist                        0.6.5
tanzu-buildpacks/cpython                        0.2.0      https://github.com/pivotal-cf/tanzu-cpython
tanzu-buildpacks/dotnet-core-sdk                0.3.1
tanzu-buildpacks/node-engine                    0.8.3
tanzu-buildpacks/apache-skywalking              4.1.2      https://github.com/pivotal-cf/tanzu-apache-skywalking
tanzu-buildpacks/dotnet-core-runtime            0.3.1
tanzu-buildpacks/appdynamics                    4.1.4      https://github.com/pivotal-cf/tanzu-appdynamics
paketo-buildpacks/gradle                        6.0.2      https://github.com/paketo-buildpacks/gradle
tanzu-buildpacks/jprofiler                      4.0.2      https://github.com/pivotal-cf/tanzu-jprofiler
tanzu-buildpacks/miniconda                      0.1.4      https://github.com/pivotal-cf/tanzu-miniconda
tanzu-buildpacks/new-relic                      4.0.4      https://github.com/pivotal-cf/tanzu-new-relic
tanzu-buildpacks/overops                        4.0.3      https://github.com/pivotal-cf/tanzu-overops
tanzu-buildpacks/pipenv                         0.2.4      https://github.com/pivotal-cf/tanzu-pipenv
tanzu-buildpacks/dotnet-core-aspnet             0.3.2
paketo-buildpacks/maven                         6.1.0      https://github.com/paketo-buildpacks/maven
paketo-buildpacks/apache-tomcat                 7.0.3      https://github.com/paketo-buildpacks/apache-tomcat
tanzu-buildpacks/icu                            0.0.13
paketo-buildpacks/azure-application-insights    5.1.2      https://github.com/paketo-buildpacks/azure-application-insights
tanzu-buildpacks/jrebel                         4.0.3      https://github.com/pivotal-cf/tanzu-jrebel
paketo-buildpacks/sbt                           6.1.0      https://github.com/paketo-buildpacks/sbt
paketo-buildpacks/sbt                           6.0.4      https://github.com/paketo-buildpacks/sbt
tanzu-buildpacks/riverbed                       4.0.2      https://github.com/pivotal-cf/tanzu-riverbed
tanzu-buildpacks/yourkit                        4.0.3      https://github.com/pivotal-cf/tanzu-yourkit
tanzu-buildpacks/nginx                          0.4.4      https://docs.pivotal.io/tanzu-buildpacks/nginx/nginx-buildpack.html
tanzu-buildpacks/pip                            0.6.3      https://github.com/pivotal-cf/tanzu-pip
tanzu-buildpacks/contrast-security              4.1.1      https://github.com/pivotal-cf/tanzu-contrast-security
tanzu-buildpacks/elastic-apm                    4.1.2      https://github.com/pivotal-cf/tanzu-elastic-apm
paketo-buildpacks/maven                         6.0.2      https://github.com/paketo-buildpacks/maven
paketo-buildpacks/google-stackdriver            5.1.2      https://github.com/paketo-buildpacks/google-stackdriver
tanzu-buildpacks/elastic-apm                    4.1.3      https://github.com/pivotal-cf/tanzu-elastic-apm
tanzu-buildpacks/dep                            0.1.4
paketo-buildpacks/syft                          1.3.1      https://github.com/paketo-buildpacks/syft
tanzu-buildpacks/yarn                           0.3.3
tanzu-buildpacks/dynatrace                      4.0.2      https://github.com/pivotal-cf/tanzu-dynatrace
paketo-buildpacks/spring-boot                   5.3.0      https://github.com/paketo-buildpacks/spring-boot
tanzu-buildpacks/jacoco                         4.0.2      https://github.com/pivotal-cf/tanzu-jacoco
tanzu-buildpacks/node-module-bom                0.1.4
tanzu-buildpacks/checkmarx                      4.0.2      https://github.com/pivotal-cf/tanzu-checkmarx
paketo-buildpacks/watchexec                     2.0.2      https://github.com/paketo-buildpacks/watchexec
paketo-buildpacks/upx                           3.0.1      https://github.com/paketo-buildpacks/upx
tanzu-buildpacks/synopsys                       4.0.2      https://github.com/pivotal-cf/tanzu-synopsys
paketo-buildpacks/ca-certificates               3.0.2      https://github.com/paketo-buildpacks/ca-certificates
paketo-buildpacks/procfile                      5.0.2      https://github.com/paketo-buildpacks/procfile
paketo-buildpacks/encrypt-at-rest               4.0.2      https://github.com/paketo-buildpacks/encrypt-at-rest
paketo-buildpacks/leiningen                     4.0.2      https://github.com/paketo-buildpacks/leiningen
paketo-buildpacks/clojure-tools                 2.0.2      https://github.com/paketo-buildpacks/clojure-tools
paketo-buildpacks/syft                          1.4.0      https://github.com/paketo-buildpacks/syft
tanzu-buildpacks/snyk                           4.0.2      https://github.com/pivotal-cf/tanzu-snyk
tanzu-buildpacks/go-build                       0.3.2
tanzu-buildpacks/dotnet-publish                 0.5.1
tanzu-buildpacks/dotnet-execute                 0.4.1
tanzu-buildpacks/pipenv-install                 0.1.6      https://github.com/pivotal-cf/tanzu-pipenv-install
tanzu-buildpacks/npm-install                    0.5.3
tanzu-buildpacks/yarn-install                   0.3.2
tanzu-buildpacks/dep-ensure                     0.1.3
tanzu-buildpacks/go-mod-vendor                  0.2.3
tanzu-buildpacks/pip-install                    0.2.2      https://github.com/pivotal-cf/tanzu-pip-install
tanzu-buildpacks/conda-env-update               0.1.4      https://github.com/pivotal-cf/tanzu-conda-env-update
tanzu-buildpacks/node-run-script                0.2.2
tanzu-buildpacks/npm-start                      0.2.3
tanzu-buildpacks/yarn-start                     0.2.3
tanzu-buildpacks/python-start                   0.4.2      https://github.com/pivotal-cf/tanzu-python-start
tanzu-buildpacks/node-start                     0.3.3
paketo-buildpacks/native-image                  5.0.2      https://github.com/paketo-buildpacks/native-image
paketo-buildpacks/executable-jar                6.0.2      https://github.com/paketo-buildpacks/executable-jar
tanzu-buildpacks/aspectj                        4.0.2      https://github.com/pivotal-cf/tanzu-aspectj
paketo-buildpacks/dist-zip                      5.0.2      https://github.com/paketo-buildpacks/dist-zip
paketo-buildpacks/environment-variables         4.0.1      https://github.com/paketo-buildpacks/environment-variables
paketo-buildpacks/environment-variables         4.0.2      https://github.com/paketo-buildpacks/environment-variables
paketo-buildpacks/image-labels                  4.0.2      https://github.com/paketo-buildpacks/image-labels
tanzu-buildpacks/java                           6.4.0      https://github.com/pivotal-cf/tanzu-java
tanzu-buildpacks/java-native-image              6.5.0      https://github.com/pivotal-cf/tanzu-java-native-image
tanzu-buildpacks/nodejs                         1.13.5     https://docs.pivotal.io/tanzu-buildpacks/nodejs/nodejs-buildpack.html
tanzu-buildpacks/dotnet-core                    1.11.1     https://docs.pivotal.io/tanzu-buildpacks/dotnet-core/dotnet-core-buildpack.html
tanzu-buildpacks/go                             1.10.4     https://docs.pivotal.io/tanzu-buildpacks/go/go-buildpack.html
tanzu-buildpacks/python                         1.1.4


DETECTION ORDER
Group #1
  tanzu-buildpacks/dotnet-core@1.11.1
Group #2
  tanzu-buildpacks/nodejs@1.13.5
Group #3
  tanzu-buildpacks/go@1.10.4
Group #4
  tanzu-buildpacks/python@1.1.4
Group #5
  tanzu-buildpacks/nginx@0.4.4
Group #6
  tanzu-buildpacks/java-native-image@6.5.0
Group #7
  tanzu-buildpacks/java@6.4.0
Group #8
  paketo-buildpacks/procfile@5.0.2

We see that the buildpacks we need are tanzu-buildpacks/nodejs and tanzu-buildpacks/nginx

Now, we need to define a new builder. Let's call it webserver:

> kp builder create webserver --tag harbor.registry.com/apps/webserver --buildpack tanzu-buildpacks/nodejs --buildpack tanzu-buildpacks/nginx
Builder "webserver" created

Before we can update our image, we need to setup the source code to be more aligned with our new folder structure. Our resulting image will have all the NodeJS artifacts and also the target dist folder. Because of that, we need to do the following:

  • The npm build command doesn't need to copy the two Nginx artifacts to the dist folder anymore:

    "scripts": {
      "serve": "vue-cli-service serve",
      "build": "vue-cli-service build",
      "start": "node server.js",
      "lint": "vue-cli-service lint"
    }
    
  • The root of nginx.conf should now target the dist folder:

worker_processes 1;
daemon off;

error_log stderr;
events { worker_connections 1024; }

http {
  charset utf-8;
  log_format cloudfoundry 'NginxLog "$request" $status $body_bytes_sent';
  access_log /dev/stdout cloudfoundry;
  default_type application/octet-stream;
  include mime.types;
  sendfile on;

  tcp_nopush on;
  keepalive_timeout 30;
  port_in_redirect off; # Ensure that redirects don't include the internal container PORT - 8080

  server {
    listen {{ 8080 }};
    root dist;
    index index.html;
  }
}

With our source code setup as we want, we can initiate the build command:

> kp image save todo-vuejs \
--tag harbor.registry.com/tap/todo-vuejs \
--git https://github.com/odedia/todo-ui \
--git-revision main \
--builder webserver
Patching Image Resource...
Image Resource "todo-vuejs" patched

Let's check the updated logs. We now see that the code is first being built with NPM, and then served via NGINX, which is exactly what we want:

> kp build logs todo-vuejs
===> PREPARE
Build reason(s): CONFIG
CONFIG:
  resources: {}
  source:
  -   registry:
  -     image: harbor.registry.com/tap/todo-vuejs-source@sha256:8783abc3754540ca6c5cb0cca9b92ab5a1bca98a539d7a7473abf3bd53e9a328
  +   git:
  +     revision: 988e7e70f27a2fcb9f9edf2025f1e517cfdef86d
  +     url: https://github.com/odedia/todo-ui
Loading secret for "harbor.registry.com" from secret "registry-credentials" at location "/var/build-secrets/registry-credentials"
Cloning "https://github.com/odedia/todo-ui" @ "988e7e70f27a2fcb9f9edf2025f1e517cfdef86d"...
Successfully cloned "https://github.com/odedia/todo-ui" @ "988e7e70f27a2fcb9f9edf2025f1e517cfdef86d" in path "/workspace"
===> ANALYZE
===> DETECT
6 of 18 buildpacks participating
paketo-buildpacks/ca-certificates 3.0.2
tanzu-buildpacks/node-engine      0.8.3
tanzu-buildpacks/npm-install      0.5.3
tanzu-buildpacks/node-module-bom  0.1.4
tanzu-buildpacks/npm-start        0.2.3
tanzu-buildpacks/nginx            0.4.4
===> RESTORE
Restoring metadata for "tanzu-buildpacks/nginx:nginx" from app image
===> BUILD

Paketo CA Certificates Buildpack 3.0.2
  https://github.com/paketo-buildpacks/ca-certificates
  Launch Helper: Contributing to layer
    Creating /layers/paketo-buildpacks_ca-certificates/helper/exec.d/ca-certificates-helper
Tanzu Node Engine Buildpack 0.8.3
  Resolving Node Engine version
    Candidate version sources (in priority order):
      package.json -> ">=10.12.0"
      .nvmrc       -> "11.6.0"
      <unknown>    -> ""

    Selected Node Engine version (using package.json): 16.13.1

  Executing build process
    Installing Node Engine 16.13.1
      Completed in 1.076s

  Configuring build environment
    NODE_ENV     -> "production"
    NODE_HOME    -> "/layers/tanzu-buildpacks_node-engine/node"
    NODE_VERBOSE -> "false"

  Configuring launch environment
    NODE_ENV     -> "production"
    NODE_HOME    -> "/layers/tanzu-buildpacks_node-engine/node"
    NODE_VERBOSE -> "false"

    Writing profile.d/0_memory_available.sh
      Calculates available memory based on container limits at launch time.
      Made available in the MEMORY_AVAILABLE environment variable.

Tanzu NPM Install Buildpack 0.5.3
  Resolving installation process
    Process inputs:
      node_modules      -> "Not found"
      npm-cache         -> "Not found"
      package-lock.json -> "Found"

    Selected NPM build process: 'npm ci'

  Executing build process
    Running 'npm ci --unsafe-perm --cache /layers/tanzu-buildpacks_npm-install/npm-cache'
      Completed in 6.354s

  Configuring launch environment
    NPM_CONFIG_LOGLEVEL -> "error"

  Configuring environment shared by build and launch
    PATH -> "$PATH:/layers/tanzu-buildpacks_npm-install/modules/node_modules/.bin"


Tanzu Node Module Bill of Materials Generator Buildpack 0.1.4
  Resolving CycloneDX Node.js Module version
    Selected CycloneDX Node.js Module version: 3.0.7

  Executing build process
    Installing CycloneDX Node.js Module 3.0.7
      Completed in 46ms

  Configuring environment
    Appending CycloneDX Node.js Module onto PATH

  Running CycloneDX Node.js Module
    Running 'cyclonedx-bom -o bom.json'
      Completed in 496ms

Tanzu NPM Start Buildpack 0.2.3
  Assigning launch processes
    web: node server.js

Tanzu Nginx Server Buildpack 0.4.4
  Resolving Nginx Server version
    Candidate version sources (in priority order):
      buildpack.toml -> "1.21.*"

    Selected Nginx Server version (using buildpack.toml): 1.21.4

===> EXPORT
Reusing layers from image 'harbor.registry.com/tap/todo-vuejs@sha256:6f435c808b0b7b413b7314aeb24bb01f23c859aec27d482c8574bce2435115a3'
Adding layer 'paketo-buildpacks/ca-certificates:helper'
Adding layer 'tanzu-buildpacks/node-engine:node'
Adding layer 'tanzu-buildpacks/npm-install:modules'
Adding layer 'tanzu-buildpacks/npm-install:npm-cache'
Reusing layer 'tanzu-buildpacks/nginx:nginx'
Adding layer 'launch.sbom'
Adding 1/1 app layer(s)
Reusing layer 'launcher'
Adding layer 'config'
Reusing layer 'process-types'
Adding label 'io.buildpacks.lifecycle.metadata'
Adding label 'io.buildpacks.build.metadata'
Adding label 'io.buildpacks.project.metadata'
Setting default process type 'web'
Saving harbor.registry.com/tap/todo-vuejs...
*** Images (sha256:c8201b2c55727cd0a6ae238a9bb3f889b5cf1247b75b7b1e029c5547a8237db9):
      harbor.registry.com/tap/todo-vuejs
      harbor.registry.com/tap/todo-vuejs:b3.20220117.113942
Adding cache layer 'tanzu-buildpacks/node-engine:node'
Adding cache layer 'tanzu-buildpacks/npm-install:modules'
Adding cache layer 'tanzu-buildpacks/npm-install:npm-cache'
Adding cache layer 'tanzu-buildpacks/node-module-bom:cyclonedx-node-module'
===> COMPLETION
Build successful

Let's verify everything works as expected:

> docker run harbor.registry.com/tap/todo-vuejs:b3.20220117.113942
Unable to find image 'harbor.registry.com/tap/todo-vuejs:b3.20220117.113942' locally
b3.20220117.113942: Pulling from tap/todo-vuejs
bf99a8b93828: Already exists
1da1131b1360: Already exists
48bde579d8cc: Already exists
1929d0623312: Already exists
1fea93ec33be: Already exists
fed2bcb93d83: Already exists
eb2e57672edf: Already exists
03e598551527: Already exists
f76b3557931f: Pull complete
5ad05d7a8092: Pull complete
841d6c40c392: Pull complete
697988c1248a: Pull complete
40d17e1b116e: Pull complete
239731ce13f5: Pull complete
5a44e4f7b58d: Pull complete
Digest: sha256:c8201b2c55727cd0a6ae238a9bb3f889b5cf1247b75b7b1e029c5547a8237db9
Status: Downloaded newer image for harbor.registry.com/tap/todo-vuejs:b3.20220117.113942
cat: /sys/fs/cgroup/memory/memory.limit_in_bytes: No such file or directory
/layers/tanzu-buildpacks_node-engine/node/profile.d/0_memory_available.sh: line 3: / ( 1024 * 1024 ) : syntax error: operand expected (error token is "/ ( 1024 * 1024 ) ")

The application still works as expected:

image.png

In the docker logs, we can confirm that it's NGINX hosting the content:

NginxLog "GET / HTTP/1.1" 200 771
NginxLog "GET /js/app.8278f7ef.js HTTP/1.1" 200 10484
NginxLog "GET / HTTP/1.1" 200 771
NginxLog "GET / HTTP/1.1" 200 771
NginxLog "GET / HTTP/1.1" 200 771
NginxLog "GET / HTTP/1.1" 200 771
NginxLog "GET / HTTP/1.1" 200 771
NginxLog "GET / HTTP/1.1" 200 771
NginxLog "GET / HTTP/1.1" 200 771
NginxLog "GET / HTTP/1.1" 200 771

Great! Everything works. However, there is still a small thing that bugs me: Do I really need the entire NPM stack in the target image? This includes the bloated node_modules folder and other artifacts. The size of this new image is around 210mb, while the size of the NGINX-only image is 102mb.

Still, this is probably the recommended way to build frontend applications with Build Service, and I believe this area will improve significantly soon.

This concludes part 1 of this tutorial. In the next one, we'll dive deep into other buildpacks such as Spring Native (Powered by GraalVM), Python applications and some other extreme use cases. Stay tuned!