Create an ACK dedicated cluster with Terraform

更新时间:
复制 MD 格式

Deploy a Terway-based ACK dedicated cluster with auto-provisioned VPC, vSwitches, and add-ons.

Run this code in your browser on OpenAPI Portal.
Important

Creating ACK dedicated clusters is restricted. To request access, submit a ticket.

Prerequisites

Ensure the following:

  • ACK is activated (activate ACK by using Terraform).

  • An AccessKey pair created for the RAM user running Terraform (Create an AccessKey pair, RAM users).

    Use a RAM user instead of your Alibaba Cloud root account. Limited permissions reduce risk if credentials are compromised.
  • The following minimum permissions policy attached to the RAM user. Covers creating, viewing, and deleting Virtual Private Clouds (VPCs), vSwitches, and ACK clusters (grant permissions).

    {
      "Version": "1",
      "Statement": [
        {
          "Effect": "Allow",
          "Action": [
            "vpc:CreateVpc",
            "vpc:CreateVSwitch",
            "vpc:DescribeRouteTableList",
            "vpc:DescribeVpcAttribute",
            "vpc:ListEnhancedNatGatewayAvailableZones",
            "vpc:DescribeVSwitchAttributes",
            "vpc:DescribeNatGateways",
            "cs:CreateCluster",
            "cs:DescribeTaskInfo",
            "cs:DescribeClusterDetail",
            "cs:DescribeClusterCerts",
            "cs:CheckControlPlaneLogEnable",
            "vpc:DeleteVpc",
            "vpc:DeleteVSwitch",
            "cs:DeleteCluster"
          ],
          "Resource": "*"
        }
      ]
    }
  • Terraform v0.12.28 or later. Verify with terraform --version.

    Option

    Best for

    — online, no installation required

    Quick testing and debugging at no cost

    Cloud Shell — pre-installed, pre-configured with your credentials

    Fast, convenient runs without local setup

    Resource Orchestration Service (ROS) — managed Terraform

    Templates that define Alibaba Cloud, AWS, or Azure resources with managed lifecycle

    Local installation

    Custom development environments or restricted network access

Terraform resources

The configuration uses the following resources. Fees apply—release them when no longer needed.

Resource

Purpose

alicloud_instance_types

Query Elastic Compute Service (ECS) instance types that meet specific conditions

alicloud_vpc

Create a VPC

alicloud_vswitch

Create vSwitches (subnets) inside the VPC

alicloud_resource_manager_resource_groups

Query the resource group managed by the RAM user

alicloud_cs_kubernetes

Create an ACK dedicated cluster

The configuration selects instance types available across all three zones, ensuring control plane nodes can be scheduled in any zone.

Generate Terraform parameters from the console

If the example doesn't match your requirements, generate parameters from the ACK console:

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

  2. On the Clusters page, click Cluster Templates.

  3. Select a cluster type, click Create, and configure the cluster on the Cluster Configurations page.

  4. On the Confirm page, click Console-to-Code.

  5. In the sidebar, click the Terraform tab and copy the generated parameters.

Create an ACK dedicated cluster with Terway

These steps create an ACK dedicated cluster with Terway. The configuration provisions a VPC, three control-plane vSwitches, three Terway pod vSwitches, and the cluster—8 resources total.

Step 1: Create the configuration file

Create a working directory and a main.tf file with the following content:

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"]
}

# Specify the resource name or label.
variable "name" {
  default = "tf-example"
}

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

# Specify the CIDR block of the new VPC. This variable takes effect if you leave the vpc_id variable blank.
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"
}

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

# If vswitch_ids is not specified, you must specify three CIDR blocks to create vSwitches. The CIDR blocks cannot overlap with each other.
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"]
}

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

# This variable specifies the CIDR blocks in which Terway vSwitches are created if you leave the terway_vswitch_ids variable blank.
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"]
}

# Specify the components that you want to install in the ACK cluster. You must specify the name and configuration of each component that you want to install.
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))

  # Obtain the instance types available 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] }

  # Obtain 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 into a collection
  sets = [for s in local.all_instance_types_in_zones : toset(s)]

  # Calculate the instance types that are common to 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)]
}

# Query the zones that support enhanced NAT gateways.
data "alicloud_enhanced_nat_available_zones" "enhanced" {
}

# If you do not specify the vpc_id variable, this Terraform resource creates a VPC. The CIDR block of the VPC is specified by the vpc_cidr variable.
resource "alicloud_vpc" "vpc" {
  count      = var.vpc_id == "" ?  1 : 0
  cidr_block = var.vpc_cidr
}

# If you do not specify the vswitch_ids variable, a new vSwitch is created based on the vswitch_cidrs.
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 you do not specify the terway_vswitch_ids variable, the vSwitch used by Terway is created based on the vswitch_cidrs parameter.
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]
}

# Query the resource group managed by the RAM user.
data "alicloud_resource_manager_resource_groups" "default" {
  status = "OK"
}

# Query ECS instance types.
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"
}

# Create an ACK dedicated cluster and configure control plane vSwitches, pod vSwitches, instance types, disks, the password used to log on to nodes, 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)) # Query the zones that support enhanced NAT gateways.
  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 CIDR blocks of pod vSwitches if you use Terway as the network component.
  master_instance_types = [local.common_instance_types[0],local.common_instance_types[0],local.common_instance_types[0]] # The instance type of the control planes.
  master_disk_category  = "cloud_essd"            # The system disk type of the control plane.
  password              = "Yourpassword1234"     # The password used for SSH logon.
  service_cidr          = "172.18.0.0/16"        # The Service CIDR block.
  load_balancer_spec    = "slb.s1.small"         # The Server Load Balancer (SLB) instance type.
  install_cloud_monitor = "true"                 # Enable CloudMonitor.
  resource_group_id     = data.alicloud_resource_manager_resource_groups.default.groups.0.id # The ID of the resource group to which the cluster belongs. Resource groups are used to isolate resources.
  deletion_protection   = "false"                # Deletion protection can prevent clusters from being accidentally deleted in the console or by calling API operations.
  timezone              = "Asia/Shanghai"        # The time zone of the cluster.
  os_type               = "Linux"                # The type of the node OS.
  platform              = "AliyunLinux3"         # The OS distribution.
  cluster_domain        = "cluster.local"        # The cluster domain name.
  proxy_mode            = "ipvs"                 # The kube-proxy mode.
  custom_san            = "www.terraform.io"     # The custom subject alternative name (SAN) of the API server certificate of the cluster.
  new_nat_gateway       = "true"                 # Create a 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)
    }
  }
}

Step 2: Initialize Terraform

terraform init

A successful initialization returns:

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.

Step 3: Preview the execution plan

terraform plan

Previews the planned resource changes without applying them.

A successful plan returns:

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

Step 4: Create the cluster

terraform apply

When prompted, type yes and press Enter.

A successful apply returns:

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

Verify the cluster

After terraform apply completes, verify the cluster using either method:

Run the terraform show command

Option 1: Use `terraform show`

terraform show

Lists all resources Terraform created and their current state.

Log on to the ACK console

Option 2: Check the ACK console

Log on to the ACK console and confirm the new cluster appears in the Clusters list.

Clean up resources

Important

Running terraform destroy permanently deletes all resources created by this configuration. This action cannot be undone.

Release the resources. See Common commands for terraform destroy options.Run with one click

terraform destroy

When prompted, type yes and press Enter. A successful destroy returns:

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

Sample code

Run this code in 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"]
}

# Specify the resource name or label.
variable "name" {
  default = "tf-example"
}

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

# Specify the CIDR block of the new VPC. This variable takes effect if you leave the vpc_id variable blank.
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"
}

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

# If vswitch_ids is not specified, you must specify three CIDR blocks to create vSwitches. The CIDR blocks cannot overlap with each other.
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"]
}

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

# This variable specifies the CIDR blocks in which Terway vSwitches are created if you leave the terway_vswitch_ids variable blank.
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"]
}

# Specify the components that you want to install in the ACK cluster. You must specify the name and configuration of each component that you want to install.
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))

  # Obtain the instance types available 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] }

  # Obtain 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 into a collection
  sets = [for s in local.all_instance_types_in_zones : toset(s)]

  # Calculate the instance types that are common to 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)]
}

# Query the zones that support enhanced NAT gateways.
data "alicloud_enhanced_nat_available_zones" "enhanced" {
}

# If you do not specify the vpc_id variable, this Terraform resource creates a VPC. The CIDR block of the VPC is specified by the vpc_cidr variable.
resource "alicloud_vpc" "vpc" {
  count      = var.vpc_id == "" ?  1 : 0
  cidr_block = var.vpc_cidr
}

# If you do not specify the vswitch_ids variable, a new vSwitch is created based on the vswitch_cidrs.
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 you do not specify the terway_vswitch_ids variable, the vSwitch used by Terway is created based on the vswitch_cidrs parameter.
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]
}

# Query the resource group managed by the RAM user.
data "alicloud_resource_manager_resource_groups" "default" {
  status = "OK"
}

# Query ECS instance types.
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"
}

# Create an ACK dedicated cluster and configure control plane vSwitches, pod vSwitches, instance types, disks, the password used to log on to nodes, 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)) # Query the zones that support enhanced NAT gateways.
  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 CIDR blocks of pod vSwitches if you use Terway as the network component.
  master_instance_types = [local.common_instance_types[0],local.common_instance_types[0],local.common_instance_types[0]] # The instance type of the control planes.
  master_disk_category  = "cloud_essd"            # The system disk type of the control plane.
  password              = "Yourpassword1234"     # The password used for SSH logon.
  service_cidr          = "172.18.0.0/16"        # The Service CIDR block.
  load_balancer_spec    = "slb.s1.small"         # The SLB instance type.
  install_cloud_monitor = "true"                 # Enable CloudMonitor.
  resource_group_id     = data.alicloud_resource_manager_resource_groups.default.groups.0.id # The ID of the resource group to which the cluster belongs. Resource groups are used to isolate resources.
  deletion_protection   = "false"                # Deletion protection can prevent clusters from being accidentally deleted in the console or by calling API operations.
  timezone              = "Asia/Shanghai"        # The time zone of the cluster.
  os_type               = "Linux"                # The type of the node OS.
  platform              = "AliyunLinux3"         # The OS distribution.
  cluster_domain        = "cluster.local"        # The cluster domain name.
  proxy_mode            = "ipvs"                 # The kube-proxy mode.
  custom_san            = "www.terraform.io"     # The custom SAN for the API server certificate of the cluster.
  new_nat_gateway       = "true"                 # Create a 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)
    }
  }
}

Next steps