Dockerizing a FastAPI CRUD App: Automating Builds and Pushes with GitHub Actions

Kene OjiteliKene Ojiteli
4 min read

FastAPI is a high-performance Python framework for building APIs, and Docker allows us to containerize applications to make them easier to deploy. In this guide, we'll containerize a FastAPI app with Docker, and automate the build and push of the Image to a private container registry using GitHub actions.

Prerequisites

  • Python and fastAPI dependencies (including pydantic for validation, fastAPI, uvicorn).

  • Docker - to build the fastAPI application into an image and push to a private registry.

  • GitHub and GitHub Actions: for version control and CICD to automate image build and push.

  • Terminal and a code editor / IDE: for code development, image building and CICD.

Steps taken

  • Testing the application locally.

  • Manually build the image.

  • Automate with GitHub Actions.

Testing the application locally

  • Install Python and fastAPI using pip, verify the installation by checking the version

  • Create a main.py, requirements.txt (I did a pip freeze and saved it to the requirements.txt file).

  • The main.py contains the CRUD app built with fastAPI.

crud app

crud app-1

  • I also installed an email-validator, since my validation with pydantic requires validating the email field.

Install email validator

  • I ran the application with uvicorn main:app --reload

run with uvicorn

  • I accessed the application via http://127.0.0.1:8000/users/ or via http://127.0.0.1:8000/docs#/

Access API

Access via swagger UI

Manually build the image

  • I built the image with the Dockerfile (as a best practice, I copied the project's dependencies in the requirements file before copying other application files needed, to leverage Docker's caching) in the project directory.

  • The Dockerfile contains the instructions to create the Docker image.

Dockerfile

build image

  • I created a container with the new image to test that the application worked fine. I had to exec into the container to test with curl.

fastapi container

Testing post method

Testing get method

Automate Image build and push with GitHub Actions

  • Working with the GitHub container registry (a private registry) requires generating a Personal Access Token (PAT), my password to log in to the registry and push my image.

  • To generate a Personal Access Token (PAT), navigate to settings => developer settings => personal access tokens(tokens classic) and generate a new token(classic), with read, write and delete packages permission, ensure to :

    • Give the token a name.

    • An expiration date.

    • Copy the token to a safe place as it is viewable only once.

generate PAT

  • Before setting up my workflow, I added my generated PAT and my username as a repository secret, which was used for authentication to the GitHub container registry.

how to add secrets to github

Add PAT as secret

Add username as secret

  • After adding secrets, this is what it should look like.

  • To automate with GitHub actions, I created a ./github/workflows folder with a build_push.yml file containing the workflow.

build_push.yml file

build_push.yml file

  • After the workflow file is completed, initialize the repo, add files and remote origin, commit and push code to GitHub.

  • Once the code is pushed to GitHub, it triggers the workflow(the workflow is configured to trigger when there is a push or pull request event on the repository), which builds the image, logs into the registry and pushes the image.

Build succeeded

Breakdown of build

Summary of successful build

Challenges encountered and fixes

  • I had a couple of unsuccessful builds, and I realised there were some rules to follow while working with GitHub container registry. I will be outlining some challenges I encountered and how I resolved them.

unsuccessful builds

Some of the challenges I encountered include:

  • I discovered that GitHub Container Registry (GHCR) requires all repository names to be in lowercase; a suggested fix was to change from tags: ghcr.io/${{ github.actor }}/fast-api-crud:latest to tags: ghcr.io/${{ github.repository_owner }}/fast-api-crud:latest (this converts username to lowercase using GitHub's toLower function)

GHCR error: repo name

  • The option above did not work, so I renamed my GitHub account (this is not advisable, but I took the risk) and removed all uppercase letters, and updated my secret.

update username

GHCR error: repo name1

  • The next error is something around organizations. I do not know much about organizations, so I deleted the organizations attached to my account (it was not useful to me anymore) and renamed the secret name for my token from TOKEN to GHCR_PAT (I also effected this change on the workflow).

  • I also forgot to allow pip read the list of dependencies from the specified file (requirements.txt). I fixed it by adding the -r flag.

This tutorial shows how to:

  • Structure a FastAPI application for seamless containerization.

  • Write a Dockerfile to package the app into a container.

  • Automate builds and pushes using GitHub Actions.

  • Troubleshoot common issues with private container registries.

Because this setup is automated, any code changes automatically trigger a new Docker image build and push to GitHub container registry, which streamlines the deployment process.

Thank you for reading. Kindly check out the repository. Till my next project, happy building! โœŒ๐Ÿฝ

1
Subscribe to my newsletter

Read articles from Kene Ojiteli directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Kene Ojiteli
Kene Ojiteli

I have experience building highly accessible, scalable, and reliable cloud infrastructure and have experience with AWS, Linux, Git, Docker, and Kubernetes. S3, EC2, CloudFormation, CloudFront, Auto-Scaling Group, Elastic Load Balancer, IAM, Cloud9, VPC, RDS, Route53, and other AWS services are just a few of the ones I am familiar with. I have experience building CI/CD pipelines, high-availability web apps, and websites. I'm excited about designing, implementing, and automating cloud-based apps while utilizing best practices like configuration management, continuous integration, and deployment.