How to Build A Docker Image and Publish To Docker Hub with Github Actions

In this post we will understand how to create a docker image and upload it to Docker Hub using Github actions.
Workflow
To understand the basics of how to work with Github Actions workflow yaml (.yml) file, you can read through the post:
GitHub Actions workflow to enable a simple CI pipeline for a java web app with maven and junit
We will need to create 2 jobs for the current scenario. In the first job we will build the code and upload the build artifact. In the second job we will download the build artifact, build a docker image using dockerfile and push it to Docker Hub. This second job should run after the first job is completed as we will need the build artifact uploaded in the first job. This will be ensured using the needs keyword.
Now let us understand the 2 jobs that we will create in detail
Build Job
First job named Build will create the build and upload the build artifact.
Build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Set up JDK 11 uses: actions/setup-java@v1 with: java-version: '11' - name: Build package run: mvn --batch-mode package --file pom.xml - name: Upload build artifacts uses: actions/upload-artifact@v2 with: name: DevOpsPipeline.war path: target/DevOpsPipeline.war
You can understand how to create this first job step by step by going through the post GitHub Actions workflow to enable a simple CI pipeline for a java web app with maven and junit
In addition to creating a build, we will also use a pre-written action to upload the build artifact so that it can be downloaded and used in the second job. Let us understand this in little more detail in next section.
Working with build artifacts
- name:Upload artifact. - uses: actions/upload-artifact@v2 with: name: DevOpsPipeline.war path: target/*.war
The above code will upload the build artifact. The.war file is created in the target folder, hence we have mentioned that as the path for the .war file. This artifact can be downloaded in the subsequent job for deployment.
Why do we need to upload and download artifacts in between jobs: This is because the environment is destroyed once we complete a job and we will create a similar but a new environment in the new job and hence we will need to download the artifacts from previous build in order to use them.
Publish Job
Next let us create another job called publish. In this job we will create a docker image and deploy to docker hub. To implement this we will use 3 actions created by docker and available in github actions marketplace. We will also use another action by github actions to download the build artifact uploaded in the previous job.
Dockerfile
In order to create the image we need to create a dockerfile.
Let us consider a simple maven java web application which creates a .war file as a build artifact. We will deploy this file on tomcat.
With this knowledge let us create a dockerfile .
We can take the OS itself as the base image or along with the required installations upon which we can further add layers that we will mention in the dockerfile. To create image for our application, we will take tomcat as the base image.
Let us consider the below contents for the dockerfile
FROM tomcat USER root COPY DevOpsPipeline.war /usr/local/tomcat/webapps/ CMD ["catalina.sh","run"]
This file will pick up the latest image of tomcat from Dockerhub and copy the build artifact in the webapps folder and will start tomcat server.
Actions Used
We have used pre-written actions to achieve our objective.
1. – name: Setup Docker Buildx uses: docker/setup-buildx-action@v1
Buildx is a Docker CLI plugin that extends the docker build
command. It provides the same user experience as docker build
with many new features like creating scoped builder instances and building against multiple nodes concurrently.
2. – name: Login to DockerHub uses: docker/login-action@v1
Using this action, we can login to Docker Hub. It is recommended to add username and personal access token/password to github secrets and refer to the secrets in input parameters instead of entering them as plain text. Additionally, to authenticate against Docker Hub it’s strongly recommended to create a personal access token as an alternative to your password.
3. – name: Download artifact uses: actions/download-artifact@v2
This will simply download the file to the current working directory.
4.- name: Build and push id: docker_build uses: docker/build-push-action@v2
Builds a Docker image and pushes it to the private registry of your choosing. It will build the docker image as specified in the dockerfile. If dockerfile is not available in the default folder, you can provide path to dockerfile in the file parameter. You need to provide the username/ repo name where you want the image to get created in docker hub.
Related Post: Publish to Github Releases and Github Package Registry
Complete Workflow Code
# This workflow will build a Java project with Maven and build and push docker image to Docker Hub name: Build and Push docker image to Docker Hub on: push: branches: [ main ] pull_request: branches: [ main ] jobs: Build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Set up JDK 11 uses: actions/setup-java@v1 with: java-version: '11' - name: Build package run: mvn --batch-mode package --file pom.xml # env: # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Create artifacts directory and copy war file # run: mkdir artifacts && cp target/*.war artifacts uses: actions/upload-artifact@v2 with: name: DevOpsPipeline.war path: target/DevOpsPipeline.war Publish: needs: Build runs-on: ubuntu-latest steps:Create - uses: actions/checkout@v2 - name: Set up JDK 11 uses: actions/setup-java@v1 with: java-version: '11' - name: Update version run: mvn -B versions:set -DnewVersion=v${{github.run_number}} -DgenerateBackupPoms=false - name: Setup Docker Buildx uses: docker/setup-buildx-action@v1 - name: Login to DockerHub uses: docker/login-action@v1 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Download artifact uses: actions/download-artifact@v2 - name: Build and push id: docker_build uses: docker/build-push-action@v2 with: context: . push: true tags: saranitact/repo1:v${{github.run_number}}