Skip to main content

Django_CloudRun Module — Configuration Guide

Django is a high-level Python web framework that encourages rapid development and clean, pragmatic design. This module deploys a production-ready Django application on Google Cloud Run, backed by a managed Cloud SQL PostgreSQL instance, GCS media storage, and Secret Manager for secrets including the Django SECRET_KEY.

Django_CloudRun is a wrapper module built on top of App_CloudRun. It uses App_CloudRun for all GCP infrastructure provisioning (Cloud Run service, networking, Cloud SQL, GCS, Filestore, secrets, CI/CD) and adds Django-specific application configuration on top via the Django_Common sub-module.

Note: Variables marked as platform-managed are set and maintained by the platform. You do not normally need to change them.


How This Guide Is Structured

This guide documents only the variables that are unique to Django_CloudRun or that have Django-specific defaults that differ from the App_CloudRun base module. For all other variables — project identity, runtime scaling, CI/CD, backup, custom SQL, storage, networking, IAP, Cloud Armor, and VPC Service Controls — refer directly to the App_CloudRun Configuration Guide.

Variables fully covered by the App_CloudRun guide:

Configuration AreaApp_CloudRun_Guide SectionDjango-Specific Notes
Module Metadata & ConfigurationGroup 0Different defaults for module_description and module_documentation.
Project & IdentityGroup 1Refer to base App_CloudRun module documentation.
Application IdentityGroup 2See Django Application Identity below. application_name defaults to "django".
Runtime & ScalingGroup 3min_instance_count defaults to 0 (scale-to-zero). container_port defaults to 8080. enable_cloudsql_volume defaults to true (Unix socket connection to Cloud SQL).
Environment Variables & SecretsGroup 4Django_Common injects DB_HOST, DB_ENGINE, SECRET_KEY, and other database variables automatically — see Platform-Managed Behaviours.
Observability & HealthGroup 5See Django Health Probes — Django_CloudRun exposes a dual probe system with /healthz defaults.
Jobs & Scheduled TasksGroup 6See Initialization Jobs — a default db-init job is pre-configured.
CI/CD & GitHub IntegrationGroup 7Refer to base App_CloudRun module documentation.
Storage — NFSGroup 8enable_nfs defaults to true for Django. Requires execution_environment = "gen2" (the default).
Storage — GCSGroup 9Refer to base App_CloudRun module documentation. The media GCS bucket is provisioned automatically by Django_Common.
Redis CacheGroup 10See Redis Configuration — Django uses Redis for sessions and caching.
Database BackendGroup 11See Django Database Configuration — PostgreSQL required, extensions auto-installed.
Backup & MaintenanceGroup 12Refer to base App_CloudRun module documentation.
Custom Initialisation & SQLGroup 13Refer to base App_CloudRun module documentation.
Access & NetworkingGroup 14vpc_egress_setting defaults to "PRIVATE_RANGES_ONLY". ingress_settings defaults to "all". Refer to the App_CloudRun guide for full documentation.
Identity-Aware ProxyGroup 15Refer to base App_CloudRun module documentation.
Cloud Armor & CDNGroup 16Refer to base App_CloudRun module documentation.
VPC Service ControlsGroup 17Refer to base App_CloudRun module documentation.

Platform-Managed Behaviours

The following behaviours are applied automatically by Django_CloudRun (via the Django_Common sub-module) regardless of the variable values in your tfvars file. They cannot be overridden by user configuration.

BehaviourDetail
Django environment variablesDjango_Common injects the following environment variables automatically: DB_ENGINE (django.db.backends.postgresql), DB_HOST (Cloud SQL Auth Proxy socket path, e.g. /cloudsql/PROJECT:REGION:INSTANCE), DB_PORT (5432), DB_NAME, DB_USER. These values are derived from the Cloud SQL instance provisioned by App_CloudRun and do not need to be set manually in environment_variables.
Django secret keyA random SECRET_KEY is auto-generated and stored in Secret Manager. It is injected into the container as the SECRET_KEY environment variable via module_secret_env_vars. Do not set SECRET_KEY in environment_variables — the platform-managed value in Secret Manager takes precedence.
PostgreSQL extensionsThe following extensions are installed automatically in the application database during the initialisation job: pg_trgm, unaccent, hstore, citext. These are required for Django's full-text search, accent-insensitive lookups, and schema-flexible field types. You do not need to set enable_postgres_extensions = true for these extensions.
Database initialisationA dedicated Django database user is created with the password from Secret Manager and granted the permissions required by the application. The postgres superuser is used only for the extension and user setup jobs.
GCS media storageWhen gcs_volumes is configured (e.g. a bucket mounted at /app/media), Django_Common provisions the bucket and grants the application service account roles/storage.objectAdmin and roles/storage.legacyBucketReader. The Django container (running as UID 2000) can read and write user-uploaded media files directly to the GCS-mounted path.
Non-root container userThe Django container runs as a non-root user (UID 2000). This UID matches the GCS FUSE user mapping to ensure write permissions on the media mount. Do not change the container's UID unless you also update the GCS FUSE mount configuration.
NFS enabled by defaultenable_nfs defaults to true. Requires execution_environment = "gen2" (the default). If you configure GCS volumes for media instead of NFS, set enable_nfs = false to suppress Filestore provisioning.
Default db-init jobThe initialization_jobs variable includes a pre-configured db-init job that creates the Django database and user. This job runs automatically on the first deployment. See Initialization Jobs.

Django Application Identity

These variables have Django-specific defaults. Their semantics are identical to the equivalents in App_CloudRun_Guide Group 2.

VariableDefaultDescription & Implications
application_name"django"Internal identifier used as the base name for the Cloud Run service, Artifact Registry repository, Secret Manager secrets, and GCS buckets. Functionally identical to application_name in App_CloudRun. Do not change after initial deployment.
application_display_name"Django Application"Human-readable name shown in the platform UI, the Cloud Run service list, and monitoring dashboards. Can be updated freely at any time.
application_description"Django Application - High-level Python Web framework"Brief description populated into the Cloud Run service description field and platform documentation.
application_version"latest"Version tag applied to the container image. When container_image_source = "custom", incrementing this value triggers a new Cloud Build run. Prefer a pinned version (e.g. "v1.2.0") over "latest" in production to ensure reproducible deployments.

Validating Application Identity

# Confirm the Cloud Run service exists with the expected name
gcloud run services describe django \
--region=REGION \
--format="table(metadata.name,metadata.annotations['run.googleapis.com/description'])"

Django Database Configuration

Django requires PostgreSQL. All database variables behave identically to those documented in App_CloudRun_Guide Group 11, with the following Django-specific notes.

VariableDefaultDescription & Implications
application_database_name"django_db"The name of the PostgreSQL database created within the Cloud SQL instance. Injected as DB_NAME. Do not change after initial deployment — renaming the database requires manual data migration.
application_database_user"django_user"The PostgreSQL user created for the Django application. Injected as DB_USER. The password is auto-generated, stored in Secret Manager, and injected as DB_PASSWORD.

Note on database_type: Django requires PostgreSQL. The module uses the Cloud SQL engine specified by database_type (documented in App_CloudRun_Guide Group 11). Do not change to MYSQL or SQLSERVER — the DB_ENGINE variable (django.db.backends.postgresql) is hard-wired by Django_Common and will not work with non-PostgreSQL engines. Use a versioned value such as "POSTGRES_15" for consistency across environments.

PostgreSQL extensions are installed automatically by Django_Common — see Platform-Managed Behaviours. You do not need to set enable_postgres_extensions = true for the Django-required extensions.

Validating Database Configuration

# Confirm the database and user were created
gcloud sql databases list --instance=INSTANCE_NAME --project=PROJECT_ID

gcloud sql users list --instance=INSTANCE_NAME --project=PROJECT_ID

# Confirm DB environment variables are injected into the Cloud Run service
gcloud run services describe django \
--region=REGION \
--format="yaml(spec.template.spec.containers[0].env)" | grep -E "DB_"

# Confirm SECRET_KEY is injected as a secret reference
gcloud run services describe django \
--region=REGION \
--format="yaml(spec.template.spec.containers[0].env)" | grep SECRET_KEY

Django Health Probes

Django_CloudRun exposes two independent probe systems:

  1. startup_probe / liveness_probe — these are used by the Django_Common sub-module and configure how the initialisation scripts and application entrypoint assess Django readiness. They are passed into Django_Common and are separate from the Cloud Run infrastructure probe configuration.

  2. startup_probe_config / health_check_config — these are passed directly to App_CloudRun and configure the actual Cloud Run startup and liveness probes on the container revision. They correspond to the variables of the same names documented in App_CloudRun_Guide Group 5.

For most deployments you will adjust both sets. startup_probe / liveness_probe control Django_Common's internal readiness assessment, while startup_probe_config / health_check_config control the Cloud Run infrastructure health checks that determine whether traffic is routed to an instance.

startup_probe and liveness_probe (Django_Common internal probes):

VariableDefaultDescription & Implications
startup_probe{ enabled = true, type = "HTTP", path = "/healthz", initial_delay_seconds = 60, timeout_seconds = 5, period_seconds = 10, failure_threshold = 3 }Used by Django_Common to assess whether Django has started successfully. The /healthz path is the recommended Django health check endpoint. initial_delay_seconds = 60 accounts for database connection establishment and application loading.
liveness_probe{ enabled = true, type = "HTTP", path = "/healthz", initial_delay_seconds = 30, timeout_seconds = 5, period_seconds = 30, failure_threshold = 3 }Used by Django_Common to assess whether a running Django instance is healthy. Periodically hits /healthz and triggers a restart if failure_threshold consecutive checks fail.

startup_probe_config / health_check_config (Cloud Run infrastructure probes):

Django-specific defaults differ from the App_CloudRun base:

  • startup_probe_config: { enabled = true, type = "HTTP", path = "/healthz", initial_delay_seconds = 10, timeout_seconds = 5, period_seconds = 10, failure_threshold = 10 }
  • health_check_config: { enabled = true, type = "HTTP", path = "/healthz", initial_delay_seconds = 15, timeout_seconds = 5, period_seconds = 30, failure_threshold = 3 }

Both use /healthz as the default path. Cloud Run will not route traffic to an instance until startup_probe_config succeeds. failure_threshold = 10 gives Django up to ~110 seconds of startup time before the instance is considered failed.

Best practice: Implement a dedicated /healthz view in your Django application that returns HTTP 200 when the app is ready (database connected, migrations applied). The django-health-check package or a simple view function that tests the database connection is recommended.

Validating Health Probe Configuration

Google Cloud Console: Navigate to Cloud Run → Services → django → Revisions, select the latest revision, then click Container(s) and view the Health checks section.

# View startup and liveness probe config on the latest revision
gcloud run services describe django \
--region=REGION \
--format="yaml(spec.template.spec.containers[0].livenessProbe,spec.template.spec.containers[0].startupProbe)"

# View Cloud Run logs for startup or probe failures
gcloud logging read \
"resource.type=cloud_run_revision AND resource.labels.service_name=django AND severity>=WARNING" \
--project=PROJECT_ID \
--limit=20 \
--format="table(timestamp,severity,textPayload)"

Redis Configuration

Django uses Redis as a session store and caching backend via django-redis. When enable_redis = true, the REDIS_HOST and REDIS_PORT environment variables are injected automatically into the Django container by Django_Common.

VariableDefaultOptions / FormatDescription & Implications
enable_redisfalsetrue / falseWhen true, REDIS_HOST and REDIS_PORT are injected into the container. Your Django settings.py must be configured to use these variables for CACHES and SESSION_ENGINE. Recommended for production deployments where persistent sessions or shared caching across multiple instances is required.
redis_host""IP address or hostnameThe hostname or IP address of the Redis server. For Cloud Run, this must be a reachable address over the VPC — typically the private IP of a Cloud Memorystore for Redis instance. Ensure vpc_egress_setting is set to "PRIVATE_RANGES_ONLY" (the default) or "ALL_TRAFFIC" so that Cloud Run can reach the private Redis endpoint.
redis_port6379IntegerThe TCP port of the Redis server. The default 6379 is correct for Cloud Memorystore and most self-hosted Redis instances.
redis_auth"" (no authentication)Password string (sensitive)Authentication password for the Redis server. Leave empty if the Redis instance does not require authentication. When set, the value is stored securely and never appears in Terraform state in plaintext. For Cloud Memorystore with AUTH enabled, set this to the instance's auth string.

Provisioning Redis: The Django_CloudRun module does not provision a Redis instance. Provision a Cloud Memorystore for Redis instance separately and set redis_host to its private IP address.

VPC connectivity: Cloud Run must be able to reach the private Redis IP. Ensure the Cloud Run service has VPC egress configured (vpc_egress_setting = "PRIVATE_RANGES_ONLY") and that the VPC network contains a subnet in the same region as the Redis instance.

Validating Redis Configuration

# Confirm REDIS_HOST and REDIS_PORT are injected into the Cloud Run revision
gcloud run services describe django \
--region=REGION \
--format="yaml(spec.template.spec.containers[0].env)" | grep REDIS

Initialization Jobs

Django deployments require database setup and schema migration jobs to run before (or immediately after) the application starts. Django_CloudRun pre-configures a default db-init job and supports additional Django-specific jobs.

Default initialization_jobs in Django_CloudRun:

initialization_jobs = [
{
name = "db-init"
description = "Initialize Sample Database"
image = "postgres:15-alpine"
command = ["/bin/sh"]
script_path = "scripts/db-init.sh"
mount_nfs = false
mount_gcs_volumes = []
execute_on_apply = true
}
]

The db-init job runs automatically on every terraform apply (execute_on_apply = true). It uses the postgres:15-alpine image (separate from the Django application image) to create the database, user, and PostgreSQL extensions using the postgres superuser credentials from Secret Manager. The script is idempotent — running it on an already-initialised database is safe.

Adding a Django migration job:

To run python manage.py migrate as part of the deployment, extend the initialization_jobs list:

initialization_jobs = [
{
name = "db-init"
description = "Create Django Database and User"
image = "postgres:15-alpine"
command = ["/bin/sh"]
script_path = "scripts/db-init.sh"
mount_nfs = false
mount_gcs_volumes = []
execute_on_apply = true
},
{
name = "db-migrate"
description = "Run Django Migrations"
image = null # Uses the application image
script_path = "migrate.sh"
mount_nfs = false
mount_gcs_volumes = ["django-media"] # If GCS media volume is configured
execute_on_apply = false
}
]

Script location: Both db-init.sh and migrate.sh are provided by Django_Common at modules/Django_Common/scripts/. They are referenced via script_path and loaded automatically by the platform.

Job ordering: Jobs are executed in the order they appear in the list, unless depends_on_jobs is specified. Always list db-init before db-migrate.

Superuser creation: The entrypoint.sh in the Django_Common container checks for DJANGO_SUPERUSER_USERNAME, DJANGO_SUPERUSER_EMAIL, and DJANGO_SUPERUSER_PASSWORD environment variables and programmatically creates a superuser if one does not already exist. Set these via secret_environment_variables rather than environment_variables to keep credentials out of Terraform state.

For full documentation of all initialization_jobs sub-fields (resource limits, timeouts, retry policies, volume mounts), refer to App_CloudRun_Guide Group 6.

Validating Initialization Jobs

# List all Cloud Run job executions
gcloud run jobs executions list \
--job=django-db-init \
--region=REGION \
--format="table(name,status.conditions[0].type,status.startTime,status.completionTime)"

# View db-init job logs
gcloud logging read \
"resource.type=cloud_run_job AND resource.labels.job_name=django-db-init" \
--project=PROJECT_ID \
--limit=50 \
--order=asc \
--format="table(timestamp,severity,textPayload)"

# Confirm the database was created
gcloud sql databases list --instance=INSTANCE_NAME --project=PROJECT_ID

Password Rotation Propagation Delay

The rotation_propagation_delay_sec variable controls how long the module waits after writing a new database password to Secret Manager before restarting the Cloud Run service to pick up the new credentials. It is used together with enable_auto_password_rotation (documented in App_CloudRun_Guide Group 11).

VariableDefaultOptions / FormatDescription & Implications
rotation_propagation_delay_sec90Integer (seconds)Seconds to wait after updating the DB_PASSWORD secret before triggering a new Cloud Run revision to pick up the new credentials. This delay allows Secret Manager's global replication to complete before the application reconnects. Increase to 120 in multi-region deployments or if you observe rotation failures. Only used when enable_auto_password_rotation = true.

Resource Creator Identity

VariableDefaultOptions / FormatDescription & Implications
resource_creator_identity"rad-module-creator@tec-rad-ui-2b65.iam.gserviceaccount.com"Service account emailThe service account used by Terraform to create and manage GCP resources. For enhanced security, replace with a project-scoped service account granted only the minimum permissions required by this module.

Deployment Prerequisites & Validation

After deploying Django_CloudRun, confirm the deployment is healthy:

# Confirm the Cloud Run service is deployed and view its URL
gcloud run services describe django \
--region=REGION \
--format="table(status.url,status.conditions[0].type)"

# View the latest revision status
gcloud run revisions list \
--service=django \
--region=REGION \
--format="table(name,status.conditions[0].status,spec.containerConcurrency)"

# Confirm the GCS bucket provisioned for Django media storage
gcloud storage buckets list \
--project=PROJECT_ID \
--filter="name:django-media"

# Confirm the db-init job completed successfully
gcloud run jobs executions list \
--job=django-db-init \
--region=REGION \
--format="table(name,status.conditions[0].type)"

# Confirm DB environment variables and SECRET_KEY are injected
gcloud run services describe django \
--region=REGION \
--format="yaml(spec.template.spec.containers[0].env)" | grep -E "DB_|SECRET_KEY"

# Verify the Django health endpoint is responding
SERVICE_URL=$(gcloud run services describe django --region=REGION --format="value(status.url)")
curl -s -o /dev/null -w "%{http_code}" ${SERVICE_URL}/healthz
# Expect: 200