Skip to main content

Elasticsearch GKE Module — Configuration Guide

Elasticsearch is an open-source distributed search and analytics engine based on Apache Lucene. This module deploys a single-node Elasticsearch cluster on GKE Autopilot as a Kubernetes StatefulSet with persistent SSD storage. It is designed as a shared search infrastructure dependency — primarily for RAGFlow GKE, which uses it for document vector storage and full-text search.

Elasticsearch GKE is a wrapper module built on top of App GKE. It delegates all GCP infrastructure provisioning to App GKE and assembles the Elasticsearch-specific configuration locally using a locals block (there is no separate *_Common module).

Elasticsearch GKE must be deployed before RAGFlow GKE. After deployment, run tofu output elasticsearch_endpoint and pass the result to RAGFlow GKE's elasticsearch_hosts variable.


§1 · Module Overview

What Elasticsearch GKE provides

  • An Elasticsearch StatefulSet (prebuilt docker.elastic.co/elasticsearch/elasticsearch image, optionally mirrored to Artifact Registry) with a LoadBalancer service on port 9200, enabling cross-namespace access from RAGFlow GKE.
  • A PersistentVolumeClaim (30 Gi SSD by default) mounted at /usr/share/elasticsearch/data for durable index storage.
  • A headless Kubernetes Service providing stable pod DNS entries.
  • No Cloud SQL, no Redis, no GCS buckets — Elasticsearch is self-contained.
  • Probes use TCP (not HTTP) because HTTP probes would fail on Elasticsearch 9.x with X-Pack security enabled. TCP probes validate port readiness regardless of auth state.

Key differences from App GKE defaults

FeatureApp GKE defaultElasticsearch GKE default
container_port80809200
workload_type"Deployment""StatefulSet"
service_typevaries"LoadBalancer"
session_affinity"None""None"
min_instance_count11 (single-node mode)
max_instance_count31 (single-node mode)
termination_grace_period_seconds60120 (segment flush time)
deployment_timeout6001800 (shard recovery)
stateful_pvc_enabledfalsetrue
stateful_pvc_size"10Gi""30Gi"
stateful_pvc_mount_path"/data""/usr/share/elasticsearch/data"
stateful_headless_servicefalsetrue
enable_pod_disruption_budgettruetrue
image_sourcevaries"prebuilt"
database_typevaries"NONE" (hard-coded)
enable_cloudsql_volumetruefalse (hard-coded)
enable_redisvariesfalse (hard-coded)
create_cloud_storagetruefalse
enable_nfsfalsefalse
module_dependencyvaries["Services GCP"]
credit_costvaries150

Architecture

Elasticsearch_GKE
└── App_GKE (foundation module)
├── GKE Autopilot cluster
├── Kubernetes StatefulSet (elasticsearch)
│ ├── PVC: 30Gi at /usr/share/elasticsearch/data
│ └── fsGroup=1000 (UID of the elasticsearch process)
├── Kubernetes Service (LoadBalancer on port 9200)
├── Headless Service (stable pod DNS)
└── PodDisruptionBudget (min 1 available)

Automatically injected environment variables

The module assembles a local es_env_vars map that is always injected, regardless of environment_variables:

VariableValuePurpose
discovery.type"single-node"Disables cluster discovery for single-node operation.
cluster.namevar.cluster_nameElasticsearch cluster name.
network.host"0.0.0.0"Binds to all interfaces for Kubernetes service forwarding.
http.portvar.container_portHTTP API port (default 9200).
transport.port"9300"Internal transport port.
path.data"/usr/share/elasticsearch/data"Data directory (must match stateful_pvc_mount_path).
path.logs"/usr/share/elasticsearch/logs"Log directory.
ES_JAVA_OPTS"-Xms<heap> -Xmx<heap>"JVM heap sizing from es_java_heap.
xpack.security.enabledvar.enable_xpack_securityX-Pack security toggle.
xpack.security.http.ssl.enabled"false"TLS disabled (HTTP only).
indices.memory.index_buffer_size"10%"Indexing buffer fraction.
bootstrap.memory_lock"false"Required on GKE Autopilot (no privileged initContainers).
node.store.allow_mmap"false"Disables mmap — required because GKE Autopilot cannot raise vm.max_map_count via privileged initContainers. Incurs a minor sequential-read penalty vs. mmap mode.

User-supplied environment_variables are merged after these defaults, so they can override any of the above.


§2 · IAM & Project Identity (Group 0 & 1)

VariableTypeDefaultDescription
module_descriptionstring(Elasticsearch GKE description)Platform UI description. {{UIMeta group=0 order=1}}
module_documentationstring"https://docs.radmodules.dev/docs/modules/Elasticsearch_GKE"Documentation URL. {{UIMeta group=0 order=2}}
module_dependencylist(string)["Services GCP"]Modules that must be deployed first. {{UIMeta group=0 order=3}}
module_serviceslist(string)["Google Kubernetes Engine", "Persistent Disk", ...]GCP services consumed. {{UIMeta group=0 order=4}}
credit_costnumber150Platform credits consumed on deployment. {{UIMeta group=0 order=5}}
require_credit_purchasesboolfalseEnforce credit balance check. {{UIMeta group=0 order=6}}
enable_purgebooltruePermit full deletion on destroy. {{UIMeta group=0 order=7}}
public_accessbooltruePlatform UI visibility. {{UIMeta group=0 order=8}}
deployment_idstring""Fixed deployment ID; auto-generated when blank. {{UIMeta group=0 order=9}}
resource_creator_identitystring"rad-module-creator@tec-rad-ui-2b65.iam.gserviceaccount.com"Terraform service account. {{UIMeta group=0 order=9}}
project_idstringrequiredGCP project ID. {{UIMeta group=1 order=1}}
tenant_deployment_idstring"demo"1–20 lowercase letters, numbers, hyphens. {{UIMeta group=1 order=2}}
support_userslist(string)[]Email addresses granted IAM access and monitoring alerts. {{UIMeta group=1 order=3}}
resource_labelsmap(string){}Labels applied to all resources. {{UIMeta group=1 order=4}}
deployment_regionstring"us-central1"GCP region fallback when VPC discovery finds no subnets. {{UIMeta group=1 order=5}}

§3 · Application Identity (Group 2)

VariableTypeDefaultDescription
application_namestring"elasticsearch"Base name for Kubernetes resources and resource prefix. Do not change after deployment. {{UIMeta group=2 order=1}}
application_display_namestring"Elasticsearch"Human-readable name in the UI. {{UIMeta group=2 order=2}}
application_descriptionstring"Elasticsearch search and analytics engine on GKE Autopilot"Description in Kubernetes annotations. {{UIMeta group=2 order=3}}
application_versionstring"8.13.4"Elasticsearch image tag. Increment to trigger a new image pull and rollout. {{UIMeta group=2 order=4}}
cluster_namestring"ragflow"Elasticsearch cluster name injected via cluster.name. Use a descriptive name tied to the use case. {{UIMeta group=2 order=5}}

§4 · Runtime & Scaling (Group 3)

VariableTypeDefaultDescription
deploy_applicationbooltrueSet false to provision the GKE namespace and IAM without deploying the Elasticsearch workload. {{UIMeta group=3 order=0}}
container_image_sourcestring"prebuilt"Always "prebuilt" — Elasticsearch uses the official image. Options: prebuilt, custom. {{UIMeta group=3 order=1}}
container_imagestring""Override image URI. Leave empty to use docker.elastic.co/elasticsearch/elasticsearch. {{UIMeta group=3 order=2}}
container_build_configobject{ enabled=false }Not used for Elasticsearch. {{UIMeta group=3 order=3}}
enable_image_mirroringbooltrueMirror the Elasticsearch image from Elastic's registry to Artifact Registry before deployment. {{UIMeta group=3 order=4}}
min_instance_countnumber1Minimum pod replicas. Keep at 1 for single-node mode. {{UIMeta group=3 order=5}}
max_instance_countnumber1Maximum pod replicas. Keep at 1 for single-node mode. Increasing this without changing discovery.type will cause split-brain. {{UIMeta group=3 order=6}}
enable_vertical_pod_autoscalingboolfalseEnable VPA. {{UIMeta group=3 order=7}}
container_portnumber9200Elasticsearch HTTP port. {{UIMeta group=3 order=8}}
container_protocolstring"http1"HTTP protocol version. Options: http1, h2c. {{UIMeta group=3 order=9}}
container_resourcesobject{ cpu_limit="1000m", memory_limit="512Mi" }Full container resource override. When set, takes precedence over cpu_limit and memory_limit. {{UIMeta group=3 order=10}}
timeout_secondsnumber300Load balancer backend timeout. Valid range: 0–3600. {{UIMeta group=3 order=11}}
enable_cloudsql_volumeboolfalseNot used for Elasticsearch. Always false. {{UIMeta group=3 order=12}}
cloudsql_volume_mount_pathstring"/cloudsql"Not used for Elasticsearch. {{UIMeta group=3 order=13}}
service_annotationsmap(string){}Custom annotations on the Kubernetes Service. {{UIMeta group=3 order=14}}
service_labelsmap(string){}Custom labels on the Kubernetes Service. {{UIMeta group=3 order=15}}
cpu_limitstring"2000m"CPU limit. Must be sufficient to handle the configured JVM heap without CPU throttling. {{UIMeta group=3 order=20}}
memory_limitstring"4Gi"Memory limit. Must be at least 2× es_java_heap to leave headroom for OS page cache and JVM overhead. {{UIMeta group=3 order=21}}
es_java_heapstring"1g"JVM heap size (sets both -Xms and -Xmx). Should be no more than half of memory_limit. (e.g. "1g", "2g", "4g") {{UIMeta group=3 order=22}}
enable_xpack_securityboolfalseEnable Elasticsearch X-Pack security (authentication). When false, the cluster is accessible without credentials. Recommended false for initial setup alongside RAGFlow; enable for production after configuring certificates. {{UIMeta group=3 order=23}}

Heap sizing rule: es_java_heapmemory_limit / 2. Example: memory_limit = "4Gi"es_java_heap = "2g". Elasticsearch also needs memory for the OS page cache to accelerate index segment reads.


§5 · GKE Backend Configuration (Group 5)

VariableTypeDefaultDescription
gke_cluster_namestring""GKE cluster name. Auto-discovered when empty. {{UIMeta group=5 order=1}}
gke_cluster_selection_modestring"primary"Cluster selection strategy. Options: explicit, round-robin, primary. {{UIMeta group=5 order=2}}
namespace_namestring""Kubernetes namespace. Auto-generated when empty. {{UIMeta group=5 order=3}}
workload_typestring"StatefulSet"Required StatefulSet for data persistence. Deployment is not recommended — PVC data would not survive pod reschedule. {{UIMeta group=5 order=4}}
service_typestring"LoadBalancer""LoadBalancer" is required for cross-namespace access from RAGFlow GKE. "ClusterIP" requires RAGFlow and Elasticsearch to share the same namespace. Options: ClusterIP, LoadBalancer, NodePort. {{UIMeta group=5 order=5}}
session_affinitystring"None"Session affinity for the Kubernetes Service. {{UIMeta group=5 order=6}}
enable_multi_cluster_serviceboolfalseEnable Multi-Cluster Services (MCS). {{UIMeta group=5 order=7}}
configure_service_meshboolfalseEnable Istio service mesh. {{UIMeta group=5 order=8}}
enable_network_segmentationboolfalseApply Kubernetes NetworkPolicies. {{UIMeta group=5 order=9}}
termination_grace_period_secondsnumber120Seconds Kubernetes waits after SIGTERM. Elasticsearch needs time to flush segments. Valid range: 0–3600. {{UIMeta group=5 order=10}}
deployment_timeoutnumber1800Seconds Terraform waits for the StatefulSet rollout. Elasticsearch shard recovery can be slow. {{UIMeta group=5 order=11}}

§6 · StatefulSet & Persistence (Group 6)

Data persistence is critical for Elasticsearch — all index data lives in the PVC.

VariableTypeDefaultDescription
stateful_pvc_enabledbooltrueRequired for data durability. Provisions a PVC per StatefulSet pod. {{UIMeta group=6 order=1}}
stateful_pvc_sizestring"30Gi"PVC size. Size based on expected index volume. (e.g. "30Gi" for small RAGFlow deployments, "200Gi" for large production indexes) {{UIMeta group=6 order=2}}
stateful_pvc_mount_pathstring"/usr/share/elasticsearch/data"Must match the path.data Elasticsearch setting. Do not change. {{UIMeta group=6 order=3}}
stateful_pvc_storage_classstring"standard-rwo"GKE StorageClass. "premium-rwo" provides higher IOPS for production index workloads. {{UIMeta group=6 order=4}}
stateful_headless_servicebooltrueCreates a headless Service for stable pod DNS. {{UIMeta group=6 order=5}}
stateful_pod_management_policystring"OrderedReady""OrderedReady" or "Parallel". {{UIMeta group=6 order=6}}
stateful_update_strategystring"RollingUpdate""RollingUpdate" or "OnDelete". {{UIMeta group=6 order=7}}
stateful_fs_groupnumbernullPod fsGroup GID so the Elasticsearch process (UID 1000) can write to the PVC. Defaults to 1000 via the module's application config; override only if using a custom image with a different GID. {{UIMeta group=6 order=8}}

§7 · Environment Variables & Secrets (Group 4)

VariableTypeDefaultDescription
environment_variablesmap(string){}Additional env vars injected into the Elasticsearch container. Merged after the auto-injected ES settings; can override any auto-injected value. {{UIMeta group=4 order=1}}
secret_environment_variablesmap(string){}Secret Manager secret references injected as env vars. {{UIMeta group=4 order=2}}
secret_rotation_periodstring"2592000s"Rotation notification period (30 days). {{UIMeta group=4 order=3}}
secret_propagation_delaynumber30Seconds to wait after secret creation. {{UIMeta group=4 order=4}}

§8 · Access & Networking (Groups 18–21)

VariableTypeDefaultDescription
enable_iapboolfalseNot recommended for Elasticsearch — use NetworkPolicy instead. {{UIMeta group=19 order=1}}
iap_authorized_userslist(string)[]IAP user allowlist. {{UIMeta group=19 order=2}}
iap_authorized_groupslist(string)[]IAP group allowlist. {{UIMeta group=19 order=3}}
iap_oauth_client_idstring""OAuth 2.0 client ID for IAP. Sensitive. {{UIMeta group=19 order=4}}
iap_oauth_client_secretstring""OAuth 2.0 client secret. Sensitive. {{UIMeta group=19 order=5}}
iap_support_emailstring""Support email for the OAuth consent screen. {{UIMeta group=19 order=6}}
enable_custom_domainboolfalseProvision a Kubernetes Ingress for custom domain routing. {{UIMeta group=18 order=1}}
application_domainslist(string)[]Custom domain names for the Ingress. {{UIMeta group=18 order=2}}
reserve_static_ipboolfalseReserve a global static external IP. {{UIMeta group=18 order=3}}
static_ip_namestring""Static IP name. Auto-generated when empty. {{UIMeta group=18 order=4}}
network_tagslist(string)["nfsserver"]GCP network tags applied to GKE pods. {{UIMeta group=18 order=5}}
network_namestring""VPC network name. Auto-discovered when empty. {{UIMeta group=18 order=6}}
enable_cloud_armorboolfalseAttach Cloud Armor WAF policy. {{UIMeta group=20 order=1}}
admin_ip_rangeslist(string)[]Admin CIDR ranges. {{UIMeta group=20 order=2}}
cloud_armor_policy_namestring"default-waf-policy"Cloud Armor policy name. {{UIMeta group=20 order=3}}
enable_cdnboolfalseNot applicable for Elasticsearch. {{UIMeta group=20 order=4}}
enable_vpc_scboolfalseEnable VPC Service Controls perimeter. {{UIMeta group=21 order=1}}
vpc_cidr_rangeslist(string)[]VPC subnet CIDRs for VPC-SC. {{UIMeta group=21 order=2}}
vpc_sc_dry_runbooltrueLog VPC-SC violations without blocking. {{UIMeta group=21 order=3}}
organization_idstring""GCP Organization ID for VPC-SC policy. {{UIMeta group=21 order=4}}
enable_audit_loggingboolfalseEnable detailed Cloud Audit Logs. {{UIMeta group=21 order=5}}

§9 · Storage (Group 13) — Not Used

Elasticsearch stores all data in the PVC. No GCS buckets or NFS mounts are needed.

VariableTypeDefaultDescription
create_cloud_storageboolfalseNot required for Elasticsearch. {{UIMeta group=13 order=1}}
storage_bucketslist(object)[]Not required for Elasticsearch. {{UIMeta group=13 order=2}}
gcs_volumeslist(object)[]Not required for Elasticsearch. {{UIMeta group=13 order=3}}
manage_storage_kms_iamboolfalseCreate CMEK KMS keyring for storage encryption. {{UIMeta group=13 order=4}}
enable_artifact_registry_cmekboolfalseEnable CMEK for Artifact Registry. {{UIMeta group=13 order=5}}
enable_nfsboolfalseNot required — use StatefulSet PVC instead. {{UIMeta group=12 order=1}}
nfs_mount_pathstring"/mnt/nfs"NFS mount path (present for interface compatibility). {{UIMeta group=12 order=2}}
nfs_instance_namestring""NFS instance name (present for interface compatibility). {{UIMeta group=12 order=3}}
nfs_instance_base_namestring"app-nfs"NFS base name (present for interface compatibility). {{UIMeta group=12 order=4}}

§10 · Observability & Health (Group 9)

Probes use TCP (not HTTP) because:

  • HTTP probes would return 401 Unauthorized when enable_xpack_security = true.
  • TCP probes validate that the port is open, which implies the Elasticsearch bootstrap checks have passed — a stronger readiness signal than an HTTP path check.
VariableTypeDefaultDescription
startup_probe_configobject{ enabled=true, type="HTTP", path="/_cluster/health", initial_delay_seconds=30, period_seconds=10, failure_threshold=18 }App GKE-standard startup probe. The 18-attempt threshold (3 minutes) allows for shard recovery. {{UIMeta group=9 order=1}}
health_check_configobject{ enabled=true, type="HTTP", path="/_cluster/health", initial_delay_seconds=60, period_seconds=30, failure_threshold=3 }App GKE-standard liveness probe. {{UIMeta group=9 order=2}}
uptime_check_configobject{ enabled=false, path="/_cluster/health", check_interval="60s", timeout="10s" }Cloud Monitoring uptime check. Disabled by default. {{UIMeta group=9 order=3}}
alert_policieslist(object)[]Cloud Monitoring alert policies. {{UIMeta group=9 order=4}}

Note: The container-level probes (forwarded via the application config) use TCP, while startup_probe_config and health_check_config at the App GKE level default to HTTP with /_cluster/health. When enable_xpack_security = true, override both configs to use TCP.


§11 · Reliability Policies (Group 8)

VariableTypeDefaultDescription
enable_pod_disruption_budgetbooltrueCreate a PodDisruptionBudget. Recommended for production Elasticsearch. {{UIMeta group=8 order=1}}
pdb_min_availablestring"1"Minimum pods available during voluntary disruptions. For single-node ES, "1" prevents any voluntary disruption from succeeding — increase the node count before reducing this. {{UIMeta group=8 order=2}}
enable_topology_spreadboolfalseAdd TopologySpreadConstraints. {{UIMeta group=8 order=3}}
topology_spread_strictboolfalseDoNotSchedule (strict) vs ScheduleAnyway. {{UIMeta group=8 order=4}}

§12 · Backup & CI/CD (Groups 11 & 16)

VariableTypeDefaultDescription
backup_schedulestring"0 2 * * *"Backup cron schedule (UTC). For Elasticsearch, consider Elasticsearch Snapshots to GCS rather than OS-level backups. {{UIMeta group=16 order=1}}
backup_retention_daysnumber7Days to retain backup files. {{UIMeta group=16 order=2}}
enable_backup_importboolfalseNot applicable for Elasticsearch. {{UIMeta group=16 order=3}}
backup_sourcestring"gcs"Backup import source. Options: gcs, gdrive. {{UIMeta group=16 order=4}}
backup_uristring""Backup file URI for import. {{UIMeta group=6 order=7}}
backup_formatstring"sql"Backup file format. {{UIMeta group=16 order=6}}
enable_cicd_triggerboolfalseCreate a Cloud Build trigger on GitHub pushes. {{UIMeta group=11 order=1}}
github_repository_urlstring""GitHub repository URL. {{UIMeta group=11 order=2}}
github_tokenstring""GitHub Personal Access Token. Sensitive. {{UIMeta group=11 order=3}}
github_app_installation_idstring""Cloud Build GitHub App installation ID. {{UIMeta group=11 order=4}}
cicd_trigger_configobject{ branch_pattern="^main$" }CI/CD trigger configuration. {{UIMeta group=11 order=5}}
enable_cloud_deployboolfalseSwitch to Cloud Deploy pipeline. {{UIMeta group=11 order=6}}
cloud_deploy_stageslist(object)[dev, staging, prod(approval)]Cloud Deploy pipeline stages. {{UIMeta group=11 order=7}}
enable_binary_authorizationboolfalseEnforce Binary Authorization. {{UIMeta group=11 order=8}}

§13 · Database (Group 15) — Not Used

Elasticsearch requires no Cloud SQL. All variables are present for interface compatibility with App GKE.

VariableTypeDefaultDescription
database_typestring"NONE"Hard-coded to NONE in main.tf. Not configurable. {{UIMeta group=15 order=1}}
application_database_namestring"none"Not used. {{UIMeta group=15 order=4}}
application_database_userstring"none"Not used. {{UIMeta group=15 order=5}}
database_password_lengthnumber32Not used. Valid range: 16–64. {{UIMeta group=15 order=6}}
enable_postgres_extensionsboolfalseNot used. {{UIMeta group=15 order=7}}
postgres_extensionslist(string)[]Not used. {{UIMeta group=15 order=8}}
enable_mysql_pluginsboolfalseNot used. {{UIMeta group=15 order=9}}
mysql_pluginslist(string)[]Not used. {{UIMeta group=15 order=10}}
enable_auto_password_rotationboolfalseNot applicable when database_type = "NONE". {{UIMeta group=15 order=11}}
rotation_propagation_delay_secnumber90Not applicable. {{UIMeta group=15 order=12}}

§14 · Workload Automation (Group 10 & 17)

Elasticsearch requires no initialization jobs or custom SQL.

VariableTypeDefaultDescription
initialization_jobslist(object)[]Kubernetes Jobs run before Elasticsearch starts. Each job requires at least one of command, args, or script_path. {{UIMeta group=10 order=1}}
cron_jobslist(object)[]Recurring Kubernetes CronJobs. {{UIMeta group=10 order=2}}
additional_serviceslist(object)[]Additional container deployments. {{UIMeta group=10 order=3}}
enable_custom_sql_scriptsboolfalseNot used for Elasticsearch. {{UIMeta group=17 order=1}}
custom_sql_scripts_bucketstring""Not used. {{UIMeta group=17 order=2}}
custom_sql_scripts_pathstring""Not used. {{UIMeta group=17 order=3}}
custom_sql_scripts_use_rootboolfalseNot used. {{UIMeta group=17 order=4}}

§15 · Resource Quota (Group 7)

VariableTypeDefaultDescription
enable_resource_quotaboolfalseCreate a Kubernetes ResourceQuota. {{UIMeta group=7 order=1}}
quota_cpu_requestsstring""Total CPU requests allowed in the namespace. {{UIMeta group=7 order=2}}
quota_cpu_limitsstring""Total CPU limits allowed. {{UIMeta group=7 order=3}}
quota_memory_requestsstring""Total memory requests allowed. {{UIMeta group=7 order=4}}
quota_memory_limitsstring""Total memory limits allowed. {{UIMeta group=7 order=5}}

§16 · Outputs

OutputDescription
service_nameKubernetes service name.
service_urlService URL.
service_external_ipExternal IP of the LoadBalancer service.
elasticsearch_endpointPrimary output for RAGFlow. http://<service_external_ip>:9200. Pass this to RAGFlow_GKE's elasticsearch_hosts variable. Returns null if the external IP is not yet assigned.
project_idGCP project ID.
deployment_idUnique deployment identifier.
namespaceKubernetes namespace.
storage_bucketsProvisioned GCS buckets (empty list — no buckets are provisioned).
nfs_server_ipNFS server IP (sensitive). Returns null when enable_nfs = false.
nfs_mount_pathNFS mount path.
container_imageContainer image URI.
cicd_enabledWhether CI/CD pipeline is enabled.
github_repository_urlConnected GitHub repository URL.
kubernetes_readytrue when the GKE cluster endpoint is available and all workload resources have been deployed. false on first apply of a new cluster — the CI/CD pipeline must re-run apply to complete deployment.

§17 · Configuration Examples

Basic Deployment

Minimal single-node Elasticsearch for RAGFlow integration. Deploy this first, then use elasticsearch_endpoint in RAGFlow GKE.

# config/basic.tfvars
resource_creator_identity = ""
project_id = "your-gcp-project-id"
tenant_deployment_id = "basic"

application_version = "8.13.4"

es_java_heap = "1g"
cpu_limit = "2000m"
memory_limit = "4Gi"

stateful_pvc_size = "30Gi"

service_type = "LoadBalancer"

After deployment:

tofu output elasticsearch_endpoint
# → http://1.2.3.4:9200
# Paste this into RAGFlow_GKE tfvars as: elasticsearch_hosts = "http://1.2.3.4:9200"

Advanced Deployment

Production-grade Elasticsearch with large heap, premium SSD, and monitoring.

# config/advanced.tfvars
resource_creator_identity = ""
project_id = "your-gcp-project-id"
tenant_deployment_id = "prod"

application_version = "8.13.4"
cluster_name = "ragflow-production"

es_java_heap = "4g"
cpu_limit = "8000m"
memory_limit = "10Gi"
stateful_pvc_size = "200Gi"

stateful_pvc_storage_class = "premium-rwo"

service_type = "LoadBalancer"
reserve_static_ip = false

enable_pod_disruption_budget = true
pdb_min_available = "1"

uptime_check_config = {
enabled = true
path = "/_cluster/health"
check_interval = "60s"
timeout = "10s"
}

resource_labels = {
env = "production"
service = "elasticsearch"
}

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).

VariableSensible DefaultRiskConsequence of Incorrect Value
es_java_heap"512m"CriticalJVM heap must be set to no more than half of memory_limit. The default 512m heap with the default 4Gi memory limit is safe but under-provisioned for production. Setting es_java_heap greater than memory_limit / 2 causes the JVM to compete with OS page cache, severely degrading performance and eventually causing OOM kills. For a 4Gi container, the heap should be no more than 2g.
memory_limit"4Gi"CriticalElasticsearch requires enough memory for JVM heap plus OS page cache. The container memory must be at least 2 × es_java_heap. Setting memory_limit below 2 × es_java_heap causes the Elasticsearch process to be killed by the OOM killer during index operations. For production with es_java_heap = "2g", set memory_limit = "4Gi" or higher.
stateful_pvc_enablednullCriticalWithout a PVC, Elasticsearch stores all indexes in the ephemeral pod filesystem. Any pod restart, rolling update, or node eviction permanently destroys all indexed data. Set stateful_pvc_enabled = true for all production deployments.
stateful_pvc_size"30Gi"HighAn undersized PVC causes Elasticsearch to trigger flood-stage watermark protection (default: 95% full), making the index read-only. All write operations are rejected until disk is freed. Index data cannot be reduced without deleting indices — plan capacity with 50–100% headroom above expected data volume.
stateful_pvc_mount_path"/usr/share/elasticsearch/data"CriticalMust match Elasticsearch's path.data configuration. A mismatch causes Elasticsearch to write data to the ephemeral container layer, silently losing all indexes on pod restart. Do not change this value.
cluster_name"ragflow"Criticalcluster.name is baked into node identity. Changing the cluster name after initial deployment causes Elasticsearch to treat itself as a new cluster, rejecting all existing data on the PVC as foreign. Rename requires full data re-indexing. Choose a meaningful name before first deploy.
enable_xpack_securityfalseHighWhen false, the Elasticsearch HTTP endpoint is accessible without credentials. Any caller who can reach port 9200 can read, modify, or delete all indexes. Enable for production. Note: enabling on an existing deployment that was created with false requires certificate generation and rolling restart — plan carefully.
workload_typenullHighElasticsearch requires StatefulSet for stable pod identity and orderly PVC attachment. Defaulting to Deployment without PVC support risks data inconsistency. Use stateful_pvc_enabled = true which auto-selects StatefulSet.
cpu_limit"2000m"HighElasticsearch is CPU-intensive during indexing (BM25 scoring, vector kNN graph construction). Under 1000m, indexing throughput degrades and cluster bootstrap can time out. For RAGFlow use, 2000m is a reasonable baseline; scale to 4000m for heavy ingestion.
min_instance_count1HighScale-to-zero is not supported for Elasticsearch — the GKE StatefulSet pod should always be running. Setting min_instance_count = 0 with HPA can cause the pod to be removed, losing all in-memory state and requiring a slow recovery from PVC.
max_instance_count1MediumThis module deploys a single-node Elasticsearch cluster. Increasing max_instance_count beyond 1 provisions multiple isolated single-node clusters, not a distributed cluster. For multi-node Elasticsearch, use a dedicated operator (e.g., ECK).
index mapping immutability(immutable after first indexing)CriticalElasticsearch index mappings (field types, dense_vector dimensions) are immutable after documents are indexed. Changing an embedding dimension (e.g. from 768 to 1536) requires deleting the index and re-indexing all documents. Plan embedding model selection carefully before production deployment.
fsgroup_id1000HighElasticsearch runs as UID/GID 1000. The fsGroup in the StatefulSet security context chowns the PVC mount to this GID. Setting fsgroup_id = 0 (disabled) leaves the PVC mounted as root-owned; the Elasticsearch process cannot write to it and crashes immediately.
stateful_pvc_storage_class"standard-rwo"MediumBalanced PD is adequate for typical log/search workloads. High-throughput vector kNN indexing benefits from premium-rwo. Storage class cannot be changed after PVC creation.
enable_image_mirroringtrueLowDisabling mirroring pulls from the Elastic Docker registry directly. Docker Hub / Elastic registry pull rate limits can cause intermittent deployment failures. Keep mirroring enabled.
application_version"8.13.4"MediumElasticsearch minor version upgrades are generally safe. Major version upgrades (7.x → 8.x) require index compatibility checks and may need a re-index of all data. Do not upgrade major versions without consulting the Elasticsearch migration guide.
enable_iapfalseHighWithout IAP, the GKE LoadBalancer endpoint is accessible to any caller (subject to firewall). Enable enable_xpack_security = true and IAP together for defense-in-depth on public-facing deployments.
quota_memory_requests""CriticalIf enable_resource_quota = true and this value is set as a bare integer (e.g. "4" instead of "4Gi"), Kubernetes treats it as bytes, blocking all pod scheduling. Always use binary suffixes (Gi or Mi).