In this tutorial, we will be building a Docker image of an existing project and pushing it to Docker Hub using GitHub Actions. We will be using the following technologies:
We want to build a Docker image and push it to Docker Hub whenever we push to the main branch. We also want to build a Docker image and push it to GitHub Packages whenever we push to the dev branch. We want to do this automatically using GitHub Actions. We want to be able to do this without exposing our Docker Hub credentials.
The Solution ā”
We will use GitHub Actions to build and push Docker images to Docker Hub. We will use the following steps:
Create a workflow file.
Add a job to build and push the Docker image to Docker Hub.
Commit and push the changes to the dev branch.
Specify our docker crenentials as secrets in the repository settings.
Open a pull request to merge the dev branch into the main branch.
Watch the workflow run and verify that the Docker image is pushed to Docker Hub.
Prerequisites š
A GitHub account.
A Docker Hub account.
Docker installed on your machine. You can follow the official documentation to install Docker on your machine.
A GitHub repository with a Dockerfile and a project that you want to build and push to Docker Hub.
Step 1: Create a workflow file š
All GitHub Actions workflows are defined in YAML files in the .github/workflows directory of your repository.
We'll stary by creating a workflow file for building and pushing the Docker image to Docker Hub.
Create a file named .github/workflows/docker-hub.yml in your repository. This file will contain the workflow that we will use to build and push the Docker image. The workflow will be triggered whenever we push to the main or dev branch. We will also specify the Docker image name and tag. We will use the following workflow:
name:Build and Push Docker Image to Docker Hubon:push:branches:["dev","main"]pull_request:branches:["dev","main"]env:# Use docker.io for Docker Hub if emptyREGISTRY:docker.io# github.repository as <account>/<repo>IMAGE_NAME:${{ github.repository }}jobs:build:runs-on:ubuntu-lateststeps:-uses:actions/checkout@v3-name:Build the Docker imagerun:docker-compose build --no-cache --force-rmtest:runs-on:ubuntu-lateststeps:-uses:actions/checkout@v2-name:Test the Docker imagerun:docker-compose up -dpush_to_registry:name:Push Docker image to Docker Hubruns-on:ubuntu-lateststeps:-name:Check out the repouses:actions/checkout@v3-name:Set up Docker Buildxuses:docker/setup-buildx-action@v2-name:Log in to Docker Hubuses:docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9with:username:${{ secrets.DOCKER_USERNAME }}password:${{ secrets.DOCKER_PASSWORD }}-name:Extract metadata (tags, labels) for Dockerid:metauses:docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38with:images:${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-name:Build and push Docker imageuses:docker/build-push-action@v2with:context:"{{defaultContext}}"push:truetags:${{ steps.meta.outputs.tags }}labels:${{ steps.meta.outputs.labels }}
Lets break down the workflow file:
name: The name of the workflow.
on: The events that trigger the workflow. We will trigger the workflow whenever we push to the main or dev branch.
env: The environment variables that we will use in the workflow. We will use the following environment variables:
REGISTRY: The registry that we will use to push the Docker image. We will use docker.io for Docker Hub.
IMAGE_NAME: The name of the Docker image. We will use the name of the repository as the name of the Docker image.
jobs: The jobs that will run in the workflow. We will use the following jobs:
build: The job that will build the Docker image. We will use the following steps:
Checkout: We will use the actions/checkout action to checkout the repository.
Build the Docker image: We will use the docker-compose build command to build the Docker image. We will use the --no-cache and --force-rm flags to ensure that we are building the Docker image from scratch. This will ensure that we are building the Docker image with the latest changes before pushing it to Docker Hub.
test: The job that will test the Docker image. We will use the following steps:
Checkout: We will use the actions/checkout action to checkout the repository.
Test the Docker image: We will use the docker-compose up -d command to test the Docker image. We will use the -d flag to run the Docker image in the background.
push_to_registry: The job that will push the Docker image to Docker Hub. We will use the following steps:
Check out the repo: We will use the actions/checkout action to checkout the repository.
Log in to Docker Hub: We will use the docker/login-action action to log in to Docker Hub. We will use the following inputs:
username: The username of the Docker Hub account. We will use the DOCKER_USERNAME secret.
password: The password of the Docker Hub account. We will use the DOCKER_PASSWORD secret.
Extract metadata (tags, labels) for Docker: We will use the docker/metadata-action action to extract the metadata for the Docker image. We will use the following inputs:
images: The name of the Docker image. We will use the REGISTRY and IMAGE_NAME environment variables.
Build and push Docker image: We will use the docker/build-push-action action to build and push the Docker image to Docker Hub. We will use the following inputs:
context: The context of the Docker image. We will use the defaultContext variable.
push: A boolean value that specifies whether to push the Docker image to Docker Hub. We will set this to true.
tags: The tags of the Docker image. We will use the tags output of the docker/metadata-action action.
labels: The labels of the Docker image. We will use the labels output of the docker/metadata-action action.
Step 2: Create a dev branch and commit the changes to the dev branch šæ
Create a dev branch and commit the changes to the dev branch. This will allow us to test the workflow before merging the changes to the main branch. We will use the following commands:
git checkout -b dev
git add .
git commit -m"Add workflow to build and push Docker image to Docker Hub"
Step 3: Push the changes to the dev branch š§āš»
Create a Github Repository if you dont already have one and push the changes to the dev branch. We will use the following commands:
git add .
git commit -m"Add workflow to build and push Docker image to Docker Hub"
git push -u origin dev
Step 4: Specify our docker credentials as secrets in the repository settings š
We will specify our Docker Hub credentials as secrets in the repository settings. We will use the following secrets:
DOCKER_USERNAME: The username of our Docker Hub account.
DOCKER_PASSWORD: The password of our Docker Hub account.
This will allow us to use the credentials in the workflow file without exposing them. Thus keeping sensitive information secure. This gives the workflow access to the Docker Hub account. As well ability to use the workflow across multiple repositories.
Step 5: Open a pull request to merge the dev branch into the main branch š£ļø
Once the workflow successfully runs on the dev branch, we can merge the changes to the main branch. Open a pull request to merge the dev branch into the main branch. This will trigger the workflow. The workflow will run on the main branch and push the Docker image to Docker Hub. Example of successful workflow run on open pull request:
Step 6: Watch the workflow run šŗ
Watch the workflow run and verify that the Docker image is pushed to Docker Hub. Login to Docker Hub and check if the image is successfully pushed to Docker Hub. The image should be pushed to Docker Hub with the appropriate tags. for example kenmwaura1/fastapi-vue:main and kenmwaura1/fastapi-vue:sha-<sha>. Example of successful workflow run on merge pull request:
Screenshot of workflow running on merge pull request:
Step 7: Verify that the Docker image is pushed to Docker Hub š
Login to Docker Hub and check if the image is successfully pushed to Docker Hub. The image should be pushed to Docker Hub with the appropriate tags. for example kenmwaura1/fastapi-vue:main and kenmwaura1/fastapi-vue:sha-<sha>. Example of image pushed to Docker Hub:
GitHub Repo for this tutorial š
Find the sample code for this workflow in the following GitHub repository:
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)
In this tutorial, we learned how to build and push Docker images to Docker Hub and GitHub Packages using GitHub Actions. We also learned how to specify our Docker Hub credentials as secrets in the repository settings.
Next Steps
On the next tutorial, we will learn how to build and push Docker images to GitHub Packages using GitHub Actions. Stay tuned!