Cloud SQL for Postgres
Runway supports provisioning and connecting to managed Cloud SQL for Postgres instances from your GKE workloads. Unlike unmanaged instances, Runway owns the lifecycle of the database — you do not need to enable PSC or obtain PSC details.
Request a managed Cloud SQL instance
Section titled “Request a managed Cloud SQL instance”File an MR to add your database to config/runtimes/gke/cloud-sql/managed.yml
in the Runway provisioner:
- name: my-service-db provider: GCP db_version: "POSTGRES_18" region: us-east1 zone: us-east1-b env_configuration: staging: instance_type: 2xsmall disk_size_gb: 10 backup_configuration: transaction_log_retention_days: 2 retained_backups_count: 3 production: instance_type: xsmall disk_size_gb: 10 backup_configuration: transaction_log_retention_days: 7 retained_backups_count: 7 labels: owner_email_handle: my-team department: eng-infra department_group: eng-infra-my-group product_category: my-categoryThe name you choose here is your database name and is referenced in the steps below.
Set up database credentials
Section titled “Set up database credentials”The application credentials (username and password) created for the app should be stored in Vault by the app owner and exposed to the workload as environment variables via workloadSecrets in gke-service.yaml — choose whatever variable names make sense for your application. See secrets management for details.
Add the instance to your workload config
Section titled “Add the instance to your workload config”In config/runtimes/gke/workloads.yml,
add a postgres_instances key to your workload entry with the database name from the previous step:
your-service-gke: postgres_instances: - my-service-dbThis grants the GKE workload’s service account the IAM permissions required to connect to Cloud SQL.
Update your deployment file
Section titled “Update your deployment file”Add cloudsql_instances to your gke-service.yaml. For managed instances, the project is always
gitlab-runway-<env> (for example, gitlab-runway-staging or gitlab-runway-production), the region
is whatever region you specified in managed.yml, and the instance name is your database name:
apiVersion: runway/v1kind: RunwayKubernetesDeployment
your-service-gke: serviceMixins: - "runway-gke.service-mixin"
cloudsql_instances: - instance_connection_name: gitlab-runway-<env>:<region>:<name>For example:
cloudsql_instances: - instance_connection_name: gitlab-runway-staging:us-east1:my-service-dbConnecting to Cloud SQL
Section titled “Connecting to Cloud SQL”Connecting to a managed Cloud SQL instance works the same as for unmanaged instances.
The Cloud SQL Auth Proxy exposes databases on localhost with sequential ports starting at 5432:
| Instance | Port |
|---|---|
| First | 5432 |
| Second | 5433 |
| Third | 5434 |
Connect using:
- Host:
127.0.0.1 - Port:
5432(first instance),5433(second), etc. - Username and password via environment variables (see secrets management)
Restore validation
Section titled “Restore validation”The provisioner creates a GitLab project on ops.gitlab.net for every Postgres instance. Each project has a scheduled pipeline that restores the latest backup to a separate Cloud SQL instance and, optionally, runs a data validation query against the restored database.
For production Cloud SQL instances, an alert will be fired if a restore validation pipeline was not triggered in the last 24 hours or if a pipeline has started but not completed within 2 hours.
The data validation query is optional and is configured in the env_configuration.<env>.backup_configuration.restore_validation field:
- Omitted entirely - the scheduled pipeline still runs and restores the latest backup, but no data validation query is executed.
- Set with
database,user,vault_secret_name,vault_secret_key, andquery- the restore test runs and the validation query is executed against the restored database.
Unlike the Cloud Run runtime, managed Cloud SQL on GKE does not auto-create the validation user. You must supply credentials for a user that exists in the source database with privileges to run the validation query. The password is read from a Vault KV v2 secret, where:
- The secret name (path) is
env/<environment>/service/<runway_service_id>/<vault_secret_name>. <vault_secret_key>is the key inside that secret’s data whose value holds the password.
runway_service_id is auto-derived from the workload that owns this Cloud SQL instance - you only need to supply vault_secret_name (the last path segment) and vault_secret_key (the key within the secret).
When a validation query is provided, it should return 1 row of at least 2 columns to pass validation. The two columns can be data of any kind and will be printed in the CI job. Users can generate summary statistics and expose them through the two columns (see example below). The query should return no rows if the data is invalid. An alert will be fired if the validation query fails on production.
- name: runway-db-foo ... env_configuration: staging: backup_configuration: restore_validation: database: runway user: validator vault_secret_name: cloudsql-restore-validation vault_secret_key: password query: "SELECT COUNT(*) AS row_count, MAX(timestamp_column) AS most_recent_timestamp FROM your_table WHERE timestamp_column >= NOW() - INTERVAL '1 DAY' LIMIT 1;"