And we’re back! 👋
In this blog post we will be looking at building and publishing a container image to GitHub Packages using GitHub Actions!
I recently revisited an old project of mine; now called speeder. It’s a Python script to monitor your internet speed and send the results to InfluxDB. The results can then be visualised in Grafana. I originally created this script during the Coronavirus lockdowns whilst internet usage was high and essential for work. Since that time, I’ve learned a lot about CI/CD and noticed I hadn’t automated the build and publish process of the container image! 😬 Time to fix that! 👷
What is CI/CD?
Before we get started, let’s take a quick look at what CI/CD is. According to ChatGPT:
Continuous Integration (CI) is the practice of frequently and automatically integrating code changes from multiple developers, leading to early issue detection and smoother teamwork. Continuous Delivery (CD) extends CI by automating the deployment process, allowing for faster and more reliable software releases. The benefits of CI/CD include quicker development cycles, higher software quality, reduced errors, and more frequent and reliable software updates.
Thanks ChatGPT! 🤖
In short, CI/CD helps developers to automate the process of building, testing and deploying software. It reduces the time and effort required to complete these processes, and helps ensure software is built and tested consistently and reliably.
Build and Publish a Container Image using GitHub Actions
Begin by creating the GitHub Actions workflow directory .github/workflows
in your project:
mkdir -pv .github/workflows
Next, create a .github/workflows/build.yml
file with the following content:
name: Build
on:
push:
tags:
- 'v*'
env:
REGISTRY: ghcr.io
# https://docs.github.com/en/actions/learn-github-actions/contexts#github-context
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-push-image:
runs-on: ubuntu-latest
# Sets the permissions granted to the `GITHUB_TOKEN` for the actions in this job
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Log in to the Container registry
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
# https://docs.github.com/en/actions/security-guides/automatic-token-authentication
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v4
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
- name: Build and push Docker image
uses: docker/build-push-action@v4
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
The above GitHub Actions workflow will perform the following steps 📝:
- Checkout the repository.
- Login to the GitHub Packages (
ghcr.io
) container registry. - Use git to extract repository metadata to be used for the container image tag(s) and labels.
- Build the container image and push it to the GitHub Packages container registry.
Now, commit and push the build.yml
workflow:
git add .github/workflows/build.yml
git commit -m "chore: build and publish container image"
git push
The workflow will only trigger when a push
event occurs for tags matching the pattern v*
. To trigger the workflow, create a new tag for your repository following the semver convention:
# Once PR is merged
git checkout main
git pull
git tag v1.0.0
git push --tags
And that’s it! 🎉 Once the tag is pushed the workflow will trigger! Here is an example from my speeder project :slight_smile:
Closing Thoughts
The best part about this workflow is the docker/metadata-action. It uses git metadata from the repository to create the container image’s labels according to the Open Container Initiative image-spec ❤️
❯ skopeo inspect docker://ghcr.io/dbrennand/speeder | jq .Labels
{
"org.opencontainers.image.created": "2023-09-07T16:55:29.525Z",
"org.opencontainers.image.description": "Python script to monitor your internet speed! 🚀 Periodically run librespeed/speedtest-cli and send results to InfluxDB.",
"org.opencontainers.image.licenses": "MIT",
"org.opencontainers.image.revision": "1e9dc09c6a95554ecb74f736029ec09c3ba6910c",
"org.opencontainers.image.source": "https://github.com/dbrennand/speeder",
"org.opencontainers.image.title": "speeder",
"org.opencontainers.image.url": "https://github.com/dbrennand/speeder",
"org.opencontainers.image.version": "v1.1.0"
}
Overall, this GitHub Actions workflow helps save a lot of time and effort. Furthermore, it helps make sure the container image is built and published consistently and reliably every time! 🚀
That’s all folks! Thanks for reading! 👋