Skip to main content

Sample CloudRun Module — Configuration Guide

Sample CloudRun is a reference wrapper module that sits on top of App CloudRun. It deploys a pre-configured Flask application (Python 3.11, PostgreSQL 15, optional Redis, optional NFS) on Cloud Run, and serves as a working example of how to build a custom application module on top of App CloudRun.

Sample CloudRun composes two internal layers: Sample Common produces the application-specific configuration object, and App CloudRun provisions all GCP infrastructure. You do not interact with Sample Common directly — all inputs are exposed as variables on Sample CloudRun itself.


§1 · Module Overview

AttributeValue
Underlying platformApp CloudRun
Sub-moduleSample Common
ApplicationFlask (Python 3.11-slim), listening on port 8080
Default version"latest"
DatabaseCloud SQL PostgreSQL 15, initialised by the db-init job
Default imageus-docker.pkg.dev/cloudrun/container/hello (container_image_source = "prebuilt")
Min instances0hardcoded in sample.tf; overrides user input (see §9)
Max instances1
NFSOptional (enable_nfs = true by default), mounted at /mnt/nfs
RedisOptional (enable_redis = false by default); no NFS-server fallback
Platform-managed secretSECRET_KEY (auto-generated 32-char Flask secret key)
Platform-managed jobdb-init (PostgreSQL schema initialisation)

Wrapper Architecture

Sample_CloudRun (variables.tf / sample.tf / main.tf)
└─ Sample_Common ← resolves app config, db-init job, SECRET_KEY secret, Redis service
└─ App_CloudRun ← provisions all GCP infrastructure

Sample Common outputs:

  • config → merged into application_config (with min_instance_count = 0 forced)
  • secret_ids.FLASK_SECRET_KEY → injected as SECRET_KEY via module_secret_env_vars
  • storage_buckets → merged into module_storage_buckets
  • path → used to resolve scripts_dir

module_env_vars injects ENABLE_REDIS, REDIS_HOST, and REDIS_PORT from the Redis variables. REDIS_HOST is left empty when redis_host is not set — there is no NFS-server fallback (see §8.A).


§2 · IAM & Project Identity

VariableDefaultDescription
project_idGCP project ID. All resources are created in this project. Grant the Owner role to rad-module-creator@tec-rad-ui-2b65.iam.gserviceaccount.com.
tenant_deployment_id"demo"Short suffix appended to resource names. Use "prod", "staging", etc. for multiple environments in the same project.
resource_creator_identity"rad-module-creator@…"Service account used by Terraform. Override with a project-specific SA for production.
support_users[]Email addresses of users granted IAM access and added as monitoring alert recipients.
resource_labels{}Key-value labels applied to all resources (cost centre, team, environment).
deployment_id""Optional fixed deployment ID. A random hex ID is generated when left empty.

§3 · Core Service Configuration

§3.A · Application Identity

application_display_name and application_description are passed to Sample Common as display_name and description, then merged into application_config for App CloudRun.

VariableDefaultDescription
application_name"cloudrunapp"Internal identifier used as the base name for the Cloud Run service, Artifact Registry repository, and Secret Manager secrets. Do not change after initial deployment.
application_display_name"Cloudrun Application"Human-readable name shown in the platform UI and Cloud Run console. Safe to update at any time.
application_description"Sample application to showcase Cloudrun features"Brief description of the application. Populates the Cloud Run service description field.
application_version"latest"Version tag applied to the container image. Increment to trigger a new image build or revision.
application_database_name"cloudrunapp"PostgreSQL database name. Passed to Sample Common as db_name. Do not change after initial deployment.
application_database_user"cloudrunapp"PostgreSQL user. Passed to Sample Common as db_user. Password auto-generated.

§3.B · Resource Sizing

cpu_limit and memory_limit are flat scalar variables passed to Sample Common, which assembles them into the container_resources object consumed by App CloudRun.

VariableDefaultDescription
cpu_limit"1000m"CPU per instance (millicores). Increase for CPU-bound Flask workloads.
memory_limit"512Mi"Memory per instance. Increase for memory-intensive operations or large datasets.
min_instance_count0User-configurable, but overridden to 0 in sample.tf. Scale-to-zero is hardcoded for this reference module (see §9).
max_instance_count1Maximum concurrent instances. Increase when combined with Redis session store.
timeout_seconds300Maximum request duration (0–3600 s).
execution_environment"gen2"Required for NFS mounts when enable_nfs = true.

§3.C · Environment Variables & Secrets

VariableDefaultDescription
environment_variables{}Plain-text environment variables injected at runtime. For non-sensitive config such as feature flags, log levels, or API endpoints.
secret_environment_variables{}Map of env var name → Secret Manager secret name. Values resolved at runtime; never stored in plaintext.
secret_rotation_period"2592000s"Rotation reminder period (30 days default). Set null to disable.
secret_propagation_delay30Seconds to wait after secret creation before dependent operations proceed.

§3.D · Networking

VariableDefaultDescription
ingress_settings"all"Traffic sources permitted to reach Cloud Run. "all" = public internet; "internal" = VPC only; "internal-and-cloud-load-balancing" = when fronted by a GLB.
vpc_egress_setting"PRIVATE_RANGES_ONLY"Routes RFC 1918 traffic via VPC; public traffic exits directly. Change to "ALL_TRAFFIC" for strict egress controls.
container_port8080Port the Flask application listens on. Must match the application's bind port.
container_protocol"http1"HTTP version: "http1" or "h2c".
enable_cloudsql_volumetrueInjects Cloud SQL Auth Proxy sidecar for Unix socket connections to Cloud SQL.
cloudsql_volume_mount_path"/cloudsql"Path where the Cloud SQL Auth Proxy Unix socket is mounted.

§3.E · Container Image & Build

By default the module deploys the Cloud Run hello container (prebuilt). Set container_image_source = "custom" to build the bundled sample Flask app from the Sample_Common/scripts/Dockerfile via Cloud Build.

VariableDefaultDescription
container_image_source"prebuilt""prebuilt" = deploy an existing image; "custom" = build via Cloud Build from container_build_config.
container_image"us-docker.pkg.dev/cloudrun/container/hello"Image URI when container_image_source = "prebuilt".
container_build_config{ enabled = false }Cloud Build config when container_image_source = "custom". Set enabled = true and provide dockerfile_path, context_path, build_args, artifact_repo_name.
enable_image_mirroringtrueMirrors the image into Artifact Registry before deploy. Recommended to avoid Docker Hub rate limits.
deploy_applicationtrueSet false to provision infrastructure without deploying the container.

§4 · Advanced Security

§4.A · Automated Password Rotation

VariableDefaultDescription
enable_auto_password_rotationfalseDeploys a Cloud Run + Eventarc automated rotation job. Rotates the database password on the schedule set by secret_rotation_period.
rotation_propagation_delay_sec90Seconds to wait after rotation before Cloud Run restarts to pick up the new value.
secret_rotation_period"2592000s"Rotation reminder interval (30 days default). Also used as trigger period when rotation is enabled.

§4.B · VPC Service Controls

VariableDefaultDescription
enable_vpc_scfalseEnforces VPC-SC perimeter. Restricts GCP API calls to requests from inside the perimeter. Requires an existing VPC-SC perimeter in the project.
vpc_cidr_ranges[]VPC subnet CIDR ranges for the VPC-SC network access level. Auto-discovered from the VPC network when empty; falls back to 10.0.0.0/8 if discovery finds nothing.
vpc_sc_dry_runtrueWhen true, VPC-SC violations are logged but not blocked — recommended for initial rollout. Set to false to actively enforce the perimeter.
organization_id""GCP Organization ID for the Access Context Manager policy. Auto-discovered from the project when empty.
enable_audit_loggingfalseEnables detailed Cloud Audit Logs (DATA_READ, DATA_WRITE, ADMIN_READ) for all supported services.

§4.C · Identity-Aware Proxy

VariableDefaultDescription
enable_iapfalseEnables Cloud Run native IAP. Requires Google identity authentication before the application is accessible.
iap_authorized_users[]Users granted access: "user:alice@example.com".
iap_authorized_groups[]Google Groups granted access: "group:engineering@example.com".

§4.D · Cloud Armor & CDN

VariableDefaultDescription
enable_cloud_armorfalseProvisions a Global HTTPS Load Balancer with Cloud Armor WAF policy. Required when application_domains is set.
application_domains[]Custom domains. Google-managed SSL certificates are provisioned per domain. DNS must point to the GLB IP first.
enable_cdnfalseEnables Cloud CDN on the GLB to cache static assets at edge. Only used when enable_cloud_armor = true.
admin_ip_ranges[]IP CIDR ranges permitted for direct administrative access.
max_images_to_retain7Maximum number of recent container images to keep in Artifact Registry per deployment. Set 0 to disable.
delete_untagged_imagestrueAutomatically deletes untagged images (dangling layers, intermediate build artefacts) from the Artifact Registry repository.
image_retention_days30Days after which container images are eligible for deletion from Artifact Registry. Set 0 to disable age-based deletion.

§4.E · Binary Authorization

VariableDefaultDescription
enable_binary_authorizationfalseEnforces Binary Authorization policy. Images must carry a valid attestation before deployment.

§5 · Traffic & Ingress

§5.A · Traffic Splitting

VariableDefaultDescription
traffic_split[]Canary or blue-green traffic allocations across Cloud Run revisions. All entries must sum to 100%. Leave empty to route all traffic to the latest revision.
max_revisions_to_retain7Maximum number of Cloud Run revisions to keep after each deployment. Revisions actively serving traffic are never deleted. Set to 0 to disable pruning.

Example:

traffic_split = [
{ type = "TRAFFIC_TARGET_ALLOCATION_TYPE_LATEST", percent = 90 },
{ type = "TRAFFIC_TARGET_ALLOCATION_TYPE_REVISION", percent = 10, revision = "cloudrunapp-00003-abc" },
]

§5.B · Service Annotations & Labels

VariableDefaultDescription
service_annotations{}Kubernetes-style annotations on the Cloud Run service resource.
service_labels{}Labels on the Cloud Run service (in addition to resource_labels).

§6 · CI/CD Integration

§6.A · GitHub Integration

VariableDefaultDescription
enable_cicd_triggerfalseEnables a Cloud Build trigger that builds and deploys when code is pushed to the configured repository.
github_repository_url""Full HTTPS URL of the GitHub repository. Required when enable_cicd_trigger = true.
github_token""GitHub PAT for authentication. Mutually exclusive with github_app_installation_id.
github_app_installation_id""Cloud Build GitHub App installation ID. Preferred for organisation repositories.
cicd_trigger_config{ branch_pattern = "^main$" }Advanced trigger config: branch_pattern, included_files, ignored_files, trigger_name, substitutions.

§6.B · Cloud Deploy

VariableDefaultDescription
enable_cloud_deployfalseSwitches CI/CD to a managed Cloud Deploy pipeline. Requires enable_cicd_trigger = true.
cloud_deploy_stages[dev, staging, prod]Ordered promotion stages. prod requires manual approval by default.

§7 · Reliability & Data

§7.A · Health Probes

Sample CloudRun exposes two distinct sets of health probe variables:

  • startup_probe / liveness_probe → passed to Sample Common (application config within application_config)
  • startup_probe_config / health_check_config → passed directly to App CloudRun (the actual Cloud Run container health checks)

The startup_probe_config / health_check_config pair controls Cloud Run's live health checking behaviour. startup_probe / liveness_probe embed probe definitions in the app module config for downstream reference.

VariableDefaultDescription
startup_probe{ enabled = true, type = "HTTP", path = "/healthz", initial_delay_seconds = 60, timeout_seconds = 5, period_seconds = 10, failure_threshold = 3 }Application-level startup probe passed to Sample Common.
liveness_probe{ enabled = true, type = "HTTP", path = "/healthz", initial_delay_seconds = 30, timeout_seconds = 5, period_seconds = 30, failure_threshold = 3 }Application-level liveness probe passed to Sample Common.
startup_probe_config{ enabled = true }Cloud Run infrastructure startup probe (TCP, timeout_seconds = 240, period_seconds = 240, failure_threshold = 1). Passed directly to App CloudRun.
health_check_config{ enabled = true }Cloud Run infrastructure liveness probe (HTTP, path = "/", timeout_seconds = 1, period_seconds = 10, failure_threshold = 3). Passed directly to App CloudRun.
uptime_check_config{ enabled = true, path = "/" }Cloud Monitoring uptime check. check_interval and timeout use "Ns" format.
alert_policies[]Metric-threshold alert policies. Each entry: name, metric_type, comparison, threshold_value, duration_seconds.

§7.B · Storage

VariableDefaultDescription
enable_nfstrueProvisions a Cloud Filestore NFS instance. Requires execution_environment = "gen2".
nfs_mount_path"/mnt/nfs"Container mount path for the NFS volume.
nfs_instance_name""Name of an existing NFS GCE VM to use directly. Leave empty to auto-discover or create inline.
nfs_instance_base_name"app-nfs"Base name for the inline NFS GCE VM when none is found. Deployment ID is appended.
storage_buckets[{ name_suffix = "data" }]GCS buckets to provision. Sample Common may provision additional buckets via module_storage_buckets.
create_cloud_storagetrueSet false to skip GCS bucket provisioning.
gcs_volumes[]GCS buckets to mount as GCS Fuse volumes inside the container.
manage_storage_kms_iamfalseCreates a CMEK KMS keyring and grants the GCS service account the encrypter/decrypter role, enabling CMEK on all storage buckets.
enable_artifact_registry_cmekfalseCreates an Artifact Registry KMS key and enables CMEK encryption of container images.

§7.C · Database

VariableDefaultDescription
application_database_name"cloudrunapp"PostgreSQL database name, passed to Sample Common as db_name. Initialised by the db-init job on first deployment.
application_database_user"cloudrunapp"PostgreSQL user, passed as db_user. Password auto-generated.
database_password_length32Auto-generated password length (16–64 characters). Default is 32.
enable_auto_password_rotationfalseAutomated password rotation. See §4.A.
rotation_propagation_delay_sec90Seconds to wait after rotation before Cloud Run restarts.

§7.D · Backup & Recovery

backup_uri is aliased to backup_file in main.tf (backup_file = var.backup_uri).

VariableDefaultDescription
backup_schedule"0 2 * * *"Cron expression (UTC) for automated backups. Leave empty to disable.
backup_retention_days7Days to retain backup files before automatic deletion.
enable_backup_importfalseTriggers a one-time database restore on the next terraform apply.
backup_source"gcs"Source: "gcs" (full GCS URI) or "gdrive" (Google Drive file ID).
backup_uri""For GCS: e.g. "gs://my-bucket/backups/app.sql". Mapped to backup_file in App CloudRun.
backup_format"sql"Format: sql, gz, tar, tgz, tar.gz, zip, auto.

§8 · Integrations

§8.A · Redis

Redis is disabled by default (enable_redis = false). When enabled, Sample Common deploys an internal redis:alpine Cloud Run additional service. ENABLE_REDIS, REDIS_HOST, and REDIS_PORT are injected via module_env_vars.

Important: REDIS_HOST is left empty when redis_host is not set. Unlike other modules (e.g. OpenEMR CloudRun), there is no NFS-server-IP fallback. Cloud Run instances are network-isolated — they cannot reach a co-located Redis via 127.0.0.1. You must set redis_host to the IP or internal URL of your Redis instance (e.g. a Cloud Memorystore private IP, or the Cloud Run internal URL of the Redis additional service).

VariableDefaultDescription
enable_redisfalseDeploys an internal redis:alpine Cloud Run service. Injects ENABLE_REDIS, REDIS_HOST, REDIS_PORT into the application container.
redis_host""Must be set explicitly. If left empty, REDIS_HOST is an empty string and the application cannot connect to Redis.
redis_port6379Redis TCP port. Note: this is a number type, unlike other modules where it is a string.
redis_auth""Redis AUTH password. Treated as sensitive; passed to App CloudRun. Leave empty for unauthenticated Redis.

§8.B · Custom SQL Scripts

VariableDefaultDescription
enable_custom_sql_scriptsfalseRuns .sql files from GCS against the PostgreSQL database after provisioning.
custom_sql_scripts_bucket""GCS bucket name (without gs://) containing the scripts.
custom_sql_scripts_path""Path prefix within the bucket. Files run in lexicographic order.
custom_sql_scripts_use_rootfalseRun scripts as the root database user.

§8.C · Jobs & Scheduled Tasks

VariableDefaultDescription
initialization_jobs[]Cloud Run jobs executed once during deployment. Supplements the platform-managed db-init job from Sample Common.
cron_jobs[]Recurring Cloud Scheduler-triggered jobs. Each entry: name, schedule (cron, UTC).

§8.D · Observability

VariableDefaultDescription
uptime_check_config{ enabled = true, path = "/" }Cloud Monitoring uptime check.
alert_policies[]Metric-threshold alert policies.
service_annotations{}Kubernetes-style annotations on the Cloud Run service.
service_labels{}Labels on the Cloud Run service.

§9 · Platform-Managed Behaviours

These are set automatically by the module and cannot be overridden via input variables.

Scale-to-Zero Override

min_instance_count is always forced to 0 in sample.tf, regardless of the value you configure:

# sample.tf
local.sample_module = merge(module.sample_app.config, {
min_instance_count = 0 # hardcoded; overrides var.min_instance_count
})

This is intentional for a reference module that prioritises cost efficiency. Set min_instance_count = 1 in the variables if you adapt this module for production latency requirements (and update the hardcoded value in sample.tf).

Initialisation Job

JobWhat it does
db-initRuns the bundled db-init.sh script (postgres:15-alpine image) against the Cloud SQL PostgreSQL instance on first deployment. Creates the application schema. Managed by Sample Common.

Environment Variables (always injected)

VariableValue / SourceNotes
SECRET_KEYSecret Manager refAuto-generated 32-char Flask secret key, stored as FLASK_SECRET_KEY in Secret Manager. Injected via module_secret_env_vars.
ENABLE_REDIStostring(var.enable_redis)"true" or "false". Injected via module_env_vars.
REDIS_HOSTvar.redis_host (or "")Empty string when redis_host is not set. No NFS-server fallback.
REDIS_PORTtostring(var.redis_port)Only injected when enable_redis = true; otherwise "".

Conditional: Redis Additional Service

When enable_redis = true, Sample Common declares an additional_services entry that deploys a redis:alpine Cloud Run service alongside the main application. The service is internal-only (INGRESS_TRAFFIC_INTERNAL_ONLY).

Structural Wiring

BehaviourDetail
scripts_dirResolved as abspath("${module.sample_app.path}/scripts") — points to Sample Common's bundled scripts.
backup_uribackup_filevar.backup_uri is mapped to backup_file in main.tf.
startup_probeSample Commonvar.startup_probe is passed to Sample Common, embedding it in the application_config.
startup_probe_configApp CloudRunvar.startup_probe_config is passed directly to App CloudRun as the live Cloud Run infrastructure probe.
liveness_probe / health_check_configSame dual routing as startup probes above.

§10 · Variable Reference

Complete list of all input variables, grouped by UI section.

GroupVariableTypeDefaultUpdatable
0module_descriptionstring(long description)
0module_documentationstring"https://docs.radmodules.dev/docs/modules/Sample_CloudRun"
0module_dependencylist(string)["Services GCP"]
0module_serviceslist(string)(service list)
0credit_costnumber50
0require_credit_purchasesboolfalse
0enable_purgebooltrue
0public_accessbooltrue
0deployment_idstring""yes
0resource_creator_identitystring"rad-module-creator@…"yes
1project_idstringyes
1tenant_deployment_idstring"demo"yes
1support_userslist(string)[]yes
1resource_labelsmap(string){}yes
2application_namestring"cloudrunapp"
2application_display_namestring"Cloudrun Application"yes
2application_descriptionstring"Sample application to showcase Cloudrun features"yes
2application_versionstring"latest"yes
3deploy_applicationbooltrueyes
3container_image_sourcestring"prebuilt"yes
3container_imagestring"us-docker.pkg.dev/cloudrun/container/hello"yes
3container_build_configobject{ enabled = false }yes
3enable_image_mirroringbooltrueyes
3cpu_limitstring"1000m"yes
3memory_limitstring"512Mi"yes
3min_instance_countnumber0 (hardcoded to 0 in sample.tf)yes
3max_instance_countnumber1yes
3container_portnumber8080yes
3container_protocolstring"http1"yes
3execution_environmentstring"gen2"yes
3timeout_secondsnumber300yes
3enable_cloudsql_volumebooltrueyes
3cloudsql_volume_mount_pathstring"/cloudsql"yes
3traffic_splitlist(object)[]yes
3max_revisions_to_retainnumber7yes
3service_annotationsmap(string){}yes
3service_labelsmap(string){}yes
4ingress_settingsstring"all"yes
4vpc_egress_settingstring"PRIVATE_RANGES_ONLY"yes
4enable_iapboolfalseyes
4iap_authorized_userslist(string)[]yes
4iap_authorized_groupslist(string)[]yes
5environment_variablesmap(string){}yes
5secret_environment_variablesmap(string){}yes
5secret_rotation_periodstring"2592000s"yes
5secret_propagation_delaynumber30yes
6backup_schedulestring"0 2 * * *"yes
6backup_retention_daysnumber7yes
6enable_backup_importboolfalseyes
6backup_sourcestring"gcs"yes
6backup_uristring""yes
6backup_formatstring"sql"yes
7enable_cicd_triggerboolfalseyes
7github_repository_urlstring""yes
7github_tokenstring""yes
7github_app_installation_idstring""yes
7cicd_trigger_configobject{ branch_pattern = "^main$" }yes
7enable_cloud_deployboolfalseyes
7cloud_deploy_stageslist(object)[dev, staging, prod]yes
7enable_binary_authorizationboolfalseyes
8enable_custom_sql_scriptsboolfalseyes
8custom_sql_scripts_bucketstring""yes
8custom_sql_scripts_pathstring""yes
8custom_sql_scripts_use_rootboolfalseyes
9enable_cloud_armorboolfalseyes
9admin_ip_rangeslist(string)[]yes
9application_domainslist(string)[]yes
9enable_cdnboolfalseyes
9max_images_to_retainnumber7yes
9delete_untagged_imagesbooltrueyes
9image_retention_daysnumber30yes
8nfs_instance_namestring""yes
8nfs_instance_base_namestring"app-nfs"yes
10create_cloud_storagebooltrueyes
10storage_bucketslist(object)[{ name_suffix = "data" }]yes
10enable_nfsbooltrueyes
10nfs_mount_pathstring"/mnt/nfs"yes
10gcs_volumeslist(object)[]yes
10manage_storage_kms_iamboolfalseyes
10enable_artifact_registry_cmekboolfalseyes
11application_database_namestring"cloudrunapp"
11application_database_userstring"cloudrunapp"
11database_password_lengthnumber32yes
11enable_auto_password_rotationboolfalseyes
11rotation_propagation_delay_secnumber90yes
12initialization_jobslist(object)[]yes
12cron_jobslist(object)[]yes
13startup_probeobject{ type = "HTTP", path = "/healthz", initial_delay_seconds = 60, … }yes
13liveness_probeobject{ type = "HTTP", path = "/healthz", initial_delay_seconds = 30, … }yes
13startup_probe_configobject{ enabled = true } (TCP, timeout=240, period=240, threshold=1)yes
13health_check_configobject{ enabled = true } (HTTP, path="/", timeout=1, period=10, threshold=3)yes
13uptime_check_configobject{ enabled = true, path = "/" }yes
13alert_policieslist(object)[]yes
20enable_redisboolfalseyes
20redis_hoststring""yes
20redis_portnumber6379yes
20redis_authstring""yes
21enable_vpc_scboolfalseyes
21vpc_cidr_rangeslist(string)[]yes
21vpc_sc_dry_runbooltrueyes
21organization_idstring""yes
21enable_audit_loggingboolfalseyes

Configuration Pitfalls & Sensible Defaults

The table below identifies the variables most commonly misconfigured in Sample CloudRun deployments. Because Sample CloudRun is the reference implementation used to test App CloudRun Foundation Module changes, the pitfalls here also apply to any new application module built from this template.

Risk levels: Critical (data loss, full outage, security breach) — High (service unavailable or significant degradation) — Medium (degraded function or increased cost) — Low (minor impact).

VariableSensible DefaultRiskConsequence of Incorrect Value
application_name"sample" (default; do not change after first deploy)CriticalEmbedded in Cloud Run service name, Artifact Registry repo, Secret Manager secret IDs (including FLASK_SECRET_KEY). Changing after first deploy recreates all named resources — any state stored in Secret Manager is orphaned and new secrets are generated.
tenant_deployment_idMatch environment: "prod", "staging", "dev"CriticalChanging after first deploy recreates all named resources. The old Cloud SQL instance (if used) and Secret Manager secrets are orphaned. A new empty database is created.
application_versionA pinned tag (e.g. "1.0.0"); avoid "latest" in productionMedium"latest" makes rollback ambiguous. Cloud Run cannot distinguish between two "latest" revisions. Always pin to a digest or version tag in staging and production.
container_port8080 (Flask/Gunicorn default; set in Sample Common)CriticalMismatch: Cloud Run's startup probe fails immediately. All requests return 502. The revision never becomes healthy and enters a continuous restart loop.
startup_probe_config.path"/healthz" (Flask route that returns 200)Critical"/healthz" route not implemented in the sample Flask app: Cloud Run never routes traffic. The revision is healthy at the infra level but continuously restarts. Implement the route with return "ok", 200.
min_instance_count0 for dev/testing (scale-to-zero appropriate for a reference app)Medium0 in a load-testing scenario: cold starts (5–10 s for the sample Flask image) inflate p99 latency. Set min_instance_count = 1 when benchmarking App CloudRun Foundation Module changes to eliminate cold-start noise.
max_instance_count1 for dev; ≤ Cloud SQL max_connections ÷ pool_size for load testsHighExceeding Cloud SQL connection limit during load tests: FATAL: sorry, too many clients already. All Flask instances fail DB queries simultaneously.
cpu_limit"1000m" (1 vCPU; sufficient for the hello-world pattern)MediumToo low (< 250m): CPU throttling causes slow Flask request handling and may cause the startup probe to time out. GCP bills minimum 0.083 vCPU for Cloud Run regardless.
memory_limit"512Mi" (sufficient for Flask + FLASK_SECRET_KEY)MediumToo low (< 128Mi): Flask is OOMKilled on startup when loading the application module and Secret Manager client libraries.
FLASK_SECRET_KEY (generated secret)Auto-generated 32-character random string stored in Secret ManagerHighNot injected into the Flask container: SECRET_KEY is unset, Flask raises RuntimeError on the first session or CSRF operation. Retrieve from Secret Manager: gcloud secrets versions access latest --secret=<PREFIX>-secret-key.
enable_cloudsql_volumetrue (default; required when database_type != "NONE")Criticalfalse with a PostgreSQL database: Flask must connect via TCP to Cloud SQL's private IP. If Private Service Access is not configured, all DB connections fail at startup. The db-init job also fails, blocking first-deploy.
execution_environment"gen2" (required for NFS mounts; recommended for all new deployments)High"gen1" with enable_nfs = true: NFS mount fails at container startup. All instances fail to start.
enable_nfsfalse (default for Sample; the reference app does not require shared storage)Lowtrue without the NFS server IP configured: the NFS mount hangs at container startup and the instance never becomes healthy. Only enable when testing NFS integration specifically.
ingress_settings"all" for testing; "internal-and-cloud-load-balancing" when using Cloud ArmorMedium"all" with Cloud Armor enabled: requests bypass the WAF via the direct *.run.app URL. For security testing the Sample module with Cloud Armor, use "internal-and-cloud-load-balancing".
vpc_egress_setting"PRIVATE_RANGES_ONLY" (default)Medium"PRIVATE_RANGES_ONLY" when Redis or Cloud SQL is on a non-RFC-1918 private IP: connections fail. Use "ALL_TRAFFIC" to route all egress via VPC for those configurations.
enable_iapfalse for public sample; true when testing IAP integrationHightrue without iap_oauth_client_id/iap_oauth_client_secret: IAP is silently disabled and the app is exposed without authentication. With credentials but no iap_authorized_users: all requests return HTTP 403.
enable_redisfalse (default; Sample does not use Redis by default)Lowtrue without redis_host set: the sample Flask app attempts to connect to an empty Redis host string, causing a ConnectionRefusedError on startup. Only enable Redis when specifically testing the Redis integration path.
binauthz_evaluation_mode"ALWAYS_ALLOW" (default; appropriate for a reference/test module)Critical"REQUIRE_ATTESTATION" in the Sample module without a CI attestation pipeline: no image can be deployed, including test images built locally. The Sample module is designed for testing — keep "ALWAYS_ALLOW" unless specifically testing Binary Authorization enforcement.
enable_vpc_scfalse (default); use vpc_sc_dry_run = true if testing VPC-SCCriticalenable_vpc_sc = true with vpc_sc_dry_run = false in a test environment: if any SA or IP is missing from the access level, Cloud Run, Cloud SQL, and Secret Manager access all fail simultaneously. Always test VPC-SC in dry-run mode first.
enable_audit_loggingfalse for dev/testLowtrue in a high-traffic test environment: audit logs for Secret Manager reads (one per container startup for FLASK_SECRET_KEY) accumulate rapidly and increase Cloud Logging costs. Keep disabled for load tests.

Destroying Resources

Known Deletion Issue: Serverless IPv4 Address Release

When destroying a Cloud Run deployment, you may encounter an error similar to:

Error: Error waiting for Subnetwork to be deleted: The following serverless IPv4 address(es) on subnet ... are still in use.

Cause: GCP holds serverless IPv4 addresses on the VPC subnet asynchronously after a Cloud Run service is deleted. These addresses are released by GCP approximately 20–30 minutes after the Cloud Run service is removed. Terraform/OpenTofu cannot complete the subnet or VPC deletion until they are fully released.

Resolution: Wait 20–30 minutes after the initial destroy attempt, then re-run the destroy command:

tofu destroy

The second run will succeed once GCP has released the reserved addresses.