App CloudRun — Lab 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
| Requirement | Detail |
|---|---|
| gcloud CLI | Authenticated (gcloud auth login) |
| GCP project with billing | Active billing account linked |
| Services GCP module deployed | Provides VPC, Cloud SQL, Artifact Registry, and Filestore |
| Service account | roles/owner granted in the target project |
| RAD UI access | Permission 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.
| Variable | Default | Description |
|---|---|---|
project_id | (required) | GCP project ID to deploy into |
deployment_id | (auto-generated) | Short alphanumeric suffix appended to all resource names |
region | us-central1 | GCP region for resource deployment |
tenant_deployment_id | demo | Unique tenant/environment identifier used in resource naming |
application_name | crapp | Base name for the Cloud Run service and associated resources |
application_version | 1.0.0 | Container image version tag |
container_image_source | custom | custom to build via Cloud Build; prebuilt to deploy an existing image URI |
container_image | "" | Full image URI — required when container_image_source = "prebuilt" |
deploy_application | true | Set to false to provision infrastructure only without deploying the container |
min_instance_count | 0 | Minimum Cloud Run instances (0 = scale to zero when idle) |
max_instance_count | 1 | Maximum Cloud Run instances; acts as a cost ceiling |
container_resources | { cpu_limit = "1000m", memory_limit = "512Mi" } | CPU and memory limits per container instance |
database_type | POSTGRES | Cloud SQL engine: POSTGRES, MYSQL, or NONE |
application_database_name | crappdb | PostgreSQL/MySQL database name |
application_database_user | crappuser | Database user name |
enable_redis | true | Injects REDIS_HOST/REDIS_PORT environment variables |
enable_nfs | true | Provisions Cloud Filestore NFS and mounts it at /mnt/nfs |
enable_cloud_armor | false | Provisions a Global HTTPS Load Balancer with Cloud Armor WAF |
enable_iap | false | Enables 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:
| Resource | Typical duration |
|---|---|
| Secret Manager secrets | < 1 minute |
| Cloud SQL database and user | 2–5 minutes |
| Cloud Build image build (custom mode) | 5–10 minutes |
| NFS setup Cloud Run Job | 2–4 minutes |
| Database init Cloud Run Job | 1–3 minutes |
| Cloud Run service deployment | 2–5 minutes |
| Uptime check and alert policies | 1–2 minutes |
| Total | 15–30 minutes |
Step 1.3 — Record Outputs
After deployment completes, the following outputs are available in the RAD UI deployment panel.
| Output | Description |
|---|---|
service_name | Name of the deployed Cloud Run service |
service_url | Public HTTPS URL of the Cloud Run service |
service_location | GCP region where the service is running |
database_instance_name | Cloud SQL instance name |
database_name | Application database name |
database_user | Application database username |
database_password_secret | Secret Manager secret name for the database password |
storage_buckets | GCS bucket names created for the application |
container_registry | Artifact Registry repository name |
deployment_id | Unique deployment identifier |
resource_prefix | Resource naming prefix applied to all resources |
initialization_jobs | Names of Cloud Run initialisation jobs |
nfs_setup_job | Name of the NFS setup Cloud Run Job |
uptime_check_names | Names of the configured uptime checks |
deployment_summary | Human-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:
- Go to Cloud Run > your service > Edit & Deploy New Revision.
- After deploying, go to the Revisions tab.
- Click Manage Traffic and split traffic between two revisions (e.g., 90% latest, 10% previous).
- 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 countautoscaling.knative.dev/maxScale— maximum instance countrun.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:
| Resource | Typical duration |
|---|---|
| Cloud Run service and revisions | 1–2 minutes |
| Cloud Run Jobs | < 1 minute |
| Secret Manager secrets | < 1 minute |
| GCS buckets | 1–2 minutes |
| Cloud SQL database and user | 1–2 minutes |
| Artifact Registry images | 1–2 minutes |
| Uptime checks and alert policies | < 1 minute |
| Total | 6–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
| Action | Phase | Automated |
|---|---|---|
| Configure variables in RAD UI | 1.1 | Manual |
| Build image and deploy to Cloud Run | 1.2 | Automated |
| Note outputs from RAD UI deployment panel | 1.3 | Manual |
| Access the application URL | 2 | Manual |
| Inspect Secret Manager secrets | 2 | Manual |
| Explore revisions, traffic splitting, concurrency | 3 | Manual |
| Inspect GCS bucket and storage volumes | 4 | Manual |
| Query structured logs in Cloud Logging | 5 | Manual |
| View request latency, instance count, uptime checks | 6 | Manual |
| Undeploy all module resources | 7 | Automated |