Skip to main content

App CloudRun — Lab Guide

📖 Configuration Guide

Overview

App CloudRun is the foundation deployment engine for all Cloud Run application modules in this repository. It is a highly parameterized Terraform child module that provisions a production-ready Cloud Run v2 service, including Cloud SQL (PostgreSQL or MySQL), Cloud Filestore NFS, GCS storage, Secret Manager, Cloud Build CI/CD, Cloud Monitoring, and optional Cloud Armor WAF.

Application modules such as Django CloudRun, Ghost CloudRun, and Wordpress CloudRun call this module and pass application-specific configuration. You can also call App CloudRun directly to deploy a generic containerised workload on Cloud Run.

Estimated time: 1.5–2.5 hours

What the Module Automates

  • Cloud Run service and revision creation with Direct VPC Egress
  • Cloud Build image build and push to Artifact Registry (custom mode) or image mirroring (prebuilt mode)
  • Cloud SQL database and user provisioning, with Cloud SQL Auth Proxy sidecar
  • Secret Manager secrets for database credentials and application settings
  • Cloud Filestore NFS provisioning and GCS Fuse volume mount configuration
  • Cloud IAM bindings for the Cloud Run service account
  • Cloud Run Jobs for initialisation tasks (e.g. db-init) and Cloud Scheduler cron jobs
  • Cloud Monitoring uptime checks and alert policies
  • Optional: Cloud Armor WAF + Global HTTPS Load Balancer, Identity-Aware Proxy, VPC Service Controls, CI/CD trigger

What You Do Manually

  • Note the service URL and other deployment outputs from the RAD UI deployment panel
  • Inspect Cloud Run revisions and traffic splits in the Cloud Console
  • Query structured logs in Cloud Logging
  • View request latency, instance count, and uptime check status in Cloud Monitoring

CLI and REST API Overview

Set these shell variables at the start of each session — all gcloud and REST examples below reference them.

export PROJECT="your-gcp-project-id"   # set this first — your GCP project ID
export REGION="us-central1" # the region you deployed into
export TOKEN=$(gcloud auth print-access-token)

# Discover the Cloud Run service
export SERVICE=$(gcloud run services list \
--project=${PROJECT} \
--region=${REGION} \
--format="value(metadata.name)" \
--limit=1)
export SERVICE_URL=$(gcloud run services describe ${SERVICE} \
--project=${PROJECT} \
--region=${REGION} \
--format="value(status.url)")

Prerequisites

RequirementDetail
gcloud CLIAuthenticated (gcloud auth login)
GCP project with billingActive billing account linked
Services GCP module deployedProvides VPC, Cloud SQL, Artifact Registry, and Filestore
Service accountroles/owner granted in the target project
RAD UI accessPermission to deploy modules in the target GCP project

The Services GCP module must be deployed and healthy before running this module. It supplies the shared VPC, Cloud SQL instance, Artifact Registry repository, and Filestore NFS server that App CloudRun discovers automatically at deploy time.


Phase 1 — Deploy Infrastructure [AUTOMATED]

Step 1.1 — Configure Variables

Configure the following variables in the RAD UI deployment form before deploying.

VariableDefaultDescription
project_id(required)GCP project ID to deploy into
deployment_id(auto-generated)Short alphanumeric suffix appended to all resource names
regionus-central1GCP region for resource deployment
tenant_deployment_iddemoUnique tenant/environment identifier used in resource naming
application_namecrappBase name for the Cloud Run service and associated resources
application_version1.0.0Container image version tag
container_image_sourcecustomcustom to build via Cloud Build; prebuilt to deploy an existing image URI
container_image""Full image URI — required when container_image_source = "prebuilt"
deploy_applicationtrueSet to false to provision infrastructure only without deploying the container
min_instance_count0Minimum Cloud Run instances (0 = scale to zero when idle)
max_instance_count1Maximum Cloud Run instances; acts as a cost ceiling
container_resources{ cpu_limit = "1000m", memory_limit = "512Mi" }CPU and memory limits per container instance
database_typePOSTGRESCloud SQL engine: POSTGRES, MYSQL, or NONE
application_database_namecrappdbPostgreSQL/MySQL database name
application_database_usercrappuserDatabase user name
enable_redistrueInjects REDIS_HOST/REDIS_PORT environment variables
enable_nfstrueProvisions Cloud Filestore NFS and mounts it at /mnt/nfs
enable_cloud_armorfalseProvisions a Global HTTPS Load Balancer with Cloud Armor WAF
enable_iapfalseEnables Identity-Aware Proxy authentication

Step 1.2 — Initiate Deployment

Deployment is initiated from the RAD UI. Fill in the variables form and click Deploy.

Expected resource provisioning times:

ResourceTypical duration
Secret Manager secrets< 1 minute
Cloud SQL database and user2–5 minutes
Cloud Build image build (custom mode)5–10 minutes
NFS setup Cloud Run Job2–4 minutes
Database init Cloud Run Job1–3 minutes
Cloud Run service deployment2–5 minutes
Uptime check and alert policies1–2 minutes
Total15–30 minutes

Step 1.3 — Record Outputs

After deployment completes, the following outputs are available in the RAD UI deployment panel.

OutputDescription
service_nameName of the deployed Cloud Run service
service_urlPublic HTTPS URL of the Cloud Run service
service_locationGCP region where the service is running
database_instance_nameCloud SQL instance name
database_nameApplication database name
database_userApplication database username
database_password_secretSecret Manager secret name for the database password
storage_bucketsGCS bucket names created for the application
container_registryArtifact Registry repository name
deployment_idUnique deployment identifier
resource_prefixResource naming prefix applied to all resources
initialization_jobsNames of Cloud Run initialisation jobs
nfs_setup_jobName of the NFS setup Cloud Run Job
uptime_check_namesNames of the configured uptime checks
deployment_summaryHuman-readable summary of the full deployment

Set shell variables for use in later steps using gcloud discovery:

export PROJECT="your-gcp-project-id"   # set this first — your GCP project ID
export REGION="us-central1" # the region you deployed into
export TOKEN=$(gcloud auth print-access-token)

# Discover the Cloud Run service
export SERVICE=$(gcloud run services list \
--project=${PROJECT} \
--region=${REGION} \
--format="value(metadata.name)" \
--limit=1)
export SERVICE_URL=$(gcloud run services describe ${SERVICE} \
--project=${PROJECT} \
--region=${REGION} \
--format="value(status.url)")

# Discover the database password secret
export DB_SECRET=$(gcloud secrets list \
--project=${PROJECT} \
--filter="name~crapp" \
--format="value(name)" \
--limit=1)

echo "Application URL: ${SERVICE_URL}"

Phase 2 — Access the Application [MANUAL]

Step 2.1 — Open the Application URL

echo "Navigate to: ${SERVICE_URL}"

Open the URL in your browser.

Expected result: The deployed container responds over HTTPS.

gcloud equivalent:

gcloud run services describe ${SERVICE} \
--region=${REGION} \
--project=${PROJECT} \
--format="value(status.url)"

REST API equivalent:

curl -s -H "Authorization: Bearer ${TOKEN}" \
"https://run.googleapis.com/v2/projects/${PROJECT}/locations/${REGION}/services/${SERVICE}" \
| jq '{name, uri: .urls[0], latestReadyRevision}'

Step 2.2 — Check the Service Health Endpoint

curl -s -o /dev/null -w "%{http_code}" "${SERVICE_URL}/healthz"

Expected result: HTTP 200 (or your application's configured health path response code).

Step 2.3 — Inspect Secret Manager Secrets

List secrets created for this deployment:

gcloud secrets list \
--project=${PROJECT} \
--filter="name~${SERVICE}" \
--format="table(name)"

Access the database password:

gcloud secrets versions access latest \
--secret="${DB_SECRET}" \
--project=${PROJECT}

REST API equivalent:

curl -s -H "Authorization: Bearer ${TOKEN}" \
"https://secretmanager.googleapis.com/v1/projects/${PROJECT}/secrets/${DB_SECRET}/versions/latest:access" \
| jq -r '.payload.data' | base64 --decode

Phase 3 — Explore Cloud Run Features [MANUAL]

Step 3.1 — View the Service in the Cloud Console

Navigate to Cloud Run in the Google Cloud Console and click your service (${SERVICE}). Review:

  • Overview tab: service URL, region, last deployed revision
  • Revisions tab: list of all revisions with traffic split percentages
  • Metrics tab: request count, latency, and instance count graphs
  • Logs tab: streaming log view

Step 3.2 — Examine Revisions

List all revisions of the service:

gcloud run revisions list \
--service=${SERVICE} \
--region=${REGION} \
--project=${PROJECT} \
--format="table(metadata.name,status.conditions[0].status,spec.containerConcurrency,metadata.creationTimestamp)"

Expected result: A table showing revision names, ready status, and creation timestamps.

REST API equivalent:

curl -s -H "Authorization: Bearer ${TOKEN}" \
"https://run.googleapis.com/v2/projects/${PROJECT}/locations/${REGION}/services/${SERVICE}/revisions" \
| jq '.revisions[] | {name, createTime, serviceAccount}'

Step 3.3 — Test Traffic Splitting

Traffic splitting allows you to route a percentage of traffic to a specific revision. In the Cloud Console:

  1. Go to Cloud Run > your service > Edit & Deploy New Revision.
  2. After deploying, go to the Revisions tab.
  3. Click Manage Traffic and split traffic between two revisions (e.g., 90% latest, 10% previous).
  4. Save and send requests to observe which revision responds.
for i in {1..10}; do
curl -s -o /dev/null -w "%{http_code}\n" "${SERVICE_URL}"
done

To review the current traffic split:

gcloud run services describe ${SERVICE} \
--region=${REGION} \
--project=${PROJECT} \
--format="yaml(spec.traffic)"

Step 3.4 — Inspect Scaling and Concurrency Settings

gcloud run services describe ${SERVICE} \
--region=${REGION} \
--project=${PROJECT} \
--format="yaml(spec.template.spec.containerConcurrency,spec.template.spec.containers[0].resources,spec.template.metadata.annotations)"

Key annotations to observe:

  • autoscaling.knative.dev/minScale — minimum instance count
  • autoscaling.knative.dev/maxScale — maximum instance count
  • run.googleapis.com/vpc-access-egress — egress routing mode

Phase 4 — Inspect Storage [MANUAL]

Step 4.1 — Explore the GCS Bucket

List the GCS buckets created by this module:

gsutil ls -p ${PROJECT} | grep "${SERVICE}"

List bucket contents:

BUCKET=$(gcloud storage buckets list --project=${PROJECT} --format="value(name)" --filter="name~${SERVICE}" --limit=1)
gsutil ls gs://${BUCKET}/

REST API equivalent:

curl -s -H "Authorization: Bearer ${TOKEN}" \
"https://storage.googleapis.com/storage/v1/b?project=${PROJECT}" \
| jq '.items[] | {name, location, storageClass}'

Step 4.2 — Verify GCS Fuse Volume Mount

Check that the GCS Fuse volume mount is configured:

gcloud run services describe ${SERVICE} \
--region=${REGION} \
--project=${PROJECT} \
--format="yaml(spec.template.spec.volumes)"

Expected result: Volume entries appear for the NFS mount and any GCS Fuse volumes.

Step 4.3 — Inspect Cloud SQL Connection

Verify the Cloud SQL Auth Proxy sidecar is configured as a volume:

gcloud run services describe ${SERVICE} \
--region=${REGION} \
--project=${PROJECT} \
--format="yaml(spec.template.spec.containers)"

Expected result: A sidecar container entry for cloud-sql-proxy appears alongside the main application container.


Phase 5 — Explore Cloud Logging [MANUAL]

Step 5.1 — View Logs in the Console

Navigate to Logging > Logs Explorer in the Cloud Console.

Step 5.2 — Query Cloud Run Application Logs

All Cloud Run service logs:

resource.type="cloud_run_revision"
resource.labels.service_name="${SERVICE}"
resource.labels.location="${REGION}"

Error logs only:

resource.type="cloud_run_revision"
resource.labels.service_name="${SERVICE}"
severity>=ERROR

HTTP request logs (4xx/5xx):

resource.type="cloud_run_revision"
resource.labels.service_name="${SERVICE}"
httpRequest.status>=400

Cloud SQL Auth Proxy logs:

resource.type="cloud_run_revision"
resource.labels.service_name="${SERVICE}"
textPayload=~"cloud-sql-proxy|pq:"

gcloud equivalent:

gcloud logging read \
'resource.type="cloud_run_revision" AND resource.labels.service_name="'${SERVICE}'"' \
--project=${PROJECT} \
--limit=50 \
--format="table(timestamp,severity,textPayload,httpRequest.status)"

REST API equivalent:

curl -s -X POST -H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
"https://logging.googleapis.com/v2/entries:list" \
-d '{
"resourceNames": ["projects/'${PROJECT}'"],
"filter": "resource.type=\"cloud_run_revision\" AND resource.labels.service_name=\"'${SERVICE}'\"",
"orderBy": "timestamp desc",
"pageSize": 20
}' | jq '.entries[] | {timestamp, severity, textPayload}'

Phase 6 — Explore Cloud Monitoring [MANUAL]

Step 6.1 — View Request Metrics

Navigate to Monitoring > Metrics Explorer and query:

Request count by response code:

fetch cloud_run_revision
| metric 'run.googleapis.com/request_count'
| filter resource.service_name == '${SERVICE}'
| group_by [metric.response_code_class], [value_request_count_aggregate: aggregate(value.request_count)]
| every 1m

Request latencies (p99):

fetch cloud_run_revision
| metric 'run.googleapis.com/request_latencies'
| filter resource.service_name == '${SERVICE}'
| align delta(1m)
| every 1m
| percentile(99)

Step 6.2 — Monitor Instance Count

Active container instance count:

fetch cloud_run_revision
| metric 'run.googleapis.com/container/instance_count'
| filter resource.service_name == '${SERVICE}'
| group_by [metric.state], [value: mean(value.instance_count)]
| every 1m

Generate load to observe scale-up behaviour:

for i in {1..50}; do
curl -s -o /dev/null "${SERVICE_URL}" &
done
wait

Step 6.3 — Check Uptime Checks

Navigate to Monitoring > Uptime checks to view the uptime check configured by the module.

Expected result: The check shows passing status, probing your service URL from multiple global locations.

REST API equivalent:

curl -s -H "Authorization: Bearer ${TOKEN}" \
"https://monitoring.googleapis.com/v3/projects/${PROJECT}/uptimeCheckConfigs" \
| jq '.uptimeCheckConfigs[] | {displayName, httpCheck, period, selectedRegions}'

gcloud equivalent:

gcloud monitoring uptime list-configs --project=${PROJECT}

Phase 7 — Undeploy [AUTOMATED]

When you are finished, return to the RAD UI, navigate to your deployment, and click Undeploy (or Delete) to remove all resources provisioned by this module.

Expected undeploy times:

ResourceTypical duration
Cloud Run service and revisions1–2 minutes
Cloud Run Jobs< 1 minute
Secret Manager secrets< 1 minute
GCS buckets1–2 minutes
Cloud SQL database and user1–2 minutes
Artifact Registry images1–2 minutes
Uptime checks and alert policies< 1 minute
Total6–12 minutes

Resources provisioned by the Services GCP module (VPC, Cloud SQL instance, GKE cluster) are managed separately and must be undeployed via their own RAD UI deployment entry.


Summary

ActionPhaseAutomated
Configure variables in RAD UI1.1Manual
Build image and deploy to Cloud Run1.2Automated
Note outputs from RAD UI deployment panel1.3Manual
Access the application URL2Manual
Inspect Secret Manager secrets2Manual
Explore revisions, traffic splitting, concurrency3Manual
Inspect GCS bucket and storage volumes4Manual
Query structured logs in Cloud Logging5Manual
View request latency, instance count, uptime checks6Manual
Undeploy all module resources7Automated