This article is a follow to previous article on how to automate Docker image builds and push to Docker Hub using GitHub Actions.
Introduction
This article will be on how to automate Docker builds and push to GitHub Registry. This is a very useful feature for developers who want to build and push Docker images to GitHub Registry. We go through how to automate Docker builds and push to GitHub Registry using GitHub Actions.
Overview
The Problem
We currently have a project that builds and pushes Docker images to Docker Hub. We want to automate the process of building and pushing Docker images to GitHub Registry. This will allow the image to available for use in other CI/CD pipelines or testing.
The Solution
We will use GitHub Actions to automate the process of building and pushing Docker images to GitHub Registry.
We will use the same Dockerfile and Docker Compose file from the previous article. We will also use the same GitHub repository.
The Steps are as follows
Create a GitHub repository.
Connect you local repository to the GitHub repository.
Push your code including the Dockerfile and Docker Compose file to the GitHub repository.
Create a .github folder in the root of your project.
Inside the .github folder, create a workflows folder.
Create a docker-publish.yml file inside the workflows folder.
Add the workflow code.
Commit and push the changes to the GitHub repository.
Watch as the workflow runs and builds and pushes the Docker image to GitHub Registry.
Alternatively,if you already have an existing project with a Dockerfile and/or Docker Compose file, you can skip steps 1-3 and start from step 4. Or fork/clone my repository.
Docker Compose installed on your machine. (optional if you intend to build multiple containers)
A GitHub repository with a Dockerfile and/or Docker Compose file.
Enough Talk, Let's Get Started
Since we already have a project with a Dockerfile and Docker Compose file, we will skip steps 1-3 and start from step 4.
Step 4: Create a .github folder in the root of your project
Here is the folder structure of the current project.
Ensure you are in the root of your project and create a .github folder.
mkdir .github
Step 5: Inside the .github folder, create a workflows folder
cd .github
mkdir workflows
Step 6: Create a docker-publish.yml file inside the workflows folder
cd workflows
touch docker-publish.yml
Step 7: Add the workflow code
name:Docker Image Publishon:push:branches:["main"]# Publish semver tags as releases.tags:['v*.*.*']pull_request:branches:["main"]env:# Use docker.io for Docker Hub if emptyREGISTRY:ghcr.io# github.repository as <account>/<repo>IMAGE_NAME:${{ github.repository }}jobs:build:runs-on:ubuntu-latestpermissions:contents:readpackages:write# This is used to complete the identity challenge# with sigstore/fulcio when running outside of PRs.id-token:writesteps:-name:Checkout repositoryuses:actions/checkout@v3# Install the cosign tool except on PR# https://github.com/sigstore/cosign-installer-name:Install cosignif:github.event_name != 'pull_request'uses:sigstore/cosign-installer@f3c664df7af409cb4873aa5068053ba9d61a57b6#v2.6.0with:cosign-release:'v1.11.0'# Workaround: https://github.com/docker/build-push-action/issues/461-name:Setup Docker buildxuses:docker/setup-buildx-action@v2# Login against a Docker registry except on PR# https://github.com/docker/login-action-name:Log into registry ${{ env.REGISTRY }}if:github.event_name != 'pull_request'uses:docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336cwith:registry:${{ env.REGISTRY }}username:${{ github.actor }}password:${{ secrets.GITHUB_TOKEN }}# Extract metadata (tags, labels) for Docker# https://github.com/docker/metadata-action-name:Extract Docker metadataid:metauses:docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38with:images:${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}# Build and push Docker image with Buildx (don't push on PR)# https://github.com/docker/build-push-action-name:Build and push Docker imageid:build-and-pushuses:docker/build-push-action@v4with:context:"{{defaultContext}}:src"push:${{ github.event_name != 'pull_request' }}# Don't push on PRtags:${{ steps.meta.outputs.tags }}labels:${{ steps.meta.outputs.labels }}cache-from:type=ghacache-to:type=gha,mode=max
Lets break down the code.
name:Docker Image Publishon:push:branches:["main"]# Publish semver tags as releases.tags:['v*.*.*']pull_request:branches:["main"]
The above code specifies when the workflow should run. In this case, the workflow will run when a push is made to the main branch or when a tag is pushed to the repository.
name: Docker Image Publish
env:# Use docker.io for Docker Hub if emptyREGISTRY:ghcr.io# github.repository as <account>/<repo>IMAGE_NAME:${{ github.repository }}
The above code specifies the registry to use and the image name. In this case, we are using GitHub Registry and the image name is the name of the repository.
jobs:build:runs-on:ubuntu-latestpermissions:contents:readpackages:write# This is used to complete the identity challenge# with sigstore/fulcio when running outside of PRs.id-token:writesteps:-name:Checkout repositoryuses:actions/checkout@v3# Install the cosign tool except on PR# https://github.com/sigstore/cosign-installer-name:Install cosignif:github.event_name != 'pull_request'uses:sigstore/cosign-installer@f3c664df7af409cb4873aa5068053ba9d61a57b6#v2.6.0with:cosign-release:'v1.11.0'
The above code specifies the job to run. In this case, we are running a job called build. The job will run on an Ubuntu machine and will have the following permissions:
Read access to the repository contents
package write access
id-token write access
The job will have the following steps:
Checkout the repository
Install the cosign tool
The cosign tool is used to sign the image before pushing it to the registry.
The above code sets up the Docker buildx action. Buildx is a Docker CLI plugin that extends the docker command with the full support of the features provided by Moby BuildKit builder toolkit.
# Login against a Docker registry except on PR-name:Log into registry ${{ env.REGISTRY }}if:github.event_name != 'pull_request'uses:docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336cwith:registry:${{ env.REGISTRY }}username:${{ github.actor }}password:${{ secrets.GITHUB_TOKEN }}
The above code logs into the registry. In this case, we are logging into GitHub Registry. The username and password are the GitHub username and the GitHub token respectively. Ensure you have the secrets.GITHUB_TOKEN secret in your repository or configure a personal access token.
The if condition ensures that the step is not run on a pull request. This ensures we only run the step on a push to the main branch.
The above code extracts the metadata for the Docker image. The metadata includes the tags and labels for the image.
# Build and push Docker image with Buildx (don't push on PR)-name:Build and push Docker imageid:build-and-pushuses:docker/build-push-action@v4with:context:"{{defaultContext}}:src"push:${{ github.event_name != 'pull_request' }}# Don't push on PRtags:${{ steps.meta.outputs.tags }}labels:${{ steps.meta.outputs.labels }}cache-from:type=ghacache-to:type=gha,mode=max
The above code builds and pushes the Docker image to the registry. The push condition ensures that the image is only pushed to the registry on a push to the main branch.
# Sign the image with cosign-name:Sign the image with cosignif:github.event_name != 'pull_request'run:|cosign sign --key cosign.key ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.tags }}
Step 8: Commit and push the changes
Commit the changes locally and push to your dev branch first. This allows you to test the workflow before merging to the main branch. It also provides a way to revert the changes if something goes wrong.
git branch dev
git checkout dev
git add .
git commit -m"Add Docker workflow"
git push
Example of successful workflow run:
Step 9: Workflow Run and Image on GitHub Registry
Create a pull request to merge the dev branch to the main branch. Once the pull request is merged, the workflow will run and push the image to the registry. Example of successful run on main.
If everything runs successfully, your image should be on GitHub Container Registry, and you should see a link to the image in the repo as shown below:
Conclusion
In this tutorial, we have learned how to create a Docker workflow to build and push a Docker image to GitHub Container Registry. We have also learned how to use the docker/metadata-action action to extract the metadata for the image.
We have also learned how to use the docker/build-push-action action to build and push the image to the registry. This should serve as a starting point for you to build your own Docker workflow. Curious to see what you Build!
Simple asynchronous API implemented with Fast-Api framework utilizing Postgres as a Database and SqlAlchemy as ORM . GiHub Actions as CI/CD Pipeline. Vue + Daisy UI for the frontend
FastAPI Vue Starter App
This repository contains code for asynchronous example api using the Fast Api framework ,Uvicorn server and Postgres Database to perform crud operations on notes.
Ensure you have a Postgres Database running locally
Additionally create a fast_api_dev database with user **fast_api** having required privileges
OR
Change the DATABASE_URL variable in the .env file inside then app folder to reflect database settings (user:password/db)
. The repository contains the code for the Fast-API application and the Vue application. The repository also contains the Docker workflow. Feel free to fork the repository and play around with the code. Link to the image is here.
Thanks for reading! If you have any questions, feel free to leave a comment below.
Ken Mwaura is a Freelance Back-end Software Engineer He is passionate about building scalable and maintainable software. He is also passionate about learning new technologies and sharing his knowledge with others. You can find him on Twitter and LinkedIn.