All Products
Search
Document Center

Container Service for Kubernetes:Use Terraform to create an ACK dedicated cluster

Last Updated:Dec 22, 2025

This topic describes how to use Terraform to create an ACK dedicated cluster.

Note

You can run the sample code in this topic with only a few clicks. For more information, see Terraform Explorer.

Important

You can no longer create new ACK Dedicated Clusters. You must submit a ticket to request access.

Prerequisites

  • You have activated Container Service for Kubernetes (ACK). To use Terraform to activate ACK, see Use Terraform to activate ACK and grant permissions to a role.

  • An AccessKey pair is created for the Resource Access Management (RAM) user you log on as.

    Note

    By default, an Alibaba Cloud account has full permissions on all resources that belong to this account. We recommend using a RAM account, as it provides limited resource permissions, minimizing potential security risks in case your credentials are compromised.

  • The following policy is attached to the RAM user that you use to run commands in Terraform. The policy includes the minimum permissions required to run commands in Terraform. For more information, see Grant permissions to a RAM user.

    This access policy allows the RAM user to create, view, and delete VPCs, vSwitches, and ACK clusters.

    {
      "Version": "1",
      "Statement": [
        {
          "Effect": "Allow",
          "Action": [
            "vpc:CreateVpc",
            "vpc:CreateVSwitch",
            "vpc:DescribeRouteTableList",
            "vpc:DescribeVpcAttribute",
            "vpc:ListEnhanhcedNatGatewayAvailableZones",
            "vpc:DescribeVSwitchAttributes",
            "vpc:DescribeNatGateways",
            "cs:CreateCluster",
            "cs:DescribeTaskInfo",
            "cs:DescribeClusterDetail",
            "cs:DescribeClusterCerts",
            "cs:CheckControlPlaneLogEnable",
            "vpc:DeleteVpc",
            "vpc:DeleteVSwitch",
            "cs:DeleteCluster"
          ],
          "Resource": "*"
        }
      ]
    }
  • Prepare a Terraform runtime environment. You can run Terraform using one of the following methods.

    • Use Terraform in Terraform Explorer: Alibaba Cloud provides an online runtime environment for Terraform that you can use without installation. This method is suitable for scenarios in which you want to quickly and conveniently test and debug Terraform at no cost.

    • Cloud Shell: Cloud Shell is preinstalled with Terraform and configured with your identity credentials. You can run Terraform commands directly in Cloud Shell. This method is a fast, convenient, and low-cost way to use Terraform.

    • Use Terraform in Resource Orchestration Service (ROS): ROS provides managed capabilities for Terraform. You can create Terraform templates, define Alibaba Cloud, AWS, or Azure resources, and configure resource parameters and dependencies.

    • Install and configure Terraform on your computer: This method is suitable for scenarios where you have poor network connectivity or need a custom development environment.

    Important

    Make sure that your Terraform version is 0.12.28 or later. To check your current version, run the terraform --version command.

Resources

Note

You are charged for some of the resources that are used in this example. If you no longer need the resources, release them to avoid incurring fees.

Generate Terraform request parameters from the console

If the examples do not contain your required configuration or if your parameter combination is incorrect, you can generate the required parameters from the console. To do this, perform the following steps:

  1. Log on to the ACK console. In the left navigation pane, click Clusters.

  2. On the Clusters page, click Cluster Templates.

  3. In the dialog box that appears, select the type of cluster that you want to create, click Create, and then configure the cluster on the Cluster Configurations page.

  4. After you complete the configuration, click Console-to-Code in the upper-right corner of the Confirm page.

  5. In the sidebar, click the Terraform tab. The parameters required to create the cluster are displayed. You can then copy and use these parameters.

Use Terraform to create an ACK dedicated cluster (Terway)

In this section, you can create an ACK dedicated cluster that uses Terway as the network component.

  1. Create a working directory. In the working directory, create a configuration file named main.tf. Copy the following code to the main.tf file.

    provider "alicloud" {
      region = var.region_id
    }
    
    variable "region_id" {
      type    = string
      default = "cn-hangzhou"
    }
    
    variable "zone_ids" {
      type    = list(string)
      default = ["cn-hangzhou-i","cn-hangzhou-j","cn-hangzhou-k"]
    }
    
    # Defines the name or tag for the resource.
    variable "name" {      
      default = "tf-example"
    }
    
    # The ID of an existing VPC. If this is empty, a new VPC is created.
    variable "vpc_id" {    
      description = "Existing vpc id used to create several vswitches and other resources."
      default     = ""
    }
    
    # The CIDR block for the new VPC if 'vpc_id' is not specified.
    variable "vpc_cidr" {  
      description = "The cidr block used to launch a new vpc when 'vpc_id' is not specified."
      default     = "10.0.0.0/8"
    }
    
    # The IDs of existing vSwitches.
    variable "vswitch_ids" { 
      description = "List of existing vswitch id."
      type        = list(string)
      default     = []
    }
    
    # The CIDR blocks for the new vSwitches if 'vswitch_ids' is not specified. Three non-overlapping CIDR blocks are required.
    variable "vswitch_cidrs" { 
      description = "List of cidr blocks used to create several new vswitches when 'vswitch_ids' is not specified."
      type        = list(string)
      default     = ["10.1.0.0/16", "10.2.0.0/16", "10.3.0.0/16"]
    }
    
    # The IDs of existing vSwitches for Terway.
    variable "terway_vswitch_ids" {  
      description = "List of existing vswitch ids for terway."
      type        = list(string)
      default     = []
    }
    
    # The CIDR blocks for the vSwitches used by Terway if 'terway_vswitch_ids' is not specified.
    variable "terway_vswitch_cidrs" { 
      description = "List of cidr blocks used to create several new vswitches when 'terway_vswitch_cidrs' is not specified."
      type        = list(string)
      default     = ["10.4.0.0/16", "10.5.0.0/16", "10.6.0.0/16"]
    }
    
    # The components to install in the ACK cluster. Specify the name and configuration for each component.
    variable "cluster_addons" { 
      type = list(object({
        name   = string
        config = string
      }))
    
      default = [
        {
          "name"   = "terway-eniip",
          "config" = "",
        },
        {
          "name"   = "csi-plugin",
          "config" = "",
        },
        {
          "name"   = "csi-provisioner",
          "config" = "",
        },
        {
          "name"   = "logtail-ds",
          "config" = "{\"IngressDashboardEnabled\":\"true\"}",
        },
        {
          "name"   = "nginx-ingress-controller",
          "config" = "{\"IngressSlbNetworkType\":\"internet\"}",
        },
        {
          "name"   = "arms-prometheus",
          "config" = "",
        },
        {
          "name"   = "ack-node-problem-detector",
          "config" = "{\"sls_project_name\":\"\"}",
        }
      ]
    }
    
    locals {
      all_zone_ids = [for zones in data.alicloud_enhanced_nat_available_zones.enhanced.zones : zones.zone_id]
      common_zone_ids = setintersection(toset(var.zone_ids),toset(local.all_zone_ids))
       
      # Get the instance types supported in each zone.
      instance_types_per_az = { for az, types in data.alicloud_instance_types.default : az => [for t in types.instance_types : t.id] }
    
      # Get the list of instance types in all listed zones.
      all_instance_types_in_zones = [for zone in local.common_zone_ids : local.instance_types_per_az[zone]]
    
      # Convert each list to a set.
      sets = [for s in local.all_instance_types_in_zones : toset(s)]
      
      # Calculate the common instance types across all zones.
      common_instance_types = [for element in local.sets[0]: element if length([for set in local.sets: set if contains(set, element)]) == length(local.sets)]
    }
    
    # Queries for zones that support enhanced NAT gateways.
    data "alicloud_enhanced_nat_available_zones" "enhanced" {
    } 
    
    # If the vpc_id variable is not provided, this resource creates a new VPC with the CIDR block specified by the vpc_cidr variable.
    resource "alicloud_vpc" "vpc" {  
      count      = var.vpc_id == "" ? 1 : 0
      cidr_block = var.vpc_cidr
    }
    
    # If the vswitch_ids variable is not provided, new vSwitches are created based on the specified vswitch_cidrs by default.
    resource "alicloud_vswitch" "vswitches" { 
      count      = length(var.vswitch_ids) > 0 ? 0 : length(var.vswitch_cidrs)
      vpc_id     = var.vpc_id == "" ? join("", alicloud_vpc.vpc.*.id) : var.vpc_id
      cidr_block = element(var.vswitch_cidrs, count.index)
      zone_id    = tolist(local.common_zone_ids)[count.index]
    }
    
    # If the terway_vswitch_ids variable is not provided, the vSwitches for Terway are created based on the specified terway_vswitch_cidrs by default.
    resource "alicloud_vswitch" "terway_vswitches" { 
      count      = length(var.terway_vswitch_ids) > 0 ? 0 : length(var.terway_vswitch_cidrs)
      vpc_id     = var.vpc_id == "" ? join("", alicloud_vpc.vpc.*.id) : var.vpc_id
      cidr_block = element(var.terway_vswitch_cidrs, count.index)
      zone_id    = tolist(local.common_zone_ids)[count.index]
    }
    
    # Queries the resource groups of the current Alibaba Cloud user.
    data "alicloud_resource_manager_resource_groups" "default" { 
      status = "OK"
    }
    
    # Queries the ECS instance types of Alibaba Cloud.
    data "alicloud_instance_types" "default" {
      for_each            = toset(local.common_zone_ids )
      availability_zone   = each.key
      cpu_core_count      = 8
      memory_size         = 16
      kubernetes_node_role = "Master"
      system_disk_category = "cloud_essd"
    }
    
     # Creates an ACK dedicated cluster. Configurations include control plane vSwitches, Pod vSwitches, instance types, disks, passwords, and the Service CIDR block.
    resource "alicloud_cs_kubernetes" "default" { 
      master_vswitch_ids    = length(var.vswitch_ids) > 0 ? split(",", join(",", var.vswitch_ids)) : length(var.vswitch_cidrs) < 1 ? [] : split(",", join(",", alicloud_vswitch.vswitches.*.id)) # The list of zones that support enhanced NAT.
      pod_vswitch_ids       = length(var.terway_vswitch_ids) > 0 ? split(",", join(",", var.terway_vswitch_ids)) : length(var.terway_vswitch_cidrs) < 1 ? [] : split(",", join(",", alicloud_vswitch.terway_vswitches.*.id)) # The vSwitch CIDR blocks for the pod network when using Terway.
      master_instance_types = [local.common_instance_types[0],local.common_instance_types[0],local.common_instance_types[0]] # The instance types for the master nodes.
      master_disk_category  = "cloud_essd"            # The system disk type for the master nodes.
      password              = "Yourpassword1234"     # The SSH logon password.
      service_cidr          = "172.18.0.0/16"        # The Service CIDR block.
      load_balancer_spec    = "slb.s1.small"         # The Server Load Balancer specification.
      install_cloud_monitor = "true"                 # Install the CloudMonitor service.
      resource_group_id     = data.alicloud_resource_manager_resource_groups.default.groups.0.id # The ID of the resource group to which the cluster belongs. This is used to isolate resources.
      deletion_protection   = "false"                # Deletion protection for the cluster to prevent accidental deletion in the console or through API calls.
      timezone              = "Asia/Shanghai"        # The time zone used by the cluster.
      os_type               = "Linux"                # The operating system platform type.
      platform              = "AliyunLinux3"         # The operating system distribution.
      cluster_domain        = "cluster.local"        # The local domain name of the cluster.
      proxy_mode            = "ipvs"                 # The kube-proxy proxy mode.
      custom_san            = "www.terraform.io"     # The custom certificate SAN.
      new_nat_gateway       = "true"                 # Creates a new NAT Gateway.
      dynamic "addons" {
        for_each = var.cluster_addons
        content {
          name   = lookup(addons.value, "name", var.cluster_addons)
          config = lookup(addons.value, "config", var.cluster_addons)
        }
      }
    }
  2. Run the following command to initialize the Terraform runtime environment.

    terraform init

    The following output indicates that the initialization is successful.

    Terraform has been successfully initialized!
    
    You may now begin working with Terraform. Try running "terraform plan" to see
    any changes that are required for your infrastructure. All Terraform commands
    should now work.
    
    If you ever set or change modules or backend configuration for Terraform,
    rerun this command to reinitialize your working directory. If you forget, other
    commands will detect it and remind you to do so if necessary.
  3. Create an execution plan and preview the changes.

    terraform plan

    The following output indicates that the execution plan is created. You can view the information about the resources to be created.

    Refreshing Terraform state in-memory prior to plan...
    The refreshed state will be used to calculate this plan, but will not be
    persisted to local or remote state storage.
    ...
    Plan: 8 to add, 0 to change, 0 to destroy.
    ...
  4. Run the following command to create the ACK dedicated cluster.

    terraform apply

    When prompted, enter yes and press Enter. Wait for the command to complete. The following output indicates that the ACK dedicated cluster is created.

    ...
    Do you want to perform these actions?
      Terraform will perform the actions described above.
      Only 'yes' will be accepted to approve.
    
      Enter a value: yes
    ...
    alicloud_cs_managed_kubernetes.default: Creation complete after 8m26s [id=************]
    
    Apply complete! Resources: 8 added, 0 changed, 0 destroyed.
  5. Verification results

    Run the terraform show command

    Run the following command to query the details of the resources that are created by Terraform.

    terraform show

    Log on to the ACK console

    Log on to the ACK console to view the cluster that you created.

Clean up resources

If you no longer need the resources that are created or managed by Terraform, run the following command to release them. For more information about the terraform destroy command, see Common commands.

Important

The terraform destroy command destroys all the resources that you created. Proceed with caution.

terraform destroy

When prompted, enter yes and press the Enter key. Wait for the command to complete. The return of the following information indicates that the ACK dedicated cluster has been successfully deleted.

...
Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes
...
Destroy complete! Resources: 7 destroyed.

Complete example

Note

You can run the sample code in this topic with only a few clicks. For more information, see Terraform Explorer.

provider "alicloud" {
  region = var.region_id
}

variable "region_id" {
  type    = string
  default = "cn-hangzhou"
}

variable "zone_ids" {
  type    = list(string)
  default = ["cn-hangzhou-i","cn-hangzhou-j","cn-hangzhou-k"]
}

# Defines the name or tag for the resource.
variable "name" {      
  default = "tf-example"
}

# The ID of an existing VPC. If this is empty, a new VPC is created.
variable "vpc_id" {    
  description = "Existing vpc id used to create several vswitches and other resources."
  default     = ""
}

# The CIDR block for the new VPC if 'vpc_id' is not specified.
variable "vpc_cidr" {  
  description = "The cidr block used to launch a new vpc when 'vpc_id' is not specified."
  default     = "10.0.0.0/8"
}

# The IDs of existing vSwitches.
variable "vswitch_ids" { 
  description = "List of existing vswitch id."
  type        = list(string)
  default     = []
}

# The CIDR blocks for the new vSwitches if 'vswitch_ids' is not specified. Three non-overlapping CIDR blocks are required.
variable "vswitch_cidrs" { 
  description = "List of cidr blocks used to create several new vswitches when 'vswitch_ids' is not specified."
  type        = list(string)
  default     = ["10.1.0.0/16", "10.2.0.0/16", "10.3.0.0/16"]
}

# The IDs of existing vSwitches for Terway.
variable "terway_vswitch_ids" {  
  description = "List of existing vswitch ids for terway."
  type        = list(string)
  default     = []
}

# The CIDR blocks for the vSwitches used by Terway if 'terway_vswitch_ids' is not specified.
variable "terway_vswitch_cidrs" { 
  description = "List of cidr blocks used to create several new vswitches when 'terway_vswitch_cidrs' is not specified."
  type        = list(string)
  default     = ["10.4.0.0/16", "10.5.0.0/16", "10.6.0.0/16"]
}

# The components to install in the ACK cluster. Specify the name and configuration for each component.
variable "cluster_addons" { 
  type = list(object({
    name   = string
    config = string
  }))

  default = [
    {
      "name"   = "terway-eniip",
      "config" = "",
    },
    {
      "name"   = "csi-plugin",
      "config" = "",
    },
    {
      "name"   = "csi-provisioner",
      "config" = "",
    },
    {
      "name"   = "logtail-ds",
      "config" = "{\"IngressDashboardEnabled\":\"true\"}",
    },
    {
      "name"   = "nginx-ingress-controller",
      "config" = "{\"IngressSlbNetworkType\":\"internet\"}",
    },
    {
      "name"   = "arms-prometheus",
      "config" = "",
    },
    {
      "name"   = "ack-node-problem-detector",
      "config" = "{\"sls_project_name\":\"\"}",
    }
  ]
}

locals {
  all_zone_ids = [for zones in data.alicloud_enhanced_nat_available_zones.enhanced.zones : zones.zone_id]
  common_zone_ids = setintersection(toset(var.zone_ids),toset(local.all_zone_ids))
   
  # Get the instance types supported in each zone.
  instance_types_per_az = { for az, types in data.alicloud_instance_types.default : az => [for t in types.instance_types : t.id] }

  # Get the list of instance types in all listed zones.
  all_instance_types_in_zones = [for zone in local.common_zone_ids : local.instance_types_per_az[zone]]

  # Convert each list to a set.
  sets = [for s in local.all_instance_types_in_zones : toset(s)]
  
  # Calculate the common instance types across all zones.
  common_instance_types = [for element in local.sets[0]: element if length([for set in local.sets: set if contains(set, element)]) == length(local.sets)]
}

# Queries for zones that support enhanced NAT gateways.
data "alicloud_enhanced_nat_available_zones" "enhanced" {
} 

# If the vpc_id variable is not provided, this resource creates a new VPC with the CIDR block specified by the vpc_cidr variable.
resource "alicloud_vpc" "vpc" {  
  count      = var.vpc_id == "" ? 1 : 0
  cidr_block = var.vpc_cidr
}

# If the vswitch_ids variable is not provided, new vSwitches are created based on the specified vswitch_cidrs by default.
resource "alicloud_vswitch" "vswitches" { 
  count      = length(var.vswitch_ids) > 0 ? 0 : length(var.vswitch_cidrs)
  vpc_id     = var.vpc_id == "" ? join("", alicloud_vpc.vpc.*.id) : var.vpc_id
  cidr_block = element(var.vswitch_cidrs, count.index)
  zone_id    = tolist(local.common_zone_ids)[count.index]
}

# If the terway_vswitch_ids variable is not provided, the vSwitches for Terway are created based on the specified terway_vswitch_cidrs by default.
resource "alicloud_vswitch" "terway_vswitches" { 
  count      = length(var.terway_vswitch_ids) > 0 ? 0 : length(var.terway_vswitch_cidrs)
  vpc_id     = var.vpc_id == "" ? join("", alicloud_vpc.vpc.*.id) : var.vpc_id
  cidr_block = element(var.terway_vswitch_cidrs, count.index)
  zone_id    = tolist(local.common_zone_ids)[count.index]
}

# Queries the resource groups of the current Alibaba Cloud user.
data "alicloud_resource_manager_resource_groups" "default" { 
  status = "OK"
}

# Queries the ECS instance types of Alibaba Cloud.
data "alicloud_instance_types" "default" {
  for_each            = toset(local.common_zone_ids )
  availability_zone   = each.key
  cpu_core_count      = 8
  memory_size         = 16
  kubernetes_node_role = "Master"
  system_disk_category = "cloud_essd"
}

 # Creates an ACK dedicated cluster. Configurations include control plane vSwitches, Pod vSwitches, instance types, disks, passwords, and the Service CIDR block.
resource "alicloud_cs_kubernetes" "default" { 
  master_vswitch_ids    = length(var.vswitch_ids) > 0 ? split(",", join(",", var.vswitch_ids)) : length(var.vswitch_cidrs) < 1 ? [] : split(",", join(",", alicloud_vswitch.vswitches.*.id)) # The list of zones that support enhanced NAT.
  pod_vswitch_ids       = length(var.terway_vswitch_ids) > 0 ? split(",", join(",", var.terway_vswitch_ids)) : length(var.terway_vswitch_cidrs) < 1 ? [] : split(",", join(",", alicloud_vswitch.terway_vswitches.*.id)) # The vSwitch CIDR blocks for the pod network when using Terway.
  master_instance_types = [local.common_instance_types[0],local.common_instance_types[0],local.common_instance_types[0]] # The instance types for the master nodes.
  master_disk_category  = "cloud_essd"            # The system disk type for the master nodes.
  password              = "Yourpassword1234"     # The SSH logon password.
  service_cidr          = "172.18.0.0/16"        # The Service CIDR block.
  load_balancer_spec    = "slb.s1.small"         # The Server Load Balancer specification.
  install_cloud_monitor = "true"                 # Install the CloudMonitor service.
  resource_group_id     = data.alicloud_resource_manager_resource_groups.default.groups.0.id # The ID of the resource group to which the cluster belongs. This is used to isolate resources.
  deletion_protection   = "false"                # Deletion protection for the cluster to prevent accidental deletion in the console or through API calls.
  timezone              = "Asia/Shanghai"        # The time zone used by the cluster.
  os_type               = "Linux"                # The operating system platform type.
  platform              = "AliyunLinux3"         # The operating system distribution.
  cluster_domain        = "cluster.local"        # The local domain name of the cluster.
  proxy_mode            = "ipvs"                 # The kube-proxy proxy mode.
  custom_san            = "www.terraform.io"     # The custom certificate SAN.
  new_nat_gateway       = "true"                 # Creates a new NAT Gateway.
  dynamic "addons" {
    for_each = var.cluster_addons
    content {
      name   = lookup(addons.value, "name", var.cluster_addons)
      config = lookup(addons.value, "config", var.cluster_addons)
    }
  }
}

Related documents