Home Virtualisation Docker Automating your Dockerfile Builds

Automating your Dockerfile Builds

320
0
Reading Time: 4 minutes

Hellooo people of the interwebs, in this post, I shall be showing how I’ve learnt how to automate my docker image builds using a GitHub Action with multiple branches. So let me give you some high-level background, the TDLR is that there is a process at my work which is too hands-on and we want to remove the hands and free up engineering time to be more productive elsewhere, thus we shall ‘Automate All The Things!’ Starting with the build process.

Scope of Project

Currently, the docker build process is a manual step and requires someone to run about three commands in theory, on the premise that the GitHub repository is already cloned to their machine, the following steps are.

Step One : Authenticate to Container Registry

$PatToken = "<insert-github-pat-token-here>"
$PatToken | docker login ghcr.io/<username>/<repository> -u <username> --password-stdin

Step Two : Build a new Docker Image from the Docker file

docker build -t ghcr.io/<username>/<repository>:1.0.0 .

Step Three : Push said new image to the Container Registry

docker push ghcr.io/<username>/<repository>:1.0.0

Currently, this whole process can take around 10-15 minutes, due to the build image and packages required for the image and then upload time to the container registry, I could make like 5 coffees in that time!! – So Enough, we will automate this.

The GitHub Repository Breakdown

So for this example, I wanted to try and be slick and clever and break up the GitHub repository into branches, So have the following.

Branch NameBranch Description
mainreadme and overview files
container-imageDockerfile
modulesAutomation Modules, Which will get clones into the next yaml file


NOTE, there might be better or more efficient ways to do this, But figured I would learn some extra about branch control at the same time 🙂

YAML Timeeee

Ok, So you want to see the YAML, Before we get to the YAML file let me give you a super quick rundown of what the action does.

Step One: Job Starts
Step Two : Check Out the Branch “Container-Image”
Step Three : Check the Contence of Checkout, echo “pwd” and “ls”
Step Four: Get the Current Package version from Container Registry (Using GitHub API)
Step Five: Increase the version Number N+1 (This will be improved later on – not in this post though)
Step Six: Log into the GitHub Container Registry
Step Seven: Build Time (Create Image from Dockerfile) and then Push to GHCR
Step Eight: Check Image has been pushed successfully to GHCR (Using GitHub API)
Step Nine: Update GitHub Repository Variable for image for next yaml file reference (Using GitHub API)
Step Ten : Post Cleanup of Github Action

The YAML

Please note, If you are going to use this you will need to replace the ${{secret.PAT_TOKEN}} value or create one for your Action

name: Update Container Image
on:
  workflow_dispatch:
  push:
    branches:
      - container-image
  schedule:
    - cron: '0 0 1 */3 *'
    
jobs:
  Update_Container_Image:
    runs-on: ubuntu-latest
    
    steps:
      - name: Checkout repository
        uses: actions/checkout@v3
        with:
          ref: container-image
    
      - name: Check Directory Contents
        run: |
          pwd
          ls 

      - name: Get Current Package Version
        run: |
          response=$(curl -s -H "Accept: application/vnd.github.v3+json" -H "Authorization: Bearer ${{ secrets.PAT_TOKEN }}" \
          "https://api.github.com/user/packages/container/${{ github.event.repository.name }}/versions" | jq '.[0]')
          
          # Verbose 
          current_version=$(echo "$response" | jq -r '.metadata.container.tags[0]')
          echo "Current Package Version: $current_version"
          echo "CURRENT_VERSION=$current_version" >> $GITHUB_ENV

      - name: Increment Package Version Tag
        run: |
          current_version=${{ env.CURRENT_VERSION }}
          IFS='.' read -ra version_parts <<< "$current_version"
          major="${version_parts[0]}"
          minor="${version_parts[1]}"
          patch="${version_parts[2]}"
          incremented_patch=$((patch + 1))
          incremented_version="$major.$minor.$incremented_patch"
          echo "Incremented Package Version: $incremented_version"
          echo "NEXT_VERSION=$incremented_version" >> $GITHUB_ENV

      - name: Login to GitHub Container Registry
        uses: docker/login-action@v2.2.0
        with:
          registry: ghcr.io
          username: ${{ github.repository_owner }}
          password: ${{ secrets.PAT_TOKEN }}
          
      - name: Build and Push Updated Container to GHCR
        uses: docker/build-push-action@v4
        with:
          tags: ghcr.io/${{ github.repository }}:${{ env.NEXT_VERSION }}          
          context: /home/runner/work/${{ github.event.repository.name }}/${{ github.event.repository.name }}
          file: ./Dockerfile
          push: true
        env:
          github_token: ${{ secrets.PAT_TOKEN }}
          
      - name: Check Updated Container Version in GitHub Container Registry
        run: |
          response=$(curl -s -H "Accept: application/vnd.github.v3+json" -H "Authorization: Bearer ${{ secrets.PAT_TOKEN }}" \
          "https://api.github.com/user/packages/container/${{ github.event.repository.name }}/versions" | jq '.[0]')
          
          # Verbose 
          updated_version=$(echo "$response" | jq -r '.metadata.container.tags[0]')
          echo "Updated Package Version: $updated_version"
          echo "UPDATED_VERSION=$updated_version" >> $GITHUB_ENV          

      - name: Update GitHub Variable [CONTAINER_IMAGE]
        run: |
          echo "ghcr.io/${{ github.repository }}:${{ env.UPDATED_VERSION }}"
          curl -X PATCH \
            -H "Authorization: Bearer ${{ secrets.PAT_TOKEN }}" -H "Accept: application/vnd.github.v3+json" \
            -d '{"name": "CONTAINER_IMAGE", "value": "ghcr.io/${{ github.repository }}:${{ env.UPDATED_VERSION }}" }' \
            "https://api.github.com/repos/${{ github.repository }}/actions/variables/CONTAINER_IMAGE"

Update GitHub Variable Step

Just to give some better context for this stage (for those who might be newer to Git, YAML and Action), In the GitHub Repository I have a variable named CONTAINER_IMAGE. This allows for zero-touch updates to the YAML File for the actual deployment steps, As it will just reference the value and mean I don’t have to manually keep updating things 🥳

Once the GitHub Action has been either manually triggered – by a person or automatically based on a push to the branch or the cronjob.

it will update the variable. just 👏 like 👏 that 👏

Wrap Up

So this pretty much covers this v1 release of this YAML File, There is some improvement I want to make to version control and tagging, but as a read-to-run file which might help people get started in automating some of their container builds, I hope this helps.

If you want to discuss this further, you can find me on Twitter as @smoon_lee and until then I shall see you next time 👋

LEAVE A REPLY

Please enter your comment!
Please enter your name here