Certification track: Professional Cloud Developer (PCD)
Django Common — Shared Application Configuration
Django_Common is the shared application layer for Django. It is not deployed on
its own; instead it supplies the Django-specific configuration that both
Django_GKE and Django_CloudRun build on, so
the two platform variants behave identically where it matters. End users never
configure this layer directly — it has no deployment UI inputs of its own — but
understanding what it provides explains the defaults you see in the platform docs.
For the infrastructure that actually provisions and runs Django, see the platform guides (Django_GKE, Django_CloudRun) and the foundation guides (App_GKE, App_CloudRun).
1. What this layer provides
| Area | Provided by Django_Common | Where it surfaces |
|---|---|---|
Django SECRET_KEY | Generates a 50-character random key and stores it in Secret Manager | Injected as SECRET_KEY at runtime; retrieve via Secret Manager (see below) |
| Container image | Pins the Django/Gunicorn image and Cloud Build source, UID 2000 | container_image output of the platform deployment |
| Database engine | Fixes Cloud SQL for PostgreSQL 15 as the only supported engine | §Database in the platform guides |
| Database bootstrap | Defines the db-init job that creates the database, user, and installs extensions | initialization_jobs output |
| Schema migrations | Defines the db-migrate job that runs manage.py migrate + collectstatic | Runs automatically on every deploy |
| PostgreSQL extensions | Auto-installs pg_trgm, unaccent, hstore, citext | No user action required |
| Object storage | Declares the Cloud Storage media bucket | storage_buckets output |
| Core settings | Sets container port (8080), image source (custom), extension flag, Gunicorn server | Application behaviour in the platform guides |
| Health probes | Forwards startup_probe/liveness_probe unchanged (defaults null here — the CloudRun variant defaults to /healthz, the GKE variant defaults to /) | §Observability in the platform guides |
2. Django SECRET_KEY in Secret Manager
The Django SECRET_KEY is generated automatically and stored as a Secret Manager
secret — it is never set in plain text. Retrieve it after deployment:
# The secret name follows the deployment's resource prefix; list and read it:
gcloud secrets list --project "$PROJECT" --filter="name~key"
gcloud secrets versions access latest --secret=<resource-prefix>-django-key --project "$PROJECT"
The database password is generated and managed separately by the foundation; its
secret name is reported in the platform deployment outputs (database_password_secret).
3. Database engine and bootstrap
Django requires PostgreSQL 15; the engine is fixed and MySQL is not supported through this module. On the first deployment two jobs run in sequence:
-
db-init(image:postgres:15-alpine) — connects to Cloud SQL through the Auth Proxy and idempotently creates the application database and user, grants privileges, and installs the four required PostgreSQL extensions:Extension Purpose pg_trgmTrigram similarity for full-text search unaccentAccent-insensitive text search hstoreKey-value store column type citextCase-insensitive text column type -
db-migrate(application image) — runsmanage.py migrateto apply all pending migrations andmanage.py collectstatic --noinput --clearto collect static files to the configured location.
Both jobs run with execute_on_apply = true so they fire automatically on each
deployment. They are idempotent and safe to re-run. Inspect or re-trigger the
database with:
# Cloud Run:
gcloud run jobs list --region "$REGION" --project "$PROJECT"
gcloud run jobs execute db-init-<resource-prefix> --region "$REGION" --project "$PROJECT"
# GKE:
kubectl get jobs -n "$NAMESPACE"
kubectl describe job db-init -n "$NAMESPACE"
The instance, database, and user names are in the platform deployment outputs.
4. Core application settings
Django_Common establishes the baseline Django environment so the application comes
up correctly on first boot:
- Container port 8080. Gunicorn binds to port 8080. The foundation configures the Cloud Run service or Kubernetes Service to target this port.
- Custom image via Cloud Build.
container_image_source = "custom"instructs the foundation to trigger a Cloud Build from theDjango_Common/scripts/Dockerfile, which produces a Gunicorn-based Django image tagged withapplication_version. - PostgreSQL extensions flag.
enable_postgres_extensions = trueis set internally so the foundation provisions the extensions IAM grants. The four extensions are installed bydb-init.sh; you do not need to set this flag manually. - Superuser creation.
entrypoint.shlooks forDJANGO_SUPERUSER_USERNAMEandDJANGO_SUPERUSER_PASSWORDon startup (ifDJANGO_SUPERUSER_PASSWORDis unset butDB_PASSWORDis present, it defaults the superuser password toDB_PASSWORD) and creates the account via amanage.py shellscript that callsUser.objects.create_superuser(...)directly — notmanage.py createsuperuser --noinput.DJANGO_SUPERUSER_EMAILis optional and defaults toadmin@example.com. Usesecret_environment_variablesin the platform module to supplyDJANGO_SUPERUSER_PASSWORDfrom Secret Manager. - GCS media storage is opt-in, not automatic.
Django_Commonprovisions themediastorage bucket and bakesdjango-storages[google]into the image (settings.pyswitches thedefaultfile storage backend tostorages.backends.gcloud.GoogleCloudStorageonly when theGS_BUCKET_NAMEenv var is set — otherwise Django falls back to localFileSystemStoragefor media and Whitenoise for static files). NeitherGS_BUCKET_NAMEnor a matchinggcs_volumesentry is set by default, so thedb-migratejob'smount_gcs_volumes = ["django-media"]reference only takes effect if the platform module'sgcs_volumesvariable is also populated with an entry nameddjango-mediapointing at the bucket. To use GCS for media, setGS_BUCKET_NAMEviaenvironment_variables(and, if the mount is needed, add the matchinggcs_volumesentry) rather than assuming it is wired up out of the box.
Platform-specific defaults (set by the CloudRun/GKE variant, not by Django_Common itself):
- GKE defaults
session_affinity = "ClientIP"so that a given user's requests are routed to the same pod when in-process session storage is used. - Cloud Run defaults
execution_environment = "gen2"(required for NFS/GCS Fuse mounts among other gen2-only features). This is simply the module's static default — it is not toggled automatically based onenable_nfs.
5. Health probe behaviour
Django_Common itself does not set a probe default (startup_probe/liveness_probe default to
null); the values below come from the CloudRun and GKE variant variables.tf defaults, both on
port 8080. Cloud Run defaults its probe path to /healthz (served by the sample project's
myproject/urls.py, which returns HTTP 200 once the application is ready). GKE's default probe
path is / (the application root), not /healthz — the two variants diverge here, so verify
the deployed path in the platform module's variables.tf before assuming either default.
- GKE uses HTTP probes for both startup (90s initial delay) and liveness (60s initial delay) — in-cluster probe traffic reaches the container directly without routing through a load balancer.
- Cloud Run also uses HTTP probes for both startup (60s initial delay) and
liveness (30s initial delay). Unlike Mautic/Apache, Django's Gunicorn server does
not redirect HTTP to HTTPS, so plain HTTP probes work without a TCP workaround.
Ensure
SECURE_SSL_REDIRECT = Falseinsettings.py(or exempt/healthz) so the probe path is never redirected.
If your first-deploy migrations are large and the 60-second (Cloud Run) or 90-second
(GKE) initial delay is insufficient, override startup_probe with a larger
initial_delay_seconds in the platform module variables.
6. Object storage
A dedicated Cloud Storage media bucket (name_suffix = "media") is declared here
and provisioned by the foundation, which also grants the workload service account
access. The bucket is provisioned in the deployment region, but — as noted in §4 — neither the
GCS bucket nor the shared Filestore (NFS) volume is wired into Django's MEDIA_ROOT by default:
GCS needs GS_BUCKET_NAME set explicitly, and NFS's default mount path (/mnt/nfs) does not
match the image's /app/media directory, so nfs_mount_path must be set to /app/media for
NFS-backed media persistence. List and inspect the bucket with:
gcloud storage buckets list --project "$PROJECT"
gcloud storage ls gs://<resource-prefix>-media/
For the Django-specific, user-facing configuration (variables by group, outputs, and how to explore each service from the Console and CLI), see the platform guides: Django_GKE and Django_CloudRun.