NewCompare CPU & GPU pricing across AWS, Azure & GCP
Terraform

Node Policies

Configure Karpenter node provisioning policies with Terraform.

Node Policies

devzero_node_policy configures Karpenter NodePool and NodeClass resources for node provisioning. devzero_node_policy_target attaches a node policy to one or more clusters.

Node policies manage Karpenter NodePool and NodeClass resources. Ensure Karpenter is installed on your target clusters before attaching node policies.

NodePolicy

Example (minimal)

resource "devzero_node_policy" "minimal" {
  name            = "minimal-policy"
  node_pool_name  = "default-pool"
  node_class_name = "default-class"
}

Example (AWS)

resource "devzero_node_policy" "aws" {
  name            = "aws-production"
  description     = "Production-ready AWS node policy"
  node_pool_name  = "production-pool"
  node_class_name = "production-class"
  weight          = 15

  instance_categories = {
    match_expressions = [{
      key      = "instanceCategories"
      operator = "In"
      values   = ["c", "m", "r"]
    }]
  }

  instance_generations = {
    match_expressions = [{
      key      = "instanceGenerations"
      operator = "Gt"
      values   = ["5"]
    }]
  }

  architectures = {
    match_expressions = [{
      key      = "architectures"
      operator = "In"
      values   = ["amd64"]
    }]
  }

  capacity_types = {
    match_expressions = [{
      key      = "capacityTypes"
      operator = "In"
      values   = ["spot", "on-demand"]
    }]
  }

  operating_systems = {
    match_expressions = [{
      key      = "operatingSystems"
      operator = "In"
      values   = ["linux"]
    }]
  }

  labels = {
    "workload-type" = "general"
    "managed-by"    = "karpenter"
  }

  limits = {
    cpu    = "1000"
    memory = "1000Gi"
  }

  disruption = {
    consolidation_policy = "WhenEmptyOrUnderutilized"
    consolidate_after    = "15m"
    expire_after         = "720h"

    budgets = [
      {
        reasons = ["Underutilized", "Empty"]
        nodes   = "10%"
      }
    ]
  }

  aws = {
    role             = "KarpenterNodeRole-production"
    instance_profile = "KarpenterNodeInstanceProfile-production"
    ami_family       = "AL2023"

    ami_selector_terms = [
      { alias = "al2023@latest" }
    ]

    subnet_selector_terms = [
      {
        tags = {
          "karpenter.sh/discovery" = "production-cluster"
        }
      }
    ]

    security_group_selector_terms = [
      {
        tags = {
          "karpenter.sh/discovery" = "production-cluster"
        }
      }
    ]

    block_device_mappings = [
      {
        device_name = "/dev/xvda"
        ebs = {
          volume_size           = "100Gi"
          volume_type           = "gp3"
          encrypted             = true
          delete_on_termination = true
        }
      }
    ]

    metadata_options = {
      http_endpoint               = "enabled"
      http_protocol_ipv6          = "disabled"
      http_put_response_hop_limit = 2
      http_tokens                 = "required"
    }

    tags = {
      "Environment" = "production"
      "ManagedBy"   = "Karpenter"
    }
  }
}

Example (Azure)

resource "devzero_node_policy" "azure" {
  name            = "azure-production"
  node_pool_name  = "production-pool"
  node_class_name = "production-class"

  capacity_types = {
    match_expressions = [{
      key      = "capacityTypes"
      operator = "In"
      values   = ["spot", "on-demand"]
    }]
  }

  disruption = {
    consolidate_after    = "5m"
    consolidation_policy = "WhenEmptyOrUnderutilized"
    expire_after         = "168h"
  }

  azure = {
    vnet_subnet_id  = "/subscriptions/xxx/resourceGroups/yyy/providers/Microsoft.Network/virtualNetworks/zzz/subnets/aaa"
    os_disk_size_gb = 128
    image_family    = "Ubuntu2204"
    fips_mode       = "Disabled"
    max_pods        = 110
  }
}

Required Arguments

ParameterTypeDescription
namestringHuman-friendly name for the policy

Optional Arguments

ParameterTypeDescription
descriptionstringFree-form description
weightnumberPriority weight — higher weights are preferred when multiple policies match (default: 10)
node_pool_namestringName for the Karpenter NodePool
node_class_namestringName for the Karpenter NodeClass
master_override_role_namestringMaster override role name for Karpenter
labelsmap(string)Kubernetes labels to apply to provisioned nodes
taintslist(object)Kubernetes taints to apply (see Taints)
limitsobjectResource limits for the NodePool (see Limits)
disruptionobjectDisruption/consolidation settings (see Disruption)
instance_categoriesselectorInstance categories (e.g. c, m, r for AWS; D, E for Azure)
instance_familiesselectorInstance families (e.g. c5, m5d)
instance_generationsselectorInstance generations
instance_sizesselectorInstance sizes (e.g. large, xlarge)
instance_cpusselectorInstance CPU count (e.g. 4, 8, 16)
instance_hypervisorsselectorInstance hypervisors
architecturesselectorCPU architectures (e.g. amd64, arm64)
capacity_typesselectorCapacity types (e.g. spot, on-demand)
operating_systemsselectorOperating systems (e.g. linux, windows)
zonesselectorAvailability zones
rawlist(object)Raw Karpenter NodePool and NodeClass YAML for advanced use cases (see Raw)
awsobjectAWS-specific NodeClass configuration (see AWS Block)
azureobjectAzure-specific NodeClass configuration (see Azure Block)

Read-Only

AttributeTypeDescription
idstringUnique identifier of the node policy

Selector Objects

All selector fields (instance_categories, architectures, capacity_types, operating_systems, zones, etc.) use the same selector schema:

ParameterTypeDescription
match_expressionslist(object)List of label selector requirements
match_labelsmap(string)Map of label key-value pairs to match

Each match_expressions entry requires:

ParameterTypeDescription
keystringLabel key
operatorstringIn, NotIn, Exists, DoesNotExist, Gt, Lt. Gt/Lt apply to numeric selectors such as instance_generations and instance_cpus.
valueslist(string)Values for In/NotIn operators; single numeric string for Gt/Lt (e.g. ["5"])

Taints

ParameterTypeDescription
keystringTaint key
valuestringTaint value
effectstringNoSchedule, PreferNoSchedule, or NoExecute

Limits

ParameterTypeDescription
cpustringMaximum total CPU across all nodes (e.g. "1000")
memorystringMaximum total memory across all nodes (e.g. "1000Gi")

Disruption

ParameterTypeDescription
consolidation_policystringWhenEmptyOrUnderutilized or WhenEmpty (default: WhenEmptyOrUnderutilized)
consolidate_afterstringDuration before consolidating idle nodes (default: "15m")
expire_afterstringMaximum node lifetime before replacement (default: "720h")
termination_grace_period_secondsnumberGrace period for node termination
ttl_seconds_after_emptynumberSeconds to wait before terminating empty nodes
budgetslist(object)Disruption budgets (see Disruption Budgets)

Disruption Budgets

ParameterTypeDescription
nodesstringMax nodes that can be disrupted — percentage (e.g. "10%") or absolute count (e.g. "2")
reasonslist(string)Reasons that trigger this budget (e.g. "Underutilized", "Empty")
schedulestringCron schedule for when this budget applies
durationstringDuration for how long this budget applies (e.g. "1h30m")

AWS Block

ParameterTypeDescription
rolestringIAM role name
instance_profilestringIAM instance profile
ami_familystringAMI family (e.g. AL2023, Bottlerocket, Ubuntu)
ami_selector_termslist(object)AMI selector terms (alias, id, name, owner, tags)
subnet_selector_termslist(object)Subnet selection by id or tags
security_group_selector_termslist(object)Security group selection by id, name, or tags
block_device_mappingslist(object)EBS volume configuration (see Block Device Mappings)
tagsmap(string)AWS tags to apply to instances
user_datastringUser data script for instance initialization
instance_store_policystringPolicy for instance store volumes. Valid value: RAID0
detailed_monitoringboolEnable detailed CloudWatch monitoring
associate_public_ip_addressboolAssociate public IP address with instances
metadata_optionsobjectEC2 instance metadata service configuration (see Metadata Options)

Metadata Options

Secure IMDSv2 defaults are applied automatically.

ParameterTypeDescription
http_endpointstringEnable/disable HTTP metadata endpoint: enabled or disabled (default: enabled)
http_protocol_ipv6stringEnable/disable IPv6 metadata endpoint: enabled or disabled (default: disabled)
http_put_response_hop_limitnumberHTTP PUT response hop limit (default: 2)
http_tokensstringRequire session tokens (IMDSv2): required or optional (default: required)

Block Device Mappings

ParameterTypeDescription
device_namestringDevice name (e.g. /dev/xvda)
ebsobjectEBS volume configuration

EBS configuration:

ParameterTypeDescription
volume_sizestringVolume size (e.g. "100Gi")
volume_typestringVolume type: gp2, gp3, io1, io2, sc1, st1
encryptedboolEncrypt the volume
delete_on_terminationboolDelete volume on instance termination
iopsnumberIOPS for io1/io2 volumes
throughputnumberThroughput in MiB/s for gp3 volumes
kms_key_idstringKMS key ID for encryption
snapshot_idstringSnapshot ID to create volume from

Azure Block

ParameterTypeDescription
vnet_subnet_idstringVNet subnet resource ID
os_disk_size_gbnumberOS disk size in GB
image_familystringVM image family: Ubuntu, Ubuntu2204, Ubuntu2404, AzureLinux
fips_modestringFIPS 140-2 mode: FIPS or Disabled
max_podsnumberMaximum number of pods per node
tagsmap(string)Azure tags to apply to resources

Raw

Use raw to supply hand-crafted NodePool or NodeClass YAML for advanced Karpenter configurations.

ParameterTypeDescription
nodepool_yamlstringRaw NodePool YAML
nodeclass_yamlstringRaw NodeClass YAML

Import

terraform import devzero_node_policy.example <node_policy_id>

NodePolicyTarget

devzero_node_policy_target attaches a devzero_node_policy to one or more clusters.

Example

resource "devzero_node_policy_target" "cluster_nodes" {
  name        = "cluster-nodes"
  description = "Apply standard node policy to production clusters"
  policy_id   = devzero_node_policy.aws.id
  cluster_ids = [devzero_cluster.production.id]
  enabled     = true
}

Arguments

ParameterTypeRequiredDescription
namestringYesHuman-friendly name for the target
policy_idstringYesID of the devzero_node_policy to attach
cluster_idslist(string)YesList of cluster IDs to apply the policy to
descriptionstringNoFree-form description
enabledboolNoWhether the target is active (default: true)

Read-Only

AttributeTypeDescription
idstringUnique identifier of the node policy target

Import

terraform import devzero_node_policy_target.example <node_policy_target_id>

On this page