Install CloudPilot AI with Terraform or OpenTofu
Use the CloudPilot AI modules to onboard an existing Amazon EKS or Google Kubernetes Engine (GKE) cluster and manage Node Autoscaler and Workload Autoscaler configuration as code.
Recommended: Start with the EKS or GKE module. The modules provide a cloud-specific interface, reusable NodeClass and NodePool templates, and the correct dependency wiring between the cluster and Workload Autoscaler resources. Use the provider resources directly only when you need lower-level lifecycle control.
Choose an integration
| Integration | Use it for | Registry |
|---|---|---|
| EKS module | Recommended EKS onboarding and configuration | Terraform Registry · OpenTofu Registry |
| GKE module | Recommended GKE onboarding and configuration | Terraform Registry · OpenTofu Registry |
| CloudPilot AI provider | Direct resource and data-source access | Terraform Registry · OpenTofu Registry |
The same HCL configuration works with Terraform and OpenTofu. Run either the
terraform commands or the equivalent tofu commands shown below.
Prerequisites
- Terraform 1.0 or later, or OpenTofu 1.6 or later
- kubectl and HelmÂ
- A CloudPilot AI API key
- For EKS: the AWS CLIÂ with access to the target cluster
- For GKE: the Google Cloud CLI with access to the target cluster and project, plus Workload Identity when enabling Node Autoscaler or rebalance
CloudPilot AI manages an existing Kubernetes cluster. Create the EKS or GKE cluster before applying the CloudPilot AI module.
Configure the provider
Declare the provider once in your root module. Keep the API key outside source control and pass it through a sensitive input variable.
terraform {
# Required by this guide. Allowed: Terraform >= 1.0 or a compatible OpenTofu release.
# Behavior: rejects runs that use an older CLI.
required_version = ">= 1.0"
required_providers {
cloudpilotai = {
# Required. Allowed: the official CloudPilot AI provider address.
# Behavior: selects the provider package from the Terraform or OpenTofu Registry.
source = "cloudpilot-ai/cloudpilotai"
# Required for reproducible installs. Allowed: Terraform version constraints.
# Behavior: accepts provider 0.6.x releases but not 0.7.0 or later.
version = "~> 0.6"
}
}
}
variable "cloudpilotai_api_key" {
# Required by the api_key authentication method. Allowed: a CloudPilot AI API key string.
# Behavior: authenticates provider requests; sensitive hides it from normal CLI output.
type = string
sensitive = true
}
provider "cloudpilotai" {
# Required unless api_key_profile is used. Allowed: a valid CloudPilot AI API key.
# Behavior: authenticates every CloudPilot AI API request.
api_key = var.cloudpilotai_api_key
# Optional (default: https://api.cloudpilot.ai). Allowed: a valid HTTPS URL.
# Behavior: sends provider requests to a custom CloudPilot AI API endpoint.
# api_endpoint = "https://api.cloudpilot.ai"
}To read the API key from a file instead, replace api_key with
api_key_profile. Do not configure both authentication methods.
provider "cloudpilotai" {
# Required unless api_key is used. Allowed: path to a readable file containing the API key.
# Behavior: reads the API key from disk; api_key takes precedence if both are set.
api_key_profile = "/secure/path/cloudpilot-api-key"
# Optional (default: https://api.cloudpilot.ai). Allowed: a valid HTTPS URL.
# Behavior: sends provider requests to a custom CloudPilot AI API endpoint.
# api_endpoint = "https://api.cloudpilot.ai"
}For local use, set the sensitive variable without adding a .tfvars file to
Git:
export TF_VAR_cloudpilotai_api_key="<cloudpilot-api-key>"Recommended quick start: EKS module
The EKS module installs CloudPilot AI using the ambient AWS credential chain.
Set aws_profile for local named-profile access or aws_assume_role for
CI/OIDC workflows.
module "cloudpilotai_eks" {
# Required. Allowed: the official EKS module address.
# Behavior: downloads the CloudPilot AI EKS module.
source = "cloudpilot-ai/eks/cloudpilotai"
# Required for reproducible installs. Allowed: Terraform version constraints.
# Behavior: accepts module 0.5.x releases but not 0.6.0 or later.
version = "~> 0.5"
# Required. Allowed: a non-empty existing EKS cluster name.
# Behavior: selects the cluster to onboard and manage.
cluster_name = "my-eks-cluster"
# Required. Allowed: an AWS Region ID such as us-west-2.
# Behavior: locates the EKS cluster and its AWS resources.
region = "us-west-2"
# Optional (default: false). Allowed: true or false.
# Behavior: enables Node Autoscaler rebalance; true overrides only_install_agent.
enable_rebalance = true
# Optional (default: 0). Allowed: a non-negative integer; 0 disables restore.
# Behavior: restores this many nodes before uninstall on destroy.
restore_node_number = 3
# Optional (default: true). Allowed: true or false.
# Behavior: creates and manages Workload Autoscaler configuration.
enable_workload_autoscaler = true
# Optional (default: []). Allowed: EKS NodeClass objects described in the full reference.
# Behavior: creates concrete NodeClasses; names must be unique.
nodeclasses = [
{
# Required. Allowed: a unique Kubernetes-compatible NodeClass name.
# Behavior: identifies this concrete NodeClass.
name = "cloudpilot"
# Optional. Allowed: a valid Karpenter EKS AMI alias such as al2023@latest.
# Behavior: selects the base AMI family/version for launched nodes.
ami_alias = "al2023@latest"
# Optional. Allowed: a positive integer GiB; do not combine with block_device_mappings.
# Behavior: sets the root system disk size.
system_disk_size_gib = 80
}
]
# Optional (default: []). Allowed: NodePool objects described in the full reference.
# Behavior: creates concrete NodePools; names must be unique.
nodepools = [
{
# Required. Allowed: a unique Kubernetes-compatible NodePool name.
# Behavior: identifies this concrete NodePool.
name = "cloudpilot-general"
# Optional. Allowed: the name of a NodeClass in this configuration.
# Behavior: makes the NodePool launch nodes through that NodeClass.
nodeclass = "cloudpilot"
# Optional. Allowed: spot and/or on-demand.
# Behavior: restricts the capacity types the NodePool may provision.
capacity_type = ["spot", "on-demand"]
# Optional. Allowed: amd64 and/or arm64.
# Behavior: restricts CPU architectures unless instance_family takes precedence.
instance_arch = ["amd64"]
}
]
}Recommended quick start: GKE module
For a regional cluster, region is also the cluster location. Set
cluster_location for a zonal cluster. When project_id, cluster_uid, or
kubeconfig is omitted, the provider attempts to discover it from GKE,
Kubernetes, and the active gcloud configuration.
module "cloudpilotai_gke" {
# Required. Allowed: the official GKE module address.
# Behavior: downloads the CloudPilot AI GKE module.
source = "cloudpilot-ai/gke/cloudpilotai"
# Required for reproducible installs. Allowed: Terraform version constraints.
# Behavior: accepts module 0.2.x releases but not 0.3.0 or later.
version = "~> 0.2"
# Required. Allowed: a non-empty existing GKE cluster name.
# Behavior: selects the cluster to onboard and manage.
cluster_name = "my-gke-cluster"
# Required. Allowed: a Google Cloud region ID such as us-central1.
# Behavior: selects the regional control-plane context and module resources.
region = "us-central1"
# Optional (default: discovered). Allowed: a Google Cloud project ID.
# Behavior: locates the cluster; omitted uses metadata, then active gcloud project.
project_id = "my-gcp-project"
# Optional (default: false). Allowed: true or false.
# Behavior: enables Node Autoscaler rebalance; true overrides only_install_agent.
enable_rebalance = true
# Optional (default: unset). Allowed: a non-negative integer; 0 means no restore.
# Behavior: restores this total node count before uninstall on destroy.
restore_node_number = 3
# Optional (default: true). Allowed: true or false.
# Behavior: creates and manages Workload Autoscaler configuration.
enable_workload_autoscaler = true
# Optional (default: []). Allowed: GCE NodeClass objects described in the full reference.
# Behavior: creates concrete NodeClasses; names must be unique.
nodeclasses = [
{
# Required. Allowed: a unique Kubernetes-compatible NodeClass name.
# Behavior: identifies this concrete NodeClass.
name = "cloudpilot"
# Optional. Allowed: a valid Google service-account email.
# Behavior: attaches that identity to nodes launched through the NodeClass.
service_account = "nodes@my-gcp-project.iam.gserviceaccount.com"
}
]
# Optional (default: []). Allowed: NodePool objects described in the full reference.
# Behavior: creates concrete NodePools; names must be unique.
nodepools = [
{
# Required. Allowed: a unique Kubernetes-compatible NodePool name.
# Behavior: identifies this concrete NodePool.
name = "cloudpilot-general"
# Optional. Allowed: the name of a NodeClass in this configuration.
# Behavior: makes the NodePool launch nodes through that NodeClass.
nodeclass = "cloudpilot"
# Optional. Allowed: spot and/or on-demand.
# Behavior: restricts the capacity types the NodePool may provision.
capacity_type = ["spot", "on-demand"]
# Optional. Allowed: amd64 and/or arm64.
# Behavior: restricts CPU architectures unless instance_family takes precedence.
instance_arch = ["amd64"]
# Optional. Allowed: GCE machine-family names available in the selected region.
# Behavior: restricts provisioning to these families and takes precedence over architecture.
instance_family = ["n4", "n2", "e2"]
}
]
}Initialize, review, and apply
Use one CLI consistently for a working directory and commit its dependency lock file.
# Terraform
terraform init
terraform plan
terraform apply
# OpenTofu
tofu init
tofu plan
tofu applyReview every plan before applying it. A successful validate confirms HCL and
schema wiring; provider validators that require real values or cluster access
can run during plan.
Complete EKS module configuration
The following reference demonstrates every current EKS module input. Optional raw JSON fields and mutually exclusive or deprecated alternatives are left commented so the example remains safe to adapt.
Every input is preceded by a compact contract comment:
- Required/Optional states whether the schema requires the field and gives the default or omission behavior when relevant.
- Allowed lists an enum, range, format, or the kind of free-form value the field accepts.
- Behavior explains what CloudPilot AI does with the value. Map entries such as tag keys and label keys are user-defined data, so the comment is attached to the containing map rather than repeated for every entry.
module "cloudpilotai_eks" {
# Required. Allowed: the official EKS module address.
# Behavior: downloads the CloudPilot AI EKS module.
source = "cloudpilot-ai/eks/cloudpilotai"
# Required for reproducible installs. Allowed: Terraform version constraints.
# Behavior: accepts module 0.5.x releases but not 0.6.0 or later.
version = "~> 0.5"
# Required. Allowed: a non-empty existing EKS cluster name.
# Behavior: selects the cluster to onboard and manage.
cluster_name = "my-eks-cluster"
# Required. Allowed: an AWS Region ID such as us-west-2.
# Behavior: locates the EKS cluster and its AWS resources.
region = "us-west-2"
# Optional (default: null). Allowed: an existing CloudPilot cluster ID.
# Behavior: binds to that registration; null lets the provider look it up or create it.
cluster_id = null
# Optional (default: ""). Allowed: an AWS shared-config profile name.
# Behavior: an empty string uses the ambient/default AWS credential chain.
aws_profile = ""
# Optional (default: null). Allowed: an AWS role-assumption object.
# Behavior: assumes the role before reading or changing cluster resources.
aws_assume_role = {
# Required in aws_assume_role. Allowed: a valid IAM role ARN.
# Behavior: identifies the role to assume.
role_arn = "arn:aws:iam::123456789012:role/cloudpilot-terraform"
# Optional (default: cloudpilotai-terraform). Allowed: a valid STS session name.
# Behavior: labels the AssumeRole session in AWS audit records.
session_name = "cloudpilotai-terraform"
}
# Optional (default: null). Allowed: a readable kubeconfig path.
# Behavior: null makes the provider generate an execution-local kubeconfig.
kubeconfig = null
# Optional (default: null). Allowed: an IAM role name, not an ARN.
# Behavior: uses that node role for PassRole and install/upgrade operations.
custom_node_role = "CloudPilotNodeRole-my-eks-cluster"
# Optional (default: false). Allowed: true or false.
# Behavior: true installs monitoring only, unless enable_rebalance is also true.
only_install_agent = false
# Optional (default: false). Allowed: true or false.
# Behavior: enables Node Autoscaler rebalance and overrides only_install_agent.
enable_rebalance = true
# Optional (default: false). Allowed: true or false.
# Behavior: true stops uploading workload metadata to CloudPilot AI.
disable_workload_uploading = false
# Optional (default: false). Allowed: true or false.
# Behavior: checks the service and upgrades installed components when needed.
enable_upgrade = true
# Optional (default: null). Allowed: a cluster-setting object.
# Behavior: null leaves these server-side settings unmanaged.
cluster_setting = {
# Optional (omitted: unmanaged). Allowed: true or false.
# Behavior: enables or disables automatic unhealthy-node repair.
enable_node_repair = true
# Optional (omitted: unmanaged). Allowed: true or false.
# Behavior: enables or disables node disk-pressure monitoring.
enable_disk_monitor = true
# Optional (omitted: unmanaged). Allowed: true or false.
# Behavior: controls automatic decommissioning of obsolete node pools.
enable_node_pool_decommission = true
# Optional (omitted: unmanaged). Allowed: true or false.
# Behavior: enforces each workload's minimum non-Spot replica target.
enable_workload_min_non_spot = true
# Optional (omitted: unmanaged). Allowed: a numeric discount ratio.
# Behavior: adjusts cost calculations with the organization's effective discount.
discount = 0.15
# Optional (omitted: unmanaged). Allowed: a shell command string.
# Behavior: runs before CloudPilot AI's applicable cluster workflow.
pre_run_command = "kubectl get nodes"
# Optional (omitted: unmanaged). Allowed: a shell command string.
# Behavior: runs after CloudPilot AI's applicable cluster workflow.
post_run_command = "kubectl get pods -A"
}
# Optional (default: false). Allowed: true or false.
# Behavior: true skips node restoration during destroy and overrides restore_node_number.
skip_restore = false
# Optional (default: 0). Allowed: a non-negative integer; 0 disables restore.
# Behavior: restores this many nodes before uninstall during destroy.
restore_node_number = 3
# Optional (default: []). Allowed: reusable EKS NodeClass template objects.
# Behavior: defines settings inherited by nodeclasses that reference template_name.
nodeclass_templates = [
{
# Required. Allowed: a unique non-empty template name.
# Behavior: identifies this reusable NodeClass template.
template_name = "general"
# Optional (default: CloudPilotNodeRole-{cluster_name}). Allowed: an IAM role name.
# Behavior: attaches that role to EC2 instances launched through this NodeClass.
role = "CloudPilotNodeRole-my-eks-cluster"
# Optional (omitted: CloudPilot/server default). Allowed: true or false.
# Behavior: enables or disables peer-assisted image acceleration on launched nodes.
enable_image_accelerator = true
# Optional (omitted: CloudPilot/server default). Allowed: true or false.
# Behavior: uses instance-store NVMe as kubelet ephemeral storage when supported.
enable_local_ssd_ephemeral_storage = true
# Optional (omitted: CloudPilot default). Allowed: a Karpenter EKS AMI alias.
# Behavior: selects an AMI family/version, for example al2023@latest.
ami_alias = "al2023@latest"
# Optional (omitted: no custom user data). Allowed: a MIME or shell user-data string.
# Behavior: merges custom bootstrap data into launched instances.
user_data = "#!/bin/bash\necho cloudpilot"
# Optional (omitted: CloudPilot managed tags only). Allowed: map(string).
# Behavior: adds these AWS tags to provisioned instances and related resources.
instance_tags = {
"cloudpilot.ai/managed" = "true"
"environment" = "production"
}
# Optional (omitted: no extra allocation). Allowed: a non-negative integer millicores.
# Behavior: reserves additional reported CPU capacity for burstable workloads.
extra_cpu_allocation_mcore = 250
# Optional (omitted: no extra allocation). Allowed: a non-negative integer MiB.
# Behavior: reserves additional reported memory capacity for burstable workloads.
extra_memory_allocation_mib = 512
# Optional (omitted: CloudPilot default disks). Allowed: block-device objects.
# Behavior: configures EC2 volumes; mutually exclusive with system_disk_size_gib.
block_device_mappings = [
{
# Optional (omitted: provider/device default). Allowed: a Linux device path.
# Behavior: selects the instance device name for this mapping.
device_name = "/dev/xvda"
# Optional (omitted: inferred). Allowed: true or false.
# Behavior: marks this mapping as the root volume.
root_volume = true
# Optional (omitted: no EBS override). Allowed: an EBS configuration object.
# Behavior: configures the EBS volume attached at device_name.
ebs = {
# Optional (omitted: image/provider default). Allowed: a positive size such as 80Gi.
# Behavior: sets EBS volume capacity.
volume_size = "80Gi"
# Optional (omitted: image/provider default). Allowed: an EBS volume type such as gp3.
# Behavior: selects the EBS storage class.
volume_type = "gp3"
# Optional (omitted: image/provider default). Allowed: true or false.
# Behavior: enables or disables EBS encryption.
encrypted = true
}
}
]
# Optional alternative (omitted: CloudPilot default). Allowed: a positive integer GiB.
# Behavior: sets root-disk size; do not set with block_device_mappings.
# system_disk_size_gib = 80
# Optional (omitted: CloudPilot discovery-tag selector). Allowed: one or more OR terms.
# Behavior: restricts node placement to matching subnets.
subnet_selector_terms = [
{
# Optional per term. Allowed: a non-empty map(string); keys are ANDed.
# Behavior: matches subnets by tags; mutually exclusive with id in the same term.
tags = {
"karpenter.sh/discovery" = "my-eks-cluster"
}
}
# Optional alternative per term. Allowed: a subnet ID.
# Behavior: selects that subnet directly; mutually exclusive with tags.
# { id = "subnet-0123456789abcdef0" }
]
# Optional (omitted: CloudPilot discovery-tag selector). Allowed: one or more OR terms.
# Behavior: attaches security groups matching any term.
security_group_selector_terms = [
{
# Optional per term. Allowed: a non-empty map(string); keys are ANDed.
# Behavior: matches security groups by tags; use exactly one of tags, id, or name.
tags = {
"karpenter.sh/discovery" = "my-eks-cluster"
}
}
# Optional alternatives per term. Allowed: a security-group ID or name.
# Behavior: selects directly; use exactly one selector form per term.
# { id = "sg-0123456789abcdef0" }
# { name = "my-security-group" }
]
}
]
# Optional (default: []). Allowed: concrete EKS NodeClass objects.
# Behavior: creates NodeClasses after merging referenced template settings.
nodeclasses = [
{
# Required. Allowed: a unique Kubernetes-compatible NodeClass name.
# Behavior: identifies the concrete NodeClass.
name = "cloudpilot"
# Optional (omitted: no template). Allowed: a nodeclass_templates name.
# Behavior: inherits that template before applying object-level overrides.
template_name = "general"
# Optional (omitted: use typed fields). Allowed: valid EC2NodeClass JSON.
# Behavior: replaces the typed NodeClass settings; do not combine both approaches.
# origin_nodeclass_json = file("ec2nodeclass.json")
}
]
# Optional (default: []). Allowed: reusable NodePool template objects.
# Behavior: defines settings inherited by nodepools that reference template_name.
nodepool_templates = [
{
# Required. Allowed: a unique non-empty template name.
# Behavior: identifies this reusable NodePool template.
template_name = "general"
# Optional (omitted: CloudPilot/server default). Allowed: true or false.
# Behavior: enables or disables provisioning through matching NodePools.
enable = true
# Optional (omitted: CloudPilot default/reference). Allowed: a NodeClass name.
# Behavior: selects the NodeClass used to launch nodes.
nodeclass = "cloudpilot"
# Optional (omitted: no GPU-specific restriction). Allowed: true or false.
# Behavior: enables or disables GPU-capable provisioning for the pool.
enable_gpu = false
# Optional (omitted: inherit NodeClass/server setting). Allowed: true or false.
# Behavior: enables image acceleration for nodes in this pool.
enable_image_accelerator = true
# Optional (omitted: CloudPilot default). Allowed: a signed integer; larger is higher.
# Behavior: orders this pool relative to other eligible pools.
provision_priority = 10
# Optional (omitted: no architecture filter). Allowed: amd64 and/or arm64.
# Behavior: restricts architectures unless instance_family is configured.
instance_arch = ["amd64"]
# Optional (omitted: no family filter). Allowed: AWS instance-family names.
# Behavior: restricts families and takes precedence over instance_arch.
# instance_family = ["m7i", "m7a", "c7i"]
# Optional (omitted: no capacity-type filter). Allowed: spot and/or on-demand.
# Behavior: restricts which purchase models may be provisioned.
capacity_type = ["spot", "on-demand"]
# Optional (omitted: any eligible zone). Allowed: AWS Availability Zone IDs.
# Behavior: restricts node placement to these zones.
zone = ["us-west-2a", "us-west-2b"]
# Optional (default/omitted: 0, no lower bound). Allowed: non-negative CPU cores.
# Behavior: sets the minimum instance vCPU count.
instance_cpu_min = 2
# Optional (default/omitted: 0, no upper bound). Allowed: non-negative CPU cores.
# Behavior: sets the maximum instance vCPU count; must be >= the minimum.
instance_cpu_max = 32
# Optional (default/omitted: 0, no lower bound). Allowed: non-negative MiB.
# Behavior: sets the minimum instance memory.
instance_memory_min = 4096
# Optional (default/omitted: 0, no upper bound). Allowed: non-negative MiB.
# Behavior: sets maximum instance memory; must be >= the minimum.
instance_memory_max = 131072
# Optional (omitted: CloudPilot default). Allowed: a Go duration such as 10m.
# Behavior: delays disruption after a node becomes eligible.
node_disruption_delay = "10m"
# Optional (omitted/null: unmanaged). Allowed: one or more non-empty budget objects.
# Behavior: limits simultaneous voluntary disruptions; entries are evaluated together.
node_disruption_budgets = [
{
# Required. Allowed: a non-negative integer string or percentage such as 20%.
# Behavior: caps disruptions matching this budget.
nodes = "20%"
# Optional (omitted: all reasons). Allowed: Empty, Underutilized, and/or Drifted.
# Behavior: limits the budget to these disruption reasons.
reasons = ["Empty", "Underutilized"]
},
{
# Required. Allowed: a non-negative integer string or percentage.
# Behavior: zero blocks matching voluntary disruptions during this window.
nodes = "0"
# Optional (omitted: all reasons). Allowed: Empty, Underutilized, and/or Drifted.
# Behavior: applies this budget only to drift-driven disruptions.
reasons = ["Drifted"]
# Optional with duration. Allowed: a five-field cron expression.
# Behavior: starts the recurring active budget window.
schedule = "0 9 * * 1-5"
# Optional with schedule. Allowed: a Go duration such as 8h.
# Behavior: controls how long each scheduled budget window stays active.
duration = "8h"
}
]
# Optional, deprecated (omitted: unmanaged). Allowed: count or percentage string.
# Behavior: legacy single disruption cap; use node_disruption_budgets instead.
# node_disruption_limit = "20%"
# Optional (omitted: no additional labels). Allowed: map(string).
# Behavior: applies these Kubernetes labels to provisioned nodes.
labels = {
team = "platform"
}
# Optional (omitted: no additional taints). Allowed: Kubernetes taint objects.
# Behavior: applies scheduling taints to provisioned nodes.
taints = [
{
# Required. Allowed: a valid Kubernetes taint key.
# Behavior: identifies the taint.
key = "dedicated"
# Optional (omitted: empty value). Allowed: a valid taint value string.
# Behavior: supplies the taint value used by matching tolerations.
value = "platform"
# Required. Allowed: NoSchedule, PreferNoSchedule, or NoExecute.
# Behavior: determines the taint's scheduling/eviction effect.
effect = "NoSchedule"
}
]
}
]
# Optional (default: []). Allowed: concrete NodePool objects.
# Behavior: creates NodePools after merging referenced template settings.
nodepools = [
{
# Required. Allowed: a unique Kubernetes-compatible NodePool name.
# Behavior: identifies the concrete NodePool.
name = "cloudpilot-general"
# Optional (omitted: no template). Allowed: a nodepool_templates name.
# Behavior: inherits that template before applying object-level overrides.
template_name = "general"
# Optional (omitted: use typed fields). Allowed: valid NodePool JSON.
# Behavior: replaces the typed NodePool settings; do not combine both approaches.
# origin_nodepool_json = file("nodepool.json")
}
]
# Optional (default: []). Allowed: reusable workload template objects.
# Behavior: defines scheduling/rebalance settings inherited by workloads.
workload_templates = [
{
# Required. Allowed: a unique non-empty template name.
# Behavior: identifies this reusable workload template.
template_name = "spot-friendly"
# Optional (omitted: CloudPilot/server default). Allowed: true or false.
# Behavior: permits or prevents Node Autoscaler from rebalancing this workload.
rebalance_able = true
# Optional (omitted: CloudPilot/server default). Allowed: true or false.
# Behavior: marks whether replicas may run on Spot capacity.
spot_friendly = true
# Optional (omitted: CloudPilot/server default). Allowed: a non-negative integer.
# Behavior: keeps at least this many replicas on non-Spot capacity.
min_non_spot_replicas = 1
}
]
# Optional (default: []). Allowed: workload configuration objects.
# Behavior: manages Node Autoscaler behavior for specific Kubernetes workloads.
workloads = [
{
# Required. Allowed: the existing workload resource name.
# Behavior: identifies the workload with type and namespace.
name = "api"
# Required. Allowed: a CloudPilot-supported workload type, for example deployment.
# Behavior: selects the Kubernetes controller kind to configure.
type = "deployment"
# Required. Allowed: an existing Kubernetes namespace name.
# Behavior: scopes the workload lookup.
namespace = "production"
# Optional (omitted: no template). Allowed: a workload_templates name.
# Behavior: inherits that template before applying object-level overrides.
template_name = "spot-friendly"
# Optional (omitted: inherited/server default). Allowed: true or false.
# Behavior: permits or prevents Node Autoscaler rebalance.
rebalance_able = true
# Optional (omitted: inherited/server default). Allowed: true or false.
# Behavior: permits or prevents scheduling replicas on Spot capacity.
spot_friendly = true
# Optional (omitted: inherited/server default). Allowed: a non-negative integer.
# Behavior: keeps at least this many replicas on non-Spot capacity.
min_non_spot_replicas = 2
}
]
# Optional (default: null). Allowed: null or a list of schedule objects.
# Behavior: null leaves schedules unmanaged; [] removes previously module-managed schedules.
scheduled_rebalances = [
{
# Required. Allowed: a unique non-empty policy name.
# Behavior: identifies the scheduled rebalance policy.
name = "weekday-maintenance"
# Required for a new policy. Allowed: a five-field cron expression.
# Behavior: determines when the rebalance starts.
cron = "0 10 * * 1-5"
# Optional (omitted: server/default timezone). Allowed: an IANA timezone name.
# Behavior: interprets cron in that timezone.
timezone = "America/Los_Angeles"
# Optional (omitted: preserve/default). Allowed: true or false.
# Behavior: activates or suspends the policy.
enabled = true
# Optional (omitted: preserve/default). Allowed: true or false.
# Behavior: true may force-drain nodes instead of waiting for graceful eviction.
force_drain = false
# Optional (omitted: server/default order). Allowed: oldest_first, newest_first,
# name_asc, or lowest_utilization_first. Behavior: orders eligible nodes.
selection_order = "lowest_utilization_first"
# Optional (omitted: no additional constraints). Allowed: a constraint object.
# Behavior: applies safety bounds before selecting nodes.
node_constraints = {
# Optional (omitted: no cap). Allowed: a non-negative integer.
# Behavior: caps nodes selected by one run.
max_nodes = 5
# Optional (omitted: no age floor). Allowed: non-negative seconds.
# Behavior: excludes nodes younger than this age.
min_age_seconds = 3600
# Optional (omitted: no size floor). Allowed: a non-negative integer.
# Behavior: skips rebalance when the cluster is smaller than this value.
min_cluster_size = 3
}
# Optional (omitted: all eligible nodes). Allowed: a scope object.
# Behavior: includes or excludes nodes before constraints and ordering are applied.
scope = {
# Optional (omitted/empty: any type). Allowed: spot and/or on-demand.
# Behavior: limits the policy to these capacity types.
capacity_types = ["spot"]
# Optional (omitted/empty: any pool). Allowed: a NodePool name.
# Behavior: limits the policy to one NodePool.
node_pool_name = "cloudpilot-general"
# Optional (omitted/empty: no name allowlist). Allowed: node-name strings.
# Behavior: limits selection to these exact nodes when non-empty.
node_names = []
# Optional (omitted/empty: no exclusions). Allowed: node-name strings.
# Behavior: removes these exact nodes from selection.
exclude_node_names = ["critical-node"]
# Optional (omitted/empty: no selector allowlist). Allowed: ORed selector terms.
# Behavior: includes nodes matching any term; expressions inside a term are ANDed.
node_selector_terms = [
{
# Required in a selector term. Allowed: one or more match expressions.
# Behavior: all expressions in this term must match.
match_expressions = [
{
# Required. Allowed: a Kubernetes label key.
# Behavior: selects the label evaluated by this expression.
key = "team"
# Required. Allowed: In, NotIn, Exists, or DoesNotExist.
# Behavior: controls how the label is compared with values.
operator = "In"
# Optional by schema. Allowed: non-empty for In/NotIn; empty for Exists/DoesNotExist.
# Behavior: supplies comparison values for the operator.
values = ["platform"]
}
]
}
]
# Optional (omitted/empty: no selector exclusions). Allowed: ORed selector terms.
# Behavior: excludes nodes matching any term.
exclude_node_selector_terms = [
{
# Required in a selector term. Allowed: one or more match expressions.
# Behavior: all expressions in this exclusion term must match.
match_expressions = [
{
# Required. Allowed: a Kubernetes label key.
# Behavior: selects the label evaluated by this expression.
key = "do-not-disrupt"
# Required. Allowed: In, NotIn, Exists, or DoesNotExist.
# Behavior: Exists matches when the key is present.
operator = "Exists"
# Optional by schema. Allowed: empty for Exists/DoesNotExist.
# Behavior: no values are evaluated for Exists.
values = []
}
]
}
]
}
}
]
# Add the shared Workload Autoscaler inputs from the section below.
}Complete GKE module configuration
This example covers every current non-deprecated GKE module input and every typed GCE NodeClass and NodePool field.
module "cloudpilotai_gke" {
# Required. Allowed: the official GKE module address.
# Behavior: downloads the CloudPilot AI GKE module.
source = "cloudpilot-ai/gke/cloudpilotai"
# Required for reproducible installs. Allowed: Terraform version constraints.
# Behavior: accepts module 0.2.x releases but not 0.3.0 or later.
version = "~> 0.2"
# Required. Allowed: a non-empty existing GKE cluster name.
# Behavior: selects the cluster to onboard and manage.
cluster_name = "my-gke-cluster"
# Required. Allowed: a Google Cloud region ID such as us-central1.
# Behavior: supplies the module's regional context.
region = "us-central1"
# Optional (default: discovered). Allowed: a Google Cloud project ID.
# Behavior: omitted uses instance metadata, then the active gcloud project.
project_id = "my-gcp-project"
# Optional (default: null/discovered). Allowed: the kube-system namespace UID.
# Behavior: uniquely identifies the Kubernetes cluster when names may be reused.
cluster_uid = null
# Optional (default: null). Allowed: an existing CloudPilot cluster ID.
# Behavior: binds to that registration; null lets the provider look it up or create it.
cluster_id = null
# Optional (default: region). Allowed: an exact GKE region or zone ID.
# Behavior: set the zone for a zonal cluster; regional clusters normally omit it.
cluster_location = "us-central1"
# Optional (default: null). Allowed: a readable kubeconfig path.
# Behavior: null makes the provider generate an execution-local kubeconfig.
kubeconfig = null
# Optional (default: false). Allowed: true or false.
# Behavior: true stops uploading workload metadata to CloudPilot AI.
disable_workload_uploading = false
# Optional (default: null/full management). Allowed: true or false.
# Behavior: true installs monitoring only, unless enable_rebalance is also true.
only_install_agent = false
# Optional (default: false). Allowed: true or false.
# Behavior: checks the service and upgrades installed components when needed.
enable_upgrade = true
# Optional (default: false). Allowed: true or false.
# Behavior: enables Node Autoscaler rebalance and overrides only_install_agent.
enable_rebalance = true
# Optional (default: null). Allowed: a cluster-setting object.
# Behavior: null leaves these server-side settings unmanaged.
cluster_setting = {
# Optional (omitted: unmanaged). Allowed: true or false.
# Behavior: enables or disables automatic unhealthy-node repair.
enable_node_repair = true
# Optional (omitted: unmanaged). Allowed: true or false.
# Behavior: enables or disables node disk-pressure monitoring.
enable_disk_monitor = true
# Optional (omitted: unmanaged). Allowed: true or false.
# Behavior: controls automatic decommissioning of obsolete node pools.
enable_node_pool_decommission = true
# Optional (omitted: unmanaged). Allowed: true or false.
# Behavior: enforces each workload's minimum non-Spot replica target.
enable_workload_min_non_spot = true
# Optional (omitted: unmanaged). Allowed: a numeric discount ratio.
# Behavior: adjusts cost calculations with the organization's effective discount.
discount = 0.15
# Optional (omitted: unmanaged). Allowed: a shell command string.
# Behavior: runs before CloudPilot AI's applicable cluster workflow.
pre_run_command = "kubectl get nodes"
# Optional (omitted: unmanaged). Allowed: a shell command string.
# Behavior: runs after CloudPilot AI's applicable cluster workflow.
post_run_command = "kubectl get pods -A"
}
# Optional (default: null/server default). Allowed: true or false.
# Behavior: true skips restore during destroy and overrides all restore counts.
skip_restore = false
# Optional (default: null). Allowed: a non-negative integer; 0 means no restore.
# Behavior: restores this total node count across pools during destroy.
restore_node_number = 3
# Optional (default: null). Allowed: map(number) from node-pool name to non-negative total.
# Behavior: restores per-pool desired sizes; named entries override the total count.
restore_desired_sizes = {
default-pool = 3
}
# Optional (default: []). Allowed: reusable GCE NodeClass template objects.
# Behavior: defines settings inherited by nodeclasses that reference template_name.
nodeclass_templates = [
{
# Required. Allowed: a unique non-empty template name.
# Behavior: identifies this reusable NodeClass template.
template_name = "general"
# Optional (omitted: CloudPilot/server default). Allowed: true or false.
# Behavior: enables or disables peer-assisted image acceleration on launched nodes.
enable_image_accelerator = true
# Optional (omitted: preserve server setting). Allowed: true or false.
# Behavior: uses Local SSD as kubelet and container-runtime ephemeral storage.
enable_local_ssd_ephemeral_storage = true
# Optional (omitted: preserve server setting). Allowed: a Local SSD object.
# Behavior: controls the Local SSD count for compatible machine types.
ephemeral_storage_local_ssd = {
# Optional (omitted: use bundled SSDs on storage-optimized machines). Allowed: 1-32.
# Behavior: attaches this many Local SSD devices.
count = 2
}
# Optional (omitted: CloudPilot/default node identity). Allowed: a service-account email.
# Behavior: attaches that Google service account to launched nodes.
service_account = "nodes@my-gcp-project.iam.gserviceaccount.com"
# Optional (omitted: cluster/default pod range). Allowed: an alias-IP secondary range name.
# Behavior: allocates pod IPs from that secondary range.
subnet_range_name = "pods"
# Optional (omitted: CloudPilot/default boot disk). Allowed: GCE disk objects.
# Behavior: configures disks attached to provisioned nodes.
disks = [
{
# Optional (omitted: inferred). Allowed: true or false.
# Behavior: marks this disk as the boot disk.
boot = true
# Optional (omitted: provider default). Allowed: a GCE disk type such as pd-balanced.
# Behavior: selects the disk storage class.
category = "pd-balanced"
# Optional (omitted: image/provider default). Allowed: a positive integer GiB.
# Behavior: sets disk capacity.
size_gib = 80
}
]
# Optional (omitted: CloudPilot image selection). Allowed: one or more OR terms.
# Behavior: selects the OS image used to launch nodes.
image_selector_terms = [
{
# Optional per term. Allowed: ContainerOptimizedOS, Ubuntu2404, or Ubuntu2204.
# Behavior: selects an image family; requires exactly one of channel or version.
family = "ContainerOptimizedOS"
# Optional per term. Allowed: rapid, regular, stable, extended, or cluster.
# Behavior: follows that channel; valid only with ContainerOptimizedOS family.
channel = "cluster"
# Optional per term. Allowed: a full GCE image resource URL.
# Behavior: selects an exact image; use id alone instead of family/channel/version.
id = null
# Optional per term. Allowed: latest or a family-specific release version.
# Behavior: pins the family; use version instead of channel, not with it.
version = null
}
]
# Optional (omitted: kubelet defaults). Allowed: a kubelet-configuration object.
# Behavior: overrides reservations and eviction thresholds for launched nodes.
kubelet_configuration = {
# Optional (omitted: kubelet default). Allowed: map from eviction signal to quantity/%.
# Behavior: immediately evicts pods after a hard threshold is crossed.
eviction_hard = {
"memory.available" = "5%"
}
# Optional (omitted: kubelet default). Allowed: map from eviction signal to quantity/%.
# Behavior: starts graceful eviction after a soft threshold is crossed.
eviction_soft = {
"memory.available" = "10%"
}
# Optional (omitted: kubelet default). Allowed: map from resource to Kubernetes quantity.
# Behavior: reserves node resources for Kubernetes system daemons.
kube_reserved = {
cpu = "200m"
memory = "512Mi"
}
# Optional (omitted: kubelet default). Allowed: map from resource to Kubernetes quantity.
# Behavior: reserves node resources for operating-system daemons.
system_reserved = {
cpu = "200m"
memory = "512Mi"
}
}
# Optional (omitted: no additional labels). Allowed: map(string).
# Behavior: applies these labels through the GCE NodeClass.
labels = {
environment = "production"
}
# Optional (omitted: no additional metadata). Allowed: map(string).
# Behavior: applies these GCE instance metadata entries.
metadata = {
"enable-oslogin" = "TRUE"
}
# Optional (omitted: no additional tags). Allowed: GCE network-tag strings.
# Behavior: attaches tags used by firewall and network policies.
network_tags = ["cloudpilot-managed"]
# Optional (omitted: CloudPilot/default network settings). Allowed: a network object.
# Behavior: controls primary and additional node network interfaces.
network_config = {
# Optional (omitted: server/default). Allowed: true or false.
# Behavior: removes public node IPs when true; requires NAT or equivalent egress.
enable_private_nodes = false
# Optional (omitted: cluster/default subnet). Allowed: a subnetwork resource path.
# Behavior: places the primary node interface on that subnetwork.
subnetwork = "projects/my-gcp-project/regions/us-central1/subnetworks/nodes"
# Optional (omitted: no extra interfaces). Allowed: interface objects.
# Behavior: attaches additional VPC interfaces to each provisioned node.
additional_network_interfaces = [
{
# Optional (omitted: inferred from subnetwork). Allowed: a network resource path.
# Behavior: selects the VPC for this additional interface.
network = "projects/my-gcp-project/global/networks/secondary"
# Optional (omitted: network default). Allowed: a subnetwork resource path.
# Behavior: selects the subnet for this additional interface.
subnetwork = "projects/my-gcp-project/regions/us-central1/subnetworks/secondary"
}
]
}
# Optional (omitted: server/default). Allowed: true or false.
# Behavior: automatically adds GKE-compatible taints to GPU nodes.
auto_gpu_taint = true
# Optional (default/omitted: default). Allowed: default, latest, or disabled.
# Behavior: installs the stable, newest COS-only, or no NVIDIA driver; ignored on non-GPU nodes.
gpu_driver_version = "latest"
# Optional (omitted: use typed fields). Allowed: valid GCENodeClass JSON.
# Behavior: replaces the typed NodeClass settings; do not combine both approaches.
# origin_nodeclass_json = file("gcenodeclass.json")
}
]
# Optional (default: []). Allowed: concrete GCE NodeClass objects.
# Behavior: creates NodeClasses after merging referenced template settings.
nodeclasses = [
{
# Required. Allowed: a unique Kubernetes-compatible NodeClass name.
# Behavior: identifies the concrete NodeClass.
name = "cloudpilot"
# Optional (omitted: no template). Allowed: a nodeclass_templates name.
# Behavior: inherits that template before applying object-level overrides.
template_name = "general"
}
]
# Optional (default: []). Allowed: reusable NodePool template objects.
# Behavior: defines settings inherited by nodepools that reference template_name.
nodepool_templates = [
{
# Required. Allowed: a unique non-empty template name.
# Behavior: identifies this reusable NodePool template.
template_name = "general"
# Optional (omitted: CloudPilot/server default). Allowed: true or false.
# Behavior: enables or disables provisioning through matching NodePools.
enable = true
# Optional (omitted: inherit NodeClass/server setting). Allowed: true or false.
# Behavior: enables image acceleration for nodes in this pool.
enable_image_accelerator = true
# Optional (omitted: CloudPilot default/reference). Allowed: a NodeClass name.
# Behavior: selects the NodeClass used to launch nodes.
nodeclass = "cloudpilot"
# Optional (omitted: no GPU-specific restriction). Allowed: true or false.
# Behavior: enables or disables GPU-capable provisioning for the pool.
enable_gpu = false
# Optional (omitted: CloudPilot default). Allowed: a signed integer; larger is higher.
# Behavior: orders this pool relative to other eligible pools.
provision_priority = 10
# Optional (omitted: no family filter). Allowed: GCE machine-family names.
# Behavior: restricts families and takes precedence over instance_arch.
instance_family = ["n4", "n2", "e2"]
# Optional (omitted: no architecture filter). Allowed: amd64 and/or arm64.
# Behavior: restricts architectures unless instance_family is configured.
instance_arch = ["amd64"]
# Optional (omitted: no capacity-type filter). Allowed: spot and/or on-demand.
# Behavior: restricts which purchase models may be provisioned.
capacity_type = ["spot", "on-demand"]
# Optional (omitted: any eligible zone). Allowed: Google Cloud zone IDs.
# Behavior: restricts node placement to these zones.
zone = ["us-central1-a", "us-central1-b"]
# Optional (default/omitted: 0, no lower bound). Allowed: non-negative CPU cores.
# Behavior: sets the minimum instance vCPU count.
instance_cpu_min = 2
# Optional (default/omitted: 0, no upper bound). Allowed: non-negative CPU cores.
# Behavior: sets the maximum instance vCPU count; must be >= the minimum.
instance_cpu_max = 32
# Optional (default/omitted: 0, no lower bound). Allowed: non-negative MiB.
# Behavior: sets the minimum instance memory.
instance_memory_min = 4096
# Optional (default/omitted: 0, no upper bound). Allowed: non-negative MiB.
# Behavior: sets maximum instance memory; must be >= the minimum.
instance_memory_max = 131072
# Optional (omitted: CloudPilot default). Allowed: a Go duration such as 10m.
# Behavior: delays disruption after a node becomes eligible.
node_disruption_delay = "10m"
# Optional (omitted/null: unmanaged). Allowed: one or more non-empty budget objects.
# Behavior: limits simultaneous voluntary disruptions; entries are evaluated together.
node_disruption_budgets = [
{
# Required. Allowed: a non-negative integer string or percentage such as 20%.
# Behavior: caps disruptions matching this budget.
nodes = "20%"
# Optional (omitted: all reasons). Allowed: Empty, Underutilized, and/or Drifted.
# Behavior: limits the budget to these disruption reasons.
reasons = ["Empty", "Underutilized"]
},
{
# Required. Allowed: a non-negative integer string or percentage.
# Behavior: zero blocks matching voluntary disruptions during this window.
nodes = "0"
# Optional (omitted: all reasons). Allowed: Empty, Underutilized, and/or Drifted.
# Behavior: applies this budget only to drift-driven disruptions.
reasons = ["Drifted"]
# Optional with duration. Allowed: a five-field cron expression.
# Behavior: starts the recurring active budget window.
schedule = "0 9 * * 1-5"
# Optional with schedule. Allowed: a Go duration such as 8h.
# Behavior: controls how long each scheduled budget window stays active.
duration = "8h"
}
]
# Optional, deprecated (omitted: unmanaged). Allowed: count or percentage string.
# Behavior: legacy single disruption cap; use node_disruption_budgets instead.
# node_disruption_limit = "20%"
# Optional (omitted: no additional labels). Allowed: map(string).
# Behavior: applies these Kubernetes labels to provisioned nodes.
labels = {
team = "platform"
}
# Optional (omitted: no additional taints). Allowed: Kubernetes taint objects.
# Behavior: applies scheduling taints to provisioned nodes.
taints = [
{
# Required. Allowed: a valid Kubernetes taint key.
# Behavior: identifies the taint.
key = "dedicated"
# Optional (omitted: empty value). Allowed: a valid taint value string.
# Behavior: supplies the taint value used by matching tolerations.
value = "platform"
# Required. Allowed: NoSchedule, PreferNoSchedule, or NoExecute.
# Behavior: determines the taint's scheduling/eviction effect.
effect = "NoSchedule"
}
]
# Optional (omitted: use typed fields). Allowed: valid NodePool JSON.
# Behavior: replaces the typed NodePool settings; do not combine both approaches.
# origin_nodepool_json = file("gcenodepool.json")
}
]
# Optional (default: []). Allowed: concrete NodePool objects.
# Behavior: creates NodePools after merging referenced template settings.
nodepools = [
{
# Required. Allowed: a unique Kubernetes-compatible NodePool name.
# Behavior: identifies the concrete NodePool.
name = "cloudpilot-general"
# Optional (omitted: no template). Allowed: a nodepool_templates name.
# Behavior: inherits that template before applying object-level overrides.
template_name = "general"
}
]
# Optional (default: null). Allowed: null or a list of schedule objects.
# Behavior: null leaves schedules unmanaged; [] removes previously module-managed schedules.
scheduled_rebalances = [
{
# Required. Allowed: a unique non-empty policy name.
# Behavior: identifies the scheduled rebalance policy.
name = "weekday-maintenance"
# Required for a new policy. Allowed: a five-field cron expression.
# Behavior: determines when the rebalance starts.
cron = "0 10 * * 1-5"
# Optional (omitted: server/default timezone). Allowed: an IANA timezone name.
# Behavior: interprets cron in that timezone.
timezone = "America/Los_Angeles"
# Optional (omitted: preserve/default). Allowed: true or false.
# Behavior: activates or suspends the policy.
enabled = true
# Optional (omitted: preserve/default). Allowed: true or false.
# Behavior: true may force-drain nodes instead of waiting for graceful eviction.
force_drain = false
# Optional (omitted: server/default order). Allowed: oldest_first, newest_first,
# name_asc, or lowest_utilization_first. Behavior: orders eligible nodes.
selection_order = "lowest_utilization_first"
# Optional (omitted: no additional constraints). Allowed: a constraint object.
# Behavior: applies safety bounds before selecting nodes.
node_constraints = {
# Optional (omitted: no cap). Allowed: a non-negative integer.
# Behavior: caps nodes selected by one run.
max_nodes = 5
# Optional (omitted: no age floor). Allowed: non-negative seconds.
# Behavior: excludes nodes younger than this age.
min_age_seconds = 3600
# Optional (omitted: no size floor). Allowed: a non-negative integer.
# Behavior: skips rebalance when the cluster is smaller than this value.
min_cluster_size = 3
}
# Optional (omitted: all eligible nodes). Allowed: a scope object.
# Behavior: includes or excludes nodes before constraints and ordering are applied.
scope = {
# Optional (omitted/empty: any type). Allowed: spot and/or on-demand.
# Behavior: limits the policy to these capacity types.
capacity_types = ["spot"]
# Optional (omitted/empty: any pool). Allowed: a NodePool name.
# Behavior: limits the policy to one NodePool.
node_pool_name = "cloudpilot-general"
# Optional (omitted/empty: no name allowlist). Allowed: node-name strings.
# Behavior: limits selection to these exact nodes when non-empty.
node_names = []
# Optional (omitted/empty: no exclusions). Allowed: node-name strings.
# Behavior: removes these exact nodes from selection.
exclude_node_names = ["critical-node"]
# Optional (omitted/empty: no selector allowlist). Allowed: ORed selector terms.
# Behavior: includes nodes matching any term; expressions inside a term are ANDed.
node_selector_terms = [
{
# Required in a selector term. Allowed: one or more match expressions.
# Behavior: all expressions in this term must match.
match_expressions = [
{
# Required. Allowed: a Kubernetes label key.
# Behavior: selects the label evaluated by this expression.
key = "team"
# Required. Allowed: In, NotIn, Exists, or DoesNotExist.
# Behavior: controls how the label is compared with values.
operator = "In"
# Optional by schema. Allowed: non-empty for In/NotIn; empty for Exists/DoesNotExist.
# Behavior: supplies comparison values for the operator.
values = ["platform"]
}
]
}
]
# Optional (omitted/empty: no selector exclusions). Allowed: ORed selector terms.
# Behavior: excludes nodes matching any term.
exclude_node_selector_terms = [
{
# Required in a selector term. Allowed: one or more match expressions.
# Behavior: all expressions in this exclusion term must match.
match_expressions = [
{
# Required. Allowed: a Kubernetes label key.
# Behavior: selects the label evaluated by this expression.
key = "do-not-disrupt"
# Required. Allowed: In, NotIn, Exists, or DoesNotExist.
# Behavior: Exists matches when the key is present.
operator = "Exists"
# Optional by schema. Allowed: empty for Exists/DoesNotExist.
# Behavior: no values are evaluated for Exists.
values = []
}
]
}
]
}
}
]
# Add the shared Workload Autoscaler inputs from the section below.
}One uncommon advanced NodeClass field is intentionally not included in the runnable example:
| Input | Contract |
|---|---|
confidential_instance_type | Optional (omitted: Confidential VM disabled). Allowed: SEV, SEV_SNP, or TDX. Behavior: enables in-use memory encryption with the selected Confidential VM technology; only use it with a compatible GCE machine family. |
The following GKE inputs are optional compatibility aliases and are deprecated. Use the replacement inputs in new configurations.
| Deprecated input | Allowed and behavior | Replacement |
|---|---|---|
enable_node_autoscaler | Optional (default: null). Allowed: true, false, or null. false maps to agent-only mode; null leaves the compatibility alias unused. | only_install_agent and enable_rebalance |
node_autoscaler_skip_restore | Optional (default: null). Allowed: true, false, or null. true skips restore during destroy unless the replacement input is set, which takes precedence. | skip_restore |
node_autoscaler_restore_desired_size | Optional (default: null). Allowed: a non-negative number or null. Sets the total desired restore size unless the replacement input is set. | restore_node_number |
node_autoscaler_restore_desired_sizes | Optional (default: null). Allowed: a map from node-pool name to non-negative desired total. Sets per-pool restore sizes unless the replacement input is set. | restore_desired_sizes |
Complete Workload Autoscaler configuration
The EKS and GKE modules expose the same Workload Autoscaler inputs. Add this configuration inside either module block.
# Optional (default: true). Allowed: true or false.
# Behavior: creates the Workload Autoscaler resource and installs its components.
enable_workload_autoscaler = true
# Optional (default: ""). Allowed: a Kubernetes StorageClass name or empty string.
# Behavior: selects VictoriaMetrics persistent storage; empty uses the cluster default.
wa_storage_class = ""
# Optional (default: true). Allowed: true or false.
# Behavior: installs the per-node metrics DaemonSet when true.
wa_enable_node_agent = true
# Optional (default: false). Allowed: true or false.
# Behavior: automatically enables proactive update when a new workload's recommendation is ready.
wa_enable_new_workloads_proactive_update = false
# Optional (default: 5). Allowed: an integer greater than zero.
# Behavior: caps Workload Autoscaler operations in each limiter window.
wa_limiter_quota_per_window = 5
# Optional (default: 10). Allowed: an integer greater than zero.
# Behavior: sets the maximum temporary operation burst.
wa_limiter_burst = 10
# Optional (default: 30). Allowed: an integer greater than zero, in seconds.
# Behavior: sets the rate-limiter window length.
wa_limiter_window_seconds = 30
# Optional (default: true). Allowed: true or false.
# Behavior: garbage-collects pods left by preemption when true.
wa_enable_preempted_pod_gc = true
# Optional (default: 30m). Allowed: a Go duration such as 30m or 1h30m.
# Behavior: waits this long before deleting a preempted pod.
wa_preempted_pod_gc_ttl = "30m"
# Optional (default: true). Allowed: true or false.
# Behavior: waits for the initial data window before mutating or updating new workloads.
wa_enable_initial_optimization_data_window_check = true
# Optional (default: []). Allowed: RecommendationPolicy objects with unique names.
# Behavior: [] manages no policies and removes previously module-managed policies when unreferenced.
recommendation_policies = [
{
# Required. Allowed: a unique non-empty RecommendationPolicy name.
# Behavior: identifies the policy referenced by autoscaling policies.
name = "balanced"
# Optional (default for a new policy: percentile). Allowed: percentile.
# Behavior: selects percentile-based resource recommendations.
strategy_type = "percentile"
# Optional (default with both percentiles omitted: 95). Allowed: integer 50-100.
# Behavior: targets this CPU-usage percentile; configure with percentile_memory.
percentile_cpu = 95
# Optional (default with both percentiles omitted: 95). Allowed: integer 50-100.
# Behavior: targets this memory-usage percentile; configure with percentile_cpu.
percentile_memory = 99
# Required. Allowed: a Go duration such as 24h or 168h.
# Behavior: selects the CPU history used for recommendations.
history_window_cpu = "24h"
# Required. Allowed: a Go duration such as 48h or 168h.
# Behavior: selects the memory history used for recommendations.
history_window_memory = "48h"
# Required. Allowed: a Go duration such as 1m or 1h.
# Behavior: controls how often recommendations are evaluated.
evaluation_period = "1m"
# Optional (omitted: controller default). Allowed: CPU quantity or percentage.
# Behavior: adds headroom to the computed CPU request.
buffer_cpu = "10%"
# Optional (omitted: controller default). Allowed: memory quantity or percentage.
# Behavior: adds headroom to the computed memory request.
buffer_memory = "20%"
# Optional (omitted: no Terraform-managed floor). Allowed: a Kubernetes CPU quantity.
# Behavior: prevents CPU recommendations below this value.
request_min_cpu = "50m"
# Optional (omitted: no Terraform-managed floor). Allowed: a Kubernetes memory quantity.
# Behavior: prevents memory recommendations below this value.
request_min_memory = "64Mi"
# Optional (omitted: no Terraform-managed ceiling). Allowed: a Kubernetes CPU quantity.
# Behavior: prevents CPU recommendations above this value; must be >= the minimum.
request_max_cpu = "8"
# Optional (omitted: no Terraform-managed ceiling). Allowed: a Kubernetes memory quantity.
# Behavior: prevents memory recommendations above this value; must be >= the minimum.
request_max_memory = "16Gi"
# Optional (omitted: controller default). Allowed: a memory quantity or percentage.
# Behavior: adds headroom to the JVM HeapXmx recommendation.
jvm_heap_buffer = "300Mi"
# Optional (omitted: unmanaged). Allowed: a Kubernetes memory quantity.
# Behavior: enforces a minimum JVM initial heap size (Xms).
jvm_min_heap_xms = "512Mi"
# Optional (omitted: unmanaged). Allowed: numeric string in [0, 1); 0 disables this floor.
# Behavior: floors JVM Xms as a ratio of the memory recommendation.
jvm_min_heap_xms_ratio_of_memory = "0.25"
# Optional (omitted: controller default). Allowed: a Go duration such as 2h.
# Behavior: protects recent JVM non-heap usage across this window.
jvm_recent_non_heap_window = "2h"
# Optional (controller default: 20). Allowed: integer 20-100.
# Behavior: selects the JVM heap-used percentile for recommendations.
jvm_heap_used_percentile = 95
}
]
# Optional (default: []). Allowed: AutoscalingPolicy objects with unique names.
# Behavior: [] manages no policies and removes previously module-managed policies.
autoscaling_policies = [
{
# Required. Allowed: a unique non-empty AutoscalingPolicy name.
# Behavior: identifies this workload-matching policy.
name = "production"
# Optional (omitted: server/default). Allowed: true or false.
# Behavior: activates or suspends this policy.
enable = true
# Required. Allowed: the name of an existing or managed RecommendationPolicy.
# Behavior: selects the recommendation algorithm used by matched workloads.
recommendation_policy_name = "balanced"
# Optional (default for a new policy: 0). Allowed: signed 32-bit integer.
# Behavior: higher values win when multiple policies match; ties use the oldest.
priority = 10
# Optional (omitted/[]: cpu and memory). Allowed: cpu and/or memory.
# Behavior: restricts which resource requests CloudPilot AI optimizes.
update_resources = ["cpu", "memory"]
# Optional (omitted: controller default). Allowed: CPU quantity or percentage.
# Behavior: requires at least this CPU drift before an update is eligible.
drift_threshold_cpu = "5%"
# Optional (omitted: controller default). Allowed: memory quantity or percentage.
# Behavior: requires at least this memory drift before an update is eligible.
drift_threshold_memory = "5%"
# Optional (default for a new policy: off). Allowed: off, recreate, or inplace.
# Behavior: controls how pods return toward baseline when this policy is removed.
on_policy_removal = "recreate"
# Optional (omitted: server/default). Allowed: true or false.
# Behavior: keep false for new policies; current Terraform lacks a dedicated startup policy.
startup_boost_enabled = false
# Optional (omitted: runtime optimization enabled). Allowed: true or false.
# Behavior: disables runtime-language-specific optimization when true.
disable_runtime_optimization = false
# Optional (kind default: DaemonSet hold, otherwise recreate). Allowed: recreate or hold.
# Behavior: chooses the fallback when an in-place update cannot continue.
in_place_fallback_default_policy = "recreate"
# Optional (omitted: use default fallback). Allowed keys are PodResizePending,
# QoSChangeForbidden, MemoryLimitsAddForbidden, ResourceLimitsRemoveForbidden,
# ResourceRequestsRemoveForbidden, ResourceMemoryLimitCannotBeDecreased, and
# JVMHeapDrift; values: recreate or hold. Behavior: overrides fallback per reason.
in_place_fallback_reason_policies = {
JVMHeapDrift = "hold"
}
# Optional (omitted/[]: no workload targets). Allowed: target reference objects.
# Behavior: selects workloads to which this AutoscalingPolicy applies.
target_refs = [
{
# Required. Allowed: a Kubernetes API version such as apps/v1.
# Behavior: identifies the target resource API group/version.
api_version = "apps/v1"
# Required. Allowed: Deployment, StatefulSet, or DaemonSet.
# Behavior: restricts the target controller kind.
kind = "Deployment"
# Optional (omitted/empty: all names of this kind). Allowed: a workload name.
# Behavior: restricts the target to this exact name.
name = "api"
# Optional (omitted/empty: all namespaces). Allowed: a namespace name.
# Behavior: restricts the target to this namespace.
namespace = "production"
# Optional (omitted: no label selector). Allowed: a Kubernetes selector object.
# Behavior: further restricts matching workloads; all selector parts are ANDed.
label_selector = {
# Optional (omitted/empty: no exact-label constraints). Allowed: map(string).
# Behavior: requires every listed label key/value pair.
match_labels = {
app = "api"
}
# Optional (omitted/empty: no expression constraints). Allowed: selector expressions.
# Behavior: requires every listed expression to match.
match_expressions = [
{
# Required. Allowed: a valid Kubernetes label key.
# Behavior: selects the label evaluated by this expression.
key = "tier"
# Required. Allowed: In, NotIn, Exists, or DoesNotExist.
# Behavior: controls how the label is compared with values.
operator = "In"
# Optional by schema. Allowed: non-empty for In/NotIn; empty for Exists/DoesNotExist.
# Behavior: supplies comparison values for the operator.
values = ["backend"]
}
]
}
}
]
# Optional (omitted/[]: controller/default update behavior). Allowed: schedule objects.
# Behavior: controls when matched workloads may update and which mode is active.
update_schedules = [
{
# Required. Allowed: a unique non-empty schedule name within this policy.
# Behavior: identifies the update-window item.
name = "weekday-window"
# Required. Allowed: oncreate, recreate, inplace, or off.
# Behavior: selects the update method during this item.
mode = "inplace"
# Optional. Allowed: a standard cron expression.
# Behavior: starts the window; if schedule or duration is omitted, the item is always active.
schedule = "0 9 * * 1-5"
# Optional. Allowed: a Go duration such as 8h.
# Behavior: sets window length; if schedule or duration is omitted, the item is always active.
duration = "8h"
}
]
# Optional (omitted/[]: controller/default limit behavior). Allowed: per-resource policies.
# Behavior: controls how CPU or memory limits relate to recommended requests.
limit_policies = [
{
# Required. Allowed: cpu or memory.
# Behavior: selects the resource governed by this entry.
resource = "cpu"
# Optional. Allowed: true; configure only one action in a limit-policy entry.
# Behavior: removes the CPU limit from matched workloads.
remove_limit = true
# Optional alternative. Allowed: true.
# Behavior: keeps the baseline limit unchanged instead of removing it.
# keep_limit = true
# Optional legacy-compatible alternative. Allowed: numeric string 1.0-5.0.
# Behavior: sets limit to recommended request multiplied by this value.
# multiplier = "2.0"
},
{
# Required. Allowed: cpu or memory.
# Behavior: selects the resource governed by this entry.
resource = "memory"
# Optional. Allowed: numeric string 1.0-5.0; configure only one action per entry.
# Behavior: preserves existing limits unless more headroom is needed; never decreases them.
auto_headroom = "1.5"
}
]
}
]
# Optional (default: []). Allowed: proactive-update filter objects.
# Behavior: performs enable operations during create/update; this is not a persistent policy list.
enable_proactive = [
{
# Optional (omitted/[]: all namespaces). Allowed: exact namespace names.
# Behavior: matches workloads in these namespaces.
namespaces = ["production"]
# Optional (omitted/[]: all supported kinds). Allowed: Deployment, StatefulSet, DaemonSet.
# Behavior: matches only these workload kinds.
workload_kinds = ["Deployment", "StatefulSet"]
# Optional (omitted/empty: any name). Allowed: a string.
# Behavior: performs a substring match against workload names.
workload_name = "api"
# Optional (omitted/empty: any state). Allowed: Ready or NotReady.
# Behavior: matches workloads currently in this readiness state.
workload_state = "Ready"
# Optional (omitted/[]: any policy). Allowed: AutoscalingPolicy names.
# Behavior: matches workloads currently assigned to any listed policy.
autoscaling_policy_names = ["production"]
# Optional (omitted/[]: any state). Allowed: Ready, Recommending, Updating, Deleting.
# Behavior: matches workloads in any listed optimization state.
optimization_states = ["Ready"]
# Optional (omitted: either state). Allowed: true or false.
# Behavior: filters current state; true selects disabled workloads for this enable operation.
disable_proactive_update = true
# Optional (omitted/[]: any policy). Allowed: RecommendationPolicy names.
# Behavior: matches workloads currently using any listed policy.
recommendation_policy_names = ["balanced"]
# Optional (omitted/[]: any runtime). Allowed: java, golang, python, nodejs,
# dotnet, ruby, or php. Behavior: matches the primary detected runtime language.
runtime_languages = ["java"]
# Optional (omitted: either state). Allowed: true or false.
# Behavior: matches workloads by whether their resources are already optimized.
optimized = false
}
]
# Optional (default: []). Allowed: the same filter fields as enable_proactive.
# Behavior: performs disable operations during create/update; this is not a persistent policy list.
disable_proactive = [
{
# Optional (omitted/[]: all namespaces). Allowed: exact namespace names.
# Behavior: limits this disable operation to kube-system workloads.
namespaces = ["kube-system"]
# Optional (omitted: either state). Allowed: true or false.
# Behavior: false selects workloads where proactive update is currently enabled.
disable_proactive_update = false
}
]Legacy startup boost compatibility
The startup boost multiplier inputs are nested inside an autoscaling_policies
object and are exposed only for compatibility with legacy policies. Do not use
them as the recommended configuration for a new policy.
# Legacy compatibility only. Add this list inside the module block.
# Optional (default: []). Allowed: AutoscalingPolicy objects.
# Behavior: this example represents an existing legacy startup-boost policy only.
autoscaling_policies = [
{
# Required. Allowed: a unique non-empty AutoscalingPolicy name.
# Behavior: identifies the legacy policy.
name = "legacy-startup-boost"
# Optional (omitted: server/default). Allowed: true or false.
# Behavior: activates or suspends the policy.
enable = true
# Required. Allowed: an existing RecommendationPolicy name.
# Behavior: selects the steady-state recommendation policy.
recommendation_policy_name = "balanced"
# Optional, legacy compatibility only. Allowed: true or false.
# Behavior: enables legacy multiplier-based startup boost.
startup_boost_enabled = true
# Optional, legacy compatibility only. Allowed: a Go duration such as 5m.
# Behavior: keeps the boost active for at least this long.
startup_boost_min_boost_duration = "5m"
# Optional, legacy compatibility only. Allowed: a Go duration such as 3m.
# Behavior: waits for this continuous ready duration before removing the boost.
startup_boost_min_ready_duration = "3m"
# Optional, legacy compatibility only. Allowed: numeric string 1.0-5.0.
# Behavior: multiplies startup CPU resources by this value.
startup_boost_multiplier_cpu = "2.0"
# Optional, legacy compatibility only. Allowed: numeric string 1.0-5.0.
# Behavior: multiplies startup memory resources by this value.
startup_boost_multiplier_memory = "2.0"
# Optional (omitted/[]: no workload targets). Allowed: target reference objects.
# Behavior: selects workloads to which this legacy policy applies.
target_refs = [
{
# Required. Allowed: a Kubernetes API version such as apps/v1.
# Behavior: identifies the target resource API group/version.
api_version = "apps/v1"
# Required. Allowed: Deployment, StatefulSet, or DaemonSet.
# Behavior: restricts the target controller kind.
kind = "Deployment"
# Optional (omitted/empty: all names of this kind). Allowed: a workload name.
# Behavior: restricts the target to this exact name.
name = "api"
# Optional (omitted/empty: all namespaces). Allowed: a namespace name.
# Behavior: restricts the target to this namespace.
namespace = "production"
}
]
}
]The current Terraform provider and modules do not yet expose the dedicated startup RecommendationPolicy required by the current ResourceStartupBoost model. Keep startup boost disabled for new Terraform-managed policies. After support is released in Server and EnhancedVPA, then the provider, then the modules, this guide will update the version constraints and provide a complete runnable example with two distinct RecommendationPolicy objects: one for steady-state recommendations and one for startup recommendations.
Management semantics
Some inputs intentionally distinguish between omitted, empty, and disabled values:
scheduled_rebalances = nullleaves server-side schedules unmanaged.scheduled_rebalances = []manages an empty set and removes schedules that were previously managed by this module.- Raw
origin_nodeclass_jsonandorigin_nodepool_jsonvalues replace the corresponding typed configuration. Do not set both approaches on the same object. skip_restore = truetakes precedence over restore counts during destroy.- A GKE
restore_desired_sizesentry takes precedence for the named node pool. - Changing the same managed fields in the CloudPilot console can create drift; treat the Terraform or OpenTofu configuration as the source of truth.
Use provider resources directly
Direct provider resources are useful when an existing root module needs resource-level control or when module composition is not appropriate.
resource "cloudpilotai_eks_cluster" "example" {
# Required. Allowed: a non-empty existing EKS cluster name.
# Behavior: selects the EKS cluster to onboard and manage.
cluster_name = "my-eks-cluster"
# Required. Allowed: an AWS Region ID.
# Behavior: locates the cluster and AWS resources.
region = "us-west-2"
# Optional (default: false). Allowed: true or false.
# Behavior: enables Node Autoscaler rebalance.
enable_rebalance = true
# Optional (default: 0). Allowed: a non-negative integer.
# Behavior: restores this many nodes before uninstall; 0 disables restore.
restore_node_number = 3
}
resource "cloudpilotai_gke_cluster" "example" {
# Required. Allowed: a non-empty existing GKE cluster name.
# Behavior: selects the GKE cluster to onboard and manage.
cluster_name = "my-gke-cluster"
# Required. Allowed: a Google Cloud region ID.
# Behavior: supplies the resource's regional context.
region = "us-central1"
# Optional (default: discovered). Allowed: a Google Cloud project ID.
# Behavior: locates the cluster; omitted uses metadata, then active gcloud project.
project_id = "my-gcp-project"
# Optional (default: false). Allowed: true or false.
# Behavior: enables Node Autoscaler rebalance.
enable_rebalance = true
# Optional (default: unset). Allowed: a non-negative integer.
# Behavior: restores this total node count before uninstall.
restore_node_number = 3
}The provider also includes cloudpilotai_workload_autoscaler and read-only
data sources for EKS clusters, GKE clusters, and Workload Autoscaler state. See
the provider documentationÂ
for the generated resource and data-source schemas.