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 Name | Branch Description |
main | readme and overview files |
container-image | Dockerfile |
modules | Automation 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 👋