This guide demonstrates how to write a Terraform template to deploy NGINX on a single ECS instance, starting with a basic configuration and evolving it into an advanced, reusable template.
Prerequisites
Familiarize yourself with the template syntax and structure. For more information, see Quick Start.
Example scenario
Create an ECS instance in a VPC and deploy NGINX on the instance.

Usage notes
View the property details for each resource type. For more information, see View resource types.
The documentation for each resource type specifies whether properties are Required or Optional. You must declare all Required properties in your template's resource definition.
Author the template
You can find the required resource types in the Resource type index.
This scenario involves creating a VPC (alicloud_vpc), an ECS instance (alicloud_instance), a VSwitch (alicloud_vswitch), a security group (alicloud_security_group), and a security group rule (alicloud_security_group_rule). NGINX is installed when the ECS instance is created.
Define resources and dependencies
Define basic network resources
You can define the following basic network resources in the template: vpc, vsw, and security_group.
-
Use
alicloud_vpc.vpc.idto get the output ID of thealicloud_vpcresource. -
Use
var.***to access custom variables, that is, the values of parameters in avariableblock. For example,var.zone_idaccesses the value ofzone_idin thevariableblock.
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
}
Define security group rules
Define the security group rules allow_ssh, allow_web, and allow_egress.
Use alicloud_security_group.security_group.id to get the ID of the security_group resource.
# Allow SSH ingress
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
}
# Allow web ingress
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
}
# Allow all egress traffic
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
}
Define the ECS instance
Define the ECS instance in the template.
-
Use
var.***to retrieve custom variables, that is, the parameter values invariable. For example,var.instance_typeretrieves the value ofinstance_typefromvariable. -
Use
local.***to retrieve a local variable, which is the value of a parameter inlocals. For example,local.new_host_nameretrieves the value ofnew_host_nameinlocals. -
Use
${path.cwd}in theuser_dataargument to get the current working directory. -
The
user-data.shfile is an initialization script that runs on the ECS instance at boot. The script's content is as follows:
#!/bin/bash -v
# Mount the data disk to /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
# Configure the installation script.
yum install -y nginx
# Configure the startup script.
/usr/sbin/nginx
The following code defines the ECS instance.
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"
}
}
Complete template example
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
}
# Define default resource names.
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
}
# Configure basic information for the security group.
resource "alicloud_security_group" "security_group" {
name = local.new_scg_name
description = "nginx scg"
vpc_id = alicloud_vpc.vpc.id
}
# Allow SSH ingress.
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
}
# Allow web ingress.
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
}
# Allow all egress traffic.
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
}
# Configure basic settings for the instance.
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
}
}
# Output the IP address of the NGINX server.
output "nginx_ip" {
value = "http://${alicloud_instance.instance.public_ip}"
}
Convert the Terraform template
You can convert a Terraform template to a ROS template in the ROS console to use features like parameter grouping and dynamic lookups.
-
Log on to the ROS console.
-
In the navigation pane on the left, choose Templates > My Templates.
-
On the My Templates page, click Create Template.
-
Under Template Type, select Terraform.
-
Edit the Terraform template.
-
Create a
main.tffile and add the content from the complete template example. -
Create a
user-data.shfile and add the content of the initialization script.
-
-
Under Template Type, select ROS to convert the Terraform template into a ROS template. The following code provides an example of the converted ROS template.
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 } # Define default resource names. 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 } # Configure basic information for the security group. resource "alicloud_security_group" "security_group" { name = local.new_scg_name description = "nginx scg" vpc_id = alicloud_vpc.vpc.id } # Allow SSH ingress. 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 } # Allow web ingress. 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 } # Allow all egress traffic. 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 } # Configure basic settings for the instance. 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 = "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 = var.data_disk_size category = "cloud_essd" } } # Output the IP address of the NGINX server. output "nginx_ip" { value = "http://${alicloud_instance.instance.public_ip}" } user-data.sh: |- #!/bin/bash -v # Mount the data disk to /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 # Configure the installation script. yum install -y nginx # Configure the startup script. /usr/sbin/nginx
Group parameters and add dynamic configurations
This template hardcodes some property values, such as system_disk_category. As a result, you must modify the template for deployments with different settings or in different regions.
To make the template more flexible and reusable, you can add parameters.
Group template parameters
You can use Metadata to group parameters and define labels for the parameter groups that appear in the console. For more information, see Metadata.
You can group parameters based on their corresponding resources. For this example, you can divide the resources as shown in the following table.
|
Parameter group |
Resource name |
Parameter |
|
Basic network configuration |
|
|
|
ECS instance configuration |
|
|
Under the Terraform tab, create a new .metadata file and enter the following content.
{
"ALIYUN::ROS::Interface": {
"ParameterGroups": [
{
"Parameters": [
"pay_type",
"pay_period_unit",
"pay_period"
],
"Label": {
"default": {
"en": "Payment mode"
}
}
},
{
"Parameters": [
"zone_id"
],
"Label": {
"default": {
"en": "Zone"
}
}
},
{
"Parameters": [
"vpc_cidr_block",
"vswitch_cidr_block"
],
"Label": {
"default": {
"en": "Existing infrastructure"
}
}
},
{
"Parameters": [
"instance_type",
"system_disk_category",
"system_disk_size",
"data_disk_category",
"data_disk_size",
"instance_password"
],
"Label": {
"default": {
"en": "Instance configuration"
}
}
}
]
}
}
Dynamically configure parameters
Take the instance parameter as an example. When you need to set filter conditions for a parameter and dynamically select a configuration in the ROS console, you can find the supported AssociationProperty value for the parameter, such as ALIYUN::ECS::Instance::InstanceType, in the AssociationProperty and AssociationPropertyMetadata documentation based on the parameter's resource type (ALIYUN::ECS::Instance). Then, view the AssociationPropertyMetadata value that uses ZoneId as a filter condition for the retrieved AssociationProperty. For more information, see AssociationProperty and AssociationPropertyMetadata.
In the main.tf file on the Terraform tab, enter the following content.
variable "pay_type" {
type = string
default = "PostPaid"
description = <<EOT
{
"Label": {
"en": "Charge type"
},
"AllowedValues": [
"PostPaid",
"PrePaid"
],
"AssociationProperty": "ChargeType",
"AssociationPropertyMetadata": {
"LocaleKey": "InstanceChargeType"
}
}
EOT
}
variable "pay_period_unit" {
type = string
default = "Month"
description = <<EOT
{
"Label": {
"en": "Pay period unit"
},
"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"
},
"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": {
"en": "The ID of the Availability Zone.<br><b>Note: <font color='blue'>Before you select an Availability Zone, confirm that it supports the instance types you plan to create. We recommend selecting a different Availability Zone from your other VSwitches.</font></b>"
},
"Label": {
"en": "VSwitch availability zone"
}
}
EOT
}
variable "vpc_cidr_block" {
type = string
default = "192.168.0.0/16"
description = <<EOT
{
"Label": {
"en": "VPC CIDR block"
},
"Description": {
"en": "The IP address range for the new VPC. We recommend using one of the following standard private network ranges:<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": {
"en": "Must be a subnet of the VPC and not be in use by another VSwitch."
},
"Label": {
"en": "VSwitch CIDR block"
}
}
EOT
}
variable "instance_type" {
type = string
description = <<EOT
{
"Label": {
"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>Valid 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'>Basic Cloud Disk</font><br>ephemeral_ssd: <font color='green'>Local SSD</font>"
},
"AssociationProperty": "ALIYUN::ECS::Disk::SystemDiskCategory",
"AssociationPropertyMetadata": {
"ZoneId": "$${zone_id}",
"InstanceType": "$${instance_type}"
},
"Label": {
"en": "System disk type"
}
}
EOT
}
variable "system_disk_size" {
type = number
default = 40
description = <<EOT
{
"Description": {
"en": "The size of the system disk, in GB. Valid values: 40 to 500."
},
"Label": {
"en": "System disk size"
}
}
EOT
}
variable "data_disk_category" {
type = string
description = <<EOT
{
"Label": {
"en": "Data disk type"
},
"Description": {
"en": "<font color='blue'><b>Valid 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'>Basic Cloud Disk</font>"
},
"AssociationProperty": "ALIYUN::ECS::Disk::DataDiskCategory",
"AssociationPropertyMetadata": {
"ZoneId": "$${zone_id}",
"InstanceType": "$${instance_type}"
},
"Label": {
"en": "Data disk type"
}
}
EOT
}
variable "data_disk_size" {
type = number
default = 100
description = <<EOT
{
"Description": {
"en": "The size of the data disk, in GiB. Valid values: 20 to 32768."
},
"MaxValue": 32768,
"MinValue": 20,
"Label": {
"en": "Data disk size"
}
}
EOT
}
variable "instance_password" {
type = string
sensitive = true
description = <<EOT
{
"Description": {
"en": "The login password for the instance. The password must be 8 to 30 characters in length and contain at least three of the following character types: uppercase letters, lowercase letters, digits, and special characters, which include ()`~!@#$%^&*_-+=|{}[]:;<>,.?/"
},
"Label": {
"en": "Instance password"
},
"ConstraintDescription": {
"en": "The password must be 8 to 30 characters long and contain at least three of the following character types: uppercase letters, lowercase letters, digits, and special characters from the set ()`~!@#$%^&*_-+=|{}[]:;<>,.?/"
},
"AssociationProperty": "ALIYUN::ECS::Instance::Password",
"AllowedPattern": "^[a-zA-Z0-9-\\(\\)\\`\\~\\!\\@\\#\\$\\%\\^\\&\\*\\_\\-\\+\\=\\|\\{\\}\\[\\]\\:\\;\\<\\>\\,\\.\\?\\/]*$",
"MinLength": 8,
"MaxLength": 30
}
EOT
}
Add parameter associations and constraints
The Terraform template defines an ECS instance, and the parameters to be constrained (zone_id, instance_type, vswitch_id, system_disk_category, system_disk_size, data_disk_category, and data_disk_size) are all related to alicloud_instance.
In the ResourcesForParameterConstraints field, you can apply constraints to instance_type and zone_id by defining the ALIYUN::ECS::Instance (alicloud_instance) resource type and associating the image_id, instance_type, and zone_id parameters.
{
"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"
}
}
},
{
"Parameters": [
"zone_id"
],
"Label": {
"default": {
"en": "Zone"
}
}
},
{
"Parameters": [
"vpc_cidr_block",
"vswitch_cidr_block"
],
"Label": {
"default": {
"en": "Existing infrastructure"
}
}
},
{
"Parameters": [
"instance_type",
"system_disk_category",
"system_disk_size",
"data_disk_category",
"data_disk_size",
"instance_password"
],
"Label": {
"default": {
"en": "Instance configuration"
}
}
}
]
}
}
Complete template example
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"
}
}
},
{
"Parameters": [
"zone_id"
],
"Label": {
"default": {
"en": "Zone"
}
}
},
{
"Parameters": [
"vpc_cidr_block",
"vswitch_cidr_block"
],
"Label": {
"default": {
"en": "Existing infrastructure"
}
}
},
{
"Parameters": [
"instance_type",
"system_disk_category",
"system_disk_size",
"data_disk_category",
"data_disk_size",
"instance_password"
],
"Label": {
"default": {
"en": "Instance configuration"
}
}
}
]
}
}
main.tf: |-
variable "pay_type" {
type = string
default = "PostPaid"
description = <<EOT
{
"Label": {
"en": "Charge type"
},
"AllowedValues": [
"PostPaid",
"PrePaid"
],
"AssociationProperty": "ChargeType",
"AssociationPropertyMetadata": {
"LocaleKey": "InstanceChargeType"
}
}
EOT
}
variable "pay_period_unit" {
type = string
default = "Month"
description = <<EOT
{
"Label": {
"en": "Pay period unit"
},
"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"
},
"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": {
"en": "The ID of the Availability Zone.<br><b>Note: <font color='blue'>Before you select an Availability Zone, confirm that it supports the instance types you plan to create. We recommend selecting a different Availability Zone from your other VSwitches.</font></b>"
},
"Label": {
"en": "VSwitch availability zone"
}
}
EOT
}
variable "vpc_cidr_block" {
type = string
default = "192.168.0.0/16"
description = <<EOT
{
"Label": {
"en": "VPC CIDR block"
},
"Description": {
"en": "The IP address range for the new VPC. We recommend using one of the following standard private network ranges:<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": {
"en": "Must be a subnet of the VPC and not be in use by another VSwitch."
},
"Label": {
"en": "VSwitch CIDR block"
}
}
EOT
}
variable "instance_type" {
type = string
description = <<EOT
{
"Label": {
"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>Valid 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'>Basic Cloud Disk</font><br>ephemeral_ssd: <font color='green'>Local SSD</font>"
},
"AssociationProperty": "ALIYUN::ECS::Disk::SystemDiskCategory",
"AssociationPropertyMetadata": {
"ZoneId": "$${zone_id}",
"InstanceType": "$${instance_type}"
},
"Label": {
"en": "System disk type"
}
}
EOT
}
variable "system_disk_size" {
type = number
default = 40
description = <<EOT
{
"Description": {
"en": "The size of the system disk, in GB. Valid values: 40 to 500."
},
"Label": {
"en": "System disk size"
}
}
EOT
}
variable "data_disk_category" {
type = string
description = <<EOT
{
"Label": {
"en": "Data disk type"
},
"Description": {
"en": "<font color='blue'><b>Valid 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'>Basic 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": {
"en": "The size of the data disk, in GiB. Valid values: 20 to 32768."
},
"MaxValue": 32768,
"MinValue": 20,
"Label": {
"en": "Data disk size"
}
}
EOT
}
variable "instance_password" {
type = string
sensitive = true
description = <<EOT
{
"Description": {
"en": "The login password for the instance. The password must be 8 to 30 characters in length and contain at least three of the following character types: uppercase letters, lowercase letters, digits, and special characters, which include ()`~!@#$%^&*_-+=|{}[]:;<>,.?/"
},
"Label": {
"en": "Instance password"
},
"ConstraintDescription": {
"en": "The password must be 8 to 30 characters long and contain at least three of the following character types: uppercase letters, lowercase letters, digits, and special characters from the set ()`~!@#$%^&*_-+=|{}[]:;<>,.?/"
},
"AssociationProperty": "ALIYUN::ECS::Instance::Password",
"AllowedPattern": "^[a-zA-Z0-9-\\(\\)\\`\\~\\!\\@\\#\\$\\%\\^\\&\\*\\_\\-\\+\\=\\|\\{\\}\\[\\]\\:\\;\\<\\>\\,\\.\\?\\/]*$",
"MinLength": 8,
"MaxLength": 30
}
EOT
}
# Define default resource names.
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
}
# Configure basic information for the security group.
resource "alicloud_security_group" "security_group" {
name = local.new_scg_name
description = "nginx scg"
vpc_id = alicloud_vpc.vpc.id
}
# Allow SSH ingress.
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
}
# Allow web ingress.
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
}
# Allow all egress traffic.
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
}
# Configure basic settings for the instance.
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
}
}
# Output the IP address of the NGINX server.
output "nginx_ip" {
value = "http://${alicloud_instance.instance.public_ip}"
}
user-data.sh: |-
#!/bin/bash -v
# Mount the data disk to /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
# Configure the installation script.
yum install -y nginx
# Configure the startup script.
/usr/sbin/nginx