Kestra GKE Module — Configuration Guide
Kestra is an open-source data orchestration and scheduling platform (Apache 2.0 licence). It allows you to build, schedule, and monitor ETL/ELT pipelines, batch jobs, and workflow automation through a YAML-based flow definition and a rich plugin ecosystem. This module deploys Kestra on GKE Autopilot in standalone mode (server, worker, and scheduler in a single container) with a PostgreSQL 15 backend and GCS artifact storage.
Kestra GKE is a wrapper module built on top of App GKE. It uses App GKE for all GCP infrastructure provisioning (GKE Autopilot cluster, networking, Cloud SQL Auth Proxy, GCS, secrets, CI/CD) and a Kestra Common sub-module to supply Kestra-specific application configuration, secret generation, and storage bucket definitions.
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 variables that are unique to Kestra_GKE or that have Kestra-specific defaults differing from the App_GKE base module. For variables with identical semantics, refer to the App_GKE Configuration Guide.
Key differences from App GKE defaults:
| Feature | App GKE default | Kestra GKE default |
|---|
container_port | 8080 | 8080 |
cpu_limit | "1000m" | "2000m" |
memory_limit | "512Mi" | "4Gi" |
min_instance_count | 1 | 1 |
max_instance_count | 1 | 1 |
container_image_source | "prebuilt" | "custom" |
enable_cloudsql_volume | true | true |
session_affinity | "None" | "ClientIP" |
termination_grace_period_seconds | 30 | 60 |
enable_pod_disruption_budget | false | true |
enable_redis | false | false (fixed) |
| Health probe path | varies | /health |
application_database_name | — | "kestra" |
application_database_user | — | "kestra" |
The following behaviours are set automatically and cannot be overridden via user variables.
| Behaviour | Detail |
|---|
| Admin password auto-generated | A 24-character random KESTRA_BASICAUTH_PASSWORD is generated by Kestra Common and stored in Secret Manager as <resource_prefix>-admin-password. Passed via explicit_secret_values for direct Kubernetes Secret injection, bypassing read-after-write delays. |
| GCS bucket always provisioned | Kestra Common provisions a -kestra-storage GCS bucket. Its name is injected automatically as KESTRA_STORAGE_GCS_BUCKET. |
| PostgreSQL queue and repository | KESTRA_QUEUE_TYPE=postgres and KESTRA_REPOSITORY_TYPE=postgres are always injected. |
| Redis is disabled | enable_redis = false is hardcoded in main.tf. Kestra standalone mode uses PostgreSQL for queuing. |
| Cloud SQL TCP sidecar | On GKE, the Cloud SQL Auth Proxy sidecar runs as a standard TCP proxy on 127.0.0.1:5432. Unlike Cloud Run, no socat bridge is needed — the Java JDBC driver connects directly. entrypoint.sh detects GKE and skips the Unix socket bridge. |
| Service URL pre-computed | The internal Kubernetes DNS URL (http://<service_name>.<namespace>.svc.cluster.local) is passed to Kestra_Common before deployment and injected as a Kestra configuration variable. |
| Fixed environment variables | MICRONAUT_SERVER_PORT=8080, KESTRA_QUEUE_TYPE=postgres, KESTRA_REPOSITORY_TYPE=postgres, KESTRA_STORAGE_TYPE=gcs, KESTRA_STORAGE_GCS_BUCKET, KESTRA_BASICAUTH_ENABLED=true, KESTRA_BASICAUTH_USERNAME=admin, DATASOURCES_POSTGRES_DRIVERCLASSNAME, ENDPOINTS_ALL_PORT, and two Flyway baseline variables are always injected. |
| Scripts directory | Resolved as abspath("${module.kestra_app.path}/scripts") — points to Kestra Common's bundled scripts directory. |
backup_format normalised | Lowercased before passing to App GKE (UI may send uppercase "SQL"). |
| Variable | Default | Description |
|---|
module_description | (long description) | Platform UI description. Do not modify unless customising. |
module_documentation | "https://docs.radmodules.dev/docs/modules/Kestra_GKE" | External documentation URL. |
module_dependency | ["Services GCP"] | Platform modules that must be deployed first. |
module_services | ["GKE Autopilot", "Kubernetes Deployments", "Kubernetes Services", "Kubernetes Jobs", "HPA", "Cloud Build", "Artifact Registry", "Cloud Storage", "GCS Fuse CSI Driver", "Cloud SQL", "Cloud SQL Auth Proxy", "PostgreSQL 15", "VPC Network", "Workload Identity", "Secret Manager", "Cloud IAM", "Service Accounts", "Cloud Logging", "Cloud Monitoring", "Health Checks", "Webhooks", "Filestore (NFS)"] | GCP services consumed. |
credit_cost | 150 | Platform credits consumed on deployment. |
require_credit_purchases | false | Enforces credit balance check before deploy. |
enable_purge | true | Permits full resource deletion on destroy. |
public_access | true | Controls platform catalogue visibility. |
deployment_id | "" | Auto-generated suffix. Set explicitly to pin resource names across Terraform runs. |
resource_creator_identity | "rad-module-creator@tec-rad-ui-2b65.iam.gserviceaccount.com" | Service account used by Terraform. |
§2 · Project & Identity (Group 1)
| Variable | Default | Description |
|---|
project_id | (required) | GCP project ID. Must be 6–30 chars, lowercase letters/numbers/hyphens. |
tenant_deployment_id | "demo" | Short suffix appended to resource names. 1–20 lowercase alphanumeric characters and hyphens. |
support_users | [] | Emails granted IAM access and added to monitoring alert channels. |
resource_labels | {} | Labels applied to all module-managed resources. |
region | "us-central1" | Fallback region when network discovery cannot determine region from VPC subnets. |
§3 · Application Identity (Group 2)
| Variable | Default | Description |
|---|
application_name | "kestra" | Base name for GKE workloads, Secret Manager secrets, and Artifact Registry. Do not change after initial deployment — changing it forces resource recreation. |
application_version | "latest" | Version tag applied to the container image. Increment to trigger a new build and rollout (e.g. "0.17.0"). |
display_name | "Kestra Data Orchestration" | Human-readable name in the platform UI and GKE console. |
description | "Kestra Data Orchestration - ETL/ELT pipeline and workflow orchestration on GKE Autopilot" | Brief description. |
deploy_application | true | Set false to provision infrastructure without deploying the GKE workload. |
§4 · Runtime & Scaling (Group 3)
| Variable | Default | Options / Format | Description |
|---|
cpu_limit | "2000m" | CPU quantity | CPU limit per Kestra container. Kestra (Java JVM) benefits from at least 2 vCPUs. |
memory_limit | "4Gi" | Memory quantity | Memory limit. Kestra requires a minimum of 2Gi; 4Gi recommended. |
container_port | 8080 | Integer 1–65535 | Port Kestra listens on. Must match MICRONAUT_SERVER_PORT. |
min_instance_count | 1 | Integer ≥ 0 | Minimum pod replicas. Keep at 1 — Kestra JVM has slow cold start. |
max_instance_count | 1 | Integer ≥ 1 | Maximum pod replicas. Kestra standalone runs all components in one pod — set to 1 for predictable state. |
timeout_seconds | 300 | Integer 0–3600 | Maximum request timeout. |
enable_vertical_pod_autoscaling | false | bool | Enables VPA. When enabled, HPA based on CPU/memory is disabled. |
enable_image_mirroring | true | bool | Mirrors the container image into Artifact Registry before deployment. |
enable_cloudsql_volume | true | bool | Injects Cloud SQL Auth Proxy sidecar. Required for database connectivity. |
service_annotations | {} | map(string) | Custom annotations applied to the Kubernetes Service. |
service_labels | {} | map(string) | Custom labels applied to the Kubernetes Service. |
deployment_timeout | 1800 | Integer seconds | Max seconds Terraform waits for the Kubernetes Deployment rollout to complete. Increase for large Java images. |
§5 · GKE Backend Configuration (Group 5)
| Variable | Default | Options / Format | Description |
|---|
gke_cluster_name | "" | Cluster name string | GKE cluster name. Leave empty to auto-discover a Services GCP-managed cluster. |
namespace_name | "" | Namespace string | Kubernetes namespace. Leave empty to auto-generate from application_name and tenant_deployment_id. |
workload_type | "Deployment" | Deployment, StatefulSet | Use "StatefulSet" if Kestra flows are stored locally rather than in GCS. |
service_type | "LoadBalancer" | ClusterIP, LoadBalancer, NodePort | Kubernetes Service type. |
session_affinity | "ClientIP" | None, ClientIP | Routes requests from the same client IP to the same pod. "ClientIP" is required for the Kestra UI session. |
termination_grace_period_seconds | 60 | Integer 0–3600 | Seconds Kubernetes waits after SIGTERM before forcibly terminating. Kestra needs time to finish in-flight executions gracefully. |
configure_service_mesh | false | bool | Enables Istio service mesh injection for the namespace. |
enable_network_segmentation | false | bool | Creates Kubernetes NetworkPolicy resources to restrict pod-to-pod traffic. |
network_tags | ["nfsserver"] | list(string) | Network tags applied to GKE nodes for VPC firewall rules. |
prereq_gke_subnet_cidr | "10.201.0.0/24" | CIDR string | CIDR for the inline GKE subnet. Must not overlap other subnets. |
§6 · Environment Variables & Secrets (Group 4)
| Variable | Default | Description |
|---|
environment_variables | {} | Additional static env vars for Kestra. Use for plugin configs and custom Micronaut properties. Do not set platform-managed vars. |
secret_environment_variables | {} | Map of env var name to Secret Manager secret name. Example: { KESTRA_ENCRYPTION_SECRET = "kestra-enc-key" }. |
secret_propagation_delay | 30 | Seconds to wait after secret creation. Valid range: 0–300. |
secret_rotation_period | "2592000s" | Rotation notification period. Format: "<N>s". |
enable_auto_password_rotation | false | Deploys automated database password rotation via a Kubernetes CronJob. |
rotation_propagation_delay_sec | 90 | Seconds to wait after rotation before restarting GKE pods. |
Do not set in environment_variables: MICRONAUT_SERVER_PORT, KESTRA_QUEUE_TYPE, KESTRA_REPOSITORY_TYPE, KESTRA_STORAGE_TYPE, KESTRA_STORAGE_GCS_BUCKET, KESTRA_BASICAUTH_ENABLED, KESTRA_BASICAUTH_USERNAME, DATASOURCES_POSTGRES_URL, DATASOURCES_POSTGRES_USERNAME, DATASOURCES_POSTGRES_PASSWORD, or KESTRA_BASICAUTH_PASSWORD.
§7 · Access & Networking
Identity-Aware Proxy (Group 19)
| Variable | Default | Description |
|---|
enable_iap | false | Enables IAP authentication via Kubernetes Gateway. Requires enable_custom_domain or service_type = "LoadBalancer". |
iap_authorized_users | [] | User allowlist. Format: "user:email@example.com". |
iap_authorized_groups | [] | Group allowlist. Format: "group:name@example.com". |
iap_oauth_client_id | "" | OAuth 2.0 Client ID. Required when enable_iap = true. |
iap_oauth_client_secret | "" | OAuth 2.0 Client Secret. Required when enable_iap = true. |
Custom Domain & Static IP (Group 18)
| Variable | Default | Description |
|---|
enable_custom_domain | false | Enables Kubernetes Gateway API with SSL certificates. |
application_domains | [] | Custom domain names. If enable_custom_domain = true and empty, a nip.io domain is used. |
reserve_static_ip | true | Reserves a global static external IP. Recommended for production. |
static_ip_name | "" | Name for the static IP. Auto-generated from resource prefix when empty. |
enable_cdn | false | Enables Cloud CDN. Only active when enable_custom_domain or enable_cloud_armor is true. |
Cloud Armor (Group 20)
| Variable | Default | Description |
|---|
enable_cloud_armor | false | Attaches a Cloud Armor security policy to the GKE Ingress backend. |
admin_ip_ranges | [] | CIDR ranges for administrative access. |
cloud_armor_policy_name | "default-waf-policy" | Cloud Armor security policy name. |
VPC Service Controls (Group 21)
| Variable | Default | Description |
|---|
enable_vpc_sc | false | Enforces VPC Service Controls perimeters. |
vpc_cidr_ranges | [] | VPC subnet CIDR ranges. Auto-discovered when empty. |
vpc_sc_dry_run | true | When true, violations are logged but not blocked. |
organization_id | "" | GCP Organization ID. Auto-discovered when empty. |
enable_audit_logging | false | Enables detailed Cloud Audit Logs. |
§8 · Database Backend (Group 15)
Kestra requires PostgreSQL for both its execution queue and flow repository.
| Variable | Default | Description |
|---|
database_type | "POSTGRES" | Cloud SQL database type. |
application_database_name | "kestra" | PostgreSQL database name. Injected as DB_NAME. Do not change after initial deployment. |
application_database_user | "kestra" | PostgreSQL application user. Injected as DB_USER. |
db_name | "kestra" | Also passed to Kestra Common. Should match application_database_name. |
db_user | "kestra" | Also passed to Kestra Common. Should match application_database_user. |
database_password_length | 32 | Auto-generated password length. Valid range: 16–64. |
enable_postgres_extensions | false | Enables installation of PostgreSQL extensions. |
postgres_extensions | [] | List of PostgreSQL extensions to install. |
enable_mysql_plugins | false | Not applicable for Kestra (PostgreSQL only). |
mysql_plugins | [] | Not applicable for Kestra (PostgreSQL only). |
sql_instance_name | "" | Existing Cloud SQL instance name. Auto-discovered when empty. |
sql_instance_base_name | "app-sql" | Base name for the inline Cloud SQL instance. |
enable_auto_password_rotation | false | Automates database password rotation. |
rotation_propagation_delay_sec | 90 | Seconds to wait after rotation before restarting pods. |
§9 · Storage (Groups 12–13)
NFS (Group 12)
| Variable | Default | Description |
|---|
enable_nfs | false | Provisions a Cloud Filestore NFS instance and mounts it into the GKE pod. |
nfs_mount_path | "/mnt/nfs" | Container path for the NFS volume. |
nfs_instance_name | "" | Existing NFS GCE VM name. Auto-discovered when empty. |
nfs_instance_base_name | "app-nfs" | Base name for the inline NFS GCE VM. |
Cloud Storage & GCS Fuse (Group 13)
Kestra Common always provisions a -kestra-storage bucket. Additional buckets can be added via storage_buckets.
| Variable | Default | Description |
|---|
create_cloud_storage | true | Controls whether the module provisions the buckets in storage_buckets. |
storage_buckets | [] | Additional GCS buckets to provision. |
gcs_volumes | [] | GCS buckets mounted as filesystem volumes via GCS Fuse CSI Driver. |
manage_storage_kms_iam | false | Creates CMEK KMS keys and enables CMEK encryption on storage buckets. |
enable_artifact_registry_cmek | false | Enables CMEK encryption on container images in Artifact Registry. |
§10 · Backup & Maintenance (Group 16)
| Variable | Default | Description |
|---|
backup_schedule | "0 2 * * *" | Cron schedule (UTC) for automated database backups. |
backup_retention_days | 7 | Days to retain backup files in GCS. |
enable_backup_import | false | Triggers a one-time database import job during deployment. |
backup_source | "gcs" | Source: "gcs" or "gdrive". |
backup_uri | "" | Full URI for the backup. For GCS: gs://bucket/path/backup.sql. For Drive: file ID. |
backup_file | "backup.sql" | Filename of the backup to import (from the module's backup bucket). |
backup_format | "sql" | Format of the backup file. Normalised to lowercase automatically. |
§11 · CI/CD & GitHub Integration (Group 11)
| Variable | Default | Description |
|---|
enable_cicd_trigger | false | Creates a Cloud Build trigger for automatic builds. |
github_repository_url | "" | Full HTTPS URL of the GitHub repository. |
github_token | "" | GitHub PAT. Sensitive. |
github_app_installation_id | "" | Cloud Build GitHub App installation ID. |
cicd_trigger_config | { branch_pattern = "^main$" } | Branch filter, included/ignored paths, substitutions. |
enable_cloud_deploy | false | Switches to a Cloud Deploy pipeline. Requires enable_cicd_trigger = true. |
cloud_deploy_stages | [dev, staging, prod(approval)] | Ordered promotion stages. |
enable_binary_authorization | false | Enforces Binary Authorization policy on the GKE cluster. |
binauthz_evaluation_mode | "ALWAYS_ALLOW" | ALWAYS_ALLOW, REQUIRE_ATTESTATION, or ALWAYS_DENY. |
§12 · Custom SQL (Group 17)
| Variable | Default | Description |
|---|
enable_custom_sql_scripts | false | Runs custom SQL scripts from GCS against the application database. |
custom_sql_scripts_bucket | "" | GCS bucket name containing SQL scripts. |
custom_sql_scripts_path | "" | Path prefix within the GCS bucket. Scripts executed in alphabetical order. |
custom_sql_scripts_use_root | false | Execute scripts as the root database user. |
§13 · Workload Automation (Group 10)
The default db-init job is supplied automatically by Kestra Common when initialization_jobs is empty.
| Variable | Default | Description |
|---|
initialization_jobs | [] | Kubernetes Jobs to run before the application starts. When non-empty, replaces the default db-init job. |
cron_jobs | [] | Scheduled cluster tasks as Kubernetes CronJobs. |
additional_services | [] | Additional Kubernetes services deployed alongside Kestra (e.g. worker sidecars for distributed mode). |
§14 · Reliability Policies (Group 8)
| Variable | Default | Description |
|---|
enable_pod_disruption_budget | true | Creates a Kubernetes PodDisruptionBudget. Default true for Kestra (ensures in-flight executions are not interrupted). |
pdb_min_available | "1" | Minimum pods available during voluntary disruptions. Integer or percentage. |
enable_topology_spread | false | Distributes pods across GKE node zones. Recommended when min_instance_count > 1. |
topology_spread_strict | false | When true, uses DoNotSchedule if topology spread cannot be satisfied. |
§15 · StatefulSet Configuration (Group 14)
Only relevant when workload_type = "StatefulSet".
| Variable | Default | Description |
|---|
stateful_pvc_enabled | false | Provisions a PVC per pod. Useful for local plugin storage or temporary execution files. |
stateful_pvc_size | "10Gi" | Storage size for each PVC. |
stateful_pvc_mount_path | "/app/storage" | Container path where the PVC is mounted. |
stateful_pvc_storage_class | "" | Kubernetes StorageClass for PVCs. Empty uses cluster default. |
stateful_headless_service | false | Creates a headless Service for direct pod DNS access. |
stateful_pod_management_policy | "OrderedReady" | OrderedReady or Parallel. |
stateful_update_strategy | "RollingUpdate" | RollingUpdate or OnDelete. |
§16 · Observability & Health (Group 9)
Kestra's health endpoint is /health. Kestra (Java JVM) has a slow startup — the default startup probe allows up to ~14 minutes (initial_delay=30 + period=20 × failure_threshold=40).
Kestra GKE exposes four probe variables across two parallel paths:
| Variable | Routed to | Configures |
|---|
startup_probe | Kestra Common → config.startup_probe | Application container startup probe |
liveness_probe | Kestra Common → config.liveness_probe | Application container liveness probe |
startup_probe_config | App GKE directly | App GKE infrastructure startup probe |
health_check_config | App GKE directly | App GKE infrastructure liveness probe |
| Variable | Default | Description |
|---|
startup_probe | { enabled=true, type="HTTP", path="/health", initial_delay_seconds=30, timeout_seconds=5, period_seconds=20, failure_threshold=40 } | Application startup probe. |
liveness_probe | { enabled=true, type="HTTP", path="/health", initial_delay_seconds=180, timeout_seconds=5, period_seconds=30, failure_threshold=5 } | Application liveness probe. |
startup_probe_config | { enabled=true, type="HTTP", path="/health", initial_delay_seconds=30, period_seconds=20, failure_threshold=40 } | App GKE startup probe. |
health_check_config | { enabled=true, type="HTTP", path="/health", initial_delay_seconds=180, period_seconds=30, failure_threshold=5 } | App GKE liveness probe. |
uptime_check_config | { enabled=false, path="/health" } | Cloud Monitoring uptime check. Disabled by default in GKE (unlike CloudRun where it defaults to enabled). |
alert_policies | [] | Custom metric alert policies. |
§17 · Resource Quota (Group 7)
| Variable | Default | Description |
|---|
quota_cpu_requests | "" | Total CPU requests allowed in the namespace. |
quota_cpu_limits | "" | Total CPU limits allowed in the namespace. |
quota_memory_requests | "" | Total memory requests allowed. |
quota_memory_limits | "" | Total memory limits allowed. |
quota_max_pods | "" | Maximum pods allowed. |
quota_max_services | "" | Maximum Kubernetes Services allowed. |
quota_max_pvcs | "" | Maximum PVCs allowed. |
§18 · Validation Guards
validation.tf enforces the following cross-variable conditions at plan time:
| Guard | Condition |
|---|
| Scaling range | min_instance_count must not exceed max_instance_count. |
| IAP credentials | When enable_iap = true, both iap_oauth_client_id and iap_oauth_client_secret must be provided. |
§19 · Outputs
| Output | Description | Sensitive |
|---|
service_name | Kubernetes service name | — |
namespace | Kubernetes namespace | — |
service_cluster_ip | ClusterIP of the Kubernetes service | — |
stage_service_cluster_ips | Map of stage-specific ClusterIPs | — |
service_external_ip | External LoadBalancer IP (when static IP reserved) | — |
service_url | Service URL | — |
database_instance_name | Cloud SQL instance name | — |
database_name | Application database name | — |
database_user | Application database user | — |
database_password_secret | Secret Manager secret name for database password | — |
database_host | Database host | — |
database_port | Database port | — |
storage_buckets | Created GCS buckets | — |
network_name | VPC network name | — |
network_exists | Whether the VPC network exists | — |
regions | Available regions in the VPC | — |
nfs_server_ip | NFS server internal IP | yes |
nfs_mount_path | NFS mount path in containers | — |
nfs_share_path | NFS share path on server | — |
container_image | Container image used for the deployment | — |
container_registry | Artifact Registry repository name | — |
monitoring_enabled | Whether monitoring is configured | — |
monitoring_notification_channels | Monitoring notification channel names | — |
deployment_id | Unique deployment identifier | — |
tenant_id | Tenant identifier | — |
resource_prefix | Resource naming prefix | — |
project_id | GCP project ID | — |
project_number | GCP project number | — |
initialization_jobs | Created initialization job names | — |
cron_jobs | Created cron job names | — |
statefulset_name | StatefulSet name (when workload_type = "StatefulSet") | — |
nfs_setup_job | NFS setup job name | — |
db_import_job | Database import job name | — |
deployment_summary | Summary of the deployment | — |
cicd_enabled | Whether CI/CD pipeline is enabled | — |
github_repository_url | GitHub repository URL for CI/CD | — |
github_repository_owner | GitHub repository owner/organization | — |
github_repository_name | GitHub repository name | — |
artifact_registry_repository | Artifact Registry repository | — |
cloudbuild_trigger_name | Cloud Build trigger name | — |
cloudbuild_trigger_id | Cloud Build trigger ID | — |
cicd_configuration | Complete CI/CD configuration | — |
kubernetes_ready | true when GKE cluster endpoint is available and all workloads deployed. false on the first apply of a new inline cluster (CI/CD must detect and re-run apply). | — |
Configuration Examples
Basic Deployment
project_id = "my-project-123"
tenant_deployment_id = "demo"
Production Deployment
project_id = "my-project-123"
tenant_deployment_id = "prod"
application_name = "kestra"
display_name = "Kestra Orchestration"
application_version = "0.17.0"
# Sizing (Kestra needs ≥ 2 vCPU, ≥ 2Gi RAM)
cpu_limit = "4000m"
memory_limit = "8Gi"
# Keep a pod running — slow JVM startup
min_instance_count = 1
max_instance_count = 1
# Database
application_database_name = "kestra"
application_database_user = "kestra"
database_password_length = 32
# GKE-specific reliability
enable_pod_disruption_budget = true
pdb_min_available = "1"
termination_grace_period_seconds = 60
# Security
enable_iap = true
iap_oauth_client_id = "your-client-id.apps.googleusercontent.com"
iap_oauth_client_secret = "your-client-secret"
iap_authorized_users = ["user:alice@example.com"]
# Backup
backup_schedule = "0 2 * * *"
backup_retention_days = 14
# Observability
uptime_check_config = {
enabled = true
path = "/health"
check_interval = "60s"
timeout = "10s"
}
# CI/CD
enable_cicd_trigger = true
github_repository_url = "https://github.com/my-org/kestra-flows"
github_token = "ghp_***"
StatefulSet with PVC
project_id = "my-project-123"
tenant_deployment_id = "stateful"
workload_type = "StatefulSet"
stateful_pvc_enabled = true
stateful_pvc_size = "20Gi"
stateful_pvc_mount_path = "/app/storage"
stateful_pvc_storage_class = "premium-rwo"
stateful_headless_service = false
stateful_pod_management_policy = "OrderedReady"
stateful_update_strategy = "RollingUpdate"
Configuration Pitfalls & Sensible Defaults
Risk levels: Critical (data loss, full outage, security breach) — High (service unavailable or significant degradation) — Medium (degraded function or increased cost) — Low (minor impact).
| Variable | Sensible Default | Risk | Consequence of Incorrect Value |
|---|
KESTRA_BASICAUTH_PASSWORD (auto-generated secret) | Auto-generated and stored in Secret Manager | Critical | The only admin access credential. Losing the secret reference or destroying the Secret Manager secret requires a direct database update to reset. |
KESTRA_BASICAUTH_ENABLED (injected as "true") | "true" | Critical | Disabling basic auth via environment_variables exposes the Kestra UI and full REST API without authentication. Only disable behind a trusted authentication proxy. |
application_name | "kestra" | Critical | Immutable after first deploy. Changing it renames all Kubernetes and GCP resources, causing full recreation with data loss. |
db_name | "kestra" | Critical | Immutable after first deploy. Changing it causes Kestra to connect to a new empty database, losing all flow definitions, execution history, and namespace configurations. |
KESTRA_QUEUE_TYPE / KESTRA_REPOSITORY_TYPE (both "postgres") | "postgres" | High | Only the PostgreSQL backend is provisioned. Overriding either value to an unsupported type causes startup failures. |
KESTRA_STORAGE_TYPE (injected as "gcs") | "gcs" | High | Changing to "local" causes all execution storage to write to ephemeral pod storage, losing all flow artifacts on pod restart or rescheduling. |
min_instance_count | 1 (GKE default) | High | Kestra must remain running to process scheduled triggers. Setting to 0 causes scheduled flows to miss their trigger windows during cold-start periods. GKE HPA validation blocks min > max. |
max_instance_count | 1 (Kestra Community — single-instance) | High | Kestra Community Edition uses PostgreSQL-based queue locking. Running multiple replicas causes task double-assignment and execution conflicts. Keep max_instance_count = 1 for the Community Edition. |
memory_limit | "4Gi" | High | Kestra's JVM requires substantial heap for loading all flow definitions and execution contexts. Values below 2Gi cause OutOfMemoryErrors and pod crashes under moderate load. |
workload_type | null (defaults to Deployment) | High | Setting stateful_pvc_enabled = true without an explicit workload_type automatically resolves to StatefulSet. Setting workload_type = "Deployment" with stateful_pvc_enabled = true fails at plan time. |
stateful_pvc_enabled | false | Medium | For single-instance Kestra deployments, a PVC provides reliable local storage. However, PVC size is immutable after creation — plan capacity in advance. |
quota_memory_requests / quota_memory_limits | "" (not enforced) | High | Must use binary suffixes ("4Gi", "8192Mi"). Bare integers (e.g. "4") are treated as bytes by Kubernetes and block all pod scheduling in the namespace. |
enable_nfs | true | Medium | Without NFS, Kestra cannot write local binary outputs for flow tasks. GCS storage handles most artifacts, but some task runners require local mount access. |
FLYWAY_DATASOURCES_POSTGRES_BASELINE_ON_MIGRATE (injected as "true") | "true" | High | Required for Flyway to baseline against an already-initialized PostgreSQL database. Removing this causes all 52 Kestra migrations to fail on first run. |
enable_iap | false | High | Enabling IAP without both iap_oauth_client_id and iap_oauth_client_secret is blocked at plan time by the GKE validation guard. |
enable_pod_disruption_budget | true | Medium | Disabling PDB allows GKE to evict the Kestra pod during maintenance, which interrupts all running flow executions. |
enable_cloudsql_volume | true | High | The Cloud SQL Auth Proxy sidecar is required for PostgreSQL connectivity in GKE. Disabling it while database_type != "NONE" is blocked by the GKE validation guard. |
session_affinity | "ClientIP" | Medium | The Kestra UI uses persistent connections for real-time execution log streaming. Disabling affinity can cause UI log streams to disconnect when routed to different pods. |
termination_grace_period_seconds | 30 | Medium | Kestra needs time to finish in-flight task executions before shutdown. Values below 30 may abort active flow runs mid-execution. Increase to 60 or more for long-running tasks. |
enable_topology_spread | false | Low | Without topology spread and with max_instance_count > 1, all Kestra pods may schedule on the same node. (Note: Community Edition should use max_instance_count = 1.) |
organization_id | "" | Medium | Required for VPC-SC. If empty, VPC Service Controls are silently skipped. |