Build and Publish Container Images using GitHub Actions
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:
1mkdir -pv .github/workflows
Next, create a .github/workflows/build.yml file with the following content:
1name: Build
2
3on:
4 push:
5 tags:
6 - 'v*'
7
8env:
9 REGISTRY: ghcr.io
10 # https://docs.github.com/en/actions/learn-github-actions/contexts#github-context
11 IMAGE_NAME: ${{ github.repository }}
12
13jobs:
14 build-and-push-image:
15 runs-on: ubuntu-latest
16 # Sets the permissions granted to the `GITHUB_TOKEN` for the actions in this job
17 permissions:
18 contents: read
19 packages: write
20 steps:
21 - name: Checkout repository
22 uses: actions/checkout@v3
23
24 - name: Log in to the Container registry
25 uses: docker/login-action@v2
26 with:
27 registry: ${{ env.REGISTRY }}
28 username: ${{ github.actor }}
29 # https://docs.github.com/en/actions/security-guides/automatic-token-authentication
30 password: ${{ secrets.GITHUB_TOKEN }}
31
32 - name: Extract metadata (tags, labels) for Docker
33 id: meta
34 uses: docker/metadata-action@v4
35 with:
36 images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
37
38 - name: Build and push Docker image
39 uses: docker/build-push-action@v4
40 with:
41 context: .
42 push: true
43 tags: ${{ steps.meta.outputs.tags }}
44 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:
1git add .github/workflows/build.yml
2git commit -m "chore: build and publish container image"
3git 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:
1# Once PR is merged
2git checkout main
3git pull
4git tag v1.0.0
5git 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 ❤️
1❯ skopeo inspect docker://ghcr.io/dbrennand/speeder | jq .Labels
2{
3 "org.opencontainers.image.created": "2023-09-07T16:55:29.525Z",
4 "org.opencontainers.image.description": "Python script to monitor your internet speed! 🚀 Periodically run librespeed/speedtest-cli and send results to InfluxDB.",
5 "org.opencontainers.image.licenses": "MIT",
6 "org.opencontainers.image.revision": "1e9dc09c6a95554ecb74f736029ec09c3ba6910c",
7 "org.opencontainers.image.source": "https://github.com/dbrennand/speeder",
8 "org.opencontainers.image.title": "speeder",
9 "org.opencontainers.image.url": "https://github.com/dbrennand/speeder",
10 "org.opencontainers.image.version": "v1.1.0"
11}
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! 👋