spring-bootdockermavenarm64docker-daemon

Building Docker image from spring maven project for arm64 platform


I'm in a Spring course, and I have a maven application (downloaded from the course resources) built from spring initializr. I can build a local Docker image with mvn spring-boot:build-image (no Dockerfile in the project). By default a Docker image is built as linux/amd64, but I am working with a M1 Apple Silicon chip (arm64). I've been looking many workarounds but with no success. Lastly, I found that maybe adding a Dockerfile and specifying the platform it would build the image accordingly.

My goal is to build a docker image for arm64 architecture.

So, I created a Dockerfile:

FROM --platform=linux/arm64 maven:3.8.4-jdk-11 AS build
COPY src /home/path_to_app/src
COPY pom.xml /home/path_to_app
RUN mvn -f /home/path_to_app/pom.xml spring-boot:build-image -DskipTests 

My project structure is:

standard maven structure

In terminal, at same pom.xml directory I run: docker buildx build --platform linux/arm64 --tag <mytag> .

Logs successful until =>Building image 'docker.io/myusername/myimage:mytag', then an exception occurs and build fails.

#8 125.7 [INFO] 
#8 125.7 [INFO] <<< spring-boot-maven-plugin:2.5.0:build-image (default-cli) < package @ currency-exchange-service <<<
#8 125.7 [INFO] 
#8 125.7 [INFO] 
#8 125.7 [INFO] --- spring-boot-maven-plugin:2.5.0:build-image (default-cli) @ currency-exchange-service ---
#8 125.8 [INFO] Building image 'docker.io/myname/myimage:0.0.1-SNAPSHOT'
#8 125.8 [INFO]
#8 125.8 [INFO] I/O exception (java.io.IOException) caught when processing request to {}->docker://localhost:2376: com.sun.jna.LastErrorException: [2] No such file or directory
#8 125.8 [INFO] Retrying request to {}->docker://localhost:2376
#8 125.8 [INFO] I/O exception (java.io.IOException) caught when processing request to {}->docker://localhost:2376: com.sun.jna.LastErrorException: [2] No such file or directory
#8 125.8 [INFO] Retrying request to {}->docker://localhost:2376
#8 125.8 [INFO] I/O exception (java.io.IOException) caught when processing request to {}->docker://localhost:2376: com.sun.jna.LastErrorException: [2] No such file or directory
#8 125.8 [INFO] Retrying request to {}->docker://localhost:2376
#8 125.9 [INFO] ------------------------------------------------------------------------
#8 125.9 [INFO] BUILD FAILURE
#8 125.9 [INFO] ------------------------------------------------------------------------
#8 125.9 [INFO] Total time:  02:04 min
#8 125.9 [INFO] Finished at: 2022-03-22T21:08:20Z
#8 125.9 [INFO] ------------------------------------------------------------------------
#8 125.9 [ERROR] Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:2.5.0:build-image 
(default-cli) on project currency-exchange-service: Execution default-cli 
of goal org.springframework.boot:spring-boot-maven-plugin:2.5.0:build-image 
failed: Connection to the Docker daemon at 'localhost' failed with error "[2] 
No such file or directory"; ensure the Docker daemon is running and accessible:
com.sun.jna.LastErrorException: [2] No such file or directory -> [Help 1]

My pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.0</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.somename.microservices</groupId>
    <artifactId>mymicroservice-service</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>mymicroservice-service-docker</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>11</java.version>
        <spring-cloud.version>2020.0.2</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-sleuth</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-sleuth-zipkin</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.amqp</groupId>
            <artifactId>spring-rabbit</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>io.github.resilience4j</groupId>
            <artifactId>resilience4j-spring-boot2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <image>
                        <name>myusername/myprefix${project.artifactId}:${project.version}</name>
                    </image>
                    <pullPolicy>IF_NOT_PRESENT</pullPolicy>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
        </repository>
    </repositories>

</project>

My docker daemon is running. Can't figure out why it tries to reach localhost:2376 (There is no such port in my project). My DOCKER_HOST is set to unix:///var/run/docker.sock and works fine. Tried to add to daemon.json:

{
"hosts": ["tcp://127.0.0.1:2376", "unix:///var/run/docker.sock"]
}

but docker daemon can't initialize (binding error, port already in use)

I don't know where does com.sun.jna.LastErrorException come from.

I suspect that maybe Docker in docker (dind) is needed, but I don't know how to set it up in my Dockerfile. Or maybe a port binding configuration.

Thank in advance for any help!!!

Note: I just want to build the image locally. I don't wish pushing to docker registry. I don't want any other stages in the build process.


Solution

  • Building an ARM-based image is not currently possible with mvn spring-boot:build-image, because the Cloud Native Buildpacks builders that Spring Boot integrates with do not support this. This is one of the possible items of focus on the Paketo buildpacks 2022 roadmap, which you can cast votes for.

    CNB documents a work-around for this, but it's not simple to set up and run.

    RUN mvn -f /home/path_to_app/pom.xml spring-boot:build-image -DskipTests

    You would need Docker-in-Docker to make something like this work, since the CNB builder processes that would run inside the Docker container need to talk to the Docker daemon. Regardless, this would not allow you to build an ARM image for the reasons stated above.