全部產品
Search
文件中心

Resource Orchestration Service:Terraform版ECS單機部署Nginx服務

更新時間:Aug 24, 2023

本文以Terraform版ECS單機部署Nginx服務為例,由簡入難的向您介紹如何編輯Terraform模板。

前提條件

請您提前瞭解模板文法和結構。更多資訊,請參見模板快速入門

情境樣本

在阿里雲Virtual Private Cloud中建立ECS執行個體,並在ECS執行個體中部署Nginx服務。

2023-04-26_17-59-47..png

使用須知

您可以訪問對應的資源類型查看屬性詳情。具體操作,請參見查看資源類型

資源類型文檔為每個屬性定義了Optional(可選)、Required(必須)等資訊。如果將屬性定義為Required(必須),則要求必須在模板資源中聲明該屬性;反之,則為非必須。

編輯模板

您可以通過資源類型索引文檔尋找所需的資源類型。更多資訊,請參見資源類型索引

例如:當前情境中需要建立Virtual Private Cloud(alicloud_vpc)、ECS執行個體(alicloud_instance)、交換器(alicloud_vswitch)、安全性群組(alicloud_security_group)和安全性群組規則(alicloud_security_group_rule),在建立ECS執行個體的同時會安裝Nginx服務。

定義模板多種資源及其依賴關係

定義基礎網路資源

您可以通過模板定義基礎網路資源vpcvswsecurity_group

  • 使用alicloud_vpc.vpc.id擷取資源alicloud_vpc的輸出ID屬性值。

  • 使用var.***擷取自訂變數,即variable中的參數值。例如var.zone_id擷取的是variablezone_id的值。

resource "alicloud_vpc" "vpc" {
  cidr_block = "10.1.0.0/21"
}
resource "alicloud_vswitch" "vsw" {
  vpc_id     = alicloud_vpc.vpc.id
  cidr_block = "172.16.0.0/21"
  zone_id    = var.zone_id
}
resource "alicloud_security_group" "security_group" {
  name       = "new-group"
  vpc_id     = alicloud_vpc.vpc.id
}

定義安全性群組規則

您可以通過模板定義安全性群組規則allow_sshallow_weballow_egress

使用alicloud_security_group.security_group.id擷取安全性群組security_group資源的輸出ID屬性值。

# 安全性群組入口端1
resource "alicloud_security_group_rule" "allow_ssh" {
  security_group_id = alicloud_security_group.security_group.id
  type              = "ingress"
  cidr_ip           = "0.0.0.0/0"
  policy            = "accept"
  ip_protocol				= "tcp"
  port_range				= "22/22"
  priority					= 1
}

# 安全性群組入口端2
resource "alicloud_security_group_rule" "allow_web" {
  security_group_id = alicloud_security_group.security_group.id
  type 							= "ingress"
  cidr_ip						= "0.0.0.0/0"
  policy 						= "accept"
  ip_protocol				= "tcp"
  port_range				= "80/443"
  priority					= 1
}

# 安全性群組出口端
resource "alicloud_security_group_rule" "allow_egress" {
  security_group_id = alicloud_security_group.security_group.id
  type 							= "egress"
  cidr_ip						= "0.0.0.0/0"
  policy 						= "accept"
  ip_protocol				= "tcp"
  port_range				= "1/65535"
  priority					= 1
}

定義ECS執行個體

您可以通過模板定義ECS執行個體instance

  • 使用var.*** 擷取自訂變數,即variable中的參數值。例如:var.instance_type擷取的是variableinstance_type的值。

  • 使用local.***擷取本地變數,即locals中的參數值。例如:local.new_host_name擷取的是localsnew_host_name的值。

  • 使用user_data中的${path.cwd}擷取當前工作目錄。

  • user_data.sh檔案中包含Elastic Compute Service需要執行的初始化指令碼。user_data.sh初始化指令碼如下所示。

#!/bin/bash -v
# 掛盤到/disk1
cat >> /root/InitDataDisk.sh << "EOF"
#!/bin/bash
echo "p
n
p
w
" |  fdisk -u /dev/vdb
EOF
/bin/bash /root/InitDataDisk.sh
rm -f /root/InitDataDisk.sh
mkfs -t ext4 /dev/vdb1
cp /etc/fstab /etc/fstab.bak
mkdir /disk1
echo `blkid /dev/vdb1 | awk '{print $2}' | sed 's/\\\"//g'` /disk1 ext4 defaults 0 0 >> /etc/fstab
mount -a
# 這裡配置安裝指令碼
yum install -y nginx
# 配置啟動指令碼
/usr/sbin/nginx

定義ECS執行個體模板如下所示。

resource "alicloud_instance" "instance" {
      availability_zone					 = var.zone_id
      security_groups 					 = [alicloud_security_group.security_group.id]
      # series III
      host_name 								 = local.new_host_name
      instance_type              = var.instance_type
      system_disk_size           = 500
      system_disk_category       = "cloud_essd"
      image_id                   = "centos_7_9_x64_20G_alibase_20210318.vhd"
      vswitch_id                 = alicloud_vswitch.vsw.id
      password                   = var.instance_password
      internet_charge_type 			 = "PayByTraffic"
      internet_max_bandwidth_out = 30
      instance_charge_type 			 = var.pay_type
      period 										 = var.pay_period
      period_unit 							 = var.pay_period_unit
      user_data									 = file("${path.cwd}/user-data.sh")
      data_disks {
        size        						 = 100
        category  						   = "cloud_essd"
      }
    }

完整模板樣本

variable "pay_type" {
	type                       = string
}
variable "pay_period_unit" {
	type                       = string
}
variable "pay_period" {
	type                       = number
}
variable "zone_id" {
	type                       = string
}
variable "vpc_cidr_block" {
	type                       = string
}
variable "vswitch_cidr_block" {
	type                       = string
} 
variable "instance_type" {
	type                       = string
}
variable "system_disk_category" {
	type                       = string
}
variable "system_disk_size" {
	type                       = number
}
variable "data_disk_category" {
	type                       = string
}
variable "data_disk_size" {
	type                       = number
} 
variable "instance_password" {
	type                       = string
}
# 預設資源名稱
locals {
  production_name            = "nginx"
  new_scg_name 							 = "sg-for-${local.production_name}"
  new_host_name						   = "app-for-${local.production_name}"
}

resource "alicloud_vpc" "vpc" {
  cidr_block 								 = var.vpc_cidr_block
}

resource "alicloud_vswitch" "vsw" {
  vpc_id     								 = alicloud_vpc.vpc.id
  cidr_block 								 = var.vswitch_cidr_block
  zone_id    								 = var.zone_id
}

# 安全性群組基本資料配置
resource "alicloud_security_group" "security_group" {
  name        							 = local.new_scg_name
  description 							 = "nginx scg"
  vpc_id 										 =  alicloud_vpc.vpc.id
}

# 安全性群組入口端1
resource "alicloud_security_group_rule" "allow_ssh" {
  security_group_id 				 = alicloud_security_group.security_group.id
  type										   = "ingress"
  cidr_ip										 = "0.0.0.0/0"
  policy 							 		   = "accept"
  ip_protocol					 			 = "tcp"
  port_range							   = "22/22"
  priority								 	 = 1
}

# 安全性群組入口端2
resource "alicloud_security_group_rule" "allow_web" {
  security_group_id 			 	 = alicloud_security_group.security_group.id
  type											 = "ingress"
  cidr_ip										 = "0.0.0.0/0"
  policy									 	 = "accept"
  ip_protocol								 = "tcp"
  port_range								 = "80/443"
  priority									 = 1
}

# 安全性群組出口端
resource "alicloud_security_group_rule" "allow_egress" {
  security_group_id 				 = alicloud_security_group.security_group.id
  type 											 = "egress"
  cidr_ip										 = "0.0.0.0/0"
  policy										 = "accept"
  ip_protocol								 = "tcp"
  port_range								 = "1/65535"
  priority									 = 1
}

# 執行個體基本配置
resource "alicloud_instance" "instance" {
  availability_zone          = var.zone_id
  security_groups						 = [alicloud_security_group.security_group.id]
  # series III
  host_name 								 = local.new_host_name
  instance_type              = var.instance_type
  system_disk_size           = var.system_disk_size
  system_disk_category       = var.system_disk_category
  image_id                   = "centos_7_9_x64_20G_alibase_20210318.vhd"
  vswitch_id                 = alicloud_vswitch.vsw.id
  password                   = var.instance_password
  internet_charge_type			 = "PayByTraffic"
  internet_max_bandwidth_out = 30
  instance_charge_type			 = var.pay_type
  period										 = var.pay_period
  period_unit								 = var.pay_period_unit
  user_data									 = file("${path.cwd}/user-data.sh")
  data_disks {
    size       							 = var.data_disk_size
    category 							   = var.data_disk_category
  }
}
# 返回Nginx的IP地址
output "nginx_ip" {
  value										 	 = "http://${alicloud_instance.instance.public_ip}:8080"
}

Terraform模板類型轉換

您可以通過Resource Orchestration Service控制台將Terraform模板轉換成ROS模板,使用ROS資源實現添加模板參數分組與動態擷取參數配置。

  1. 登入Resource Orchestration Service控制台

  2. 在左側導覽列,選擇模板>我的模板

  3. 我的模板頁面,單擊建立模板

  4. 編輯模板內容頁簽的下拉頁表中,選擇Terraform

  5. 編輯Terraform模板。

    1. 建立main.tf檔案,輸入完整模板樣本中建立的Terraform模板。

    2. 建立user-data.sh檔案,輸入user_data.sh初始化指令碼內容。

  6. 編輯模板內容頁簽的下拉頁表中,選擇ROS

    您已成功將Terraform模板轉換為ROS模板,ROS模板樣本如下所示。

    ROSTemplateFormatVersion: '2015-09-01'
    Transform: Aliyun::Terraform-v1.2
    Workspace:
      main.tf: |-
            variable "pay_type" {
              type 										   = string
            }
            variable "pay_period_unit" {
              type											 = string
            }
            variable "pay_period" {
              type											 = number
            }
            variable "zone_id" {
              type											 = string
            }
            variable "instance_type" {
              type											 = string
            }
            variable "vpc_cidr_block" {
              type											 = string
            }
            variable "vsw_cidr_block" {
              type											 = string
            }
            variable "instance_password" {
              type											 = string
            }
            # 預設資源名稱
            locals {
              production_name = "nginx"
              new_vpc_name  					   = "vpc-for-${local.production_name}"
              new_vsw_name  			 		   = "vsw-for-${local.production_name}"
              new_scg_name  						 = "sg-for-${local.production_name}"
              new_host_name   					 = "app-for-${local.production_name}"
            }
    
            resource "alicloud_vpc" "vpc" {
              vpc_name    					     = local.new_vpc_name
              cidr_block 								 = var.vpc_cidr_block
            }
    
    
            resource "alicloud_vswitch" "vsw" {
              vpc_id   								   = alicloud_vpc.vpc.id
              cidr_block								 = var.vsw_cidr_block
              zone_id   							   = var.zone_id
            }
    
            # 安全性群組基本資料配置
            resource "alicloud_security_group" "security_group" {
              name      							   = local.new_scg_name
              description							   = "nginx scg"
              vpc_id									   =  alicloud_vpc.vpc.id
            }
            
            # 安全性群組入口端1
            resource "alicloud_security_group_rule" "allow_ssh" {
              security_group_id				   = alicloud_security_group.security_group.id
              type 											 = "ingress"
              cidr_ip										 = "0.0.0.0/0"
              policy 										 = "accept"
              ip_protocol								 = "tcp"
              port_range								 = "22/22"
              priority						 		 	 = 1
            }
            
            # 安全性群組入口端2
            resource "alicloud_security_group_rule" "allow_web" {
              security_group_id					 = alicloud_security_group.security_group.id
              type											 = "ingress"
              cidr_ip										 = "0.0.0.0/0"
              policy										 = "accept"
              ip_protocol								 = "tcp"
              port_range								 = "80/443"
              priority									 = 1
            }
            
            # 安全性群組出口端
            resource "alicloud_security_group_rule" "allow_egress" {
              security_group_id					 = alicloud_security_group.security_group.id
              type 											 = "egress"
              cidr_ip										 = "0.0.0.0/0"
              policy										 = "accept"
              ip_protocol								 = "tcp"
              port_range								 = "1/65535"
              priority						 			 = 1
            }
            
            # 執行個體基本配置
            resource "alicloud_instance" "instance" {
              availability_zone					 = var.zone_id
              security_groups						 = [alicloud_security_group.security_group.id]
              # series III
              host_name									 = local.new_host_name
              instance_type              = var.instance_type
              system_disk_size           = 500
              system_disk_category       = "cloud_essd"
              image_id                   = "centos_7_9_x64_20G_alibase_20210318.vhd"
              vswitch_id                 = alicloud_vswitch.vsw.id
              password                   = var.instance_password
              internet_charge_type 			 = "PayByTraffic"
              internet_max_bandwidth_out = 30
              instance_charge_type 			 = var.pay_type
              period 										 = var.pay_period
              period_unit								 = var.pay_period_unit
              user_data 								 = file("${path.cwd}/user-data.sh")
              data_disks {
                size       							 = 100
                category  						   = "cloud_essd"
              }
            }
            # 返回Nginx的IP地址
            output "nginx_ip" {
              value											 = "http://${alicloud_instance.instance.public_ip}:8080"
            }
            
      user-data.sh: |-
        #!/bin/bash -v
        # 掛盤到/disk1
        cat >> /root/InitDataDisk.sh << "EOF"
        #!/bin/bash
        echo "p
        n
        p
        w
        " |  fdisk -u /dev/vdb
        EOF
        /bin/bash /root/InitDataDisk.sh
        rm -f /root/InitDataDisk.sh
        mkfs -t ext4 /dev/vdb1
        cp /etc/fstab /etc/fstab.bak
        mkdir /disk1
        echo `blkid /dev/vdb1 | awk '{print $2}' | sed 's/\\\"//g'` /disk1 ext4 defaults 0 0 >> /etc/fstab
        mount -a
        # 這裡配置安裝指令碼
        yum install -y nginx
        # 配置啟動指令碼
        /usr/sbin/nginx
    

添加模板參數分組與動態擷取參數配置

在以上模板中您已經完成對多種資源及其依賴關係的定義。其中instance資源的system_disk_category屬性值為固定值,當您在不同地區建立資源棧時,需要調整模板內容和變更資源屬性值以達到部署資源棧的目的。

您可以對模板添加Parameters,從而提高模板的靈活性和可複用性。

添加模板參數分組

您可以在模板中使用中繼資料(Metadata)對Parameters中定義的參數進行分組,並定義參數分組標籤。更多資訊,請參見中繼資料(Metadata)

您可以根據不同資源與資源對應的參數進行參數分組。以當前模板為例,您可以將資源按照如下結果劃分。

資源參數分類

資源名稱

參數名稱

基礎網路設定

vpcvswsecurity_group

zone_idvpc_cidr_blockvswitch_cidr_block

ECS執行個體資源配置

instance

instance_typesystem_disk_categorysystem_disk_sizedata_disk_categorydata_disk_sizeinstance_password

在Terraform標籤下,建立.metadata檔案,輸入以下內容。

{
  "ALIYUN::ROS::Interface": {
    "ParameterGroups": [
      {
        "Parameters": [
          "pay_type",
          "pay_period_unit",
          "pay_period"
        ],
        "Label": {
          "default": {
            "en": "Payment mode Configuration",
            "zh-cn": "付費模式配置"
          }
        }
      },
      {
        "Parameters": [
          "zone_id"
        ],
        "Label": {
          "default": {
            "zh-cn": "可用性區域配置",
            "en": "Zone Configuration"
          }
        }
      },
      {
        "Parameters": [
          "vpc_cidr_block",
          "vswitch_cidr_block"
        ],
        "Label": {
          "default": {
            "zh-cn": "選擇已有基礎資源配置",
            "en": "Choose existing Infrastructure Configuration"
          }
        }
      },
      {
        "Parameters": [
          "instance_type",
          "system_disk_category",
          "system_disk_size",
          "data_disk_category",
          "data_disk_size",
          "instance_password"
        ],
        "Label": {
          "default": {
            "en": "Instance",
            "zh-cn": "ECS執行個體配置"
          }
        }
      }
    ]
  }
}

動態擷取參數配置

以instance參數為例,當您需要在ROS控制台上對參數設定篩選條件並動態選擇參數配置時,可以按照參數對應的資源類型(ALIYUN::ECS::Instance)在AssociationProperty和AssociationPropertyMetadata文檔中查詢到該參數支援的AssociationProperty取值 (ALIYUN::ECS::Instance::InstanceType),然後查看對篩選到的AssociationProperty設定過濾條件為ZoneIdAssociationPropertyMetadata取值。更多資訊,請參見AssociationProperty和AssociationPropertyMetadata

在Terraform標籤下的main.tf檔案中輸入以下內容。

variable "pay_type" {
  type 				= string
  default     = "PostPaid"
  description = <<EOT
  {
    "Label": {
      "en": "ECS Instance Charge Type",
      "zh-cn": "付費類型"
    },
    "AllowedValues": [
      "PostPaid",
      "PrePaid"
    ],
    "AssociationProperty": "ChargeType",
    "AssociationPropertyMetadata": {
      "LocaleKey": "InstanceChargeType"
    }
  }
  EOT
}
variable "pay_period_unit" {
  type 				= string
  default     = "Month"
  description = <<EOT
  {
    "Label": {
      "en": "Pay Period Unit",
      "zh-cn": "購買資源時間長度周期"
    },
    "AllowedValues": [
      "Month",
      "Year"
    ],
    "AssociationProperty": "PayPeriodUnit",
    "AssociationPropertyMetadata": {
      "Visible": {
        "Condition": {
          "Fn::Not": {
            "Fn::Equals": [
              "$${pay_type}",
              "PostPaid"
            ]
          }
        }
      }
    }
  }
  EOT
}
variable "pay_period" {
  type				 = number
  default     = 1
  description = <<EOT
  {
    "Label": {
      "en": "Period",
      "zh-cn": "購買資源時間長度"
    },
    "AllowedValues": [
      1,
      2,
      3,
      4,
      5,
      6,
      7,
      8,
      9
    ],
    "AssociationProperty": "PayPeriod",
    "AssociationPropertyMetadata": {
      "Visible": {
        "Condition": {
          "Fn::Or": [
            {
              "Fn::Equals": [
                "$${pay_type}",
                "PrePaid"
              ]
            },
            {
              "Fn::Equals": [
                "$${pay_type}",
                "undefined"
              ]
            }
          ]
        }
      }
    }
  }
  EOT
}
variable "zone_id" {
  type			  = string
  description = <<EOT
  {
    "AssociationProperty": "ALIYUN::ECS::Instance:ZoneId",
    "Description": {
      "zh-cn": "可用性區域ID。<br><b>註: <font color='blue'>選擇前請確認該可用性區域是否支援建立ECS資源的規格,建議與其他交換器可用性區域不同。</font></b>",
      "en": "Availability Zone ID.<br><b>notex:<font color='blue'>before selecting, please confirm that the Availability Zone supports the specification of creating ECS resources,which is recommended to be different from other VSwitch Availability Zone.</font></b>"
    },
    "Label": {
      "zh-cn": "交換器可用性區域",
      "en": "VSwitch Availability Zone"
    }
  }
  EOT
}
variable "vpc_cidr_block" {
  type			  = string
  default     = "192.168.0.0/16"
  description = <<EOT
  {
    "Label": {
      "zh-cn": "專用網路網段",
      "en": "VPC CIDR Block"
    },
    "Description": {
      "zh-cn": "建立專用網路IP位址區段範圍,推薦使用以下的IP位址區段<br><font color='green'>[10.0.0.0/8]</font><br><font color='green'>[172.16.0.0/12]</font><br><font color='green'>[192.168.0.0/16]。</font>",
      "en": "New proprietary network IP address segment range, recommended use of the following IP address segments<br><font color='green'>[10.0.0.0/8]</font><br><font color='green'>[172.16.0.0/12]</font><br><font color='green'>[192.168.0.0/16].</font>"
    }
  }
  EOT
}
variable "vswitch_cidr_block" {
  type			  = string
  default     = "192.168.0.0/24"
  description = <<EOT
  {
    "Description": {
      "zh-cn": "必須是所屬專用網路的子網段,並且沒有被其他交換器佔用。",
      "en": "Must be a sub-network segment of the proprietary network and is not occupied by other VSwitches."
    },
    "Label": {
      "zh-cn": "交換器網段",
      "en": "VSwitch CIDR Block"
    }
  }
  EOT
} 
variable "instance_type" {
  type			  = string
  description = <<EOT
  {
    "Label": {
      "zh-cn": "執行個體規格",
      "en": "Instance Type"
    },
    "AssociationProperty": "ALIYUN::ECS::Instance::InstanceType",
    "AssociationPropertyMetadata": {
      "InstanceChargeType": "$${pay_type}",
      "ZoneId": "$${zone_id}"
    }
  }
  EOT
}
variable "system_disk_category" {
  type			  = string
  description = <<EOT
  {
    "Description": {
      "en": "<font color='blue'><b>Optional values:</b></font><br>[cloud_efficiency: <font color='green'>Efficient Cloud Disk</font>]<br>[cloud_ssd: <font color='green'>SSD Cloud Disk</font>]<br>[cloud_essd: <font color='green'>ESSD Cloud Disk</font>]<br>[cloud: <font color='green'>Cloud Disk</font>]<br>[ephemeral_ssd: <font color='green'>Local SSD Cloud Disk</font>]",
      "zh-cn": "<font color='blue'><b>可選值:</b></font><br>[cloud_efficiency: <font color='green'>高效雲端硬碟</font>]<br>[cloud_ssd: <font color='green'>SSD雲端硬碟</font>]<br>[cloud_essd: <font color='green'>ESSD雲端硬碟</font>]<br>[cloud: <font color='green'>普通雲端硬碟</font>]<br>[ephemeral_ssd: <font color='green'>本地SSD盤</font>]"
    },
    "AssociationProperty": "ALIYUN::ECS::Disk::SystemDiskCategory",
    "AssociationPropertyMetadata": {
      "ZoneId": "$${zone_id}",
      "InstanceType": "$${instance_type}"
    },
    "Label": {
      "en": "System Disk Type",
      "zh-cn": "系統硬碟類型"
    }
  }
  EOT
}
variable "system_disk_size" {
  type			  = number
  default     = 40
  description = <<EOT
  {
    "Description": {
      "zh-cn": "系統硬碟大小,取值範圍:40~500,單位:GB。",
      "en": "System disk size, range of values: 40~500, units: GB."
    },
    "Label": {
      "zh-cn": "系統硬碟空間",
      "en": "System Disk Space"
    }
  }
  EOT
}
variable "data_disk_category" {
  type			  = string
  description = <<EOT
  {
    "Label": {
      "zh-cn": "資料盤類型",
      "en": "Data Disk Type"
    },
    "Description": {
      "zh-cn": "<font color='blue'><b>可選值:</b></font><br>[cloud_efficiency: <font color='green'>高效雲端硬碟</font>]<br>[cloud_ssd: <font color='green'>SSD雲端硬碟</font>]<br>[cloud_essd: <font color='green'>ESSD雲端硬碟</font>]<br>[cloud: <font color='green'>普通雲端硬碟</font>]",
      "en": "<font color='blue'><b>Optional values:</b></font><br>[cloud_efficiency: <font color='green'>Efficient Cloud Disk</font>]<br>[cloud_ssd: <font color='green'>SSD Cloud Disk</font>]<br>[cloud_essd: <font color='green'>ESSD Cloud Disk</font>]<br>[cloud: <font color='green'>Cloud Disk</font>]"
    },      
    "AssociationProperty": "ALIYUN::ECS::Disk::DataDiskCategory",
    "AssociationPropertyMetadata": {
      "ZoneId": "$${zone_id}",
      "InstanceType": "$${instance_type}"
    }
  }
  EOT
}
variable "data_disk_size" {
  type			  = number
  default     = 100
  description = <<EOT
  {
    "Description": {
      "zh-cn": "ECS執行個體資料盤大小,單位為GiB。取值範圍:20~32768",
      "en": "ECS Instance disk size, range of values: 20~32768, units: GB"
    },
    "MaxValue": 32768,
    "MinValue": 20,
    "Label": {
      "zh-cn": "資料盤空間",
      "en": "Data Disk Space"
    }
  }
  EOT
} 
variable "instance_password" {
  type			  = string
  sensitive   = true
  description = <<EOT
  {
    "Description": {
      "en": "Server login password, Length 8~30, must contain three(Capital letters, lowercase letters, numbers, ()`~!@#$%^&*_-+=|{}[]:;<>,.?/ Special symbol in).",
      "zh-cn": "登入密碼,長度8~30,必須包含三項(大寫字母、小寫字母、數字、 ()`~!@#$%^&*_-+=|{}[]:;<>,.?/ 中的特殊符號)。"
    },
    "Label": {
      "en": "Instance Password",
      "zh-cn": "登入密碼"
    },
    "ConstraintDescription": {
      "en": "Length 8~30, must contain three(Capital letters, lowercase letters, numbers, ()`~!@#$%^&*_-+=|{}[]:;<>,.?/ Special symbol in).",
      "zh-cn": "長度8~30,必須包含三項(大寫字母、小寫字母、數字、 ()`~!@#$%^&*_-+=|{}[]:;<>,.?/ 中的特殊符號)。"
    },
    "AssociationProperty": "ALIYUN::ECS::Instance::Password",
    "AllowedPattern": "^[a-zA-Z0-9-\\(\\)\\`\\~\\!\\@\\#\\$\\%\\^\\&\\*\\_\\-\\+\\=\\|\\{\\}\\[\\]\\:\\;\\<\\>\\,\\.\\?\\/]*$",
    "MinLength": 8,
    "MaxLength": 30
  }
  EOT
}

添加模板參數關聯與約束

Terraform模板中定義了ECS執行個體,其中需要約束的參數(zone_idinstance_typevswitch_idsystem_disk_categorysystem_disk_sizedata_disk_categorydata_disk_size)都與alicloud_instance有關。

在ResourcesForParameterConstraints欄位中只需要定義資源類型ALIYUN::ECS::Instance(alicloud_instance),並關聯image_idinstance_typezone_id參數就可以實現對instance_typezone_id的約束。

{
  "ALIYUN::ROS::Interface": {
    "ResourcesForParameterConstraints": {
      "instance": {
        "Type": "ALIYUN::ECS::Instance",
        "Properties": {
          "InstanceType": {
            "Ref": "instance_type"
          },
          "ImageId": "centos_7_9_x64_20G_alibase_20210318.vhd",
          "VSwitchId": {
            "Ref": "vswitch_id"
          },
          "ZoneId": {
            "Ref": "zone_id"
          },
          "SystemDiskCategory": {
            "Ref": "system_disk_category"
          },
          "SystemDiskSize": {
            "Ref": "system_disk_size"
          },
          "DataDiskCategory": {
            "Ref": "data_disk_category"
          },
          "DataDiskSize": {
            "Ref": "data_disk_size"
          }
        }
      }
    },
    "ParameterGroups": [
      {
        "Parameters": [
          "pay_type",
          "pay_period_unit",
          "pay_period"
        ],
        "Label": {
          "default": {
            "en": "Payment mode Configuration",
            "zh-cn": "付費模式配置"
          }
        }
      },
      {
        "Parameters": [
          "zone_id"
        ],
        "Label": {
          "default": {
            "zh-cn": "可用性區域配置",
            "en": "Zone Configuration"
          }
        }
      },
      {
        "Parameters": [
          "vpc_cidr_block",
          "vswitch_cidr_block"
        ],
        "Label": {
          "default": {
            "zh-cn": "選擇已有基礎資源配置",
            "en": "Choose existing Infrastructure Configuration"
          }
        }
      },
      {
        "Parameters": [
          "instance_type",
          "system_disk_category",
          "system_disk_size",
          "data_disk_category",
          "data_disk_size",
          "instance_password"
        ],
        "Label": {
          "default": {
            "en": "Instance",
            "zh-cn": "ECS執行個體配置"
          }
        }
      }
    ]
  }
}

完整模板樣本

ROSTemplateFormatVersion: '2015-09-01'
Transform: Aliyun::Terraform-v1.2
Workspace:
  .metadata: |-
    {
      "ALIYUN::ROS::Interface": {
        "ResourcesForParameterConstraints": {
          "instance": {
            "Type": "ALIYUN::ECS::Instance",
            "Properties": {
              "InstanceType": {
                "Ref": "instance_type"
              },
              "ImageId": "centos_7_9_x64_20G_alibase_20210318.vhd",
              "VSwitchId": {
                "Ref": "vswitch_id"
              },
              "ZoneId": {
                "Ref": "zone_id"
              },
              "SystemDiskCategory": {
                "Ref": "system_disk_category"
              },
              "SystemDiskSize": {
                "Ref": "system_disk_size"
              },
              "DataDiskCategory": {
                "Ref": "data_disk_category"
              },
              "DataDiskSize": {
                "Ref": "data_disk_size"
              }
            }
          }
        },
        "ParameterGroups": [
          {
            "Parameters": [
              "pay_type",
              "pay_period_unit",
              "pay_period"
            ],
            "Label": {
              "default": {
                "en": "Payment mode Configuration",
                "zh-cn": "付費模式配置"
              }
            }
          },
          {
            "Parameters": [
              "zone_id"
            ],
            "Label": {
              "default": {
                "zh-cn": "可用性區域配置",
                "en": "Zone Configuration"
              }
            }
          },
          {
            "Parameters": [
              "vpc_cidr_block",
              "vswitch_cidr_block"
            ],
            "Label": {
              "default": {
                "zh-cn": "選擇已有基礎資源配置",
                "en": "Choose existing Infrastructure Configuration"
              }
            }
          },
          {
            "Parameters": [
              "instance_type",
              "system_disk_category",
              "system_disk_size",
              "data_disk_category",
              "data_disk_size",
              "instance_password"
            ],
            "Label": {
              "default": {
                "en": "Instance",
                "zh-cn": "ECS執行個體配置"
              }
            }
          }
        ]
      }
    }
  main.tf: |-
    variable "pay_type" {
      type			  = string
      default     = "PostPaid"
      description = <<EOT
      {
        "Label": {
          "en": "ECS Instance Charge Type",
          "zh-cn": "付費類型"
        },
        "AllowedValues": [
          "PostPaid",
          "PrePaid"
        ],
        "AssociationProperty": "ChargeType",
        "AssociationPropertyMetadata": {
          "LocaleKey": "InstanceChargeType"
        }
      }
      EOT
    }
    variable "pay_period_unit" {
      type			  = string
      default     = "Month"
      description = <<EOT
      {
        "Label": {
          "en": "Pay Period Unit",
          "zh-cn": "購買資源時間長度周期"
        },
        "AllowedValues": [
          "Month",
          "Year"
        ],
        "AssociationProperty": "PayPeriodUnit",
        "AssociationPropertyMetadata": {
          "Visible": {
            "Condition": {
              "Fn::Not": {
                "Fn::Equals": [
                  "$${pay_type}",
                  "PostPaid"
                ]
              }
            }
          }
        }
      }
      EOT
    }
    variable "pay_period" {
      type			  = number
      default     = 1
      description = <<EOT
      {
        "Label": {
          "en": "Period",
          "zh-cn": "購買資源時間長度"
        },
        "AllowedValues": [
          1,
          2,
          3,
          4,
          5,
          6,
          7,
          8,
          9
        ],
        "AssociationProperty": "PayPeriod",
        "AssociationPropertyMetadata": {
          "Visible": {
            "Condition": {
              "Fn::Or": [
                {
                  "Fn::Equals": [
                    "$${pay_type}",
                    "PrePaid"
                  ]
                },
                {
                  "Fn::Equals": [
                    "$${pay_type}",
                    "undefined"
                  ]
                }
              ]
            }
          }
        }
      }
      EOT
    }
    variable "zone_id" {
      type			  = string
      description = <<EOT
      {
        "AssociationProperty": "ALIYUN::ECS::Instance:ZoneId",
        "Description": {
          "zh-cn": "可用性區域ID。<br><b>註: <font color='blue'>選擇前請確認該可用性區域是否支援建立ECS資源的規格,建議與其他交換器可用性區域不同。</font></b>",
          "en": "Availability Zone ID.<br><b>notex:<font color='blue'>before selecting, please confirm that the Availability Zone supports the specification of creating ECS resources,which is recommended to be different from other VSwitch Availability Zone.</font></b>"
        },
        "Label": {
          "zh-cn": "交換器可用性區域",
          "en": "VSwitch Availability Zone"
        }
      }
      EOT
    }
    variable "vpc_cidr_block" {
      type			  = string
      default     = "192.168.0.0/16"
      description = <<EOT
      {
        "Label": {
          "zh-cn": "專用網路網段",
          "en": "VPC CIDR Block"
        },
        "Description": {
          "zh-cn": "建立專用網路IP位址區段範圍,推薦使用以下的IP位址區段<br><font color='green'>[10.0.0.0/8]</font><br><font color='green'>[172.16.0.0/12]</font><br><font color='green'>[192.168.0.0/16]。</font>",
          "en": "New proprietary network IP address segment range, recommended use of the following IP address segments<br><font color='green'>[10.0.0.0/8]</font><br><font color='green'>[172.16.0.0/12]</font><br><font color='green'>[192.168.0.0/16].</font>"
        }
      }
      EOT
    }
    variable "vswitch_cidr_block" {
      type			  = string
      default     = "192.168.0.0/24"
      description = <<EOT
      {
        "Description": {
          "zh-cn": "必須是所屬專用網路的子網段,並且沒有被其他交換器佔用。",
          "en": "Must be a sub-network segment of the proprietary network and is not occupied by other VSwitches."
        },
        "Label": {
          "zh-cn": "交換器網段",
          "en": "VSwitch CIDR Block"
        }
      }
      EOT
    } 
    variable "instance_type" {
      type			  = string
      description = <<EOT
      {
        "Label": {
          "zh-cn": "執行個體規格",
          "en": "Instance Type"
        },
        "AssociationProperty": "ALIYUN::ECS::Instance::InstanceType",
        "AssociationPropertyMetadata": {
          "InstanceChargeType": "$${pay_type}",
          "ZoneId": "$${zone_id}"
        }
      }
      EOT
    }
    variable "system_disk_category" {
      type			  = string
      description = <<EOT
      {
        "Description": {
          "en": "<font color='blue'><b>Optional values:</b></font><br>[cloud_efficiency: <font color='green'>Efficient Cloud Disk</font>]<br>[cloud_ssd: <font color='green'>SSD Cloud Disk</font>]<br>[cloud_essd: <font color='green'>ESSD Cloud Disk</font>]<br>[cloud: <font color='green'>Cloud Disk</font>]<br>[ephemeral_ssd: <font color='green'>Local SSD Cloud Disk</font>]",
          "zh-cn": "<font color='blue'><b>可選值:</b></font><br>[cloud_efficiency: <font color='green'>高效雲端硬碟</font>]<br>[cloud_ssd: <font color='green'>SSD雲端硬碟</font>]<br>[cloud_essd: <font color='green'>ESSD雲端硬碟</font>]<br>[cloud: <font color='green'>普通雲端硬碟</font>]<br>[ephemeral_ssd: <font color='green'>本地SSD盤</font>]"
        },
        "AssociationProperty": "ALIYUN::ECS::Disk::SystemDiskCategory",
        "AssociationPropertyMetadata": {
          "ZoneId": "$${zone_id}",
          "InstanceType": "$${instance_type}"
        },
        "Label": {
          "en": "System Disk Type",
          "zh-cn": "系統硬碟類型"
        }
      }
      EOT
    }
    variable "system_disk_size" {
      type			  = number
      default     = 40
      description = <<EOT
      {
        "Description": {
          "zh-cn": "系統硬碟大小,取值範圍:40~500,單位:GB。",
          "en": "System disk size, range of values: 40~500, units: GB."
        },
        "Label": {
          "zh-cn": "系統硬碟空間",
          "en": "System Disk Space"
        }
      }
      EOT
    }
    variable "data_disk_category" {
      type			  = string
      description = <<EOT
      {
        "Label": {
          "zh-cn": "資料盤類型",
          "en": "Data Disk Type"
        },
        "Description": {
          "zh-cn": "<font color='blue'><b>可選值:</b></font><br>[cloud_efficiency: <font color='green'>高效雲端硬碟</font>]<br>[cloud_ssd: <font color='green'>SSD雲端硬碟</font>]<br>[cloud_essd: <font color='green'>ESSD雲端硬碟</font>]<br>[cloud: <font color='green'>普通雲端硬碟</font>]",
          "en": "<font color='blue'><b>Optional values:</b></font><br>[cloud_efficiency: <font color='green'>Efficient Cloud Disk</font>]<br>[cloud_ssd: <font color='green'>SSD Cloud Disk</font>]<br>[cloud_essd: <font color='green'>ESSD Cloud Disk</font>]<br>[cloud: <font color='green'>Cloud Disk</font>]"
        },      
        "AssociationProperty": "ALIYUN::ECS::Disk::DataDiskCategory",
        "AssociationPropertyMetadata": {
          "ZoneId": "$${zone_id}",
          "InstanceType": "$${instance_type}"
        }
      }
      EOT
    }
    variable "data_disk_size" {
      type			  = number
      default     = 100
      description = <<EOT
      {
        "Description": {
          "zh-cn": "ECS執行個體資料盤大小,單位為GiB。取值範圍:20~32768。",
          "en": "ECS Instance disk size, range of values: 20~32768, units: GB."
        },
        "MaxValue": 32768,
        "MinValue": 20,
        "Label": {
          "zh-cn": "資料盤空間",
          "en": "Data Disk Space"
        }
      }
      EOT
    } 
    variable "instance_password" {
      type			  = string
      sensitive   = true
      description = <<EOT
      {
        "Description": {
          "en": "Server login password, Length 8~30, must contain three(Capital letters, lowercase letters, numbers, ()`~!@#$%^&*_-+=|{}[]:;<>,.?/ Special symbol in).",
          "zh-cn": "登入密碼,長度8~30,必須包含三項(大寫字母、小寫字母、數字、 ()`~!@#$%^&*_-+=|{}[]:;<>,.?/ 中的特殊符號)。"
        },
        "Label": {
          "en": "Instance Password",
          "zh-cn": "登入密碼"
        },
        "ConstraintDescription": {
          "en": "Length 8~30, must contain three(Capital letters, lowercase letters, numbers, ()`~!@#$%^&*_-+=|{}[]:;<>,.?/ Special symbol in).",
          "zh-cn": "長度8~30,必須包含三項(大寫字母、小寫字母、數字、 ()`~!@#$%^&*_-+=|{}[]:;<>,.?/ 中的特殊符號)。"
        },
        "AssociationProperty": "ALIYUN::ECS::Instance::Password",
        "AllowedPattern": "^[a-zA-Z0-9-\\(\\)\\`\\~\\!\\@\\#\\$\\%\\^\\&\\*\\_\\-\\+\\=\\|\\{\\}\\[\\]\\:\\;\\<\\>\\,\\.\\?\\/]*$",
        "MinLength": 8,
        "MaxLength": 30
      }
      EOT
    }
    # 預設資源名稱。
    locals {
      production_name						 = "nginx"
      new_scg_name							 = "sg-for-${local.production_name}"
      new_host_name							 = "app-for-${local.production_name}"
    }

    resource "alicloud_vpc" "vpc" {
      cidr_block								 = var.vpc_cidr_block
    }

    resource "alicloud_vswitch" "vsw" {
      vpc_id  								   = alicloud_vpc.vpc.id
      cidr_block								 = var.vswitch_cidr_block
      zone_id  								   = var.zone_id
    }

    # 安全性群組基本資料配置
    resource "alicloud_security_group" "security_group" {
      name      							   = local.new_scg_name
      description								 = "nginx scg"
      vpc_id										 =  alicloud_vpc.vpc.id
    }

    # 安全性群組入口端1
    resource "alicloud_security_group_rule" "allow_ssh" {
      security_group_id					 = alicloud_security_group.security_group.id
      type											 = "ingress"
      cidr_ip										 = "0.0.0.0/0"
      policy										 = "accept"
      ip_protocol								 = "tcp"
      port_range								 = "22/22"
      priority									 = 1
    }

    # 安全性群組入口端2
    resource "alicloud_security_group_rule" "allow_web" {
      security_group_id					 = alicloud_security_group.security_group.id
      type											 = "ingress"
      cidr_ip										 = "0.0.0.0/0"
      policy										 = "accept"
      ip_protocol								 = "tcp"
      port_range								 = "80/443"
      priority									 = 1
    }

    # 安全性群組出口端
    resource "alicloud_security_group_rule" "allow_egress" {
      security_group_id					 = alicloud_security_group.security_group.id
      type											 = "egress"
      cidr_ip										 = "0.0.0.0/0"
      policy										 = "accept"
      ip_protocol								 = "tcp"
      port_range								 = "1/65535"
      priority									 = 1
    }

    # 執行個體基本配置
    resource "alicloud_instance" "instance" {
      availability_zone					 = var.zone_id
      security_groups						 = [alicloud_security_group.security_group.id]
      # series III
      host_name									 = local.new_host_name
      instance_type              = var.instance_type
      system_disk_size           = var.system_disk_size
      system_disk_category       = var.system_disk_category
      image_id                   = "centos_7_9_x64_20G_alibase_20210318.vhd"
      vswitch_id                 = alicloud_vswitch.vsw.id
      password                   = var.instance_password
      internet_charge_type			 = "PayByTraffic"
      internet_max_bandwidth_out = 30
      instance_charge_type			 = var.pay_type
      period										 = var.pay_period
      period_unit								 = var.pay_period_unit
      user_data									 = file("${path.cwd}/user-data.sh")
      data_disks {
        size     							   = var.data_disk_size
        category						     = var.data_disk_category
      }
    }
    # 返回Nginx的IP地址
    output "nginx_ip" {
      value											 = "http://${alicloud_instance.instance.public_ip}:8080"
    }
  user-data.sh: |-
    #!/bin/bash -v
    # 掛盤到/disk1
    cat >> /root/InitDataDisk.sh << "EOF"
    #!/bin/bash
    echo "p
    n
    p
    w
    " |  fdisk -u /dev/vdb
    EOF
    /bin/bash /root/InitDataDisk.sh
    rm -f /root/InitDataDisk.sh
    mkfs -t ext4 /dev/vdb1
    cp /etc/fstab /etc/fstab.bak
    mkdir /disk1
    echo `blkid /dev/vdb1 | awk '{print $2}' | sed 's/\\\"//g'` /disk1 ext4 defaults 0 0 >> /etc/fstab
    mount -a
    # 這裡配置安裝指令碼
    yum install -y nginx
    # 配置啟動指令碼
    /usr/sbin/nginx