- Published on
FastAPI to Google Cloud Run: Prepare, Deploy, and Automate
- Authors
- Name
- Avasdream
- @avasdream_
Deploying a FastAPI application to Google Cloud Run can drastically simplify your infrastructure management. With a few steps, you can build a container, push it to Google Container Registry (GCR), and run it serverlessly on Cloud Run. In addition, you can automate deployments and updates seamlessly.
Follow along as we prepare, deploy, and then automate the process of shipping a FastAPI app to Google Cloud Run. Remember to keep sensitive environment variables secure. In the examples below, we will show placeholders for environment variables and redact them.
Requirements
- Google Cloud SDK
- Docker
- FastAPI
- Python
- Prisma
Project Data
Setup Steps:
gcloud auth login
This command authenticates your Google Cloud SDK with your Google account. It opens a browser window where you can log in.
gcloud auth configure-docker
This command configures Docker to authenticate with Google Cloud’s Container Registry (GCR) using the credentials obtained from the gcloud auth login
command. It allows Docker to push images to GCR securely.
gcloud config set project <PROJECT_ID>
This sets the active Google Cloud project to the specified <PROJECT_ID>
. This ensures that subsequent commands are executed within the correct project context.
gcloud config set run/region <REGION>
This command configures the Google Cloud Run region. It sets the default region for Cloud Run services to the provided <REGION>
, which will affect where your services are deployed.
gcloud services enable artifactregistry.googleapis.com --project=<PROJECT_ID>
Enables the Google Artifact Registry API for your project. Artifact Registry is a fully managed service for storing and managing Docker images and other artifacts.
gcloud projects add-iam-policy-binding <PROJECT_ID> \
--member="user:<YOUR_EMAIL>" \
--role="roles/run.admin"
This grants your user account (<YOUR_EMAIL>
) the roles/run.admin
role, which provides administrative access to manage Cloud Run services in the specified project.
gcloud projects add-iam-policy-binding <PROJECT_ID> \
--member="user:<YOUR_EMAIL>" \
--role="roles/iam.serviceAccountUser"
This grants your user account (<YOUR_EMAIL>
) the roles/iam.serviceAccountUser
role, which allows the user to use service accounts when interacting with Google Cloud resources.
(All env variables, including any database credentials or API keys, should be stored securely and never committed to the repository. In this example, we show placeholders only.)
Docker Build and Push
Build and push the image to GCR:
docker build -t gcr.io/<PROJECT_ID>/<SERVICE_NAME>:<TAG> -f production.Dockerfile .
This command builds a Docker image from the production.Dockerfile
file and tags it as gcr.io/<PROJECT_ID>/<SERVICE_NAME>:<TAG>
. The -t
flag specifies the name and tag of the image, while -f
points to the Dockerfile used for the build.
docker push gcr.io/<PROJECT_ID>/<SERVICE_NAME>:<TAG>
This command pushes the previously built Docker image to Google Container Registry, making it available for deployment.
gcloud run deploy <SERVICE_NAME> \
--image gcr.io/<PROJECT_ID>/<SERVICE_NAME>:<TAG> \
--platform managed \
--allow-unauthenticated \
--port=8000
Deploys the Docker image to Google Cloud Run, using the image stored in Google Container Registry. The --allow-unauthenticated
flag allows public access to the service. The --platform managed
option specifies the fully managed Cloud Run environment, and --port=8000
sets the port for the FastAPI app to listen on.
If you are on a Mac with an M1 chip, specify the platform:
docker build --platform=linux/amd64 -t gcr.io/<PROJECT_ID>/<SERVICE_NAME>:<TAG> .
This ensures that Docker builds the image for the linux/amd64
architecture, which is necessary on M1 Macs due to compatibility issues with certain architectures.
docker push gcr.io/<PROJECT_ID>/<SERVICE_NAME>:<TAG>
Pushes the image built for linux/amd64
to Google Container Registry.
gcloud run deploy <SERVICE_NAME> \
--image gcr.io/<PROJECT_ID>/<SERVICE_NAME>:<TAG> \
--platform managed \
--allow-unauthenticated \
--port=8000
Deploys the image to Cloud Run after it is pushed to Google Container Registry.
To adjust resource limits and set environment variables securely, do not hardcode them here. Instead, use placeholders and --set-env-vars
with redacted keys:
gcloud run deploy <SERVICE_NAME> \
--image gcr.io/<PROJECT_ID>/<SERVICE_NAME>:<TAG> \
--platform managed \
--allow-unauthenticated \
--port=8000 \
--memory=1Gi \
--set-env-vars=DATABASE_URL="<REDACTED>",OPENAI_API_KEY="<REDACTED>",RESEND_API_KEY="<REDACTED>",FROM_EMAIL="<REDACTED>",EXOSCALE_ACCESS_KEY="<REDACTED>",EXOSCALE_SECRET_KEY="<REDACTED>",EXOSCALE_S3_ENDPOINT="<REDACTED>",EXOSCALE_S3_REGION="<REDACTED>",EXOSCALE_S3_BUCKET_NAME="<REDACTED>",APPLICATION_URL="<REDACTED>",JWT_SECRET="<REDACTED>"
This command deploys the application to Cloud Run with additional configuration like memory allocation (--memory=1Gi
) and securely passing environment variables using --set-env-vars
. Environment variables are used for sensitive configuration, and the placeholders <REDACTED>
should be replaced with actual, securely stored values.
Dockerfile for Production Deployment
# Base image
FROM python:3.11-slim
This sets the base image for the Dockerfile. It uses a minimal Python image (python:3.11-slim
), which is optimized for production environments.
RUN apt-get update && apt-get install -y \
libpq-dev \
gcc \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
Installs system dependencies required for PostgreSQL (libpq-dev
) and gcc
for compiling certain Python packages.
WORKDIR /usr/src/app
Sets the working directory within the container where your application code will be placed.
ENV PYTHONUNBUFFERED=1
ENV PYTHONDONTWRITEBYTECODE=1
Sets environment variables to ensure Python runs in an optimized way for production (disabling bytecode files and buffering).
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
Copies the requirements.txt
file into the container and installs the Python dependencies listed in it.
COPY app ./app
COPY prisma ./prisma
Copies the application files (app
) and the Prisma schema (prisma
) into the container.
EXPOSE 8000
Exposes port 8000
to allow the application to be accessed via that port.
COPY entrypoint.sh /usr/src/app/entrypoint.sh
RUN chmod +x /usr/src/app/entrypoint.sh
Copies the entrypoint.sh
script into the container and makes it executable. The script is used to start the application.
CMD ["/usr/src/app/entrypoint.sh"]
Specifies the command to run when the container starts. This runs the entrypoint.sh
script to start the application.
entrypoint.sh:
#!/bin/sh
prisma generate --schema ./prisma/schema.prisma
uvicorn app.main:app --host 0.0.0.0 --port 8000
This script runs the prisma generate
command to generate Prisma client code and starts the FastAPI app using uvicorn
.
Automate Deployment with deployment.sh
The deployment.sh
script simplifies the deployment process for your FastAPI application. It ensures that environment variables are loaded securely from a .env
file, validates the tag format (e.g., v0.0.0
), and automates all deployment steps:
- Builds a Docker image optimized for the correct architecture (e.g.,
linux/amd64
). - Pushes the image to Google Container Registry (GCR).
- Deploys the FastAPI application to Google Cloud Run using the specified image tag, passing all environment variables dynamically.
Here is an example script:
#!/usr/bin/env bash
set -e
if [ -z "$1" ]; then
echo "Usage: $0 <tag>"
exit 1
fi
This script starts with a basic setup. It checks if a tag is passed as an argument; if not, it exits with an error message.
TAG="$1"
This stores the tag passed as the first argument into the TAG
variable.
if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Tag must follow the format v0.0.0"
exit 1
fi
This checks if the tag matches the v0.0.0
format using a regular expression. If it doesn't, it exits the script with an error message.
if [ ! -f .env ]; then
echo ".env file not found"
exit 1
fi
Checks if the .env
file exists, which contains the environment variables. If not, it exits with an error message.
export $(grep -v '^#' .env | xargs)
This loads the environment variables from the .env
file into the shell, ignoring commented lines.
ENV_VARS=$(grep -v '^#' .env | grep '=' | paste -sd ',' -)
This formats the environment variables in the .env
file into a single comma-separated string suitable for passing to gcloud
.
docker build --platform=linux/amd64 -t gcr.io/<PROJECT_ID>/fastapi-template:${TAG} -f production.Dockerfile .
docker push gcr.io/<PROJECT_ID>/fastapi-template:${TAG}
Builds and pushes the Docker image as described earlier, using the provided tag.
gcloud run deploy fastapi-template \
--image gcr.io/<PROJECT_ID>/fastapi-template:${TAG} \
--platform managed \
--allow-unauthenticated \
--port=8000 \
--memory=1Gi \
--set-env-vars=${ENV_VARS}
Deploys the image to Cloud Run, passing the environment variables dynamically and setting resource limits.
To deploy a new version, simply run the script with the desired tag, for example:
./deployment.sh v0.0.1
This command runs the script to deploy a new version of the application.
Conclusion
By following these steps, you can seamlessly set up your FastAPI application to run on Google Cloud Run. The included deployment.sh
script further simplifies deployments, making it easy to ship updates reliably and securely. Always remember to manage your environment variables securely and avoid hardcoding sensitive information.
Happy Deploying!
Files
#!/usr/bin/env bash
set -e
if [ -z "$1" ]; then
echo "Usage: $0 <tag>"
exit 1
fi
TAG="$1"
# Check if tag matches v0.0.0 format
if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Tag must follow the format v0.0.0"
exit 1
fi
# Check if .env file exists
if [ ! -f .env ]; then
echo ".env file not found"
exit 1
fi
# Load environment variables from .env file
export $(grep -v '^#' .env | xargs)
# Build the --set-env-vars argument from the .env file
ENV_VARS=$(grep -v '^#' .env | grep '=' | paste -sd ',' -)
docker build --platform=linux/amd64 -t gcr.io/saas-template-439404/fastapi-template:${TAG} -f production.Dockerfile .
docker push gcr.io/saas-template-439404/fastapi-template:${TAG}
gcloud run deploy fastapi-template \
--image gcr.io/saas-template-439404/fastapi-template:${TAG} \
--platform managed \
--allow-unauthenticated \
--port=8000 \
--memory=1Gi \
--set-env-vars=${ENV_VARS}
# Base image
FROM python:3.11-slim
# Install PostgreSQL development files and system dependencies
RUN apt-get update && apt-get install -y \
libpq-dev \
gcc \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
# Set working directory
WORKDIR /usr/src/app
# Set environment variables for FastAPI production
ENV PYTHONUNBUFFERED=1
ENV PYTHONDONTWRITEBYTECODE=1
# Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy application files
COPY app ./app
COPY prisma ./prisma
# Expose the application port
EXPOSE 8000
COPY entrypoint.sh /usr/src/app/entrypoint.sh
RUN chmod +x /usr/src/app/entrypoint.sh
EXPOSE 8000
CMD ["/usr/src/app/entrypoint.sh"]