Resource Orchestration Service服務 ROS(Resource Orchestration Service)通過 Terraform 模板,一次性自動建立完整的雲網路基礎設施、ECS 雲端服務器,並在 ECS 上自動安裝和啟動 Nginx 服務。適用於需要快速、可重複地搭建 Web 服務器環境的情境。
方案概述
本方案通過阿里雲Resource Orchestration Service服務(ROS)執行 Terraform 模板,一次性自動建立完整的雲網路基礎設施與 ECS 雲端服務器,並在 ECS 上自動安裝並啟動 Nginx 服務。適用於需要快速、可重複地搭建 Web 服務器環境的情境。
業務情境
在阿里雲Virtual Private Cloud 中建立一台 ECS 執行個體,配置安全性群組開放 SSH(22 連接埠)和 HTTP/HTTPS(80/443 連接埠)訪問,掛載資料盤,並通過 user_data 初始化指令碼自動安裝和啟動 Nginx 服務。
建立的資源清單
序號 | 資源名稱 | Terraform 資源類型 | 用途說明 |
1 | Virtual Private Cloud |
| 提供隔離的網路環境 |
2 | 交換器 VSwitch |
| 在 VPC 中劃分子網網段,指定可用性區域 |
3 | 安全性群組 |
| 控制 ECS 的網路訪問規則 |
4 | 安全性群組規則(SSH) |
| 開放 22 連接埠入站訪問 |
5 | 安全性群組規則(Web) |
| 開放 80~443 連接埠入站訪問 |
6 | 安全性群組規則(出站) |
| 允許所有出站流量 |
7 | ECS 雲端服務器執行個體 |
| 運行 Nginx 的計算節點,含資料盤 |
部署完成後獲得的結果
模板成功執行後,可獲得:
一個完整的 VPC 網路環境(包含 VPC、交換器、安全性群組及規則)
一台 ECS 雲端服務器執行個體(帶 100 GB 資料盤,已指派公網 IP)
ECS 上已自動安裝並啟動 Nginx 服務
通過輸出的公網 IP 位址即可訪問 Nginx 預設頁面
架構圖

前提條件
在使用本模板前,請確認以下條件:
帳號許可權:阿里雲帳號需要具有 ECS、VPC 產品的建立許可權。
基礎知識:瞭解 Terraform 模板的基本文法和結構。更多資訊,請參見Terraform類型模板結構。
查看資源類型:可通過 Terraform Provider alicloud 資源索引 查看 Terraform 資源屬性詳情。每個屬性標註了
Optional(可選)或Required(必須)。
模板編寫教程
本教程分兩個階段示範 Terraform 模板編寫過程:
階段一(基礎版):使用固定參數值,專註於理解 Terraform 資源定義和依賴關係。
階段二(進階版):添加
AssociationProperty動態參數篩選、參數分組和參數約束,提升控制台體驗。
階段一:基礎模板——定義資源及其依賴關係
Step 1:定義基礎網路資源
基礎網路資源包括 alicloud_vpc、alicloud_vswitch 和 alicloud_security_group,是所有其他資源的基礎。Terraform 通過資源間屬性引用自動建立依賴關係。
# ============================================================
# 基礎網路層:VPC → VSwitch → SecurityGroup
# ============================================================
resource "alicloud_vpc" "vpc" {
cidr_block = "192.168.0.0/16" # VPC 位址區段,可容納 65534 個內網 IP
}
resource "alicloud_vswitch" "vsw" {
vpc_id = alicloud_vpc.vpc.id # 引用 VPC 的 ID,Terraform 自動建立依賴關係
cidr_block = "192.168.0.0/24" # 子網位址區段,必須是 VPC 網段的子集
zone_id = "cn-beijing-h" # 此情境以北京 H 可用性區域為樣本
}
resource "alicloud_security_group" "security_group" {
name = "sg-for-nginx" # 安全性群組名稱
vpc_id = alicloud_vpc.vpc.id # 安全性群組綁定到同一 VPC
}關鍵知識點:
隱式關聯 vs 顯式依賴關聯(
depends_on):alicloud_vswitch.vsw的vpc_id屬性引用了alicloud_vpc.vpc.id,Terraform 會自動識別這個依賴關係,確保先建立 VPC 再建立 VSwitch。當兩個資源之間沒有直接參考關聯性,但業務上要求先後順序時,才需要使用
depends_on(顯式關聯)。
Step 2:定義安全性群組規則
alicloud_security_group_rule 控制進出 ECS 的網路流量。本情境需要開放 SSH 遠端連線和 Web 存取連接埠。
# ============================================================
# 安全性群組規則:入站 SSH + 入站 Web + 出站全允許存取
# ============================================================
# 入站規則 1:開放 SSH 22 連接埠(用於遠端管理)
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" # 允許所有 IP 訪問(生產環境建議限制 IP 範圍)
policy = "accept" # 允許存取策略
ip_protocol = "tcp" # TCP 協議
port_range = "22/22" # 連接埠範圍:僅 22 連接埠
priority = 1 # 優先順序:1(最高)
}
# 入站規則 2:開放 Web 連接埠 80~443(HTTP/HTTPS 訪問 Nginx)
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" # 連接埠範圍:80 到 443
priority = 1
}
# 出站規則:允許所有出站流量(ECS 可訪問外部網路,如 yum 源)
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
}關鍵知識點:
Terraform 中連接埠範圍格式為
"開始端點口/結束連接埠",如"80/443"表示 80 到 443 的所有連接埠;單個連接埠寫法為"22/22"。生產環境建議將 SSH 的
cidr_ip限制為辦公 IP,避免被惡意掃描。如需開放其他連接埠(如 8080),可新增一條
alicloud_security_group_rule資源。
Step 3:定義 ECS 執行個體與初始化指令碼
alicloud_instance 是運行 Nginx 的計算節點。通過 user_data 屬性指定初次開機時執行的初始化指令碼。
user_data 初始化指令碼(user-data.sh):
#!/bin/bash -v
# ---- 資料盤格式化與掛載 ----
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
# ---- 安裝並啟動 Nginx ----
yum install -y nginx
/usr/sbin/nginxECS 執行個體資源定義:
# ============================================================
# 計算層:ECS 執行個體(含資料盤 + Nginx 初始化)
# ============================================================
resource "alicloud_instance" "instance" {
availability_zone = "cn-beijing-h"
security_groups = [alicloud_security_group.security_group.id] # 數組格式綁定安全性群組
host_name = "app-for-nginx"
instance_type = "ecs.c6e.large" # 執行個體規格(計算增強型,2vCPU 4GiB)
system_disk_size = 100 # 系統硬碟大小
system_disk_category = "cloud_essd" # 系統硬碟類型
image_id = "centos_7_9_x64_20G_alibase_20210318.vhd" # CentOS 7.9 鏡像
vswitch_id = alicloud_vswitch.vsw.id # 綁定到交換器
password = "<YourPassword>" # 部署時請替換為實際密碼(需含大小寫字母 + 數字 + 特殊字元)
internet_charge_type = "PayByTraffic" # 公網按流量計費
internet_max_bandwidth_out = 30 # 公網出頻寬 30 Mbps
instance_charge_type = "PostPaid" # 付費類型(按量 / 訂用帳戶)
user_data = file("${path.cwd}/user-data.sh") # 載入初始化指令碼
data_disks { # 掛載資料盤配置
size = 100 # 資料盤大小
category = "cloud_essd" # 資料盤類型
}
}
# 輸出 Nginx 訪問地址
output "nginx_ip" {
value = "http://${alicloud_instance.instance.public_ip}:80"
}關鍵知識點:Terraform 變數引用方式
引用方式 | 文法 | 說明 |
變數引用 |
| 擷取 |
資源屬性引用 |
| 擷取其他資源的輸出屬性(如 |
檔案載入 |
| 載入當前工作目錄下的檔案內容 |
模板擴充與變體:
user_data通過file()函數載入外部指令檔,便於維護和複用。internet_max_bandwidth_out = 30設定了 30 Mbps 出頻寬,ECS 自動獲得公網 IP。data_disks塊可添加多個資料盤,也可省略不掛載資料盤。模板建立完資源後,可以通過模板的
output資訊直接查詢對應資源內部屬性資訊,因此可以通過定義output內容輸出 ECS 公網訪問地址(Nginx 服務訪問地址)。
基礎版完整模板
Terraform 模板結構如下所示。
main.tf 檔案內容:
resource "alicloud_vpc" "vpc" {
cidr_block = "192.168.0.0/16"
}
resource "alicloud_vswitch" "vsw" {
vpc_id = alicloud_vpc.vpc.id
cidr_block = "192.168.0.0/24"
zone_id = "cn-beijing-h"
}
# 安全性群組基本資料配置
resource "alicloud_security_group" "security_group" {
name = "sg-for-nginx"
description = "nginx scg"
vpc_id = alicloud_vpc.vpc.id
}
# 安全性群組入口端 1:SSH
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:Web
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 = "cn-beijing-h"
security_groups = [alicloud_security_group.security_group.id]
host_name = "app-for-nginx"
instance_type = "ecs.c6e.large"
system_disk_size = 100
system_disk_category = "cloud_essd"
image_id = "centos_7_9_x64_20G_alibase_20210318.vhd"
vswitch_id = alicloud_vswitch.vsw.id
password = "<YourPassword>" # 部署時請替換為實際密碼
internet_charge_type = "PayByTraffic"
internet_max_bandwidth_out = 30
instance_charge_type = "PostPaid"
user_data = file("${path.cwd}/user-data.sh")
data_disks {
size = 100
category = "cloud_essd"
}
}
# 返回 Nginx 的訪問地址
output "nginx_ip" {
value = "http://${alicloud_instance.instance.public_ip}:80"
}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
# 安裝 Nginx
yum install -y nginx
# 啟動 Nginx
/usr/sbin/nginx以下是將上述三個步驟合并後的完整可用模板。使用 ROS 部署 Terraform 模板時,需要將其封裝為 ROS Workspace 格式。
完整 ROS Workspace 格式模板:
ROSTemplateFormatVersion: '2015-09-01'
Transform: Aliyun::Terraform-v1.2
Workspace:
main.tf: |-
resource "alicloud_vpc" "vpc" {
cidr_block = "192.168.0.0/16"
}
resource "alicloud_vswitch" "vsw" {
vpc_id = alicloud_vpc.vpc.id
cidr_block = "192.168.0.0/24"
zone_id = "cn-beijing-h"
}
# 安全性群組基本資料配置
resource "alicloud_security_group" "security_group" {
name = "sg-for-nginx"
description = "nginx scg"
vpc_id = alicloud_vpc.vpc.id
}
# 安全性群組入口端 1:SSH
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:Web
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 = "cn-beijing-h"
security_groups = [alicloud_security_group.security_group.id]
host_name = "app-for-nginx"
instance_type = "ecs.c6e.large"
system_disk_size = 100
system_disk_category = "cloud_essd"
image_id = "centos_7_9_x64_20G_alibase_20210318.vhd"
vswitch_id = alicloud_vswitch.vsw.id
password = "<YourPassword>"
internet_charge_type = "PayByTraffic"
internet_max_bandwidth_out = 30
instance_charge_type = "PostPaid"
user_data = file("${path.cwd}/user-data.sh")
data_disks {
size = 100
category = "cloud_essd"
}
}
# 返回 Nginx 的訪問地址
output "nginx_ip" {
value = "http://${alicloud_instance.instance.public_ip}:80"
}
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
# 安裝 Nginx
yum install -y nginx
# 啟動 Nginx
/usr/sbin/nginx階段二:進階模板——參數化與動態配置
基礎版模板中未定義 variable 和 variable 支援的 description、default 等動態篩選配置。在 ROS 控制台使用此模板時,參數之間缺乏聯動,可能選擇到無效的組合(如在某可用性區域選擇了沒有庫存的執行個體規格)。
通過以下最佳化,可以大幅提高控制台使用體驗和模板複用性:
動態參數篩選(AssociationProperty):在
variable的description中配置 JSON 格式的AssociationProperty,讓控制台自動過濾可用選項。條件顯示(
Visible.Condition):按付費類型動態顯示 / 隱藏購買時間長度參數。參數分組(.metadata 檔案):通過 .metadata 檔案配置 ParameterGroups,控制台按邏輯分組展示。
參數約束(參數約束查詢):在 .metadata 中定義資源約束,確保參數組合有效。
參數依賴關係圖
pay_type(付費類型)
├── pay_period_unit(周期單位,僅 PrePaid 時顯示)
└── pay_period(購買時間長度,僅 PrePaid 時顯示)
zone_id(可用性區域,核心過濾參數)
├── instance_type(執行個體規格,按可用性區域 + 付費類型過濾)
│ ├── system_disk_category(系統硬碟類型,按可用性區域 + 執行個體規格過濾)
│ └── data_disk_category(資料盤類型,按可用性區域 + 執行個體規格過濾)核心思路:先選可用性區域和 ECS 付費類型,再據此篩選 ECS 規格(當選擇預付費類型時需要選擇付費周期和購買時間長度),最後根據可用性區域 + ECS 規格篩選磁碟類型。每一步都只展示當前條件下可用的選項,避免無效組合。
參數 AssociationProperty 原理詳解
1. zone_id — 可用性區域(基礎參數)
定義 AssociationProperty 為 ALIYUN::ECS::ZoneId 列出當前地區下所有可用性區域。樣本:
variable "zone_id" {
type = string
description = <<EOT
{
# AssociationProperty 指定參數關聯的資源屬性類型
# ROS 控制台會根據此配置自動列出可選值
"AssociationProperty": "ALIYUN::ECS::ZoneId",
"Label": {
"zh-cn": "交換器可用性區域",
"en": "VSwitch Availability Zone"
},
"Description": {
"zh-cn": "選擇可用性區域,後續參數會根據此可用性區域自動過濾",
"en": "Select availability zone for resource filtering"
}
}
EOT
}此參數是後續所有參數的篩選基礎,選擇後其他參數的選項列表會隨之更新。
2. pay_type — ECS 付費類型
定義 pay_type 參數,使用 AssociationPropertyMetadata.Visible.Condition 實現參數的條件動態切換——當選擇"訂用帳戶(PrePaid)"時才顯示購買時間長度相關參數。樣本:
variable "pay_type" {
type = string
default = "PostPaid"
description = <<EOT
{
"Label": { "en": "ECS Instance Charge Type", "zh-cn": "付費類型" },
"AllowedValues": ["PostPaid", "PrePaid"],
"AssociationProperty": "ChargeType"
}
EOT
}
variable "pay_period_unit" {
type = string
default = "Month"
description = <<EOT
{
"Label": { "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::Not": { "Fn::Equals": ["$${pay_type}", "PostPaid"] }
}
}
}
}
EOT
}在 ROS 控制台選擇"隨用隨付(PostPaid)"時,購買時間長度相關參數自動隱藏;選擇"訂用帳戶(PrePaid)"時才顯示這些參數。
3. instance_type — ECS 執行個體規格
定義 AssociationProperty 為 ALIYUN::ECS::Instance::InstanceType 列出可用的 ECS 執行個體規格,並通過關聯 ${zone_id} 和 ${pay_type} 篩選對應可用性區域下對應付費類型支援的可用執行個體規格。樣本:
variable "instance_type" {
type = string
description = <<EOT
{
"Label": { "zh-cn": "執行個體規格", "en": "Instance Type" },
"AssociationProperty": "ALIYUN::ECS::Instance::InstanceType",
"AssociationPropertyMetadata": {
"ZoneId": "$${zone_id}",
"InstanceChargeType": "$${pay_type}"
}
}
EOT
}不同可用性區域的執行個體規格庫存不同。如果不過濾,可能選到該可用性區域無貨的規格,導致建立失敗。
4. system_disk_category — 系統硬碟類型
定義 AssociationProperty 為 ALIYUN::ECS::Disk::SystemDiskCategory 列出可選的系統硬碟類型,並通過關聯 ${zone_id} 和 ${instance_type} 篩選對應可用性區域與 ECS 執行個體規格支援使用的 ECS 系統硬碟類型。樣本:
variable "system_disk_category" {
type = string
description = <<EOT
{
"Label": { "zh-cn": "系統硬碟類型", "en": "System Disk Type" },
"Description": {
"zh-cn": "可選值:cloud_efficiency(高效雲端硬碟)、cloud_ssd(SSD 雲端硬碟)、cloud_essd(ESSD 雲端硬碟)",
"en": "Options: cloud_efficiency, cloud_ssd, cloud_essd"
},
"AssociationProperty": "ALIYUN::ECS::Disk::SystemDiskCategory",
"AssociationPropertyMetadata": {
"ZoneId": "$${zone_id}",
"InstanceType": "$${instance_type}"
}
}
EOT
}系統硬碟類型的可用性同時取決於可用性區域(某些可用性區域不支援 ESSD)和執行個體規格(某些規格僅支援特定磁碟類型)。
5. data_disk_category — 資料盤類型
定義 AssociationProperty 為 ALIYUN::ECS::Disk::DataDiskCategory 列出可選的資料盤類型。過濾原理與系統硬碟類型完全一致,同樣通過關聯 ${zone_id} 和 ${instance_type} 篩選當前可用性區域與執行個體規格共同支援的資料盤類型。樣本:
variable "data_disk_category" {
type = string
description = <<EOT
{
"Label": { "zh-cn": "資料盤類型", "en": "Data Disk Type" },
"Description": {
"zh-cn": "可選值:cloud_efficiency(高效雲端硬碟)、cloud_ssd(SSD 雲端硬碟)、cloud_essd(ESSD 雲端硬碟)",
"en": "Options: cloud_efficiency, cloud_ssd, cloud_essd"
},
"AssociationProperty": "ALIYUN::ECS::Disk::DataDiskCategory",
"AssociationPropertyMetadata": {
"ZoneId": "$${zone_id}",
"InstanceType": "$${instance_type}"
}
}
EOT
}動態參數篩選模板樣本
variable "zone_id" {
type = string
description = <<EOT
{
"AssociationProperty": "ALIYUN::ECS::ZoneId",
"Label": {
"zh-cn": "交換器可用性區域",
"en": "VSwitch Availability Zone"
},
"Description": {
"zh-cn": "選擇可用性區域,後續參數會根據此可用性區域自動過濾",
"en": "Select availability zone for resource filtering"
}
}
EOT
}
variable "pay_type" {
type = string
default = "PostPaid"
description = <<EOT
{
"Label": { "en": "ECS Instance Charge Type", "zh-cn": "付費類型" },
"AllowedValues": ["PostPaid", "PrePaid"],
"AssociationProperty": "ChargeType"
}
EOT
}
variable "pay_period_unit" {
type = string
default = "Month"
description = <<EOT
{
"Label": { "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::Not": { "Fn::Equals": ["$${pay_type}", "PostPaid"] }
}
}
}
}
EOT
}
variable "instance_type" {
type = string
description = <<EOT
{
"Label": { "zh-cn": "執行個體規格", "en": "Instance Type" },
"AssociationProperty": "ALIYUN::ECS::Instance::InstanceType",
"AssociationPropertyMetadata": {
"ZoneId": "$${zone_id}",
"InstanceChargeType": "$${pay_type}"
}
}
EOT
}
variable "system_disk_category" {
type = string
description = <<EOT
{
"Label": { "zh-cn": "系統硬碟類型", "en": "System Disk Type" },
"Description": {
"zh-cn": "可選值:cloud_efficiency(高效雲端硬碟)、cloud_ssd(SSD 雲端硬碟)、cloud_essd(ESSD 雲端硬碟)",
"en": "Options: cloud_efficiency, cloud_ssd, cloud_essd"
},
"AssociationProperty": "ALIYUN::ECS::Disk::SystemDiskCategory",
"AssociationPropertyMetadata": {
"ZoneId": "$${zone_id}",
"InstanceType": "$${instance_type}"
}
}
EOT
}
variable "data_disk_category" {
type = string
description = <<EOT
{
"Label": { "zh-cn": "資料盤類型", "en": "Data Disk Type" },
"Description": {
"zh-cn": "可選值:cloud_efficiency(高效雲端硬碟)、cloud_ssd(SSD 雲端硬碟)、cloud_essd(ESSD 雲端硬碟)",
"en": "Options: cloud_efficiency, cloud_ssd, cloud_essd"
},
"AssociationProperty": "ALIYUN::ECS::Disk::DataDiskCategory",
"AssociationPropertyMetadata": {
"ZoneId": "$${zone_id}",
"InstanceType": "$${instance_type}"
}
}
EOT
}參數 AssociationProperty 工作原理總結
在 ROS 控制台建立資源棧時,參數的選擇過程是級聯觸發的:
選擇可用性區域(
zone_id)。選擇 ECS 付費類型(
pay_type)。ECS 執行個體規格下拉框自動重新整理,僅顯示該可用性區域下所支援對應付費類型且具備庫存的規格。
選擇 ECS 執行個體規格後,系統硬碟類型和資料盤類型下拉框自動重新整理,僅顯示該可用性區域 + 該規格共同支援的磁碟類型。
這樣,每一步選擇都只展示當前條件下可用的選項,從源頭避免因參數組合無效導致的部署失敗。
Metadata 參數分組
通過 Metadata 中的 ALIYUN::ROS::Interface 配置,可以將參數按邏輯分成多個組,每組帶一個標題,控制台上會分組展示,填寫體驗大幅提升。
Metadata 文法結構
在 Terraform 標籤下建立 .metadata 檔案,配置參數分組(ParameterGroups)和參數約束(參數約束查詢):
{
"ALIYUN::ROS::Interface": {
"ResourcesForParameterConstraints": {
"resource": {
"Type": "ALIYUN::ECS::Instance",
"Properties": {
}
}
},
"ParameterGroups": [
{
"Parameters": ["參數名 1", "參數名 2", "參數名 3"],
"Label": { "default": { "zh-cn": "XXXX 配置", "en": "Configuration" } }
}
]
}
}Metadata 文法規則:
Parameters、Label都是必填項。Parameters中列出的參數名必須與variable參數名完全一致。未出現在任何分組中的參數,會在控制台顯示在未分組地區。
本情境的分組設計
本模板將 12 個參數按資源類型分成 3 個組:
┌─────────────────────────────────────────────┐
│ 基礎網路設定 │
│ ├── 交換器可用性區域 (zone_id) │
│ ├── VPC 網段 (vpc_cidr_block) │
│ └── 交換器網段 (vswitch_cidr_block) │
├─────────────────────────────────────────────┤
│ 付費模式配置 │
│ ├── ECS 執行個體付費類型 (pay_type) │
│ ├── ECS 預付費購買資源周期 (pay_period_unit) │
│ └── ECS 預付費購買資源時間長度 (pay_period) │
├─────────────────────────────────────────────┤
│ ECS 執行個體配置 │
│ ├── ECS 執行個體規格 (instance_type) │
│ ├── 系統硬碟類型 (system_disk_category) │
│ ├── 系統硬碟大小 (system_disk_size) │
│ ├── 資料盤類型 (data_disk_category) │
│ ├── 資料盤大小 (data_disk_size) │
│ └── ECS 執行個體密碼 (instance_password) │
└─────────────────────────────────────────────┘.metadata 檔案配置
在 Terraform 標籤下建立 .metadata 檔案,配置參數分組和參數約束:
{
"ALIYUN::ROS::Interface": {
"ResourcesForParameterConstraints": {
"instance": {
"Type": "ALIYUN::ECS::Instance",
"Properties": {
"InstanceType": { "Ref": "instance_type" },
"ImageId": "centos_7_9_x64_20G_alibase_20210318.vhd",
"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": ["vpc_cidr_block", "zone_id", "vswitch_cidr_block"],
"Label": { "default": { "zh-cn": "基礎網路設定", "en": "Network Configuration" } }
},
{
"Parameters": ["pay_type", "pay_period_unit", "pay_period"],
"Label": { "default": { "zh-cn": "付費模式配置", "en": "Payment Configuration" } }
},
{
"Parameters": ["instance_type", "system_disk_category", "system_disk_size", "data_disk_category", "data_disk_size", "instance_password"],
"Label": { "default": { "zh-cn": "ECS 執行個體配置", "en": "ECS Instance Configuration" } }
}
]
}
}關鍵知識點:
定義了一個虛擬
ALIYUN::ECS::Instance資源,將模板中的參數與 ECS 資源屬性關聯。ROS 控制台據此驗證參數組合的有效性(如指定可用性區域是否支援所選執行個體規格 + 磁碟類型)。
Ref文法引用 Terraform variable 名稱(不帶var.首碼)。
進階版完整模板
以下是封裝為 ROS Workspace 格式的完整進階版模板,可直接在 ROS 控制台部署:
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",
"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": ["vpc_cidr_block", "zone_id", "vswitch_cidr_block"],
"Label": { "default": { "zh-cn": "基礎網路設定", "en": "Network Configuration" } }
},
{
"Parameters": ["pay_type", "pay_period_unit", "pay_period"],
"Label": { "default": { "zh-cn": "付費模式配置", "en": "Payment Configuration" } }
},
{
"Parameters": ["instance_type", "system_disk_category", "system_disk_size", "data_disk_category", "data_disk_size", "instance_password"],
"Label": { "default": { "zh-cn": "ECS 執行個體配置", "en": "ECS Instance Configuration" } }
}
]
}
}
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::Not": { "Fn::Equals": ["$${pay_type}", "PostPaid"] }
}
}
}
}
EOT
}
variable "zone_id" {
type = string
description = <<EOT
{
"AssociationProperty": "ALIYUN::ECS::ZoneId",
"Label": { "zh-cn": "交換器可用性區域", "en": "VSwitch Availability Zone" },
"Description": {
"zh-cn": "選擇可用性區域,後續 ECS 執行個體規格和磁碟類型將根據此可用性區域自動過濾可用選項",
"en": "Select availability zone. Instance types and disk categories will be filtered accordingly."
}
}
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": "建立 VPC 的 IP 位址段範圍。推薦使用 10.0.0.0/8、172.16.0.0/12 或 192.168.0.0/16",
"en": "VPC IP range. Recommended: 10.0.0.0/8, 172.16.0.0/12, or 192.168.0.0/16"
}
}
EOT
}
variable "vswitch_cidr_block" {
type = string
default = "192.168.0.0/24"
description = <<EOT
{
"Label": { "zh-cn": "交換器網段", "en": "VSwitch CIDR Block" },
"Description": {
"zh-cn": "必須是 VPC 網段的子網段,且不能與同 VPC 下其他交換器網段重疊",
"en": "Must be a subnet of VPC CIDR and not overlap with other VSwitches"
}
}
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
{
"Label": { "zh-cn": "系統硬碟類型", "en": "System Disk Type" },
"Description": {
"zh-cn": "可選值:cloud_efficiency(高效雲端硬碟)、cloud_ssd(SSD 雲端硬碟)、cloud_essd(ESSD 雲端硬碟)",
"en": "Options: cloud_efficiency, cloud_ssd, cloud_essd"
},
"AssociationProperty": "ALIYUN::ECS::Disk::SystemDiskCategory",
"AssociationPropertyMetadata": {
"ZoneId": "$${zone_id}",
"InstanceType": "$${instance_type}"
}
}
EOT
}
variable "system_disk_size" {
type = number
default = 40
description = <<EOT
{
"Label": { "zh-cn": "系統硬碟空間", "en": "System Disk Size" },
"Description": {
"zh-cn": "系統硬碟大小,取值範圍:40~500,單位:GB",
"en": "System disk size, range: 40~500 GB"
}
}
EOT
}
variable "data_disk_category" {
type = string
description = <<EOT
{
"Label": { "zh-cn": "資料盤類型", "en": "Data Disk Type" },
"Description": {
"zh-cn": "可選值:cloud_efficiency(高效雲端硬碟)、cloud_ssd(SSD 雲端硬碟)、cloud_essd(ESSD 雲端硬碟)",
"en": "Options: cloud_efficiency, cloud_ssd, cloud_essd"
},
"AssociationProperty": "ALIYUN::ECS::Disk::DataDiskCategory",
"AssociationPropertyMetadata": {
"ZoneId": "$${zone_id}",
"InstanceType": "$${instance_type}"
}
}
EOT
}
variable "data_disk_size" {
type = number
default = 100
description = <<EOT
{
"Label": { "zh-cn": "資料盤空間", "en": "Data Disk Space" },
"Description": {
"zh-cn": "ECS 執行個體資料盤大小,取值範圍:20~32768,單位:GiB",
"en": "ECS data disk size, range: 20~32768 GiB"
},
"MaxValue": 32768,
"MinValue": 20
}
EOT
}
variable "instance_password" {
type = string
sensitive = true
description = <<EOT
{
"Label": { "zh-cn": "登入密碼", "en": "Instance Password" },
"Description": {
"zh-cn": "長度 8~30,必須包含大寫字母、小寫字母、數字、特殊符號中的至少三種",
"en": "Length 8-30, must contain at least 3 of: uppercase, lowercase, digits, special characters"
},
"AssociationProperty": "ALIYUN::ECS::Instance::Password",
"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
}
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
}
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]
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
}
}
output "nginx_ip" {
value = "http://${alicloud_instance.instance.public_ip}:80"
}
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
# 安裝 Nginx
yum install -y nginx
# 啟動 Nginx
/usr/sbin/nginxTerraform 模板文法速查
文法 | 樣本 | 本模板中的用途 |
|
| 引用 variable 定義的輸入參數值 |
|
| 引用 locals 塊定義的本地變數 |
|
| 引用其他資源的輸出屬性,自動建立依賴 |
|
| 載入外部檔案內容作為屬性值 |
|
| 字串插值,在字串中嵌入變數值 |
|
| 多行字串,用於嵌入 JSON 配置 |
|
| 在 description 的 JSON 中引用其他 variable 的當前值 |
部署環節
部署參數
必需輸入參數(部署時需填寫)
參數名 | 類型 | 說明 | 約束 |
| String | 交換器可用性區域 | 控制台動態選擇 |
| String | ECS 執行個體規格 | 根據可用性區域自動過濾 |
| String | 系統硬碟類型 | 根據可用性區域 + 規格自動過濾 |
| String | 資料盤類型 | 根據可用性區域 + 規格自動過濾 |
| String | ECS 登入密碼 | 長度 8~30,含大小寫 + 數字 + 特殊字元 |
可選配置參數(有預設值,可不填)
參數名 | 預設值 | 說明 |
|
| 付費類型( |
| Month | 購買時間長度單位(僅 |
| 1 | 購買時間長度(僅 |
| 192.168.0.0/16 | VPC 網段位址範圍 |
| 192.168.0.0/24 | 交換器子網網段 |
| 40 | 系統硬碟大小(GB),範圍 40~500 |
| 100 | 資料盤大小(GiB),範圍 20~32768 |
部署方式
方式一:通過 ROS 控制台部署
在左側導覽列選擇模板 > 我的模板 > 建立模板。
在模板類型下選擇 Terraform模板。
建立
main.tf檔案,粘貼進階版模板中的 main.tf 內容。建立
user-data.sh檔案,粘貼 user-data.sh 指令碼內容。建立
.metadata檔案,粘貼 .metadata 的 JSON 配置。儲存模板後,前往 資源棧 > 建立資源棧 > 選擇已有模板 > 我的模板,選擇該模板。
按參數分組填寫配置參數,確認後單擊 建立。
等待資源棧狀態變為
CREATE_COMPLETE,在 輸出 頁簽查看 Nginx 訪問地址。
方式二:通過 ROS IaC Code 部署
IaC Code 是面向雲基礎設施的 AI 基礎設施即代碼助手,通過自然語言提示詞產生、部署和管理基礎設施模板。架構設計面向多雲工作流程。以下為本方案的參考提示詞:
# Prompt
幫我用 Terraform 模板建立一台 ECS 並部署 Nginx 服務。
要求:
1. 建立 VPC 和 VSwitch 作為基礎網路。
2. 安全性群組開放入方向 22 連接埠(SSH)和 80~443 連接埠(Web 存取)。
3. ECS 需要分配公網 IP,出頻寬 30 Mbps。
4. 掛載一塊 100 GB 資料盤,格式化並掛載到 /disk1。
5. 通過 user_data 指令碼自動安裝並啟動 Nginx。
6. zone_id、instance_type、system_disk_category、data_disk_category 都需要配置 AssociationProperty 動態篩選。
7. 付費型別參數需要配置條件顯示(訂用帳戶時才顯示購買時間長度)。常見問題
Q1:部署失敗,報錯 "The specified InstanceType is not available in the zone"
原因:所選 ECS 執行個體規格在指定可用性區域中沒有庫存。
解決方案:
在進階版模板中,
AssociationProperty配合ResourcesForParameterConstraints會自動過濾可用規格,避免此問題。如使用基礎版模板,請在Elastic Compute Service定價確認目標可用性區域的規格庫存。
Q2:ECS 建立成功但無法訪問 Nginx 頁面
排查步驟:
確認安全性群組規則是否已開放 80 連接埠入站訪問(檢查
allow_web規則)。登入 ECS 執行個體,執行
systemctl status nginx確認 Nginx 是否正常運行。檢查
user_data指令碼是否執行成功:查看cat /var/log/messages | grep cloud-init。確認 ECS 有公網 IP(
internet_max_bandwidth_out > 0時自動分配)。
Q3:user_data 指令碼執行失敗,資料盤未掛載
原因:可能是鏡像不相容或資料盤裝置名稱不匹配。
解決方案:
user_data指令碼中使用的/dev/vdb是資料盤的預設裝置名,確保模板中配置了data_disks塊。如使用非 CentOS 鏡像,可能需要調整分區命令(如使用
parted替代fdisk)。若不需要資料盤,可移除
data_disks塊和user_data中的掛盤指令碼部分。
Q4:Terraform 模板如何轉換為 ROS 模板?
方式一:控制台轉換
操作步驟:
在 ROS 控制台選擇 模板 > 我的模板 > 創建模板。
先在 Terraform模板 標籤下編寫完模板。
切換到 ROS模板 標籤,並在右上方選擇 YAML,系統自動將 Terraform 模板轉換為如下格式:
ROSTemplateFormatVersion: '2015-09-01'
Transform: Aliyun::Terraform-v1.2
Workspace:
.metadata: |-
{ ... } # 參數分組和約束配置
main.tf: |-
... # Terraform 模板內容
user-data.sh: |-
... # 初始化指令碼內容方式二:使用模板轉換工具
執行轉換命令:
rostran transform templates/terraform/alicloud/main.tf --target-format jsonQ5:如何改為部署其他 Web 服務(如 Apache、Tomcat)?
改造要點:
修改 user-data.sh 中的安裝和啟動命令:
Apache:
yum install -y httpd && systemctl start httpdTomcat:安裝 JDK 後下載 Tomcat 並啟動。
調整安全性群組規則的連接埠範圍(如 Tomcat 預設 8080 連接埠)。
修改 output 輸出中的連接埠號碼。
Q6:如何使用已有 VPC 而非建立?
方案:將 VPC 和 VSwitch 改為從已有資源中選擇:
variable "vpc_id" {
type = string
description = <<EOT
{
"Label": { "zh-cn": "已有 VPC" },
"AssociationProperty": "ALIYUN::ECS::VPC::VPCId"
}
EOT
}
variable "vswitch_id" {
type = string
description = <<EOT
{
"Label": { "zh-cn": "已有交換器" },
"AssociationProperty": "ALIYUN::VPC::VSwitch::VSwitchId",
"AssociationPropertyMetadata": {
"VpcId": "$${vpc_id}"
}
}
EOT
}然後將 alicloud_instance 中的 vswitch_id 改為 var.vswitch_id,並刪除 alicloud_vpc 和 alicloud_vswitch 資源塊。
想要瞭解更多資源部署問題,可以查詢 常見問題。