Skip to main content

Google Cloud Deployment

Deploy InstaCRUD to Google Cloud using Cloud Run for serverless containers and Firestore with MongoDB compatibility for the database.


Architecture Overview

┌─────────────────────────────────────────────────────────┐
│ Google Cloud │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Cloud Run │ │ Cloud Run │ │ Firestore │ │
│ │ Frontend │───>│ Backend │───>│ (MongoDB) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │ │ │
│ └───────┬───────────┘ │
│ ▼ │
│ ┌─────────────┐ │
│ │ Secret Mgr │ │
│ └─────────────┘ │
└─────────────────────────────────────────────────────────┘

Components:

  • Cloud Run — Serverless container hosting for backend and frontend
  • Firestore — MongoDB-compatible database (Enterprise edition)
  • Secret Manager — Secure storage for API keys and credentials
  • Artifact Registry — Docker image storage

Prerequisites

  1. Google Cloud account with billing enabled
  2. gcloud CLI installed and configured
  3. Docker installed locally
# Install gcloud CLI
curl https://sdk.cloud.google.com | bash

# Authenticate
gcloud auth login
gcloud config set project YOUR_PROJECT_ID

Step 1: Create Firestore Database

Firestore with MongoDB compatibility provides a fully managed database.

Create Database

  1. Go to Firestore Console
  2. Click Create Database
  3. Select Firestore with MongoDB compatibility (Enterprise edition)
  4. Choose a location (e.g., us-central1)
  5. Set a database ID (e.g., instacrud-system)

Get Connection String

  1. Open your Firestore database
  2. Click Connect and copy the MongoDB connection string
  3. Format: mongodb://USER:PASSWORD@HOST:443/DATABASE?...

Step 2: Set Up Artifact Registry

Create a Docker repository for your images:

# Enable API
gcloud services enable artifactregistry.googleapis.com

# Create repository
gcloud artifacts repositories create instacrud-images \
--repository-format=docker \
--location=us-central1 \
--description="InstaCRUD Docker images"

# Configure Docker authentication
gcloud auth configure-docker us-central1-docker.pkg.dev

Step 3: Build and Push Images

Backend Dockerfile

Ensure your backend Dockerfile exposes port 8080 (Cloud Run requirement):

FROM python:3.11-slim

WORKDIR /app

RUN pip install poetry
COPY pyproject.toml poetry.lock ./
RUN poetry config virtualenvs.create false && poetry install --no-dev

COPY . .

EXPOSE 8080

CMD ["python", "-m", "uvicorn", "instacrud.app:app", "--host", "0.0.0.0", "--port", "8080"]

Build and Push

# Backend
cd backend
docker build -t us-central1-docker.pkg.dev/YOUR_PROJECT/instacrud-images/backend:latest .
docker push us-central1-docker.pkg.dev/YOUR_PROJECT/instacrud-images/backend:latest

# Frontend
cd ../frontend
docker build -t us-central1-docker.pkg.dev/YOUR_PROJECT/instacrud-images/frontend:latest .
docker push us-central1-docker.pkg.dev/YOUR_PROJECT/instacrud-images/frontend:latest

Step 4: Create Secrets

Store sensitive values in Secret Manager:

# Enable API
gcloud services enable secretmanager.googleapis.com

# Create secrets
echo -n "your-brevo-api-key" | gcloud secrets create BREVO_API_KEY --data-file=-
echo -n "your-openai-key" | gcloud secrets create OPENAI_API_KEY --data-file=-
echo -n "your-anthropic-key" | gcloud secrets create ANTHROPIC_API_KEY --data-file=-

Step 5: Deploy Backend to Cloud Run

gcloud run deploy instacrud-backend \
--image=us-central1-docker.pkg.dev/YOUR_PROJECT/instacrud-images/backend:latest \
--region=us-central1 \
--platform=managed \
--allow-unauthenticated \
--port=8080 \
--cpu=1 \
--memory=1Gi \
--max-instances=20 \
--set-env-vars="
BASE_URL=https://instacrud-backend-HASH.us-central1.run.app,
FRONTEND_BASE_URL=https://instacrud-frontend-HASH.us-central1.run.app,
SECRET_KEY=your-jwt-secret,
ALGORITHM=HS256,
TOKEN_EXPIRATION_SECONDS=86400,
DB_ENGINE=firestore,
MONGO_URL=mongodb://USER:PASS@HOST:443/instacrud-system?loadBalanced=true&tls=true&authMechanism=SCRAM-SHA-256&retryWrites=false,
CORS_ALLOW_ORIGINS=*,
CORS_ALLOW_CREDENTIALS=True,
GOOGLE_CLIENT_ID=your-google-client-id,
GOOGLE_CLIENT_SECRET=your-google-client-secret,
MS_CLIENT_ID=your-ms-client-id,
MS_CLIENT_SECRET=your-ms-client-secret,
MS_TENANT_ID=common,
OPEN_REGISTRATION=False,
TURNSTILE_SITE_KEY=your-turnstile-site-key,
TURNSTILE_SECRET_KEY=your-turnstile-secret-key,
TURNSTILE_MODE=normal
" \
--set-secrets="
BREVO_API_KEY=BREVO_API_KEY:latest,
OPENAI_API_KEY=OPENAI_API_KEY:latest,
ANTHROPIC_API_KEY=ANTHROPIC_API_KEY:latest
"

Note the deployed URL (e.g., https://instacrud-backend-abc123-uc.a.run.app).


Step 6: Deploy Frontend to Cloud Run

gcloud run deploy instacrud-frontend \
--image=us-central1-docker.pkg.dev/YOUR_PROJECT/instacrud-images/frontend:latest \
--region=us-central1 \
--platform=managed \
--allow-unauthenticated \
--port=80 \
--cpu=1 \
--memory=512Mi \
--max-instances=3 \
--set-env-vars="
NEXT_PUBLIC_API_BASE_URL=https://instacrud-backend-abc123-uc.a.run.app
"

Step 7: Update Backend URL

After deploying frontend, update the backend with the correct frontend URL:

gcloud run services update instacrud-backend \
--region=us-central1 \
--update-env-vars="FRONTEND_BASE_URL=https://instacrud-frontend-xyz789-uc.a.run.app"

Step 8: Configure OAuth Redirects

Update your OAuth providers with the Cloud Run URLs:

Google Cloud Console

Add redirect URI:

https://instacrud-backend-abc123-uc.a.run.app/oauth/google/callback

Microsoft Azure Portal

Add redirect URI:

https://instacrud-backend-abc123-uc.a.run.app/oauth/microsoft/callback

Custom Domain (Optional)

Map a custom domain to Cloud Run:

gcloud run domain-mappings create \
--service=instacrud-frontend \
--domain=app.yourdomain.com \
--region=us-central1

Follow the DNS verification steps provided by Google.


CI/CD with GitHub Actions

Automate deployments with GitHub Actions:

# .github/workflows/deploy.yml
name: Deploy to Cloud Run

on:
push:
branches: [main]

env:
PROJECT_ID: your-project-id
REGION: us-central1

jobs:
deploy-backend:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: google-github-actions/auth@v2
with:
credentials_json: ${{ secrets.GCP_SA_KEY }}

- uses: google-github-actions/setup-gcloud@v2

- name: Configure Docker
run: gcloud auth configure-docker ${{ env.REGION }}-docker.pkg.dev

- name: Build and Push
run: |
docker build -t ${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/instacrud-images/backend:latest ./backend
docker push ${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/instacrud-images/backend:latest

- name: Deploy
run: |
gcloud run deploy instacrud-backend \
--image=${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/instacrud-images/backend:latest \
--region=${{ env.REGION }}

Firestore Database Management

Create Organization Databases

For multi-tenant setups, create separate databases per organization:

# Create organization database
gcloud firestore databases create \
--database=instacrud-org-acme \
--location=us-central1 \
--type=firestore-native

Database Naming Convention

  • System database: instacrud-system
  • Organization databases: instacrud-org-{org-code}

Cost Optimization

Cloud Run Billing Modes

Cloud Run offers two CPU allocation modes that significantly impact costs:

Request-based billing (default):

  • You're charged only when processing requests, during startup, and shutdown
  • CPU is allocated exclusively during active request processing
  • Idle instances are billed at a lower rate
  • Best for sporadic or bursty traffic patterns

Instance-based billing:

  • Charged for the entire container lifecycle, even when idle
  • Required for background async processes, goroutines, threads, or monitoring agents (e.g., OpenTelemetry)
  • Better for steady, high-volume traffic
Most Economical Setup

For the lowest cost, use request-based billing with --min-instances=0:

gcloud run deploy instacrud-backend \
--min-instances=0 \
--no-cpu-throttling=false \
# ... other flags

This scales your service to zero when inactive. The tradeoff is cold starts of approximately 30-60 seconds when the first request arrives after idle periods.

Once you have stable traffic, set --min-instances=1 to eliminate cold starts while still benefiting from request-based billing for cost savings.

Request-Based Billing Limitations

Request-based billing does not allocate CPU outside of request processing. This means:

  • Background tasks and async work after returning responses won't execute
  • Long-running background processes are not supported
  • Monitoring agents that run continuously won't work properly

If your application requires background processing, you have to use instance-based billing with --no-cpu-throttling, which increases costs significantly.

Cloud Run Instance Settings

  • --min-instances=0 — Scale to zero when idle (default, most economical)
  • --min-instances=1 — Keep one instance warm to avoid cold starts
  • --max-instances — Set limits to control maximum spend

Firestore

  • Use Enterprise edition for MongoDB compatibility
  • Monitor read/write operations
  • Implement caching where appropriate

Estimated Monthly Costs (as of early 2026)

For a minimal configuration (1 CPU, 512MB–1GB memory per service, 1 system database + 2 organization databases):

ConfigurationEstimated Monthly Cost
--min-instances=0 + request-based billing< $50
--min-instances=1 + request-based billing~$70
--min-instances=1 + instance-based billing~$180
Disclaimer

These are average costs observed by the authors for a minimal setup. Your actual costs may vary based on usage patterns, region, and resource configuration. Always monitor your spending and set up budget alerts in the Google Cloud Console.


Summary

Google Cloud deployment provides:

  • Serverless scaling with Cloud Run
  • Managed MongoDB-compatible database with Firestore
  • Secure secret management
  • Automatic HTTPS and SSL certificates
  • Global CDN for static assets
  • CI/CD integration with GitHub Actions