Skip to main content

Sample Application on Google Cloud Run

Sample Application on Google Cloud Run

The Sample module is a reference implementation that demonstrates how application modules are built on this platform. It deploys a minimal Flask web application (Python 3.11, PostgreSQL 15, optional Redis, optional NFS) on Cloud Run v2 on top of the App_CloudRun foundation, which provisions and manages the shared Google Cloud infrastructure.

This guide focuses on the cloud services the Sample application uses and how to explore and operate them from the Google Cloud Console and the command line. For the mechanics common to every Cloud Run application — service identity, ingress and load balancing, scaling and concurrency, CI/CD, Cloud Armor, IAP, Binary Authorization, VPC Service Controls, backups, and the deployment lifecycle — refer to the App_CloudRun foundation guide rather than repeating them here.


1. Overview

The Sample application runs as a Python/Gunicorn container on Cloud Run v2. The deployment wires together a focused set of Google Cloud services:

CapabilityGoogle Cloud serviceNotes
ComputeCloud Run v2Flask/Gunicorn service, 1 vCPU / 512 MiB by default, request-based autoscaling
DatabaseCloud SQL for PostgreSQL 15Required; the db-init job creates the schema on first deploy
Shared filesFilestore (NFS)Enabled by default; shared volume mounted at /mnt/nfs (requires gen2 execution environment)
Object storageCloud StorageA single data bucket provisioned by default
Cache & sessionsRedisOptional (enable_redis = false by default); when enabled, an internal redis:alpine service is deployed
SecretsSecret ManagerAuto-generated Flask SECRET_KEY stored at deploy time
IngressCloud Run URL / Cloud Load BalancingDefault run.app URL; optional external HTTPS load balancer + custom domain

Sensible defaults worth knowing up front:

  • PostgreSQL 15 is fixed. The database engine is set to POSTGRES_15 by Sample_Common and cannot be changed to MySQL or NONE in this module.
  • A db-init job runs on first deploy to create the PostgreSQL database, user, and schema. It is idempotent and safe to re-run.
  • Redis is disabled by default. When enable_redis = true, an internal redis:alpine Cloud Run service is deployed. Unlike the GKE variant, there is no automatic fallback to 127.0.0.1 — you must set redis_host explicitly to the service's internal URL or a Cloud Memorystore private IP.
  • The Flask SECRET_KEY is auto-generated and stored in Secret Manager; it is never set in plain text.
  • min_instance_count defaults to 0 (scale-to-zero). The module does not override this; set it to 1 if you want to eliminate cold starts.
  • Health probes target /healthz — a Cloud Run TCP startup probe and HTTP liveness probe against the /healthz endpoint (returns {"status": "healthy"}).

2. Google Cloud Services & How to Explore Them

All commands assume PROJECT and REGION are set. Service and resource names are reported in the deployment Outputs.

A. Cloud Run — the Sample service

The Flask application runs as a Cloud Run v2 service that autoscales by request load between the minimum and maximum instance counts. Each deployment creates an immutable revision; traffic can be split across revisions for safe rollouts.

  • Console: Cloud Run → select the service for revisions, traffic, logs, and metrics.
  • CLI:
    gcloud run services list --project "$PROJECT" --region "$REGION"
    gcloud run services describe <service-name> --project "$PROJECT" --region "$REGION"
    gcloud run revisions list --service <service-name> --project "$PROJECT" --region "$REGION"

See App_CloudRun for scaling, concurrency, execution environment, and traffic splitting.

B. Cloud SQL for PostgreSQL 15

The Sample application stores its visitor counter in a managed Cloud SQL for PostgreSQL 15 instance. The service connects privately through the Cloud SQL Auth Proxy over a Unix socket (no public IP). On first deploy an initialization Job creates the application database, user, and grants privileges.

  • Console: SQL → select the instance for connections, backups, flags, metrics.
  • CLI:
    gcloud sql instances list --project "$PROJECT"
    gcloud sql instances describe <instance-name> --project "$PROJECT"
    gcloud sql connect <instance-name> --user=<db-user> --database=<db-name> --project "$PROJECT"

The instance name, database, user, and password secret are in the Outputs. See App_CloudRun for the connection model, backups, and password rotation.

C. Filestore (NFS) and Cloud Storage

When enable_nfs = true (the default), a Filestore (NFS) share is mounted into the Cloud Run service so all instances share the same files. This requires the gen2 execution environment. A dedicated Cloud Storage bucket is also provisioned.

  • Console: Filestore → Instances; Cloud Storage → Buckets.
  • CLI:
    gcloud filestore instances list --project "$PROJECT"
    gcloud storage buckets list --project "$PROJECT"
    gcloud storage ls gs://<data-bucket>/ # bucket name is in the Outputs

See App_CloudRun for the NFS mount, GCS Fuse, and CMEK.

D. Redis cache (optional)

When enable_redis = true, an internal redis:alpine Cloud Run service is deployed alongside the application. The Flask app uses it for server-side session storage. The environment variables ENABLE_REDIS, REDIS_HOST, and REDIS_PORT are injected automatically. You must set redis_host explicitly — Cloud Run instances cannot reach a co-located service via 127.0.0.1.

  • Console: Cloud Run — the Redis service appears as a separate Cloud Run service in the same project and region.
  • CLI:
    gcloud run services list --project "$PROJECT" --region "$REGION"
    gcloud run services describe <redis-service-name> --project "$PROJECT" --region "$REGION"

E. Secret Manager

The Flask SECRET_KEY is auto-generated on first deploy and stored as a Secret Manager secret. The database password is also managed in Secret Manager by the foundation.

  • Console: Security → Secret Manager.
  • CLI:
    gcloud secrets list --project "$PROJECT"
    gcloud secrets versions access latest --secret=<secret-name> --project "$PROJECT"

See App_CloudRun for injection and rotation details.

F. Networking & ingress

The service is reachable at its run.app URL by default. An external HTTPS load balancer with a custom domain, Cloud CDN, and Cloud Armor can be layered on; ingress settings and VPC egress control connectivity.

  • Console: Cloud Run (service URL); Network services → Load balancing.
  • CLI:
    gcloud run services describe <service-name> --region "$REGION" --format='value(status.url)'
    gcloud compute addresses list --project "$PROJECT"

See App_CloudRun.

G. Cloud Logging & Monitoring

Container logs flow to Cloud Logging; Cloud Run and Cloud SQL metrics flow to Cloud Monitoring, with optional uptime checks and alert policies.

  • Console: Logging → Logs Explorer; Monitoring → Dashboards / Alerting.
  • CLI:
    gcloud run services logs read <service-name> --project "$PROJECT" --region "$REGION" --limit 50

3. Sample Application Behaviour

  • First-deploy database setup. An initialization Job runs db-init.sh (using the postgres:15-alpine image) which idempotently creates the PostgreSQL database user, database, and grants privileges. It is safe to re-run.
  • Health probes. The startup probe is TCP (checks port 8080 is open). The liveness probe targets GET /healthz, which returns {"status": "healthy"} immediately without a database query.
  • Visitor counter. The root route (GET /) increments a persistent counter in the PostgreSQL visitors table, demonstrating both database connectivity and (when Redis is enabled) per-session tracking.
  • Database diagnostics. GET /db executes SELECT version() and returns the PostgreSQL version string — useful for quickly verifying database connectivity.
  • Redis session handling. When enable_redis = true and redis_host is set to a reachable endpoint, the Flask app uses Flask-Session with a Redis backend. When REDIS_HOST is empty, a warning is logged and sessions fall back to signed cookies.
  • Flask SECRET_KEY. The auto-generated key is retrieved from Secret Manager and injected as the SECRET_KEY environment variable at instance startup. It is used for session signing.
  • Inspect running instances:
    gcloud run services describe <service-name> --region "$REGION" --project "$PROJECT"
    gcloud run revisions list --service <service-name> --region "$REGION" --project "$PROJECT"

4. Configuration Variables

Variables are grouped exactly as they appear on the deployment platform. Only settings specific to or notable for Sample_CloudRun are listed; every other input is inherited from App_CloudRun with its standard behaviour.

Group 1 — Project & Identity

VariableDefaultDescription
project_id(required)Target Google Cloud project.
regionus-central1Region for the service and regional resources.

Group 2 — Deployment Environment

VariableDefaultDescription
tenant_deployment_iddemoShort suffix that makes resource names unique per environment.
support_users[]Emails granted project access and monitoring alerts.
resource_labels{}Labels applied to all resources.

Group 3 — Application Identity

VariableDefaultDescription
application_namecloudrunappBase name for resources. Do not change after first deploy.
application_display_nameCloudrun ApplicationFriendly name shown in the Console.
application_description(set)Service description.
application_versionlatestContainer image version tag.
application_database_namesampleappPostgreSQL database name. Immutable after first deploy.
application_database_usercloudrunappApplication user. Immutable after first deploy.

Group 4 — Runtime & Scaling

VariableDefaultDescription
deploy_applicationtrueSet false to provision infrastructure only.
container_image_sourceprebuilt"prebuilt" deploys an existing image; "custom" builds via Cloud Build.
container_imageus-docker.pkg.dev/cloudrun/container/helloImage URI when container_image_source = "prebuilt".
cpu_limit1000mCPU per instance.
memory_limit512MiMemory per instance.
min_instance_count0Minimum instances (0 = scale-to-zero).
max_instance_count1Maximum instances.
container_port8080Flask/Gunicorn listens on port 8080.
execution_environmentgen2Required for NFS mounts.
enable_cloudsql_volumetrueCloud SQL Auth Proxy for socket connections.
traffic_split[]Split traffic across revisions for staged rollouts.
max_revisions_to_retain7How many old revisions to keep.

Group 5 — Access & Ingress Control

VariableDefaultDescription
ingress_settingsallWhich networks may reach the service (all / internal / internal-and-cloud-load-balancing).
vpc_egress_settingPRIVATE_RANGES_ONLYHow outbound traffic is routed through the VPC connector.
enable_iapfalseRequire Google sign-in via Identity-Aware Proxy.
iap_authorized_users / iap_authorized_groups[]Who may access through IAP.

Group 6 — Environment Variables & Secrets

VariableDefaultDescription
environment_variables{}Extra non-secret settings.
secret_environment_variables{}Map of env var → Secret Manager secret name.
secret_propagation_delay30Seconds to wait after secret creation before proceeding.
secret_rotation_period2592000sRotation notification frequency.

Group 7 — Backup & Restore

VariableDefaultDescription
backup_schedule0 2 * * *Automated backup cron (UTC).
backup_retention_days7Retention; raise for production/compliance.
enable_backup_import / backup_source / backup_uri / backup_formatrestore optionsRestore from a backup on deploy.

Group 8 — CI/CD & Binary Authorization

Standard App_CloudRun Cloud Build / Cloud Deploy integration — see App_CloudRun. Key inputs: enable_cicd_trigger, github_repository_url, github_token, enable_cloud_deploy, enable_binary_authorization.

Group 9 — Custom SQL Scripts

enable_custom_sql_scripts, custom_sql_scripts_bucket, custom_sql_scripts_path, custom_sql_scripts_use_root — run SQL from a GCS bucket after provisioning. See App_CloudRun.

Group 10 — Domain, CDN, Cloud Armor & Image Retention

VariableDefaultDescription
application_domains[]Custom hostnames for the external load balancer.
enable_cdnfalseEnable Cloud CDN on the load balancer backend.
enable_cloud_armor / admin_ip_rangesoffAttach a WAF policy / restrict privileged access.
max_images_to_retain / delete_untagged_images / image_retention_days(set)Artifact Registry cleanup policy.

Group 11 — Storage & Filesystem

VariableDefaultDescription
enable_nfstrueShared Filestore volume. Requires gen2 execution environment.
nfs_mount_path/mnt/nfsMount path inside the container.
nfs_instance_name""Name of an existing NFS VM; leave empty for auto-discovery.
nfs_instance_base_nameapp-nfsBase name for an inline NFS VM when none exists.
create_cloud_storage / storage_buckets / gcs_volumes(set)Data bucket / additional buckets / GCS Fuse mounts.
manage_storage_kms_iam / enable_artifact_registry_cmekfalseCMEK options.

Group 12 — Database Backend

VariableDefaultDescription
database_password_length32Generated password length (16–64).
enable_auto_password_rotation / rotation_propagation_delay_secoffDB password rotation.

Group 13 — Jobs & Scheduled Tasks

VariableDefaultDescription
initialization_jobs[]Leave empty to use the built-in db-init job from Sample_Common.
cron_jobs[]Recurring Cloud Run Jobs triggered by Cloud Scheduler.

Group 14 — Observability & Health

VariableDefaultDescription
startup_probe_configTCP, port 8080TCP startup probe (waits for port to open).
health_check_configHTTP GET /Liveness probe.
startup_probe / liveness_probeHTTP GET /healthzApplication-level probe settings passed to Sample_Common.
uptime_check_config{ enabled = false, path = "/" }Cloud Monitoring uptime check; disabled by default.
alert_policies[]Metric alert policies.

Group 21 — Redis Cache

VariableDefaultDescription
enable_redisfalseDeploy an internal Redis service and enable session storage.
redis_host""Must be set explicitly. No automatic fallback — leaving empty results in an empty REDIS_HOST and connection failure.
redis_port6379Redis port.
redis_auth""Optional Redis auth password (sensitive).

Group 22 — VPC Service Controls & Audit Logging

VariableDefaultDescription
enable_vpc_scfalseEnforce a VPC-SC perimeter (requires organization_id).
vpc_cidr_ranges / vpc_sc_dry_run(set)Access level CIDRs / dry-run mode.
enable_audit_loggingfalseDetailed Cloud Audit Logs.

5. Outputs

Returned on a successful deployment — the quickest way to locate and explore the running resources.

OutputDescription
service_nameCloud Run service name.
service_urlDefault run.app URL of the service.
service_locationRegion the service runs in.
stage_servicesStage-specific service URLs (Cloud Deploy).
load_balancer_ip / load_balancer_urlExternal HTTPS load balancer IP / URL (when enabled).
database_instance_nameCloud SQL instance name.
database_name / database_userApplication database name / user.
database_password_secretSecret Manager secret holding the DB password.
database_host / database_portDB endpoint / port.
storage_bucketsCreated Cloud Storage buckets.
network_name / network_exists / regionsVPC network, presence, regions.
container_image / container_registryDeployed image and Artifact Registry repo.
monitoring_enabled / monitoring_notification_channels / uptime_check_namesMonitoring status, channels, uptime checks.
initialization_jobsNames of the setup jobs.
deployment_id / tenant_id / resource_prefixNaming identifiers.
project_id / project_numberProject identifiers.
cicd_enabled / github_repository_url / github_repository_owner / github_repository_name / cicd_configurationCI/CD status and details.
artifact_registry_repository / cloudbuild_trigger_name / cloudbuild_trigger_idRegistry and build trigger.
vpc_sc_enabled / vpc_sc_perimeter_name / vpc_sc_dry_run_modeVPC-SC status.
audit_logging_enabled / artifact_registry_cmek_enabledAudit logging and CMEK status.

6. Configuration Pitfalls & Sensible Defaults

Risk: Critical (data loss / outage / security) — High (service degraded) — Medium (cost or partial degradation) — Low (minor).

SettingSensible valueRiskConsequence if wrong
database_type (via Sample_Common)PostgreSQL 15 (fixed)CriticalThe db-init script uses PostgreSQL-specific commands; a different engine breaks database setup.
application_database_name / _userset onceCriticalImmutable after first deploy; renaming recreates the DB/user and destroys data.
application_nameset onceCriticalEmbedded in Cloud Run service name, Artifact Registry repo, and Secret Manager secret IDs. Changing orphans existing secrets.
enable_backup_importfalse unless restoringCriticalEnabling without a valid backup_uri fails the import job.
container_port8080CriticalMismatch causes the TCP startup probe to fail — revision never becomes healthy.
enable_cloudsql_volumetrueCriticalfalse with PostgreSQL: all DB connections fail at startup. The db-init job also fails.
execution_environmentgen2Highgen1 with enable_nfs = true: NFS mount fails at container startup.
enable_redisfalse (default)Hightrue without redis_host set: REDIS_HOST is empty and the Flask app cannot connect to Redis.
memory_limit512Mi or moreHighToo little memory causes the Flask app to be OOM-killed on startup.
ingress_settingsall for testing; internal-and-cloud-load-balancing with Cloud ArmorMediumUsing all with Cloud Armor lets requests bypass the WAF via the *.run.app URL.
enable_iap / enable_cloud_armorenable for productionMediumThe application is otherwise publicly reachable.
min_instance_count1 for latency-sensitive workloadsMedium0 means cold starts (5–10 s) under load.
enable_vpc_sc with vpc_sc_dry_run = falsetest in dry-run firstCriticalIf any SA or IP is missing from the access level, Cloud Run, Cloud SQL, and Secret Manager access all fail simultaneously.
backup_retention_days7 (raise for prod)MediumToo short for compliance retention.

For the foundation behaviour referenced throughout — service identity, scaling and concurrency, ingress and load balancing, CI/CD, Cloud Armor, IAP, Binary Authorization, VPC-SC, backups, and image mirroring — see App_CloudRun. The shared application configuration (Flask secret, database bootstrap, probe behaviour, and Redis sidecar) is described in Sample_Common.