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.

Comments

Leave a Reply