Search code examples
spring-bootdockergradle-kotlin-dslbuildpack

Environment properties of Spring Boot OCI image aren't picked up by CNB launcher


I'm building a Spring Boot 3.1.0 application and deploying it by means of Cloud Native Buildpacks from a Gradle Kotlin DSL build script. To tune some image properties, I'm setting the following in my build.gradle.kts script:

tasks.named<BootBuildImage>("bootBuildImage") {
    verboseLogging.set(true)
    // ...
    environment.set(mapOf(
        "BPL_JMX_ENABLED" to "true",        
        "BPL_DEBUG_ENABLED" to "true",  
        "BPL_JAVA_NMT_ENABLED" to "false",
        "BPL_SPRING_CLOUD_BINDINGS_DISABLED" to "true"
    ))
}

I even see in the build log that these properties are recognized during build stage:

...
[creator]    Launch Configuration:           
[creator]      $BPL_DEBUG_ENABLED       true         enables Java remote debugging support
[creator]      $BPL_DEBUG_PORT          8000         configure the remote debugging port
...
[creator]    Launch Configuration:
[creator]      $BPL_SPRING_CLOUD_BINDINGS_DISABLED  true   whether to auto-configure Spring Boot environment properties from bindings
...

However, when the app is starting as a Docker container, none of the properties are picked up by the launcher. Here is an excerpt from the container's stdout with manual line breaks for clarity:

Spring Cloud Bindings Enabled
2023-05-20T07:48:25.857843881Z Picked up JAVA_TOOL_OPTIONS: 
-Djava.security.properties=/layers/paketo-buildpacks_bellsoft-liberica/java-security-properties/java-security.properties 
-XX:+ExitOnOutOfMemoryError 
-XX:ActiveProcessorCount=1 
-XX:MaxDirectMemorySize=10M 
-Xmx31494K 
-XX:MaxMetaspaceSize=97109K 
-XX:ReservedCodeCacheSize=240M 
-Xss1M 
-XX:+UnlockDiagnosticVMOptions 
-XX:NativeMemoryTracking=summary 
-XX:+PrintNMTStatistics 
-Dorg.springframework.cloud.bindings.boot.enable=true
2023-05-20T07:48:28.285693854Z 

I expect here to see "Spring Cloud Bindings Disabled" and a JVM option like -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8000. Accordingly, none of the desired ports opened.

No errors or warnings were observed neither in the build log nor in the run log.

How can I understand what went wrong and how to fix it?


Solution

  • There are two types of environment variable configuration properties that Paketo buildpacks understand: build time and launch time (also called run time).

    • Build time environment configuration settings all start with BP_.
    • Launch time environment configuration settings all start with BPL_.

    You can set build time properties as environment variables passed to pack (pack build -e ..) or to Spring Boot build tools as you're doing here.

    To set launch time configuration, you need to set those environment variables using your container runtime of choice. That could be Docker or Kubernetes or CloudFoundry or whatever.

    In this case, you're using docker run, so you'd add -e BPL_JMX_ENABLED=true -e BPL_DEBUG_ENABLED=true -e BPL_JAVA_NMT_ENABLED=true -e BPL_SPRING_CLOUD_BINDINGS_DISABLED=true.

    The reason there is a difference is so that you can toggle these settings on/off without rebuilding your container.

    If you would like to have these settings baked into the container image so they are automatic, you can do that. The process is defined here.

    In short, you'd modify your configuration like this:

        environment.set(mapOf(
            "BPE_DEFAULT_BPL_JMX_ENABLED" to "true",        
            "BPE_DEFAULT_BPL_DEBUG_ENABLED" to "true",  
            "BPE_DEFAULT_BPL_JAVA_NMT_ENABLED" to "false",
            "BPE_DEFAULT_BPL_SPRING_CLOUD_BINDINGS_DISABLED" to "true"
        ))
    

    Then when you build, these environment variables will be activated automatically. You won't need to include them with your runtime configuration.

    The downside as I mentioned above is that you'll need to rebuild the image when you want to change them.