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 with GitHub Actions

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: <GitHubusername>/repo1:v${{github.run_number}}

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *