NodeRED GKE Module — Configuration Guide
Node-RED is a leading open-source flow-based programming tool designed for wiring together IoT devices, APIs, and online services through a browser-based visual editor. This module deploys Node-RED on GKE Autopilot with NFS-backed persistent flow storage, optional Redis context storage, and full Kubernetes reliability controls.
NodeRED GKE is a wrapper module built on top of App GKE. It delegates all GCP infrastructure provisioning to App GKE (GKE Autopilot cluster, networking, Cloud Storage, NFS, Secret Manager, CI/CD) and uses a NodeRED Common sub-module to supply Node-RED-specific application configuration. The NodeRED Common outputs feed into App GKE's application_config, module_storage_buckets, and scripts_dir inputs.
This guide documents variables that are unique to NodeRED GKE or that have Node-RED-specific defaults differing from the App GKE base module. For full documentation of variables with identical semantics, refer to the
App_GKE Configuration Guide.
§1 · Module Overview
What NodeRED GKE provides
- A Node-RED container (prebuilt
nodered/node-red image from Docker Hub, enable_image_mirroring = true) deployed as a Kubernetes Deployment or StatefulSet, listening on port 1880.
- NFS (Cloud Filestore) enabled by default (
enable_nfs = true) and mounted at /data. Node-RED stores all persistent data in /data — flows, credentials, installed nodes, and settings.
- Network tag
nfsserver applied by default via network_tags to ensure GKE nodes have connectivity to the NFS server.
- Session affinity set to
"ClientIP" by default, ensuring the Node-RED editor UI is served consistently from the same pod during a browser session.
NODE_RED_CREDENTIAL_SECRET auto-generated by the Foundation Module and stored in Secret Manager. This secret encrypts Node-RED's stored credentials. Its length is controlled by database_password_length.
NODE_RED_ENABLE_SAFE_MODE = "false" always injected by NodeRED Common, ensuring flows execute on startup.
- Optional Redis for Node-RED context storage (
enable_redis = false by default).
- No Cloud SQL is required or used.
database_type defaults to "NONE".
- A
kubernetes_ready output gate controls all Kubernetes resource deployment; on first apply of a new inline cluster, resources are skipped and a second apply is required.
Key differences from App GKE defaults
| Feature | App GKE default | NodeRED GKE default |
|---|
container_port | 8080 | 1880 |
container_resources.cpu_limit | "1000m" | "500m" |
container_resources.memory_limit | "512Mi" | "512Mi" |
min_instance_count | 1 | 1 |
max_instance_count | 1 | 1 |
enable_nfs | false | true |
nfs_mount_path | "/mnt/nfs" | "/data" |
enable_cloudsql_volume | varies | false (unused) |
enable_redis | false | false |
session_affinity | "None" | "ClientIP" |
network_tags | [] | ["nfsserver"] |
| Health probe path | /healthz | / |
database_type | varies | "NONE" |
workload_type | "Deployment" | "Deployment" |
§2 · IAM & Project Identity
| Variable | Default | Description |
|---|
project_id | (required) | GCP project into which all resources are deployed. |
tenant_deployment_id | "demo" | Short suffix appended to resource names. |
resource_creator_identity | "rad-module-creator@tec-rad-ui-2b65.iam.gserviceaccount.com" | Service account used by Terraform. |
support_users | [] | Email addresses granted IAM access and added to monitoring alert channels. |
resource_labels | {} | Labels applied to all module-managed resources. |
module_description | (Node-RED GKE description) | Platform UI description. |
module_documentation | "https://docs.radmodules.dev/docs/modules/NodeRED_GKE" | External documentation URL. |
module_dependency | ["Services GCP"] | Platform modules that must be deployed first. |
module_services | (GKE Autopilot, Filestore, GCS, etc.) | GCP services used by this module. |
credit_cost | 150 | Platform credits consumed on deployment. |
require_credit_purchases | false | Enforces credit balance check. |
enable_purge | true | Permits full resource deletion on destroy. |
public_access | true | Visibility to all platform users. |
deployment_id | "" | Optional fixed deployment ID. Auto-generated when blank. |
region | "us-central1" | GCP region fallback when network auto-discovery cannot determine the region. |
§3 · Core Service Configuration
§3.A · Application Identity
| Variable | Default | Description |
|---|
application_name | "nodered" | Internal identifier. Used as the base name for GKE workloads, GCS buckets, Kubernetes namespace, and Artifact Registry. Do not change after initial deployment. |
application_display_name | "Node-RED" | Human-readable name in the platform UI and monitoring dashboards. |
application_description | "Node-RED - Flow-based programming for IoT and event automation" | Brief description populated into Kubernetes deployment annotations. |
application_version | "latest" | Container image tag for nodered/node-red. |
deploy_application | true | Set false to provision infrastructure without deploying the Kubernetes workload. |
§3.B · Container & Scaling
NodeRED GKE uses the full container_resources object (as documented in App GKE). The top-level cpu_limit and memory_limit shorthand variables used by NodeRED CloudRun are not present — pass resource sizing via container_resources.
| Variable | Default | Description |
|---|
container_image_source | "prebuilt" | Determines how the image is sourced. Use "prebuilt" to deploy nodered/node-red directly. "custom" activates container_build_config. |
container_image | "nodered/node-red:latest" | Full image URI. Used when container_image_source = "prebuilt". |
container_port | 1880 | TCP port Node-RED binds to inside the container. |
container_resources | { cpu_limit = "500m", memory_limit = "512Mi" } | CPU and memory resource limits. Node-RED is lightweight. Also accepts optional cpu_request, mem_request, ephemeral_storage_limit, ephemeral_storage_request. |
container_build_config | { enabled = false } | Cloud Build configuration when container_image_source = "custom". |
min_instance_count | 1 | Minimum pod replicas. Must be ≥ 1 for GKE (no scale-to-zero). |
max_instance_count | 1 | Maximum pod replicas. Keep at 1 unless using Redis-backed external context storage. |
enable_image_mirroring | true | Mirrors nodered/node-red from Docker Hub into Artifact Registry. |
enable_pod_disruption_budget | true | Creates a PodDisruptionBudget to limit simultaneous pod unavailability during voluntary disruptions. |
pdb_min_available | "1" | Minimum pods available during disruptions. Accepts an integer or percentage string (e.g. "50%"). |
termination_grace_period_seconds | 30 | Seconds Kubernetes waits after SIGTERM before forcibly terminating. |
workload_type | "Deployment" | Kubernetes workload controller. Use "StatefulSet" for per-pod persistent storage — see §3.F. |
enable_vertical_pod_autoscaling | false | Enables VPA to automatically adjust CPU and memory requests. Recommended for GKE Autopilot. |
timeout_seconds | 300 | Maximum seconds the load balancer waits for a backend pod response. |
container_protocol | "http1" | HTTP protocol version. Valid: "http1", "h2c". |
enable_cloudsql_volume | false | Not used by Node-RED. Kept for API compatibility. |
cloudsql_volume_mount_path | "/cloudsql" | Not used by Node-RED. Kept for API compatibility. |
service_annotations | {} | Custom annotations applied to the Kubernetes Service resource. |
service_labels | {} | Custom labels applied to the Kubernetes Service resource. |
§3.C · Environment Variables & Secrets
The following variable is always injected automatically and must not be set manually:
NODE_RED_CREDENTIAL_SECRET — auto-generated by App GKE using database_password_length.
Do not set in environment_variables: NODE_RED_CREDENTIAL_SECRET.
| Variable | Default | Description |
|---|
environment_variables | {} | Plain-text environment variables injected into the GKE pod. Use for Node-RED configuration such as NODE_RED_ENABLE_PROJECTS = "true". |
secret_environment_variables | {} | Map of env var name → Secret Manager secret name. |
secret_propagation_delay | 30 | Seconds to wait after secret creation before dependent operations proceed. |
secret_rotation_period | "2592000s" | Secret Manager rotation notification period. Set null to disable. |
enable_auto_password_rotation | false | Automates credential secret rotation. |
rotation_propagation_delay_sec | 90 | Seconds to wait after rotation before the application restarts. |
§3.D · GKE Backend Configuration
| Variable | Default | Description |
|---|
service_type | "LoadBalancer" | Kubernetes Service type. Use "LoadBalancer" for external access, "ClusterIP" for internal. |
session_affinity | "ClientIP" | Defaults to "ClientIP" — ensures the Node-RED editor is consistently served from the same pod, which is required for the visual editor UI to function correctly. |
namespace_name | "" | Kubernetes namespace. Leave empty to auto-generate from application_name and tenant_deployment_id. |
gke_cluster_name | "" | Name of the GKE cluster. Leave empty to auto-discover. |
gke_cluster_selection_mode | "primary" | Cluster selection strategy. Options: "explicit", "round-robin", "primary". |
network_tags | ["nfsserver"] | Network tags applied to GKE nodes. The "nfsserver" tag is required for NFS connectivity — do not remove it when enable_nfs = true. |
enable_network_segmentation | false | Creates Kubernetes NetworkPolicy resources to restrict pod ingress and egress. |
configure_service_mesh | false | Enables Istio service mesh injection for the application namespace. |
enable_multi_cluster_service | false | Enables Multi-Cluster Services by creating a ServiceExport. |
deployment_timeout | 1800 | Seconds Terraform waits for the Kubernetes rollout to complete. |
prereq_gke_subnet_cidr | "10.201.0.0/24" | CIDR for inline GKE subnet. Must not overlap with existing subnets. |
§3.E · Kubernetes Cluster Networking
| Variable | Default | Description |
|---|
enable_custom_domain | false | Provisions a Kubernetes Ingress for custom domain routing and SSL termination. |
application_domains | [] | Custom domain names for the Ingress. Only used when enable_custom_domain = true. |
reserve_static_ip | true | Provisions a global static external IP for the load balancer. Recommended for production. |
static_ip_name | "" | Name for the static IP. Auto-generated when empty. |
network_name | "" | VPC network name. Auto-discovered when empty. |
§3.F · StatefulSet Configuration
When workload_type = "StatefulSet", the following variables configure per-pod persistent volumes. For most Node-RED deployments, the default Deployment with NFS-backed /data is sufficient.
| Variable | Default | Description |
|---|
stateful_pvc_enabled | false | Provisions a PVC per pod. Only effective when workload_type = "StatefulSet". |
stateful_pvc_size | "10Gi" | Storage size for each PVC. |
stateful_pvc_mount_path | "/data" | Mount path for the per-pod PVC. Set to "/data" to back Node-RED's data directory with a PVC. |
stateful_pvc_storage_class | "standard-rwo" | Kubernetes StorageClass. Use "premium-rwo" for higher IOPS. |
stateful_headless_service | true | Creates a headless Service for stable pod DNS names. |
stateful_pod_management_policy | "OrderedReady" | Pod startup/shutdown order. "OrderedReady" starts pods sequentially. |
stateful_update_strategy | "RollingUpdate" | Update strategy. "RollingUpdate" or "OnDelete". |
§4 · Advanced Security
§4.A · Credential Secret Management
| Variable | Default | Description |
|---|
database_password_length | 32 | Length of the auto-generated NODE_RED_CREDENTIAL_SECRET. Valid range: 16–64. |
enable_auto_password_rotation | false | Automates credential secret rotation. |
rotation_propagation_delay_sec | 90 | Seconds to wait after rotation before restarting the application. |
secret_rotation_period | "2592000s" | Secret Manager rotation notification period (30 days). |
secret_propagation_delay | 30 | Seconds to wait after secret creation before proceeding. |
§4.B · Identity-Aware Proxy (IAP)
GKE IAP requires OAuth client credentials, unlike Cloud Run IAP. All four IAP variables must be set when enabling IAP.
| Variable | Default | Description |
|---|
enable_iap | false | Enables IAP authentication. Recommended for production deployments. |
iap_authorized_users | [] | Individual users granted access. Format: "user:email@example.com". |
iap_authorized_groups | [] | Google Groups granted access. Format: "group:name@example.com". |
iap_oauth_client_id | "" | OAuth 2.0 Client ID. Required when enable_iap = true. Sensitive. |
iap_oauth_client_secret | "" | OAuth 2.0 Client Secret. Required when enable_iap = true. Sensitive. |
iap_support_email | "" | Support email for the OAuth consent screen. Required when enable_iap = true. |
Validation guard: When enable_iap = true, both iap_oauth_client_id and iap_oauth_client_secret must be provided. Without them, Terraform rejects the configuration.
§4.C · Cloud Armor
| Variable | Default | Description |
|---|
enable_cloud_armor | false | Enables Cloud Armor WAF security policy. |
admin_ip_ranges | [] | IP CIDR ranges for administrative access. |
cloud_armor_policy_name | "default-waf-policy" | Cloud Armor security policy name. Only used when enable_cloud_armor = true. |
§4.D · VPC Service Controls
| Variable | Default | Description |
|---|
enable_vpc_sc | false | Enables VPC-SC perimeter enforcement. |
vpc_cidr_ranges | [] | VPC subnet CIDRs for the network access level. Auto-discovered when empty. |
vpc_sc_dry_run | true | When true, violations are logged but not blocked. Set false to enforce. |
organization_id | "" | GCP Organization ID for Access Context Manager. Auto-discovered when empty. |
enable_audit_logging | false | Enables detailed Cloud Audit Logs. |
§4.E · Binary Authorization
| Variable | Default | Description |
|---|
enable_binary_authorization | false | Enforces Binary Authorization on the GKE cluster. |
binauthz_evaluation_mode | "ALWAYS_ALLOW" | Enforcement mode. Options: "ALWAYS_ALLOW", "REQUIRE_ATTESTATION", "ALWAYS_DENY". |
§5 · Reliability
§5.A · Pod Disruption Budget
| Variable | Default | Description |
|---|
enable_pod_disruption_budget | true | Creates a PodDisruptionBudget. |
pdb_min_available | "1" | Minimum pods that must remain available during voluntary disruptions. |
§5.B · Topology Spread Constraints
| Variable | Default | Description |
|---|
enable_topology_spread | false | Adds TopologySpreadConstraints to distribute pods across zones. |
topology_spread_strict | false | When true, pods are rejected (DoNotSchedule) if spread constraints cannot be satisfied. When false, pods are placed anyway (ScheduleAnyway). |
§5.C · Resource Quotas
| Variable | Default | Description |
|---|
enable_resource_quota | false | Creates a Kubernetes ResourceQuota in the namespace. |
quota_cpu_requests | "" | Total CPU requests limit across all pods. |
quota_cpu_limits | "" | Total CPU limits across all pods. |
quota_memory_requests | "" | Total memory requests across all pods. |
quota_memory_limits | "" | Total memory limits across all pods. |
quota_max_pods | "" | Maximum pods in the namespace. |
quota_max_services | "" | Maximum Kubernetes Services in the namespace. |
quota_max_pvcs | "" | Maximum PVCs in the namespace. |
§6 · CI/CD Integration
§6.A · GitHub & Cloud Build
| Variable | Default | Description |
|---|
enable_cicd_trigger | false | Creates a Cloud Build trigger for automatic builds on code push. |
github_repository_url | "" | Full HTTPS URL of the GitHub repository. Required when enable_cicd_trigger = true. |
github_token | "" | GitHub PAT for repository authentication. Sensitive. |
github_app_installation_id | "" | Cloud Build GitHub App installation ID. Alternative to PAT. |
cicd_trigger_config | { branch_pattern = "^main$" } | Branch filter, included/ignored paths, trigger name, and substitutions. |
§6.B · Cloud Deploy Pipelines
| Variable | Default | Description |
|---|
enable_cloud_deploy | false | Switches to a Cloud Deploy pipeline with promotion stages. Requires enable_cicd_trigger = true. |
cloud_deploy_stages | [dev, staging, prod(approval)] | Ordered promotion stages. Each stage supports name, target_name, namespace, cluster, project_id, region, require_approval, auto_promote. |
§7 · Storage
§7.A · NFS (Recommended for Flow Persistence)
| Variable | Default | Description |
|---|
enable_nfs | true | Provisions Cloud Filestore NFS and mounts it at nfs_mount_path. Node-RED stores all persistent data in /data — NFS is the recommended backend. |
nfs_mount_path | "/data" | Container path for the NFS volume. |
nfs_instance_name | "" | Name of an existing NFS GCE VM. Auto-discovers or creates when empty. |
nfs_instance_base_name | "app-nfs" | Base name for a newly created NFS GCE VM. |
§7.B · Cloud Storage (GCS)
| Variable | Default | Description |
|---|
create_cloud_storage | true | Controls whether GCS buckets in storage_buckets are provisioned. |
storage_buckets | [{ name_suffix = "data" }] | GCS buckets to provision. NodeRED Common adds a "nodered-storage" bucket via module_storage_buckets. |
gcs_volumes | [] | GCS buckets mounted as filesystem volumes using the GCS Fuse CSI driver. |
manage_storage_kms_iam | false | Creates a CMEK KMS keyring and enables CMEK on all storage buckets. |
enable_artifact_registry_cmek | false | Enables CMEK for the Artifact Registry repository. |
enable_cdn | false | Enables Cloud CDN on the GKE Ingress backend. Only applies when enable_custom_domain = true. |
§7.C · Backup & Recovery
| Variable | Default | Description |
|---|
backup_schedule | "0 2 * * *" | Cron expression (UTC) for the automated NFS backup job. Leave empty to disable. |
backup_retention_days | 7 | Days to retain backup files. |
enable_backup_import | false | Triggers a one-time restore job during deployment. |
backup_source | "gcs" | Source: "gcs" or "gdrive". |
backup_file | "backup.tar" | Filename of the backup to import. Must exist in the GCS backup bucket. |
backup_format | "tar" | Format of the backup file. Options: sql, tar, gz, tgz, tar.gz, zip, auto. |
§8 · Database (Compatibility Stubs)
Node-RED does not use a relational database. The following variables are present for API compatibility with App GKE and have no operational effect:
| Variable | Default | Description |
|---|
database_type | "NONE" | No database. Do not change. |
application_database_name | "nodered" | No-op. Kept for API compatibility. |
application_database_user | "nodered" | No-op. Kept for API compatibility. |
enable_cloudsql_volume | false | No Cloud SQL Auth Proxy. |
cloudsql_volume_mount_path | "/cloudsql" | No-op. Kept for API compatibility. |
enable_postgres_extensions | false | No-op. |
postgres_extensions | [] | No-op. |
enable_mysql_plugins | false | No-op. |
mysql_plugins | [] | No-op. |
enable_custom_sql_scripts | false | No-op. |
custom_sql_scripts_bucket | "" | No-op. |
custom_sql_scripts_path | "" | No-op. |
custom_sql_scripts_use_root | false | No-op. |
sql_instance_name | "" | No-op. |
sql_instance_base_name | "app-sql" | No-op. |
§9 · Redis (Context Storage)
| Variable | Default | Description |
|---|
enable_redis | false | Enables Redis for Node-RED context storage. Injects REDIS_HOST and REDIS_PORT into the pod. |
redis_host | "" | Redis hostname or IP. Required when enable_redis = true (unless enable_nfs = true). |
redis_port | "6379" | Redis TCP port (string). |
redis_auth | "" | Redis authentication password. Sensitive. |
Validation guard: When enable_redis = true, either redis_host must be set or enable_nfs must be true (the NFS server IP is usable as a fallback Redis host). Otherwise Terraform rejects the configuration.
§10 · Observability & Health
§10.A · Health Probes
Node-RED responds to HTTP GET on / with the editor UI. Both probe types use this path. A 30-second initial delay is sufficient as Node-RED starts quickly.
| Variable | Default | Description |
|---|
startup_probe_config | { enabled=true, type="HTTP", path="/", initial_delay_seconds=30, timeout_seconds=5, period_seconds=10, failure_threshold=3 } | Kubernetes startup probe (passed directly to App GKE). |
health_check_config | { enabled=true, type="HTTP", path="/", initial_delay_seconds=30, timeout_seconds=5, period_seconds=30, failure_threshold=3 } | Kubernetes liveness probe (passed directly to App GKE). |
uptime_check_config | { enabled=true, path="/", check_interval="60s", timeout="10s" } | Cloud Monitoring uptime check. |
alert_policies | [] | List of metric-threshold alert policies. Each entry requires name, metric_type, comparison, threshold_value, duration_seconds. |
§10.B · Additional Services
| Variable | Default | Description |
|---|
additional_services | [] | Supplementary Kubernetes Deployments deployed alongside Node-RED. Each entry defines its own image, port, resources, and probes. |
§11 · Workload Automation
§11.A · Initialization Jobs
| Variable | Default | Description |
|---|
initialization_jobs | [] | Kubernetes Jobs executed once during deployment. Node-RED requires no initialization jobs — use for custom flow imports or palette installations. |
§11.B · CronJobs
| Variable | Default | Description |
|---|
cron_jobs | [] | Recurring Kubernetes CronJobs. Supports name, schedule, image, command, args, env_vars, cpu_limit, memory_limit, restart_policy, concurrency_policy, suspend, mount_nfs, mount_gcs_volumes, script_path. |
The following are set automatically and cannot be overridden via input variables.
Environment Variables (always injected)
| Variable | Value / Source | Notes |
|---|
NODE_RED_ENABLE_SAFE_MODE | "false" | Injected by NodeRED Common; ensures flows execute on startup. |
NODE_RED_CREDENTIAL_SECRET | Secret Manager ref (auto-generated) | Generated by App GKE using database_password_length. Encrypts stored credentials. |
Structural Wiring
| Behaviour | Detail |
|---|
application_config | { nodered = module.nodered_app.config } — NodeRED Common config keyed as "nodered". |
module_env_vars | Always {} — no additional Foundation-level env vars. |
module_secret_env_vars | Always {} — no auto-generated secrets from NodeRED Common. |
module_storage_buckets | module.nodered_app.storage_buckets — the "nodered-storage" GCS bucket. |
scripts_dir | abspath("${module.nodered_app.path}/scripts") — NodeRED Common's scripts/ directory. |
| Region resolution | Region is auto-discovered via module.network_discovery before being passed to NodeRED Common as region. |
| Resource prefix | "app${application_name}${tenant_deployment_id}${random_id}" — computed in main.tf locals. |
container_image_source | From var.container_image_source (default "prebuilt"); user-configurable. |
database_type | "NONE" in the NodeRED Common config output — always hardcoded. |
| Two-apply pattern | The kubernetes_ready output is false on first apply of a new inline cluster. All Kubernetes resources are gated on this value. A second tofu apply is required to complete deployment. |
Cross-Variable Validation Guards (validation.tf)
| Guard | Condition | Error |
|---|
| Instance count | min_instance_count <= max_instance_count | Conflicting HPA configuration. |
| Redis without host | !enable_redis || redis_host != "" || enable_nfs | REDIS_HOST would be empty and Node-RED would fail to connect. |
| IAP without credentials | !enable_iap || (iap_oauth_client_id != "" && iap_oauth_client_secret != "") | IAP silently disabled without credentials, leaving the application exposed. |
§13 · Outputs
| Output | Description |
|---|
service_url | The Kubernetes Service URL or external load balancer IP for the deployed Node-RED instance. |
kubernetes_ready | true when the GKE cluster endpoint is available and all Kubernetes resources are deployed. false on first apply of a new inline cluster — a second apply is required. |
§14 · Variable Reference
Complete list of all input variables, grouped by UI section.
| Group | Variable | Type | Default | Updatable |
|---|
| 0 | module_description | string | (long description) | — |
| 0 | module_documentation | string | "https://docs.radmodules.dev/docs/modules/NodeRED_GKE" | — |
| 0 | module_dependency | list(string) | ["Services GCP"] | — |
| 0 | module_services | list(string) | (service list) | — |
| 0 | credit_cost | number | 150 | — |
| 0 | require_credit_purchases | bool | false | — |
| 0 | enable_purge | bool | true | — |
| 0 | public_access | bool | true | — |
| 0 | deployment_id | string | "" | yes |
| 0 | resource_creator_identity | string | "rad-module-creator@…" | yes |
| 1 | project_id | string | — | — |
| 1 | tenant_deployment_id | string | "demo" | yes |
| 1 | support_users | list(string) | [] | yes |
| 1 | resource_labels | map(string) | {} | yes |
| 1 | region | string | "us-central1" | yes |
| 2 | application_name | string | "nodered" | yes |
| 2 | application_display_name | string | "Node-RED" | yes |
| 2 | application_description | string | "Node-RED - Flow-based programming…" | yes |
| 2 | application_version | string | "latest" | yes |
| 3 | deploy_application | bool | true | yes |
| 3 | container_image_source | string | "prebuilt" | yes |
| 3 | container_image | string | "nodered/node-red:latest" | yes |
| 3 | container_port | number | 1880 | yes |
| 3 | container_resources | object | { cpu_limit = "500m", memory_limit = "512Mi" } | yes |
| 3 | container_build_config | object | { enabled = false } | yes |
| 3 | min_instance_count | number | 1 | yes |
| 3 | max_instance_count | number | 1 | yes |
| 3 | enable_image_mirroring | bool | true | yes |
| 3 | enable_cloudsql_volume | bool | false | yes |
| 3 | cloudsql_volume_mount_path | string | "/cloudsql" | yes |
| 3 | service_annotations | map(string) | {} | yes |
| 3 | service_labels | map(string) | {} | yes |
| 3 | enable_vertical_pod_autoscaling | bool | false | yes |
| 3 | timeout_seconds | number | 300 | yes |
| 3 | container_protocol | string | "http1" | yes |
| 4 | environment_variables | map(string) | {} | yes |
| 4 | secret_environment_variables | map(string) | {} | yes |
| 4 | secret_rotation_period | string | "2592000s" | yes |
| 4 | secret_propagation_delay | number | 30 | yes |
| 5 | service_type | string | "LoadBalancer" | yes |
| 5 | workload_type | string | "Deployment" | yes |
| 5 | session_affinity | string | "ClientIP" | yes |
| 5 | namespace_name | string | "" | yes |
| 5 | gke_cluster_name | string | "" | yes |
| 5 | gke_cluster_selection_mode | string | "primary" | yes |
| 5 | enable_network_segmentation | bool | false | yes |
| 5 | configure_service_mesh | bool | false | yes |
| 5 | enable_multi_cluster_service | bool | false | yes |
| 5 | termination_grace_period_seconds | number | 30 | yes |
| 5 | deployment_timeout | number | 1800 | yes |
| 5 | prereq_gke_subnet_cidr | string | "10.201.0.0/24" | — |
| 6 | stateful_pvc_enabled | bool | false | yes |
| 6 | stateful_pvc_size | string | "10Gi" | yes |
| 6 | stateful_pvc_mount_path | string | "/data" | yes |
| 6 | stateful_pvc_storage_class | string | "standard-rwo" | yes |
| 6 | stateful_headless_service | bool | true | yes |
| 6 | stateful_pod_management_policy | string | "OrderedReady" | yes |
| 6 | stateful_update_strategy | string | "RollingUpdate" | yes |
| 7 | enable_resource_quota | bool | false | yes |
| 7 | quota_cpu_requests | string | "" | yes |
| 7 | quota_cpu_limits | string | "" | yes |
| 7 | quota_memory_requests | string | "" | yes |
| 7 | quota_memory_limits | string | "" | yes |
| 7 | quota_max_pods | string | "" | yes |
| 7 | quota_max_services | string | "" | yes |
| 7 | quota_max_pvcs | string | "" | yes |
| 8 | enable_pod_disruption_budget | bool | true | yes |
| 8 | pdb_min_available | string | "1" | yes |
| 8 | enable_topology_spread | bool | false | yes |
| 8 | topology_spread_strict | bool | false | yes |
| 9 | startup_probe_config | object | (HTTP /, 30s delay) | yes |
| 9 | health_check_config | object | (HTTP /, 30s delay) | yes |
| 9 | uptime_check_config | object | { enabled = true, path = "/" } | yes |
| 9 | alert_policies | list(object) | [] | yes |
| 10 | initialization_jobs | list(object) | [] | yes |
| 10 | cron_jobs | list(object) | [] | yes |
| 10 | additional_services | list(object) | [] | yes |
| 11 | enable_cicd_trigger | bool | false | yes |
| 11 | github_repository_url | string | "" | yes |
| 11 | github_token | string | "" | yes |
| 11 | github_app_installation_id | string | "" | yes |
| 11 | cicd_trigger_config | object | { branch_pattern = "^main$" } | yes |
| 11 | enable_cloud_deploy | bool | false | yes |
| 11 | cloud_deploy_stages | list(object) | [dev, staging, prod(approval)] | yes |
| 11 | enable_binary_authorization | bool | false | yes |
| 11 | binauthz_evaluation_mode | string | "ALWAYS_ALLOW" | yes |
| 12 | enable_nfs | bool | true | yes |
| 12 | nfs_mount_path | string | "/data" | yes |
| 12 | nfs_instance_name | string | "" | yes |
| 12 | nfs_instance_base_name | string | "app-nfs" | yes |
| 13 | create_cloud_storage | bool | true | yes |
| 13 | storage_buckets | list(object) | [{ name_suffix = "data" }] | yes |
| 13 | gcs_volumes | list(object) | [] | yes |
| 13 | manage_storage_kms_iam | bool | false | yes |
| 13 | enable_artifact_registry_cmek | bool | false | yes |
| 14 | enable_redis | bool | false | yes |
| 14 | redis_host | string | "" | yes |
| 14 | redis_port | string | "6379" | yes |
| 14 | redis_auth | string | "" | yes |
| 15 | database_type | string | "NONE" | — |
| 15 | application_database_name | string | "nodered" | yes |
| 15 | application_database_user | string | "nodered" | yes |
| 15 | database_password_length | number | 32 | yes |
| 15 | enable_auto_password_rotation | bool | false | yes |
| 15 | rotation_propagation_delay_sec | number | 90 | yes |
| 15 | enable_postgres_extensions | bool | false | yes |
| 15 | postgres_extensions | list(string) | [] | yes |
| 15 | enable_mysql_plugins | bool | false | yes |
| 15 | mysql_plugins | list(string) | [] | yes |
| 16 | backup_schedule | string | "0 2 * * *" | yes |
| 16 | backup_retention_days | number | 7 | yes |
| 16 | enable_backup_import | bool | false | yes |
| 16 | backup_source | string | "gcs" | yes |
| 16 | backup_file | string | "backup.tar" | yes |
| 16 | backup_format | string | "tar" | yes |
| 17 | enable_custom_sql_scripts | bool | false | yes |
| 17 | custom_sql_scripts_bucket | string | "" | yes |
| 17 | custom_sql_scripts_path | string | "" | yes |
| 17 | custom_sql_scripts_use_root | bool | false | yes |
| 18 | enable_custom_domain | bool | false | yes |
| 18 | application_domains | list(string) | [] | yes |
| 18 | reserve_static_ip | bool | true | yes |
| 18 | static_ip_name | string | "" | yes |
| 18 | network_tags | list(string) | ["nfsserver"] | yes |
| 18 | network_name | string | "" | yes |
| 19 | enable_iap | bool | false | yes |
| 19 | iap_authorized_users | list(string) | [] | yes |
| 19 | iap_authorized_groups | list(string) | [] | yes |
| 19 | iap_oauth_client_id | string | "" | yes |
| 19 | iap_oauth_client_secret | string | "" | yes |
| 19 | iap_support_email | string | "" | yes |
| 20 | enable_cloud_armor | bool | false | yes |
| 20 | admin_ip_ranges | list(string) | [] | yes |
| 20 | cloud_armor_policy_name | string | "default-waf-policy" | yes |
| 20 | enable_cdn | bool | false | yes |
| 21 | enable_vpc_sc | bool | false | yes |
| 21 | vpc_cidr_ranges | list(string) | [] | yes |
| 21 | vpc_sc_dry_run | bool | true | yes |
| 21 | organization_id | string | "" | yes |
| 21 | enable_audit_logging | bool | false | yes |
§15 · Configuration Examples
Basic Deployment
Deploys Node-RED on GKE using default settings. Suitable for evaluation and development.
# config/basic.tfvars
resource_creator_identity = ""
project_id = "my-project-123"
tenant_deployment_id = "basic"
Advanced Deployment
Production-grade deployment with Redis context storage, CI/CD, GKE reliability policies, and full observability.
# config/advanced.tfvars
resource_creator_identity = ""
project_id = "my-project-123"
tenant_deployment_id = "prod"
application_name = "nodered"
application_display_name = "Node-RED"
application_version = "4.0.9"
# Scaling & Performance
container_resources = {
cpu_limit = "1000m"
memory_limit = "1Gi"
cpu_request = "500m"
mem_request = "512Mi"
}
min_instance_count = 1
max_instance_count = 1
# Redis context storage
enable_redis = true
redis_host = "10.0.0.5"
redis_port = "6379"
# GKE specific
enable_resource_quota = true
enable_pod_disruption_budget = true
enable_network_segmentation = true
enable_vertical_pod_autoscaling = true
# CI/CD & Cloud Deploy
enable_cicd_trigger = true
enable_cloud_deploy = true
cloud_deploy_stages = [
{ name = "dev", require_approval = false, auto_promote = false },
{ name = "staging", require_approval = false, auto_promote = false },
{ name = "prod", require_approval = true, auto_promote = false },
]
# Security
enable_iap = true
iap_oauth_client_id = "123456789-abc.apps.googleusercontent.com"
iap_oauth_client_secret = "GOCSPX-…"
iap_support_email = "admin@example.com"
enable_binary_authorization = true
enable_cloud_armor = true
# Backup
backup_schedule = "0 2 * * *"
backup_retention_days = 14
# Observability
uptime_check_config = {
enabled = true
path = "/"
check_interval = "60s"
timeout = "10s"
}
alert_policies = [
{
name = "high-cpu"
metric_type = "kubernetes.io/container/cpu/usage_time"
comparison = "COMPARISON_GT"
threshold_value = 800
duration_seconds = 300
aggregation_period = "60s"
}
]
StatefulSet Deployment
Deploys Node-RED as a StatefulSet with a PVC for per-pod local data storage.
# config/custom.tfvars
resource_creator_identity = ""
project_id = "my-project-123"
tenant_deployment_id = "stateful"
application_name = "nodered"
# StatefulSet
workload_type = "StatefulSet"
min_instance_count = 1
max_instance_count = 1
# StatefulSet PVC (backs /data with a persistent disk)
stateful_pvc_enabled = true
stateful_pvc_size = "20Gi"
stateful_pvc_mount_path = "/data"
stateful_pvc_storage_class = "standard-rwo"
# StatefulSet behaviour
stateful_headless_service = true
stateful_pod_management_policy = "OrderedReady"
stateful_update_strategy = "RollingUpdate"
# Custom environment configuration
environment_variables = {
NODE_RED_ENABLE_PROJECTS = "true"
NODE_OPTIONS = "--max-old-space-size=512"
}
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 |
|---|
NODE_RED_CREDENTIAL_SECRET (auto-generated, length from database_password_length) | Auto-generated random string stored in Secret Manager | Critical | Encrypts all flow credentials at rest. Changing or rotating this key after flows are deployed renders all stored credentials unreadable — every API key, password, and token in every flow must be manually re-entered. |
enable_auto_password_rotation (if supported) | false | Critical | Automatic rotation of NODE_RED_CREDENTIAL_SECRET changes the encryption key, making all existing flow credentials permanently inaccessible. Only enable with a credential re-encryption procedure in place. |
database_password_length | 32 | Medium | Controls the length of NODE_RED_CREDENTIAL_SECRET. Valid range: 16–64. The GKE validation guard blocks values outside this range. |
enable_nfs | true | Critical | Node-RED stores all flow definitions, credentials (flows_cred.json), and installed nodes in /data. Without NFS persistent storage, every pod restart, rescheduling, or Kubernetes node upgrade erases all flows and credentials. |
nfs_mount_path | "/mnt/nfs" | High | The /data directory must point to the NFS mount. Changing this path without updating Node-RED's settings file causes flows to be written to ephemeral pod storage. |
application_name | "nodered" | Critical | Immutable after first deploy. Changing it renames all GCP and Kubernetes resources, causing full recreation. The NFS instance is disconnected from the new deployment. |
min_instance_count | 1 (GKE default) | High | GKE does not support true scale-to-zero without KEDA. The HPA validation guard rejects min > max. Unlike Cloud Run, scale-to-zero in GKE leaves the pod in a pending/terminated state rather than cleanly scaling. |
max_instance_count | 1 | High | Node-RED is not designed for active-active horizontal scaling — flow context and state are per-instance. Increasing above 1 without stateful_pvc_enabled = true or a shared NFS /data mount causes each pod to have isolated, potentially conflicting flow state. |
workload_type | null (defaults to Deployment) | High | For Node-RED with persistent /data, a StatefulSet with a PVC provides stronger pod-to-storage binding than a Deployment with NFS. Setting stateful_pvc_enabled = true without explicit workload_type automatically resolves to StatefulSet. |
stateful_pvc_enabled | false | Medium | A PVC-backed StatefulSet is safer than NFS for single-replica Node-RED — it guarantees the same pod always mounts the same storage. However, PVC size is immutable after creation. |
quota_memory_requests / quota_memory_limits | "" (not enforced) | High | Must use binary suffixes ("1Gi", "2048Mi"). Bare integers are treated as bytes by Kubernetes and block all pod scheduling. |
database_type | "NONE" | High | Node-RED has no database dependency. Setting this to POSTGRES or MYSQL provisions an unnecessary Cloud SQL sidecar. The GKE validation guard blocks enable_cloudsql_volume = true when database_type = "NONE". |
enable_cloudsql_volume | false | High | Setting true with database_type = "NONE" is blocked at plan time by the GKE validation guard with the message: "enable_cloudsql_volume should not be true when database_type is 'NONE'." |
environment_variables | {} | Medium | Do not override NODE_RED_ENABLE_SAFE_MODE = "true" in production — safe mode disables all flows. Do not set NODE_RED_CREDENTIAL_SECRET here; it is managed by the Foundation Module. |
session_affinity | "ClientIP" | Medium | Node-RED's editor uses WebSocket connections for the flow deployment UI. Disabling affinity causes editor disconnections and "deploy failed" errors when subsequent requests route to a different pod. |
enable_pod_disruption_budget | true | Medium | Disabling PDB allows GKE to evict the Node-RED pod during node maintenance, causing a complete service outage and potential flow data loss if the NFS write was in progress. |
termination_grace_period_seconds | 30 | Medium | Node-RED needs time to finish processing in-flight messages before shutdown. Values below 15 may truncate message processing in active flows. |
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_topology_spread | false | Low | With max_instance_count = 1, topology spread has no effect. Only relevant if multiple replicas are deployed (not recommended for Node-RED). |