Using GitHub Actions, build and push Docker images

Theara Seng | Nov 23, 2022
Using GitHub Actions, build and push Docker images

Continuous Integration and Continuous Delivery (CI/CD): GitHub Actions is a platform that lets you automate your build, test, and deployment pipeline. You can set up workflows that build and test every pull request to your repository, or you can deploy merged pull requests to production.

Requirements

  • A gradle Spring Boot project to be dockerized
  • GitHub repository
  • Docker Hub account

What are we going to build?

We will set up a GitHub workflow to build Docker images that will run automatically whenever commits are pushed to the repository.

Getting started

For this job, there are many tips and tricks that can be used. This method is a very easy and straightforward way to get there.

The Docker Hub

We need to make a repository on Docker Hub. That’s where the container images we create will be pushed.

Dockerfile

Let’s get started by creating a Dockerfile.

Because this is a Spring Boot project, we’ll use the openjdk Docker image and a jar file compiled from the Gradle.

Dockerfile

FROM openjdk:8-jdk

RUN mkdir /app

COPY app.jar /app/app.jar

WORKDIR /app

EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

Github Actions

Fun part. The most exciting part is to see what Github Actions can do to help us automatically build Gradle and Docker images without human intervention. Let’s create a main.yml file in .github/workflows folder.

The workflows would consist of two separate jobs

  • build: to build jar file
  • build-image: to build Docker image and push to it Docker hub

Github workflows

Build Jar file

The very first job of the pipeline is to build a jar file for the Spring Boot application. The simplest way to get started is to look for a sample Github workflow on Github.

  • Go to Github Repo
  • Actions

You will see workflows that could be used with your repository. In this case, it seems like the best way to build Spring Boot’s jar file is to use Java with Gradle workflow.

Github workflows

  • Click on Configure button

Github workflows

main.yml

Let’s use the above sample workflows to make main.yml file.

The should look like This is how main.yml should look:

name: Docker CI with Gradle

on:
  push:
    branches: [ "main" ]

permissions:
  contents: read

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-java@v3
        with:
          distribution: temurin
          java-version: 11
          
      - name: Setup Gradle
        uses: gradle/gradle-build-action@v2
      
      - name: Execute Gradle build
        run: |
          chmod +x ./gradlew
          ./gradlew bootJar          

      - name: Execute Gradle build
        run: |
          chmod +x ./gradlew
          ./gradlew bootJar          

      - name: Copy Jar file
        run: mv build/libs/$(ls build/libs) app.jar

      - uses: actions/upload-artifact@master
        with:
          name: jar-file
          path: app.jar
  • I’ve replaced the gradle build with ./gradlew bootJar as this Spring Boot App comes with its own gradle wrapper.
  • I also moved the compiled app.jar from the build directory to the current directory because the Dockerfile expects it to be in that location.
  • To be able to share the jar file with the next job (build-image that we’re going to do later) by using upload-artifact actions.

Let’s add the main.yml file and push it to Github repo. If everything was set up right, the workflow would be running on the Github actions page.

Github workflows
Github workflows


Build Docker Image

Just like we did for the last job, we can find a lot of public examples of workflows.

build-image:

    runs-on: ubuntu-latest
    needs: build

    steps:
      
      - uses: actions/checkout@v3

      - uses: actions/download-artifact@master
        with:
          name: jar-file
          path: app.jar

      - name: Set up QEMU
        uses: docker/setup-qemu-action@v2
      
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v2
      
      - name: Login to Docker Hub
        uses: docker/login-action@v2
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Set env
        run: echo "DATE=$(date +%s)" >> $GITHUB_ENV
      
      - name: Build and push
        uses: docker/build-push-action@v3
        with:
          context: .
          push: true
          tags: thearaseng/dockerized-spring-boot-app:${{ env.DATE }}

noted that we need to create two important variables: DOCKERHUB_USERNAME and DOCKERHUB_TOKEN


Generate Docker Hub Access Token

Because we’re going to push the images to Docker Hub, we need an access token with read and write permission. To generate this access token.

Docker Hub setting page

  • Fill out the Access Token Description field
  • In Access permission dropdown, choose Read & Write
  • Click on Generate button

Docker Hub setting page

  • Make a copy of the access token and don’t give it to anyone else.

Docker Hub setting page


Github Actions secrets

Since they are very sensitive variables, we are going to store them in Github Actions secrets.

  • Go to Settings > Secrets > Actions
  • Click on New repository secret button

Github settings page

  • Fill out the Docker Hub account name

Github settings page

  • Fill out the Docker Hub access token

Github settings page


Final Result

Let’s commit the final main.yml file and go to the Github Actions page

Github Actions

Github workflows page

Docker Repo

We can see Docker tags that have been pushed from Github Actions.

Docker Repo
Congratulations. You made it. :)

You can find the complete source code on the public Gitlab Repo.

https://github.com/thearaseng/dockerized-spring-boot-app/tree/main

Peace! Peace