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


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 apip freeze
and saved it to the requirements.txt file).The
main.py
contains the CRUD app built with fastAPI.
- I also installed an
email-validator
, since my validation with pydantic requires validating the email field.
- I ran the application with
uvicorn main:app --reload
- I accessed the application via
http://127.0.0.1:8000/users/
or viahttp://127.0.0.1:8000/docs#/
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.
- 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.
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.
- 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.
After adding secrets, this is what it should look like.
To automate with GitHub actions, I created a
./github/workflows
folder with abuild_push.yml
file containing the workflow.
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.
- After pushing to the registry, the image can be viewed using this URL format: https://github.com/users/YOUR_USERNAME/packages
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.
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
totags: ghcr.io/${{ github.repository_owner }}/fast-api-crud:latest
(this converts username to lowercase using GitHub's toLower function)
- 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.
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
toGHCR_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! โ๐ฝ
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.