Build Spring Boot multi arch docker images with GitHub actions.
In this blog post, I will show you how to build multi arch docker images of Spring Boot applications with GitHub actions. This is useful for building images that can be run on system with different architectures.
In one of my previous blog post, I have shown you how to build spring boot application multi arch docker image in local development system and push them to docker hub.
In this post, we will use GitHub actions CI/CD pipeline to automate the building of docker images and publish them to docker hub.
Why we need Multi-Arch images?
Earlier application used to run on x86/x86-64 architecture (i.e Intel/AMD processors) based processors. With introduction of Apple M1/M2 based processors which are based on ARM64 architecture , now developers need to support multiple architectures so that their application runs on machines that support ARM architecture.
Cloud provides like amazon and oracle are providing ARM64 based compute instances at lesser price compared to the x86 based instances.
As developers seek to create applications compatible with various hardware architectures, the need to build and deploy these applications efficiently and uniformly is crucial.
GitHub Actions provide a versatile and user-friendly platform for managing CI/CD workflows
GitHub Actions is a continuous integration and continuous delivery (CI/CD) platform that allows you to automate the build, test, and deployment pipeline. You can create workflows that build and test every pull request to your repository, or deploy merged pull requests to production.
Creating Dockerfile
Let’s use following docker file create spring boot application docker image.
FROM eclipse-temurin:17.0.6_10-jdk-jammy
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
RUN addgroup --system springboot && adduser --system sbuser && adduser sbuser springboot
USER sbuser
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app.jar"]
Code language: Java (java)
Generating Docker Token
Using GitHub action we going to generate the docker image and push it to docker hub. To push docker image into docker registry we need to login from GitHub action. To login into docker registry, we need to generate the docker token which acts as password.
Log into hub.docker.com
Open your account settings by clicking on <user-name>/Account settings.
Click on “Security” link on the left side menu.
Generate new token by clicking on the “New Access Token” button
Note down the access token.
Creating GitHub Secrets
GitHub actions file is publicly accessible, so we can not store sensitive information in the actions file. Secrets are encrypted variables that we create in repository, or repository environment.
- On GitHub.com, navigate to the main page of the repository.
- Under repository name, click Settings.
3.In the “Security” section of the sidebar, select Secrets and variables, then click Actions.
4.Click the Secrets tab.
5.Click New repository secret.
6.Type a name for your secret in the Name input box.
7.Enter the value for your secret
8.Click Add secret
We have to store all the sensitive information in secrets. We are going to create following secrets.
- DOCKER_USERNAME
- DOCKER_TOKEN
Creating GitHub Action Files
Next we create action file which contains the work flow steps.
Create .github/workflows directory in root of your projects.
inside workflows folder create “deployment.yml” file and place following code.
name: Docker Multi-Arch
env:
IMAGE_NAME: sureshgkhyd/sb-crud-image
DOCKER_REGISTRY: docker.io
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
publish-app:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: |
echo "IMAGE_NAME_WITH_REGISTRY=$DOCKER_REGISTRY/$IMAGE_NAME" >> $GITHUB_ENV
export IMAGE_NAME_WITH_REGISTRY=$DOCKER_REGISTRY/$IMAGE_NAME
echo "FULL_IMAGE_NAME=$IMAGE_NAME_WITH_REGISTRY:latest" >> $GITHUB_ENV
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
cache: maven
- name: Build with Maven
run: mvn --batch-mode --update-snapshots package
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_TOKEN }}
- name: Setup Docker buildx
uses: docker/setup-buildx-action@v2
- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags:
${{ env.FULL_IMAGE_NAME }}
${{ env.IMAGE_NAME_WITH_REGISTRY }}:${{ github.sha }}
Code language: Java (java)
When ever we push the code to github, action will trigger and push the docker image to dockerhub.
You can download the source code of project from GitHub
Using Multistage Docker file
In above scenario we were using simple docker file, Let’s use the below multi stage docker file.
FROM maven:3.9.0-eclipse-temurin-17 as build
COPY pom.xml pom.xml
COPY src src
RUN mvn --batch-mode clean package
FROM eclipse-temurin:17.0.6_10-jdk-jammy
COPY --from=build "./target/*.jar" /app.jar
RUN addgroup --system springboot && adduser --system sbuser && adduser sbuser springboot
USER sbuser
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app.jar"]
Code language: Java (java)
If you observe above docker file, it already contains maven and JDK are already setup inside image.
So when we write action file to automate the docker image creation then there is no need to setup JDK and Maven. We just need to setup docker and build the image.
GitHub Action File
Below action file can be used to build and push docker images
name: Docker Multi-Arch
env:
IMAGE_NAME: sureshgkhyd/sb-crud-image
DOCKER_REGISTRY: docker.io
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
publish-app:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: |
echo "IMAGE_NAME_WITH_REGISTRY=$DOCKER_REGISTRY/$IMAGE_NAME" >> $GITHUB_ENV
export IMAGE_NAME_WITH_REGISTRY=$DOCKER_REGISTRY/$IMAGE_NAME
echo "FULL_IMAGE_NAME=$IMAGE_NAME_WITH_REGISTRY:latest" >> $GITHUB_ENV
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_TOKEN }}
- name: Setup Docker buildx
uses: docker/setup-buildx-action@v2
- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: |
${{ env.FULL_IMAGE_NAME }}
${{ env.IMAGE_NAME_WITH_REGISTRY }}:${{ github.sha }}
Code language: Java (java)
You can download the source code of project from GitHub