-
-
Notifications
You must be signed in to change notification settings - Fork 10
feat(backend): add Cloud Run deployment #284
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 1 commit
cc6271e
f7384c0
f017005
233bdf5
661a662
2a1f01d
81ba1a5
5573495
cdac78f
f07535d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,179 @@ | ||||||||||||||||||
| # Backend Deployment Guide | ||||||||||||||||||
|
|
||||||||||||||||||
| ## Overview | ||||||||||||||||||
|
|
||||||||||||||||||
| The backend is deployed to Google Cloud Run automatically via GitHub Actions when changes are pushed to `main`. | ||||||||||||||||||
|
|
||||||||||||||||||
| ## Hardcoded Values (in workflow) | ||||||||||||||||||
|
|
||||||||||||||||||
| - **GCP Project ID**: `atomify-ee7b5` | ||||||||||||||||||
| - **Firebase Project ID**: `atomify-ee7b5` (same as GCP) | ||||||||||||||||||
| - **Region**: `europe-west1` | ||||||||||||||||||
| - **Service Name**: `atomify-api` | ||||||||||||||||||
| - **Database URL**: `sqlite+aiosqlite:////data/atomify.db` (SQLite file path) | ||||||||||||||||||
| - **GCS Bucket Name**: `atomify-user-files` | ||||||||||||||||||
| - **CORS Origins**: `http://localhost:3000,https://andeplane.github.io` | ||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The CORS origins listed here (and also in the manual deployment command on line 141) are inconsistent with the
Suggested change
|
||||||||||||||||||
|
|
||||||||||||||||||
| ## Required GitHub Secrets | ||||||||||||||||||
|
|
||||||||||||||||||
| Set these in your GitHub repository: **Settings → Secrets and variables → Actions** | ||||||||||||||||||
|
|
||||||||||||||||||
| ### 1. `GCP_SA_KEY` | ||||||||||||||||||
| - **Description**: Service account JSON key with Cloud Run Admin permissions | ||||||||||||||||||
| - **How to create**: | ||||||||||||||||||
| 1. Google Cloud Console → IAM & Admin → Service Accounts | ||||||||||||||||||
| 2. Create service account (e.g., `github-actions`) | ||||||||||||||||||
| 3. Grant roles: | ||||||||||||||||||
| - `Cloud Run Admin` | ||||||||||||||||||
| - `Service Account User` | ||||||||||||||||||
| - `Storage Admin` (for GCR/Artifact Registry) | ||||||||||||||||||
andeplane marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||||||
| 4. Create JSON key → Download → Copy entire JSON content | ||||||||||||||||||
| 5. Paste into GitHub secret | ||||||||||||||||||
|
|
||||||||||||||||||
| ### 2. `GCP_SERVICE_ACCOUNT_EMAIL` | ||||||||||||||||||
| - **Description**: Email of the service account that Cloud Run will use | ||||||||||||||||||
| - **Example**: `[email protected]` | ||||||||||||||||||
| - **How to create**: | ||||||||||||||||||
| 1. Create service account for Cloud Run (e.g., `atomify-api`) | ||||||||||||||||||
| 2. Grant roles: | ||||||||||||||||||
| - `Storage Object Admin` (for GCS) | ||||||||||||||||||
| - `Firebase Admin SDK Administrator Service Agent` (for Firebase Auth) | ||||||||||||||||||
andeplane marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||||||
| 3. Copy the email address | ||||||||||||||||||
|
|
||||||||||||||||||
| ## Cloud Run Setup | ||||||||||||||||||
|
|
||||||||||||||||||
| ### 1. Enable APIs | ||||||||||||||||||
|
|
||||||||||||||||||
| ```bash | ||||||||||||||||||
| gcloud services enable \ | ||||||||||||||||||
| run.googleapis.com \ | ||||||||||||||||||
| cloudbuild.googleapis.com \ | ||||||||||||||||||
| containerregistry.googleapis.com \ | ||||||||||||||||||
| storage-api.googleapis.com | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| ### 2. Create Service Account for Cloud Run | ||||||||||||||||||
|
|
||||||||||||||||||
| ```bash | ||||||||||||||||||
| gcloud iam service-accounts create atomify-api \ | ||||||||||||||||||
| --display-name="Atomify API Service Account" | ||||||||||||||||||
|
|
||||||||||||||||||
| gcloud projects add-iam-policy-binding $PROJECT_ID \ | ||||||||||||||||||
| --member="serviceAccount:atomify-api@$PROJECT_ID.iam.gserviceaccount.com" \ | ||||||||||||||||||
| --role="roles/storage.objectAdmin" | ||||||||||||||||||
|
|
||||||||||||||||||
| gcloud projects add-iam-policy-binding $PROJECT_ID \ | ||||||||||||||||||
| --member="serviceAccount:atomify-api@$PROJECT_ID.iam.gserviceaccount.com" \ | ||||||||||||||||||
| --role="roles/firebase.admin" | ||||||||||||||||||
andeplane marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| ### 3. Create GCS Bucket | ||||||||||||||||||
|
|
||||||||||||||||||
| **Note**: Billing must be enabled for the project first. | ||||||||||||||||||
|
|
||||||||||||||||||
| ```bash | ||||||||||||||||||
| gcloud storage buckets create gs://atomify-user-files \ | ||||||||||||||||||
| --project=atomify-ee7b5 \ | ||||||||||||||||||
| --location=europe-west1 | ||||||||||||||||||
|
|
||||||||||||||||||
| gcloud storage buckets add-iam-policy-binding gs://atomify-user-files \ | ||||||||||||||||||
| --member="serviceAccount:[email protected]" \ | ||||||||||||||||||
| --role="roles/storage.objectAdmin" | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| ### 4. Set Up Cloud Run Volume (for SQLite) | ||||||||||||||||||
|
|
||||||||||||||||||
| If using SQLite with a persistent volume: | ||||||||||||||||||
|
|
||||||||||||||||||
| ```bash | ||||||||||||||||||
| # Create a Cloud Storage bucket for the volume | ||||||||||||||||||
| gsutil mb -p $PROJECT_ID -l us-central1 gs://atomify-db-volume | ||||||||||||||||||
andeplane marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||||||
|
|
||||||||||||||||||
| # Mount as volume in Cloud Run (done via gcloud run deploy or console) | ||||||||||||||||||
| ``` | ||||||||||||||||||
andeplane marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||||||
|
|
||||||||||||||||||
| **Note**: For production, consider using Cloud SQL (PostgreSQL) instead of SQLite. | ||||||||||||||||||
|
|
||||||||||||||||||
| ## Database Migrations | ||||||||||||||||||
|
|
||||||||||||||||||
| Migrations are **NOT** run automatically in the container startup to avoid race conditions. | ||||||||||||||||||
|
|
||||||||||||||||||
| ### Option 1: Manual Migration (Recommended) | ||||||||||||||||||
|
|
||||||||||||||||||
| Before deploying, run migrations manually: | ||||||||||||||||||
|
|
||||||||||||||||||
| ```bash | ||||||||||||||||||
| # Build and run migration container | ||||||||||||||||||
| docker build -t atomify-api:migrate ./backend | ||||||||||||||||||
| docker run --rm \ | ||||||||||||||||||
| -e DATABASE_URL="$DATABASE_URL" \ | ||||||||||||||||||
| atomify-api:migrate \ | ||||||||||||||||||
| alembic upgrade head | ||||||||||||||||||
|
Comment on lines
+102
to
+105
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This command relies on the
Suggested change
|
||||||||||||||||||
| ``` | ||||||||||||||||||
andeplane marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||
|
|
||||||||||||||||||
| ### Option 2: Cloud Run Job | ||||||||||||||||||
|
|
||||||||||||||||||
| Create a Cloud Run Job for migrations: | ||||||||||||||||||
|
|
||||||||||||||||||
| ```bash | ||||||||||||||||||
| gcloud run jobs create atomify-api-migrate \ | ||||||||||||||||||
| --image=gcr.io/$PROJECT_ID/atomify-api:latest \ | ||||||||||||||||||
| --region=us-central1 \ | ||||||||||||||||||
| --set-env-vars="DATABASE_URL=$DATABASE_URL" \ | ||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||||||||||||||
| --command="alembic" \ | ||||||||||||||||||
| --args="upgrade,head" | ||||||||||||||||||
|
|
||||||||||||||||||
| # Run before each deployment | ||||||||||||||||||
| gcloud run jobs execute atomify-api-migrate --region=us-central1 --wait | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| ## Manual Deployment | ||||||||||||||||||
|
|
||||||||||||||||||
| If you need to deploy manually: | ||||||||||||||||||
|
|
||||||||||||||||||
| ```bash | ||||||||||||||||||
| # Build and push | ||||||||||||||||||
| docker build -t gcr.io/atomify-ee7b5/atomify-api:latest ./backend | ||||||||||||||||||
| docker push gcr.io/atomify-ee7b5/atomify-api:latest | ||||||||||||||||||
|
|
||||||||||||||||||
| # Deploy | ||||||||||||||||||
| gcloud run deploy atomify-api \ | ||||||||||||||||||
| --image=gcr.io/atomify-ee7b5/atomify-api:latest \ | ||||||||||||||||||
| --region=europe-west1 \ | ||||||||||||||||||
| --platform=managed \ | ||||||||||||||||||
| --allow-unauthenticated \ | ||||||||||||||||||
| --service-account=atomify-api@atomify-ee7b5.iam.gserviceaccount.com \ | ||||||||||||||||||
| --set-env-vars="DATABASE_URL=sqlite+aiosqlite:////data/atomify.db,FIREBASE_PROJECT_ID=atomify-ee7b5,GCS_BUCKET_NAME=atomify-user-files,CORS_ORIGINS=http://localhost:3000,https://andeplane.github.io" \ | ||||||||||||||||||
andeplane marked this conversation as resolved.
Show resolved
Hide resolved
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The
Suggested change
|
||||||||||||||||||
| --memory=512Mi \ | ||||||||||||||||||
| --cpu=1 \ | ||||||||||||||||||
| --port=8000 | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| ## Monitoring | ||||||||||||||||||
|
|
||||||||||||||||||
| - **Logs**: `gcloud run services logs read atomify-api --region=europe-west1` | ||||||||||||||||||
| - **Metrics**: Google Cloud Console → Cloud Run → atomify-api | ||||||||||||||||||
| - **Health Check**: `https://atomify-api-xxx.run.app/health` | ||||||||||||||||||
|
|
||||||||||||||||||
| ## Troubleshooting | ||||||||||||||||||
|
|
||||||||||||||||||
| ### Service won't start | ||||||||||||||||||
| - Check logs: `gcloud run services logs read atomify-api --region=us-central1` | ||||||||||||||||||
| - Verify environment variables are set correctly | ||||||||||||||||||
| - Check service account permissions | ||||||||||||||||||
|
|
||||||||||||||||||
| ### Database connection fails | ||||||||||||||||||
| - Verify `DATABASE_URL` is correct | ||||||||||||||||||
| - For Cloud SQL: Ensure Cloud SQL Admin API is enabled | ||||||||||||||||||
| - For SQLite volume: Ensure volume is mounted at `/data` | ||||||||||||||||||
|
|
||||||||||||||||||
| ### Firebase Auth fails | ||||||||||||||||||
| - Verify `FIREBASE_PROJECT_ID` matches your Firebase project | ||||||||||||||||||
| - Check service account has Firebase Admin permissions | ||||||||||||||||||
| - Ensure Firebase Admin SDK is initialized correctly | ||||||||||||||||||
|
|
||||||||||||||||||
| ### GCS access fails | ||||||||||||||||||
| - Verify `GCS_BUCKET_NAME` exists | ||||||||||||||||||
| - Check service account has `Storage Object Admin` role | ||||||||||||||||||
| - Verify bucket IAM allows the service account | ||||||||||||||||||
|
|
||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.