A Complete Guide to Setting Up a CI/CD Pipeline for FastAPI with Blue-Green Deployment
Introduction
In modern software development, automating deployments is key to ensuring fast, reliable, and consistent updates to production systems. This is where CI/CD pipelines come into play. Combined with blue-green deployment, you can deploy your FastAPI application with zero downtime, ensuring users experience no interruptions during updates.
In this guide, we will walk through setting up a CI/CD pipeline for FastAPI with blue-green deployment using GitHub Actions, Nginx, and Uvicorn. We’ll cover:
- How to back up the current environment before deploying changes.
- Deploying the new code to a separate environment.
- Switching traffic between environments.
- Handling static files and user uploads.
- Notifying your team if issues arise during deployment.
Let’s dive into the step-by-step process!
Step 1: Understanding Blue-Green Deployment
Before setting up the pipeline, let’s clarify what blue-green deployment means:
- Blue: The current, live environment that serves production traffic.
- Green: A parallel environment where the new version of the application is deployed.
The idea is simple: deploy the new version in green, test it, and once everything works, switch traffic from blue to green. If any issues arise, you can switch traffic back to blue, ensuring minimal downtime and providing a safe rollback mechanism.
Step 2: Server Setup for Blue-Green Deployment
Before we set up the CI/CD pipeline, we need to configure the server to handle blue-green deployment. This includes setting up Nginx to route traffic between the blue and green environments and running the FastAPI application using Uvicorn.
A. Install Dependencies
Ensure that your server has the necessary dependencies installed:
sudo apt update
sudo apt install nginx python3-pip python3-venv git
pip install uvicorn fastapi
B. Create Separate Environments for Blue and Green
You’ll need two directories to host the two environments:
mkdir -p /var/www/blue
mkdir -p /var/www/green
Each environment will host a different version of your FastAPI app, allowing you to deploy updates without affecting the live environment.
C. Configure Nginx for Traffic Routing
Nginx will manage which environment (blue or green) serves traffic. You can configure Nginx to switch between these two environments based on your deployment needs.
Open the Nginx configuration file:
sudo nano /etc/nginx/sites-available/fastapi
Add the following configuration:
upstream app_blue {
server 127.0.0.1:8001;
}
upstream app_green {
server 127.0.0.1:8002;
}
server {
listen 80;
server_name YOUR_SERVER_IP;
location / {
proxy_pass http://app_blue; # Initially, traffic goes to blue
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /static {
alias /var/www/shared/static; # Shared directory for static files
}
}
This configuration directs traffic to blue initially (on port 8001). You can later update this to green (port 8002) during deployment.
D. Run Uvicorn for Both Environments
You will need to start Uvicorn instances for both environments:
For blue:
cd /var/www/blue
uvicorn app:app --host 127.0.0.1 --port 8001 --workers 4 --daemon
For green:
cd /var/www/green
uvicorn app:app --host 127.0.0.1 --port 8002 --workers 4 --daemon
Now, both environments are running on different ports, and you can switch traffic between them by updating the Nginx configuration.
Step 3: Setting Up the CI/CD Pipeline with GitHub Actions
With the server and environments ready, it’s time to automate the deployment process using GitHub Actions.
A. Create a Workflow File
Inside your FastAPI project repository, create a directory .github/workflows/
and add a file ci-cd.yml
.
name: FastAPI Blue-Green Deployment
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v3
- name: SSH and Deploy to Green
uses: appleboy/ssh-action@v0.1.1
with:
host: ${{ secrets.SERVER_IP }}
username: ${{ secrets.SSH_USERNAME }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
passphrase: ${{ secrets.SSH_PASSPHRASE }}
script: |
# Sync green to blue and switch traffic to blue
rsync -avz --delete /var/www/green/ /var/www/blue/
sudo systemctl restart uvicorn_blue
sudo sed -i 's/app_green/app_blue/g' /etc/nginx/sites-available/fastapi
sudo systemctl reload nginx
# Deploy the latest code to green
cd /var/www/green
git pull origin main
source venv/bin/activate
pip install -r requirements.txt
uvicorn app:app --host 127.0.0.1 --port 8002 --workers 4 --daemon
# Check health of the green environment
curl -f http://127.0.0.1:8002/health || {
echo "Deployment failed. Keeping traffic on blue.";
exit 1;
}
# Switch traffic to green if successful
sudo sed -i 's/app_blue/app_green/g' /etc/nginx/sites-available/fastapi
sudo systemctl reload nginx
This workflow:
- Backs up the current green environment to blue.
- Deploys new changes to green, installs dependencies, and restarts Uvicorn.
- Checks the health of the green environment.
- Switches traffic to green if everything works, or keeps traffic on blue in case of failure.
B. Error Handling and Notifications
If anything goes wrong during deployment, you should be notified immediately. You can set up email notifications using GitHub Actions or a script on your server.
- name: Send Email on Failure
if: failure()
uses: dawidd6/action-send-mail@v3
with:
server_address: smtp.gmail.com
server_port: 465
username: ${{ secrets.EMAIL_USERNAME }}
password: ${{ secrets.EMAIL_PASSWORD }}
subject: "Deployment Failed"
to: "your_email@example.com"
from: "ci-cd@example.com"
content_type: text/plain
body: "Deployment to green has failed. Please check the logs."
This will notify your team if the deployment fails, keeping you informed and allowing you to act quickly.
Step 4: Handling Static Files in Blue-Green Deployment
When users upload files during blue-green deployment, it’s essential to ensure consistency between the blue and green environments.
A. Shared Storage for Static Files
A simple solution is to use a shared directory for static files. Both environments will read from and write to the same directory:
app.mount("/static", StaticFiles(directory="/var/www/shared/static"), name="static")
This ensures that user uploads remain consistent regardless of which environment is live.
B. Synchronizing Static Files with Rsync
If shared storage isn’t feasible, you can sync static files from blue to green during deployment:
rsync -avz /var/www/blue/static/ /var/www/green/static/
This step can be included in the deployment script to ensure both environments have the same static files.
Conclusion
By following this guide, you’ve set up a comprehensive CI/CD pipeline for FastAPI using blue-green deployment. This approach ensures:
- Zero downtime: Users experience no interruptions during deployments.
- Safe rollback: If something goes wrong, you can quickly switch traffic back to the previous environment.
- Automation: With GitHub Actions, the entire process is automated, from code checkout to traffic switching and error handling.
With this setup, your FastAPI application is now fully equipped for seamless and reliable updates.