xtablo-source/docs/CLOUD_BUILD_SETUP.md
Arthur Belleville 247bc8b3af
Add docs
2025-11-14 09:14:25 +01:00

268 lines
7.8 KiB
Markdown

# Google Cloud Build Setup Guide
## Overview
This guide explains how to configure Google Cloud Build for automatic deployment of the XTablo API to Cloud Run.
## Prerequisites
1. Google Cloud Project with billing enabled
2. Cloud Build API enabled
3. Cloud Run API enabled
4. Secret Manager API enabled
5. Artifact Registry repository created
## Required Substitution Variables
The `cloudbuild.yaml` uses substitution variables that must be configured in your Cloud Build trigger. Here's what each variable is for:
### Build Configuration Variables
| Variable | Description | Example |
|----------|-------------|---------|
| `$_NODE_ENV` | Environment (staging/production) | `production` |
| `$_AR_PROJECT_ID` | Artifact Registry project ID | `your-project-id` |
| `$_AR_REPOSITORY` | Artifact Registry repository name | `xtablo` |
| `$_SERVICE_NAME` | Cloud Run service name | `xtablo-api` |
### Application Environment Variables
| Variable | Description | Example |
|----------|-------------|---------|
| `$_SUPABASE_URL` | Supabase project URL | `https://xxx.supabase.co` |
| `$_STREAM_CHAT_API_KEY` | Stream Chat API key | `your-stream-api-key` |
| `$_EMAIL_USER` | Email sender address | `noreply@xtablo.com` |
| `$_EMAIL_CLIENT_ID` | OAuth2 client ID for email | `your-client-id` |
| `$_R2_ACCOUNT_ID` | Cloudflare R2 account ID | `your-r2-account-id` |
| `$_CORS_ORIGIN` | CORS allowed origin | `https://app.xtablo.com` |
| `$_XTABLO_URL` | Frontend application URL | `https://app.xtablo.com` |
## Setting Up Substitution Variables
### Option 1: Via Google Cloud Console
1. Go to Cloud Build > Triggers
2. Select your trigger (or create a new one)
3. Scroll to "Substitution variables"
4. Add each variable with its value:
```
_NODE_ENV = production
_AR_PROJECT_ID = your-project-id
_AR_REPOSITORY = xtablo
_SERVICE_NAME = xtablo-api
_SUPABASE_URL = https://your-project.supabase.co
_STREAM_CHAT_API_KEY = your-key
_EMAIL_USER = noreply@xtablo.com
_EMAIL_CLIENT_ID = your-client-id
_R2_ACCOUNT_ID = your-account-id
_CORS_ORIGIN = https://app.xtablo.com
_XTABLO_URL = https://app.xtablo.com
```
### Option 2: Via gcloud CLI
```bash
gcloud builds triggers create github \
--name="xtablo-api-production" \
--repo-name="xtablo-source" \
--repo-owner="your-github-org" \
--branch-pattern="^main$" \
--build-config="apps/api/cloudbuild.yaml" \
--substitutions='
_NODE_ENV=production,
_AR_PROJECT_ID=your-project-id,
_AR_REPOSITORY=xtablo,
_SERVICE_NAME=xtablo-api,
_SUPABASE_URL=https://your-project.supabase.co,
_STREAM_CHAT_API_KEY=your-key,
_EMAIL_USER=noreply@xtablo.com,
_EMAIL_CLIENT_ID=your-client-id,
_R2_ACCOUNT_ID=your-account-id,
_CORS_ORIGIN=https://app.xtablo.com,
_XTABLO_URL=https://app.xtablo.com
'
```
## Setting Up Secrets in Secret Manager
The sensitive values (API keys, tokens, etc.) are stored in Google Cloud Secret Manager. Create these secrets:
### Required Secrets
```bash
# Supabase secrets
echo -n "your-service-role-key" | gcloud secrets create supabase-service-role-key --data-file=-
echo -n "your-connection-string" | gcloud secrets create supabase-connection-string --data-file=-
echo -n "your-ca-cert" | gcloud secrets create supabase-ca-cert --data-file=-
# Stream Chat secret
echo -n "your-stream-secret" | gcloud secrets create stream-chat-api-secret --data-file=-
# Stripe secrets
echo -n "your-stripe-key" | gcloud secrets create stripe-secret-key --data-file=-
echo -n "your-webhook-secret" | gcloud secrets create stripe-webhook-secret --data-file=-
# Email secrets
echo -n "your-client-secret" | gcloud secrets create email-client-secret --data-file=-
echo -n "your-refresh-token" | gcloud secrets create email-refresh-token --data-file=-
# R2 (Cloudflare) secrets
echo -n "your-access-key-id" | gcloud secrets create r2-access-key-id --data-file=-
echo -n "your-secret-access-key" | gcloud secrets create r2-secret-access-key --data-file=-
```
### Grant Cloud Run Access to Secrets
```bash
# Get your Cloud Run service account
PROJECT_ID="your-project-id"
SERVICE_ACCOUNT="${PROJECT_ID}@appspot.gserviceaccount.com"
# Grant access to each secret
for secret in \
supabase-service-role-key \
supabase-connection-string \
supabase-ca-cert \
stream-chat-api-secret \
stripe-secret-key \
stripe-webhook-secret \
email-client-secret \
email-refresh-token \
r2-access-key-id \
r2-secret-access-key
do
gcloud secrets add-iam-policy-binding $secret \
--member="serviceAccount:${SERVICE_ACCOUNT}" \
--role="roles/secretmanager.secretAccessor"
done
```
## Environment-Specific Configurations
### Production Trigger
```yaml
_NODE_ENV: production
_CORS_ORIGIN: https://app.xtablo.com
_XTABLO_URL: https://app.xtablo.com
```
### Staging Trigger
```yaml
_NODE_ENV: staging
_CORS_ORIGIN: https://staging.xtablo.com
_XTABLO_URL: https://staging.xtablo.com
_SERVICE_NAME: xtablo-api-staging
```
## Verifying the Setup
After creating your trigger and setting up the secrets:
1. **Test the trigger manually:**
```bash
gcloud builds triggers run xtablo-api-production --branch=main
```
2. **Check the build logs:**
```bash
gcloud builds list --limit=5
gcloud builds log BUILD_ID
```
3. **Verify the deployed service:**
```bash
gcloud run services describe xtablo-api --region=europe-west1
```
4. **Check environment variables:**
```bash
gcloud run services describe xtablo-api --region=europe-west1 --format="value(spec.template.spec.containers[0].env)"
```
## Troubleshooting
### Build Fails with "Missing Substitution Variable"
- Ensure all `$_VARIABLE` names are defined in your trigger
- Check for typos in variable names
### Cloud Run Deployment Fails
- Verify the service account has necessary permissions
- Check that the Artifact Registry URL is correct
- Ensure the image was successfully pushed
### Application Fails to Start
- Check Cloud Run logs: `gcloud run logs read --service=xtablo-api --region=europe-west1`
- Verify all secrets are accessible to the service account
- Check that environment variables are properly set
### Secret Access Denied
- Ensure the Cloud Run service account has `roles/secretmanager.secretAccessor` for each secret
- Verify secrets exist: `gcloud secrets list`
## Additional Configuration
### Service Account Permissions
Your Cloud Run service needs these roles:
```bash
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:${SERVICE_ACCOUNT}" \
--role="roles/secretmanager.secretAccessor"
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:${SERVICE_ACCOUNT}" \
--role="roles/cloudsql.client" # If using Cloud SQL
```
### Cloud Run Configuration Options
You can add these to your `cloudbuild.yaml` deploy step:
```yaml
- '--memory'
- '512Mi'
- '--cpu'
- '1'
- '--max-instances'
- '10'
- '--min-instances'
- '0'
- '--concurrency'
- '80'
- '--timeout'
- '300'
- '--allow-unauthenticated' # If your API is public
```
## Manual Deployment
If you need to deploy manually without Cloud Build:
```bash
# Build the image
docker build -f apps/api/Dockerfile --target production -t xtablo-api:latest .
# Tag for Artifact Registry
docker tag xtablo-api:latest europe-west1-docker.pkg.dev/PROJECT_ID/xtablo/xtablo-api:latest
# Push to Artifact Registry
docker push europe-west1-docker.pkg.dev/PROJECT_ID/xtablo/xtablo-api:latest
# Deploy to Cloud Run
gcloud run deploy xtablo-api \
--image=europe-west1-docker.pkg.dev/PROJECT_ID/xtablo/xtablo-api:latest \
--region=europe-west1 \
--set-env-vars="NODE_ENV=production,PORT=8080,..." \
--update-secrets="SUPABASE_SERVICE_ROLE_KEY=supabase-service-role-key:latest,..."
```
## Support
For more information:
- [Cloud Build Documentation](https://cloud.google.com/build/docs)
- [Cloud Run Documentation](https://cloud.google.com/run/docs)
- [Secret Manager Documentation](https://cloud.google.com/secret-manager/docs)