Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for building multi-arch docker images with paketo #491

Open
maradanasai opened this issue Jun 21, 2024 · 11 comments
Open

Add support for building multi-arch docker images with paketo #491

maradanasai opened this issue Jun 21, 2024 · 11 comments

Comments

@maradanasai
Copy link

In mac M1, generated an image for testing SB 3.3 + CDS support using packeto buildpack which is part of bootBuildImage stage. This generated image is given following warning in mac M1 but able to run the app. But if I run the same image on cloud VM which is of type ARM64, it is giving following error and immediately existed with error exec /cnb/process/web: exec format error.

WARNING: The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested

Docker supports, multi arch build with specified arch types so wondering when this can be added to paketo build packs.

@dmikusa
Copy link
Contributor

dmikusa commented Jun 21, 2024

We do have ARM64 support. It is new and not totally complete across all buildpacks at this point in time. You're using Java buildpacks and those are all updated, so you should be OK.

The trick at this point is that you need to use a specific builder. Not all of the Paketo builders support ARM64.

The builder you want to use is paketobuildpacks/builder-jammy-buildpackless-tiny.

See Maven and Gradle.

The other point to note is that this is a "buildpackless" builder, so there are no buildpacks installed on the builder by default. This is intentional, but it means you need to supply a list of buildpacks you want to use when you perform your build.

With pack build this is done with the -b flag (you can set multiple).

With the Spring Boot build tools, check out the previous two links above for steps to set buildpacks too.

To confirm it's building arm64, watch the build output and look at the JVM it's installing. You should see it install an ARM64 compatible-JVM.

For what it's worth, there is no cross-compilation support with either pack or Spring Boot build tools. So if you want an ARM64 image, you need to build on a Mac m-series machine, an ARM64 VM or some other ARM64 system.

Hope that helps!

@maradanasai
Copy link
Author

Hi @dmikusa Thanks for getting back. After making changes as mentioned, seeing following errors
docker run logs

docker logs -f 219d467cfa683eacd81bbc7e3bfe2a40924949592b27b6d6f9d0b28820a3deb3
ERROR: failed to launch: exec.d: failed to execute exec.d file at path '/layers/paketo-buildpacks_ca-certificates/helper/exec.d/ca-certificates-helper': fork/exec /layers/paketo-buildpacks_ca-certificates/helper/exec.d/ca-certificates-helper: exec format error

build config

tasks.named("bootBuildImage") {
	environment["BP_JVM_VERSION"] = "21"
	environment["BP_JVM_CDS_ENABLED"] = "true"
	builder = "paketobuildpacks/builder-jammy-buildpackless-tiny"
	buildpacks = [ "gcr.io/paketo-buildpacks/java" ]
}

bootbuildImage logs

Executing 'bootBuildImage'...

> Task :compileJava UP-TO-DATE
> Task :processResources UP-TO-DATE
> Task :classes UP-TO-DATE
> Task :resolveMainClassName UP-TO-DATE
> Task :bootJar UP-TO-DATE

> Task :bootBuildImage
Building image 'docker.io/library/test-counter-resets:0.0.1-SNAPSHOT'

 > Pulling builder image 'docker.io/paketobuildpacks/builder-jammy-buildpackless-tiny:latest' ..................................................
 > Pulled builder image 'paketobuildpacks/builder-jammy-buildpackless-tiny@sha256:5ae4709eca3c7c712533704a073e180a2f4c317e34d5b1a827ac04231cd45e7a'
 > Pulling run image 'docker.io/paketobuildpacks/run-jammy-tiny:latest' ..................................................
 > Pulled run image 'paketobuildpacks/run-jammy-tiny@sha256:4e3822b34116cbd0ffdac7d99f219be39cc48faf4257c102ed6312f0d47195ff'
 > Pulling buildpack image 'gcr.io/paketo-buildpacks/java:latest' ..................................................
 > Pulled buildpack image 'gcr.io/paketo-buildpacks/java@sha256:6c7a6dd99eb7cbd6785134636a460e57a65b208860e780e5f5a4468369212e80'
 > Executing lifecycle version v0.19.7
 > Using build cache volume 'pack-cache-4f3fd4f663c7.build'

 > Running creator
    [creator]     ===> ANALYZING
    [creator]     Restoring data for SBOM from previous image
    [creator]     ===> DETECTING
    [creator]     target distro name/version labels not found, reading /etc/os-release file
    [creator]     6 of 26 buildpacks participating
    [creator]     paketo-buildpacks/ca-certificates   3.8.0
    [creator]     paketo-buildpacks/bellsoft-liberica 10.8.0
    [creator]     paketo-buildpacks/syft              1.47.0
    [creator]     paketo-buildpacks/executable-jar    6.10.0
    [creator]     paketo-buildpacks/dist-zip          5.8.0
    [creator]     paketo-buildpacks/spring-boot       5.30.0
    [creator]     ===> RESTORING
    [creator]     Restoring metadata for "paketo-buildpacks/ca-certificates:helper" from app image
    [creator]     Restoring metadata for "paketo-buildpacks/bellsoft-liberica:helper" from app image
    [creator]     Restoring metadata for "paketo-buildpacks/bellsoft-liberica:java-security-properties" from app image
    [creator]     Restoring metadata for "paketo-buildpacks/bellsoft-liberica:jre" from app image
    [creator]     Restoring metadata for "paketo-buildpacks/syft:syft" from cache
    [creator]     Restoring metadata for "paketo-buildpacks/spring-boot:spring-cloud-bindings" from app image
    [creator]     Restoring metadata for "paketo-buildpacks/spring-boot:web-application-type" from app image
    [creator]     Restoring metadata for "paketo-buildpacks/spring-boot:helper" from app image
    [creator]     Restoring data for "paketo-buildpacks/bellsoft-liberica:jre" from cache
    [creator]     Restoring data for "paketo-buildpacks/syft:syft" from cache
    [creator]     Restoring data for "paketo-buildpacks/spring-boot:spring-cloud-bindings" from cache
    [creator]     Restoring data for SBOM from cache
    [creator]     ===> BUILDING
    [creator]     target distro name/version labels not found, reading /etc/os-release file
    [creator]     
    [creator]     Paketo Buildpack for CA Certificates 3.8.0
    [creator]       https://github.com/paketo-buildpacks/ca-certificates
    [creator]       Launch Helper: Reusing cached layer
    [creator]     
    [creator]     Paketo Buildpack for BellSoft Liberica 10.8.0
    [creator]       https://github.com/paketo-buildpacks/bellsoft-liberica
    [creator]       Build Configuration:
    [creator]         $BP_JVM_JLINK_ARGS           --no-man-pages --no-header-files --strip-debug --compress=1  configure custom link arguments (--output must be omitted)
    [creator]         $BP_JVM_JLINK_ENABLED        false                                                        enables running jlink tool to generate custom JRE
    [creator]         $BP_JVM_TYPE                 JRE                                                          the JVM type - JDK or JRE
    [creator]         $BP_JVM_VERSION              21                                                           the Java version
    [creator]       Launch Configuration:
    [creator]         $BPL_DEBUG_ENABLED           false                                                        enables Java remote debugging support
    [creator]         $BPL_DEBUG_PORT              8000                                                         configure the remote debugging port
    [creator]         $BPL_DEBUG_SUSPEND           false                                                        configure whether to suspend execution until a debugger has attached
    [creator]         $BPL_HEAP_DUMP_PATH                                                                       write heap dumps on error to this path
    [creator]         $BPL_JAVA_NMT_ENABLED        true                                                         enables Java Native Memory Tracking (NMT)
    [creator]         $BPL_JAVA_NMT_LEVEL          summary                                                      configure level of NMT, summary or detail
    [creator]         $BPL_JFR_ARGS                                                                             configure custom Java Flight Recording (JFR) arguments
    [creator]         $BPL_JFR_ENABLED             false                                                        enables Java Flight Recording (JFR)
    [creator]         $BPL_JMX_ENABLED             false                                                        enables Java Management Extensions (JMX)
    [creator]         $BPL_JMX_PORT                5000                                                         configure the JMX port
    [creator]         $BPL_JVM_HEAD_ROOM           0                                                            the headroom in memory calculation
    [creator]         $BPL_JVM_LOADED_CLASS_COUNT  35% of classes                                               the number of loaded classes in memory calculation
    [creator]         $BPL_JVM_THREAD_COUNT        250                                                          the number of threads in memory calculation
    [creator]         $JAVA_TOOL_OPTIONS                                                                        the JVM launch flags
    [creator]         Using Java version 21 from BP_JVM_VERSION
    [creator]       BellSoft Liberica JRE 21.0.3: Contributing to layer
    [creator]         Downloading from https://github.com/bell-sw/Liberica/releases/download/21.0.3+12/bellsoft-jre21.0.3+12-linux-aarch64.tar.gz
    [creator]         Verifying checksum
    [creator]         Expanding to /layers/paketo-buildpacks_bellsoft-liberica/jre
    [creator]         Adding 137 container CA certificates to JVM truststore
    [creator]         Writing env.build/JAVA_HOME.default
    [creator]         Writing env.build/JRE_HOME.default
    [creator]         Writing env.launch/BPI_APPLICATION_PATH.default
    [creator]         Writing env.launch/BPI_JVM_CACERTS.default
    [creator]         Writing env.launch/BPI_JVM_CLASS_COUNT.default
    [creator]         Writing env.launch/BPI_JVM_SECURITY_PROVIDERS.default
    [creator]         Writing env.launch/JAVA_HOME.default
    [creator]         Writing env.launch/JAVA_TOOL_OPTIONS.append
    [creator]         Writing env.launch/JAVA_TOOL_OPTIONS.delim
    [creator]         Writing env.launch/MALLOC_ARENA_MAX.default
    [creator]       Launch Helper: Reusing cached layer
    [creator]       Java Security Properties: Reusing cached layer
    [creator]     
    [creator]     Paketo Buildpack for Syft 1.47.0
    [creator]       https://github.com/paketo-buildpacks/syft
    [creator]         Downloading from https://github.com/anchore/syft/releases/download/v0.105.1/syft_0.105.1_linux_arm64.tar.gz
    [creator]         Verifying checksum
    [creator]         Writing env.build/SYFT_CHECK_FOR_APP_UPDATE.default
    [creator]     
    [creator]     Paketo Buildpack for Executable JAR 6.10.0
    [creator]       https://github.com/paketo-buildpacks/executable-jar
    [creator]       Command "packages" is deprecated, use `syft scan` instead
    [creator]       Class Path: Contributing to layer
    [creator]         Writing env/CLASSPATH.delim
    [creator]         Writing env/CLASSPATH.prepend
    [creator]       Process types:
    [creator]         executable-jar: java org.springframework.boot.loader.launch.JarLauncher (direct)
    [creator]         task:           java org.springframework.boot.loader.launch.JarLauncher (direct)
    [creator]         web:            java org.springframework.boot.loader.launch.JarLauncher (direct)
    [creator]     
    [creator]     Paketo Buildpack for Spring Boot 5.30.0
    [creator]       https://github.com/paketo-buildpacks/spring-boot
    [creator]       Build Configuration:
    [creator]         $BPL_JVM_CDS_ENABLED                 false  whether to enable CDS optimizations at runtime
    [creator]         $BPL_SPRING_AOT_ENABLED              false  whether to enable Spring AOT at runtime
    [creator]         $BP_JVM_CDS_ENABLED                  true   whether to enable CDS & perform JVM training run
    [creator]         $BP_SPRING_AOT_ENABLED               false  whether to enable Spring AOT
    [creator]         $BP_SPRING_CLOUD_BINDINGS_DISABLED   false  whether to contribute Spring Boot cloud bindings support
    [creator]         $BP_SPRING_CLOUD_BINDINGS_VERSION    1      default version of Spring Cloud Bindings library to contribute
    [creator]       Launch Configuration:
    [creator]         $BPL_SPRING_CLOUD_BINDINGS_DISABLED  false  whether to auto-configure Spring Boot environment properties from bindings
    [creator]         $BPL_SPRING_CLOUD_BINDINGS_ENABLED   true   Deprecated - whether to auto-configure Spring Boot environment properties from bindings
    [creator]       Spring Cloud Bindings 2.0.3: Reusing cached layer
    [creator]       Performance: Contributing to layer
    [creator]         Extracting Jar
    [creator]       .   ____          _            __ _ _
    [creator]      /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
    [creator]     ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
    [creator]      \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
    [creator]       '  |____| .__|_| |_|_| |_\__, | / / / /
    [creator]      =========|_|==============|___/=/_/_/_/
    [creator]     
    [creator]      :: Spring Boot ::                (v3.3.0)
    [creator]     
    [creator]     2024-06-21T16:06:36.964Z  INFO 182 --- [test-counter-resets] [           main] c.e.t.TestCounterResetsApplication       : Starting TestCounterResetsApplication v0.0.1-SNAPSHOT using Java 21.0.3 with PID 182 (/workspace/runner.jar started by cnb in /workspace)
    [creator]     2024-06-21T16:06:36.966Z  INFO 182 --- [test-counter-resets] [           main] c.e.t.TestCounterResetsApplication       : No active profile set, falling back to 1 default profile: "default"
    [creator]     2024-06-21T16:06:37.974Z  INFO 182 --- [test-counter-resets] [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port 8083 (http)
    [creator]     2024-06-21T16:06:37.983Z  INFO 182 --- [test-counter-resets] [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
    [creator]     2024-06-21T16:06:37.983Z  INFO 182 --- [test-counter-resets] [           main] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/10.1.24]
    [creator]     2024-06-21T16:06:38.011Z  INFO 182 --- [test-counter-resets] [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
    [creator]     2024-06-21T16:06:38.012Z  INFO 182 --- [test-counter-resets] [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1009 ms
    [creator]     2024-06-21T16:06:38.413Z  INFO 182 --- [test-counter-resets] [           main] o.s.b.a.e.web.EndpointLinksResolver      : Exposing 4 endpoints beneath base path '/actuator'
    [creator]     [2.083s][warning][cds] Preload Warning: Verification failed for org.springframework.core.ReactiveAdapterRegistry$ReactorAdapter
    [creator]     [2.101s][warning][cds] Preload Warning: Verification failed for org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer
    [creator]     [2.102s][warning][cds] Preload Warning: Verification failed for org.springframework.boot.actuate.autoconfigure.observation.web.client.WebClientObservationConfiguration
    [creator]     [2.107s][warning][cds] Preload Warning: Verification failed for org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration
    [creator]     [2.107s][warning][cds] Preload Warning: Verification failed for org.springframework.boot.autoconfigure.cache.InfinispanCacheConfiguration
    [creator]     [2.110s][warning][cds] Preload Warning: Verification failed for org.springframework.http.codec.multipart.DefaultPartHttpMessageReader
    [creator]     [2.112s][warning][cds] Preload Warning: Verification failed for io.micrometer.core.instrument.binder.logging.Log4j2Metrics
    [creator]     [2.141s][warning][cds] Preload Warning: Verification failed for org.springframework.boot.logging.log4j2.Log4J2LoggingSystem
    [creator]     [2.160s][warning][cds] Preload Warning: Verification failed for org.springframework.web.servlet.view.freemarker.FreeMarkerView
    [creator]     [2.166s][warning][cds] Skipping jdk/proxy2/$Proxy59: Unsupported location
    [creator]     [2.166s][warning][cds] Skipping com/example/test_counter_resets/TestCounterResetsApplication$$SpringCGLIB$$0: Unsupported location
    [creator]     [2.166s][warning][cds] Skipping jdk/proxy2/$Proxy33: Unsupported location
    [creator]     [2.166s][warning][cds] Skipping org/springframework/core/ReactiveAdapterRegistry$ReactorAdapter: Failed verification
    [creator]     [2.166s][warning][cds] Skipping jdk/proxy2/$Proxy68: Unsupported location
    [creator]     [2.166s][warning][cds] Skipping jdk/proxy2/$Proxy23: Unsupported location
    [creator]     [2.166s][warning][cds] Skipping jdk/proxy2/$Proxy81: Unsupported location
    [creator]     [2.166s][warning][cds] Skipping jdk/proxy2/$Proxy24: Unsupported location
    [creator]     [2.166s][warning][cds] Skipping org/springframework/boot/actuate/autoconfigure/web/server/$Proxy69: Unsupported location
    [creator]     [2.166s][warning][cds] Skipping org/springframework/core/$Proxy55: Unsupported location
    [creator]     [2.166s][warning][cds] Skipping jdk/internal/event/ThreadSleepEvent: JFR event class
    [creator]     [2.167s][warning][cds] Skipping jdk/proxy2/$Proxy73: Unsupported location
    [creator]     [2.167s][warning][cds] Skipping jdk/proxy2/$Proxy80: Unsupported location
    [creator]     [2.167s][warning][cds] Skipping jdk/proxy2/$Proxy37: Unsupported location
    [creator]     [2.167s][warning][cds] Skipping jdk/proxy2/$Proxy70: Unsupported location
    [creator]     [2.167s][warning][cds] Skipping jdk/proxy2/$Proxy46: Unsupported location
    [creator]     [2.167s][warning][cds] Skipping jdk/proxy2/$Proxy29: Unsupported location
    [creator]     [2.167s][warning][cds] Skipping jdk/proxy2/$Proxy7: Unsupported location
    [creator]     [2.167s][warning][cds] Skipping jdk/proxy2/$Proxy25: Unsupported location
    [creator]     [2.167s][warning][cds] Skipping jdk/proxy2/$Proxy39: Unsupported location
    [creator]     [2.167s][warning][cds] Skipping jdk/proxy2/$Proxy5: Unsupported location
    [creator]     [2.167s][warning][cds] Skipping jdk/proxy2/$Proxy42: Unsupported location
    [creator]     [2.167s][warning][cds] Skipping jdk/proxy2/$Proxy76: Unsupported location
    [creator]     [2.167s][warning][cds] Skipping jdk/proxy2/$Proxy12: Unsupported location
    [creator]     [2.167s][warning][cds] Skipping jdk/proxy1/$Proxy1: Unsupported location
    [creator]     [2.167s][warning][cds] Skipping jdk/proxy2/$Proxy65: Unsupported location
    [creator]     [2.167s][warning][cds] Skipping jdk/proxy2/$Proxy34: Unsupported location
    [creator]     [2.167s][warning][cds] Skipping jdk/proxy2/$Proxy77: Unsupported location
    [creator]     [2.167s][warning][cds] Skipping jdk/proxy2/$Proxy74: Unsupported location
    [creator]     [2.167s][warning][cds] Skipping org/springframework/boot/autoconfigure/cache/RedisCacheConfiguration: Failed verification
    [creator]     [2.167s][warning][cds] Skipping jdk/proxy2/$Proxy11: Unsupported location
    [creator]     [2.167s][warning][cds] Skipping jdk/proxy2/$Proxy22: Unsupported location
    [creator]     [2.167s][warning][cds] Skipping jdk/proxy2/$Proxy56: Unsupported location
    [creator]     [2.167s][warning][cds] Skipping jdk/proxy2/$Proxy79: Unsupported location
    [creator]     [2.167s][warning][cds] Skipping jdk/proxy2/$Proxy40: Unsupported location
    [creator]     [2.167s][warning][cds] Skipping jdk/proxy1/$Proxy8: Unsupported location
    [creator]     [2.167s][warning][cds] Skipping jdk/proxy2/$Proxy60: Unsupported location
    [creator]     [2.167s][warning][cds] Skipping org/springframework/boot/autoconfigure/cache/InfinispanCacheConfiguration: Failed verification
    [creator]     [2.167s][warning][cds] Skipping jdk/proxy2/$Proxy66: Unsupported location
    [creator]     [2.167s][warning][cds] Skipping org/springframework/web/servlet/view/freemarker/FreeMarkerView: Failed verification
    [creator]     [2.167s][warning][cds] Skipping org/springframework/boot/actuate/autoconfigure/observation/web/client/WebClientObservationConfiguration: Failed verification
    [creator]     [2.167s][warning][cds] Skipping jdk/proxy2/$Proxy53: Unsupported location
    [creator]     [2.167s][warning][cds] Skipping jdk/proxy2/$Proxy28: Unsupported location
    [creator]     [2.167s][warning][cds] Skipping jdk/proxy2/$Proxy18: Unsupported location
    [creator]     [2.167s][warning][cds] Skipping jdk/proxy1/$Proxy9: Unsupported location
    [creator]     [2.167s][warning][cds] Skipping jdk/proxy2/$Proxy67: Unsupported location
    [creator]     [2.167s][warning][cds] Skipping org/springframework/core/$Proxy6: Unsupported location
    [creator]     [2.167s][warning][cds] Skipping jdk/proxy2/$Proxy43: Unsupported location
    [creator]     [2.167s][warning][cds] Skipping jdk/proxy2/$Proxy31: Unsupported location
    [creator]     [2.167s][warning][cds] Skipping jdk/proxy2/$Proxy82: Unsupported location
    [creator]     [2.167s][warning][cds] Skipping jdk/proxy2/$Proxy54: Unsupported location
    [creator]     [2.167s][warning][cds] Skipping jdk/proxy2/$Proxy2: Unsupported location
    [creator]     [2.168s][warning][cds] Skipping jdk/proxy2/$Proxy20: Unsupported location
    [creator]     [2.168s][warning][cds] Skipping jdk/proxy2/$Proxy35: Unsupported location
    [creator]     [2.168s][warning][cds] Skipping io/micrometer/core/instrument/binder/logging/Log4j2Metrics: Failed verification
    [creator]     [2.168s][warning][cds] Skipping jdk/proxy2/$Proxy17: Unsupported location
    [creator]     [2.168s][warning][cds] Skipping jdk/proxy2/$Proxy44: Unsupported location
    [creator]     [2.168s][warning][cds] Skipping jdk/proxy2/$Proxy21: Unsupported location
    [creator]     [2.168s][warning][cds] Skipping jdk/proxy1/$Proxy0: Unsupported location
    [creator]     [2.168s][warning][cds] Skipping jdk/proxy1/$Proxy3: Unsupported location
    [creator]     [2.168s][warning][cds] Skipping jdk/proxy2/$Proxy10: Unsupported location
    [creator]     [2.168s][warning][cds] Skipping jdk/proxy2/$Proxy26: Unsupported location
    [creator]     [2.168s][warning][cds] Skipping jdk/proxy2/$Proxy45: Unsupported location
    [creator]     [2.168s][warning][cds] Skipping jdk/proxy2/$Proxy48: Unsupported location
    [creator]     [2.168s][warning][cds] Skipping jdk/proxy2/$Proxy78: Unsupported location
    [creator]     [2.168s][warning][cds] Skipping jdk/proxy2/$Proxy27: Unsupported location
    [creator]     [2.168s][warning][cds] Skipping jdk/proxy1/$Proxy4: Unsupported location
    [creator]     [2.168s][warning][cds] Skipping jdk/proxy2/$Proxy47: Unsupported location
    [creator]     [2.168s][warning][cds] Skipping jdk/proxy2/$Proxy50: Unsupported location
    [creator]     [2.168s][warning][cds] Skipping jdk/internal/event/Event: JFR event class
    [creator]     [2.168s][warning][cds] Skipping jdk/proxy2/$Proxy30: Unsupported location
    [creator]     [2.168s][warning][cds] Skipping jdk/proxy2/$Proxy41: Unsupported location
    [creator]     [2.168s][warning][cds] Skipping jdk/proxy2/$Proxy63: Unsupported location
    [creator]     [2.168s][warning][cds] Skipping jdk/proxy2/$Proxy72: Unsupported location
    [creator]     [2.168s][warning][cds] Skipping jdk/proxy1/$Proxy75: Unsupported location
    [creator]     [2.168s][warning][cds] Skipping jdk/proxy2/$Proxy62: Unsupported location
    [creator]     [2.168s][warning][cds] Skipping jdk/proxy2/$Proxy51: Unsupported location
    [creator]     [2.168s][warning][cds] Skipping org/springframework/http/codec/multipart/DefaultPartHttpMessageReader: Failed verification
    [creator]     [2.168s][warning][cds] Skipping jdk/proxy2/$Proxy15: Unsupported location
    [creator]     [2.168s][warning][cds] Skipping com/sun/proxy/jdk/proxy1/$Proxy71: Unsupported location
    [creator]     [2.168s][warning][cds] Skipping jdk/proxy2/$Proxy61: Unsupported location
    [creator]     [2.168s][warning][cds] Skipping jdk/proxy2/$Proxy52: Unsupported location
    [creator]     [2.168s][warning][cds] Skipping jdk/proxy2/$Proxy36: Unsupported location
    [creator]     [2.168s][warning][cds] Skipping jdk/proxy2/$Proxy32: Unsupported location
    [creator]     [2.168s][warning][cds] Skipping jdk/proxy2/$Proxy38: Unsupported location
    [creator]     [2.168s][warning][cds] Skipping jdk/proxy2/$Proxy64: Unsupported location
    [creator]     [2.168s][warning][cds] Skipping jdk/proxy2/$Proxy57: Unsupported location
    [creator]     [2.168s][warning][cds] Skipping jdk/proxy2/$Proxy16: Unsupported location
    [creator]     [2.168s][warning][cds] Skipping org/springframework/boot/logging/log4j2/Log4J2LoggingSystem: Failed verification
    [creator]     [2.168s][warning][cds] Skipping jdk/proxy2/$Proxy13: Unsupported location
    [creator]     [2.168s][warning][cds] Skipping org/springframework/core/$Proxy58: Unsupported location
    [creator]     [2.168s][warning][cds] Skipping jdk/internal/event/SecurityProviderServiceEvent: JFR event class
    [creator]     [2.168s][warning][cds] Skipping jdk/proxy1/$Proxy19: Unsupported location
    [creator]     [2.168s][warning][cds] Skipping jdk/proxy2/$Proxy49: Unsupported location
    [creator]     [2.168s][warning][cds] Skipping org/springframework/boot/jdbc/init/DataSourceScriptDatabaseInitializer: Failed verification
    [creator]     [2.168s][warning][cds] Skipping jdk/proxy2/$Proxy14: Unsupported location
    [creator]         Writing env.launch/BPL_JVM_CDS_ENABLED.default
    [creator]         Writing env.launch/BPL_SPRING_AOT_ENABLED.default
    [creator]       Web Application Type: Reusing cached layer
    [creator]       Launch Helper: Reusing cached layer
    [creator]       Image labels:
    [creator]         org.opencontainers.image.title
    [creator]         org.opencontainers.image.version
    [creator]         org.springframework.boot.version
    [creator]       Process types:
    [creator]         spring-boot-app: java -cp runner.jar:lib/spring-cloud-bindings-2.0.3.jar com.example.test_counter_resets.TestCounterResetsApplication (direct)
    [creator]         task:            java -cp runner.jar:lib/spring-cloud-bindings-2.0.3.jar com.example.test_counter_resets.TestCounterResetsApplication (direct)
    [creator]         web:             java -cp runner.jar:lib/spring-cloud-bindings-2.0.3.jar com.example.test_counter_resets.TestCounterResetsApplication (direct)
    [creator]     ===> EXPORTING
    [creator]     Reusing layer 'paketo-buildpacks/ca-certificates:helper'
    [creator]     Reusing layer 'paketo-buildpacks/bellsoft-liberica:helper'
    [creator]     Reusing layer 'paketo-buildpacks/bellsoft-liberica:java-security-properties'
    [creator]     Adding layer 'paketo-buildpacks/bellsoft-liberica:jre'
    [creator]     Reusing layer 'paketo-buildpacks/executable-jar:classpath'
    [creator]     Adding layer 'paketo-buildpacks/spring-boot:Performance'
    [creator]     Reusing layer 'paketo-buildpacks/spring-boot:helper'
    [creator]     Reusing layer 'paketo-buildpacks/spring-boot:spring-cloud-bindings'
    [creator]     Reusing layer 'paketo-buildpacks/spring-boot:web-application-type'
    [creator]     Adding layer 'buildpacksio/lifecycle:launch.sbom'
    [creator]     Adding 1/1 app layer(s)
    [creator]     Adding layer 'buildpacksio/lifecycle:launcher'
    [creator]     Reusing layer 'buildpacksio/lifecycle:config'
    [creator]     Reusing layer 'buildpacksio/lifecycle:process-types'
    [creator]     Adding label 'io.buildpacks.lifecycle.metadata'
    [creator]     Adding label 'io.buildpacks.build.metadata'
    [creator]     Adding label 'io.buildpacks.project.metadata'
    [creator]     Adding label 'org.opencontainers.image.title'
    [creator]     Adding label 'org.opencontainers.image.version'
    [creator]     Adding label 'org.springframework.boot.version'
    [creator]     Setting default process type 'web'
    [creator]     Saving docker.io/library/test-counter-resets:0.0.1-SNAPSHOT...
    [creator]     *** Images (e341cfeab740):
    [creator]           docker.io/library/test-counter-resets:0.0.1-SNAPSHOT
    [creator]     Adding cache layer 'paketo-buildpacks/bellsoft-liberica:jre'
    [creator]     Adding cache layer 'paketo-buildpacks/syft:syft'
    [creator]     Reusing cache layer 'paketo-buildpacks/spring-boot:spring-cloud-bindings'
    [creator]     Adding cache layer 'buildpacksio/lifecycle:cache.sbom'

Successfully built image 'docker.io/library/test-counter-resets:0.0.1-SNAPSHOT'


BUILD SUCCESSFUL in 1m 19s
5 actionable tasks: 1 executed, 4 up-to-date
9:36:49 pm: Execution finished 'bootBuildImage'.

Can you please take a look? problem is my cicd runners are on both ARM64 & AMD64 machines (same about my deployment servers). so if there is no cross-compilation support i.e. not generate multi-arch builds, it will surely fail on releases. Can you please provide workarounds for this? many thanks

@dmikusa
Copy link
Contributor

dmikusa commented Jun 21, 2024

First thing, you've got some layers that were cached. Usually, caching is good and makes things faster. But in this case, it's not updating those cached layers with ARM64 binaries. I'll open a bug for that, cause it should consider the architecture in that caching decision, but for now, just delete your existing app images and the build cache.

 > Using build cache volume 'pack-cache-4f3fd4f663c7.build'

or you can change the image name, that will trigger a fresh build too.

I suspect that's going to fix your issue here. It'll give you a build that's consistently all arm64.

To your other question, what you can do is to build twice. Once for each architecture. Push those images to a registry as separate images. Then you can use the docker manifest to create an image manifest with those two images. Then you publish the manifest image and have your deployment servers pull the manifest image.

I'm hoping that in the future we'll have some support for that in pack build, but it's difficult because not every buildpack can cross-compile code. For Java apps it's simple, but for other types of apps it might not be as easy. You might need special tools or you might just have to run on separate hardware/VMs. Java native-image is in that boat presently. There's no cross-compile support in the tool, so you just need separate hardware/VMs to build that code.

@maradanasai
Copy link
Author

Thanks for checking and providing insights @dmikusa . I saw something related to this here buildpacks/pack#1570 and hopping this can be adopted

@heruan
Copy link

heruan commented Nov 21, 2024

Any update on this? I'd like to switch from

docker buildx build --platform linux/amd64,linux/arm64 --push .

to mvn spring-boot:build-image but I cannot find a way to build images (ultimate goal native images) for multiple platform and push them as a single tagged manifest to the registry (as buildx does).

@dmikusa
Copy link
Contributor

dmikusa commented Nov 21, 2024

@heruan Please try Spring Boot 3.4.0. That was recently released and I believe that fixes up the boot build tools to work with multi-platform.

@heruan
Copy link

heruan commented Nov 21, 2024

@dmikusa thanks! I'm testing Spring Boot 3.4.0 and there is a new imagePlatform attribute but it seems like it works for one platform at a time.

I can build images for both platforms with different tags running spring-boot:build-image multiple times (once for each platform), push them individually, then create and tag a single multi platform manifest — but then I have three different tags in the registry while with buildx a single tag is pushed. Would be great to achieve the same with Spring Boot!

@dmikusa
Copy link
Contributor

dmikusa commented Nov 21, 2024

@heruan Neither pack build nor spring-boot:build-image will build images for multiple architectures in one run. That may be something that comes in the future, but it's not clear how that should work, especially when there is native code involved (emulation would be required).

For now, what you can do is build the two images independently and then use a command like docker manifest to make an index image from the two.

If you have a minute and are able to share anything about your use case that would be appreciated. I've been trying to understand how folks are using the tool and building images to help shape how things work in the future. For example, what's your build environment/CI? What type of application are you building? Is it server/data center deployed? Is it used on end-user devices? or deployed by a variety of different people? How do multiple architectures come into play when you or your users are running the generated app image?

@heruan
Copy link

heruan commented Nov 21, 2024

@dmikusa sure, and thank you for the interest on this topic! The image is a Kubernetes Operator built with Spring Boot and the Java Operator SDK as a Maven project. Both architectures are needed since the image is public and might be pulled on AMD or ARM platforms.

The image is built during a GitHub Actions workflow running:

docker buildx build --platform linux/amd64,linux/arm64 --tag foo/bar:baz --push .

Result of this command is a single tag (baz) pushed to Docker Hub providing images for both architectures, i.e. the foo/bar repository gets a single new tag for each workflow run.

I'd like to keep this behavior, so that I get a single tag pushed for both architectures.

With Spring Boot, I'm able to run:

mvn spring-boot:build-image -Dspring-boot.build-image.imagePlatform=linux/amd64 -Dspring-boot.build-image.imageName=foo/bar:amd64
mvn spring-boot:build-image -Dspring-boot.build-image.imagePlatform=linux/arm64 -Dspring-boot.build-image.imageName=foo/bar:arm64

and get two images with two different tags, one per platform. At this point, I can push the two tagged images to Docker Hub and then create a foo/bar:baz manifest that references both images. Great, but I get three tags on the repository for each release, and I'd prefer to avoid that. Note: you can't create a manifest if the images are not pushed to the registry first.

I don't know how docker buildx build manages to build images for both platforms and push them with a single tag, but it's very convenient.

Ultimately, I'd like to switch to native images and building with Spring Boot and Paketo makes this very easy! I'm not looking for a single command but rather a single tag to get the images published.

@dmikusa
Copy link
Contributor

dmikusa commented Nov 21, 2024

Great, but I get three tags on the repository for each release, and I'd prefer to avoid that. Note: you can't create a manifest if the images are not pushed to the registry first.

Have you tried removing those tags after you publish the multi-arch image?

My understanding is that the container that the index manifest points to needs to exist, but it doesn't need to be tagged. The index should reference the sha hash digest of the images it points to, not the tags. So if you remove the tag, it shouldn't break the index manifest image.

We use pack for publishing multi-arch buildpacks & stacks. It handles the multi-arch image generation for us, but we don't end up with stray tagged images. I believe that's how it accomplishes this.

The other thing you can do is push your intermediate images to https://ttl.sh or a local registry (maybe only exists in your CI job) and then copy the final manifest image out to Docker Hub. We you copy that out, if you use a tool like crane, it should handle moving everything that's needed for the index image to work correctly.

@dmikusa
Copy link
Contributor

dmikusa commented Nov 21, 2024

Ultimately, I'd like to switch to native images and building with Spring Boot and Paketo makes this very easy! I'm not looking for a single command but rather a single tag to get the images published.

That is where things get more difficult. With Java, it's not too hard to cross-compile images for you because the Java code is the same on both architectures, we just need to install different JVMs for each architecture. When you switch to native image, you can't do that anymore because native-image doesn't cross-compile. You need to introduce emulation. I think docker buildx does that for you, but don't quote me on that, I'm not an expert with that tool by any means.

It's possible that pack could do something similar, but pack is not as integrated with the OS as Docker, so it gets tricky. Do we require something like QEMU? Do we require users to configure that? Does pack take on the responsibility of bundling and setting that up? Can we do that inside a container, so the host OS doesn't require it? Aside from that, performance would be the next concern. Native image compiled in QEMU is like 40x slower (unscientific guesstimate), and it's fairly slow to begin with (IMHO).

My guess, at least short term, is the recommendation is going to be to do something like a matrix-style CI build of your different arch images, then stuff them into an index manifest for end-user consumption. Hopefully, we can smooth that out a bit though, and maybe create a way to do that without the intermediate tags.


Oh, I also forgot to mention the pack cli has manifest support in it too. It's similar to what's in docker. I suspect you'll have the same issues with tags as you do with Docker but it could be something to try.

> pack manifest -h
An image index is a higher-level manifest which points to specific image manifests and is ideal for one or more platforms; see: https://github.com/opencontainers/image-spec/ for more details

'pack manifest' commands provide tooling to create, update, or delete images indexes or push them to a remote registry.
'pack' will save a local copy of the image index at '$PACK_HOME/manifests'; the environment variable 'XDG_RUNTIME_DIR'
can be set to override the location, allowing manifests to be edited locally before being pushed to a registry.

These commands are experimental. For more information, consult the RFC which can be found at https://github.com/buildpacks/rfcs/blob/main/text/0124-pack-manifest-list-commands.md

Usage:
  pack manifest [command]

Available Commands:
  create      Create a new manifest list.
  add         Add an image to a manifest list.
  annotate    Add or update information about an entry in a manifest list.
  remove      Remove one or more manifest lists from local storage
  inspect     Display information about a manifest list.
  push        Push a manifest list to a registry.
  rm          Remove an image manifest from a manifest list.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants