Todos os produtos
Search
Central de documentação

Resource Orchestration Service:Implante o NGINX em uma instância ECS usando Terraform

Última atualização: Aug 27, 2026

O Alibaba Cloud Resource Orchestration Service (ROS) usa um modelo do Terraform para criar automaticamente uma infraestrutura de rede em cloud completa e uma instância ECS, além de instalar e iniciar o NGINX na instância em uma única operação. Esta solução é ideal para cenários que exigem a construção rápida e repetitiva de ambientes de servidor web.

Visão geral da solução

Esta solução executa um modelo do Terraform por meio do Alibaba Cloud Resource Orchestration Service (ROS) para criar automaticamente uma infraestrutura de rede em cloud completa e uma instância ECS em uma única operação, instalando e iniciando o service NGINX na instância ECS automaticamente. Ela se aplica a cenários que exigem a construção rápida e recorrente de ambientes de servidor web.

Cenário de negócios

Crie uma instância ECS em uma VPC da Alibaba Cloud, configure um grupo de segurança que permita acesso via Secure Shell (SSH) na porta 22 e acesso HTTP/HTTPS nas portas 80 a 443, anexe um disco de dados e use um script de inicialização user_data para instalar e iniciar o service NGINX automaticamente.

Recursos criados pelo modelo

Nº

Recurso

Tipo de recurso Terraform

Descrição

1

VPC

alicloud_vpc

Fornece um ambiente de rede isolado

2

vSwitch

alicloud_vswitch

Aloca uma sub-rede dentro da VPC e especifica a zona

3

Grupo de segurança

alicloud_security_group

Controla as regras de acesso à rede da instância ECS

4

Regra de grupo de segurança (SSH)

alicloud_security_group_rule

Permite acesso de entrada na porta 22

5

Regra de grupo de segurança (Web)

alicloud_security_group_rule

Permite acesso de entrada nas portas 80 a 443

6

Regra de grupo de segurança (saída)

alicloud_security_group_rule

Permite todo o tráfego de saída

7

Instância ECS

alicloud_instance

Nó de computação que executa o NGINX, com um disco de dados

Resultados após a implantação

Após a execução bem-sucedida do modelo, você obtém os seguintes recursos:

  • Ambiente de rede VPC completo, incluindo a VPC, o vSwitch, o grupo de segurança e as regras de grupo de segurança

  • Instância ECS com um disco de dados de 100 GB e um endereço IP público atribuído

  • Service NGINX instalado e iniciado automaticamente na instância ECS

  • Acesso à página padrão do NGINX pelo endereço IP público retornado na saída

Diagrama de arquitetura

image

Pré-requisitos

Antes de usar este modelo, certifique-se de que as seguintes condições sejam atendidas:

  • Permissões da conta: A conta Alibaba Cloud possui permissões para criar recursos ECS e VPC.

  • Conhecimento básico: Familiaridade com a sintaxe e a estrutura básicas dos modelos do Terraform. Para mais informações, consulte Structure of Terraform templates.

  • Visualize tipos de recursos: Consulte os detalhes das propriedades de recursos do Terraform no Índice de recursos do Terraform Provider alicloud. Cada propriedade é marcada como Optional ou Required.

Tutorial de criação de modelos

Este tutorial demonstra o processo de criação de modelos do Terraform em duas etapas:

  • Etapa 1 (básica): Usa valores de parâmetros fixos e foca nas definições e dependências de recursos do Terraform.

  • Etapa 2 (avançada): Adiciona filtragem dinâmica de parâmetros com AssociationProperty, agrupamento de parâmetros e restrições de parâmetros para melhorar a experiência no console.

Etapa 1: Modelo básico — defina recursos e suas dependências

Passo 1: Defina os recursos básicos de rede

Os recursos básicos de rede incluem alicloud_vpc, alicloud_vswitch e alicloud_security_group, que servem de base para todos os outros recursos. O Terraform estabelece dependências automaticamente por meio de referências de propriedades entre recursos.

# ============================================================
# Basic network-layer resources: VPC → VSwitch → SecurityGroup
# ============================================================

resource "alicloud_vpc" "vpc" {
  cidr_block = "192.168.0.0/16"  # VPC CIDR block, which holds up to 65,534 private IP addresses
}

resource "alicloud_vswitch" "vsw" {
  vpc_id     = alicloud_vpc.vpc.id  # References the VPC ID. Terraform establishes the dependency automatically
  cidr_block = "192.168.0.0/24"    # Subnet CIDR block, which must be a subset of the VPC CIDR block
  zone_id    = "cn-beijing-h"      # This scenario uses zone H in the China (Beijing) region as an example
}

resource "alicloud_security_group" "security_group" {
  name   = "sg-for-nginx"           # Security group name
  vpc_id = alicloud_vpc.vpc.id      # Binds the security group to the same VPC
}

Pontos principais:

  • Dependência implícita versus dependência explícita (depends_on):

    • A propriedade vpc_id de alicloud_vswitch.vsw referencia alicloud_vpc.vpc.id. O Terraform reconhece essa dependência automaticamente e garante que a VPC seja criada antes do vSwitch.

    • O uso de depends_on (dependência explícita) é necessário apenas quando dois recursos não possuem referência direta entre si, mas a lógica de negócios exige uma ordem específica.

Passo 2: Defina as regras do grupo de segurança

O recurso alicloud_security_group_rule controla o tráfego de rede de entrada e saída da instância ECS. Este cenário requer que a porta de conexão remota SSH e as portas de acesso web estejam abertas.

# ============================================================
# Security group rules: inbound SSH + inbound Web + all outbound traffic allowed
# ============================================================

# Inbound rule 1: opens SSH port 22 (for remote management)
resource "alicloud_security_group_rule" "allow_ssh" {
  security_group_id = alicloud_security_group.security_group.id  # Associates the rule with the security group
  type              = "ingress"     # Inbound direction
  cidr_ip           = "0.0.0.0/0"  # Allows access from all IP addresses (restrict the IP range in production environments)
  policy            = "accept"      # Accept policy
  ip_protocol       = "tcp"         # TCP protocol
  port_range        = "22/22"       # Port range: port 22 only
  priority          = 1             # Priority: 1 (highest)
}

# Inbound rule 2: opens web ports 80 to 443 (HTTP/HTTPS access to 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"      # Port range: 80 to 443
  priority          = 1
}

# Outbound rule: allows all outbound traffic (the ECS instance can access external networks such as yum repositories)
resource "alicloud_security_group_rule" "allow_egress" {
  security_group_id = alicloud_security_group.security_group.id
  type              = "egress"      # Outbound direction
  cidr_ip           = "0.0.0.0/0"
  policy            = "accept"
  ip_protocol       = "tcp"
  port_range        = "1/65535"     # All ports
  priority          = 1
}

Pontos principais:

  • O formato de intervalo de portas no Terraform é "porta inicial/porta final". Por exemplo, "80/443" indica todas as portas de 80 a 443, e uma única porta é escrita como "22/22".

  • Em ambientes de produção, restrinja o cidr_ip da regra SSH aos endereços IP corporativos para evitar varreduras maliciosas.

  • Para abrir outra porta, como a 8080, adicione outro recurso alicloud_security_group_rule.

Passo 3: Defina a instância ECS e o script de inicialização

O recurso alicloud_instance é o nó de computação que executa o NGINX. A propriedade user_data especifica o script de inicialização executado na primeira inicialização.

Script de inicialização user_data (user-data.sh):

#!/bin/bash -v
# ---- Format and mount the data disk ----
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

# ---- Install and start NGINX ----
yum install -y nginx
/usr/sbin/nginx

Definição do recurso de instância ECS:

# ============================================================
# Compute layer: ECS instance (data disk + NGINX initialization)
# ============================================================

resource "alicloud_instance" "instance" {
  availability_zone          = "cn-beijing-h"
  security_groups            = [alicloud_security_group.security_group.id]  # Binds security groups in array format
  host_name                  = "app-for-nginx"
  instance_type              = "ecs.c6e.large"        # Instance type (compute optimized, 2 vCPUs and 4 GiB of memory)
  system_disk_size           = 100                     # System disk size
  system_disk_category       = "cloud_essd"            # System disk type
  image_id                   = "centos_7_9_x64_20G_alibase_20210318.vhd"  # CentOS 7.9 image
  vswitch_id                 = alicloud_vswitch.vsw.id # Binds the instance to the vSwitch
  password                   = "<YourPassword>"        # Replace with the actual password at deployment (must contain uppercase and lowercase letters, digits, and special characters)
  internet_charge_type       = "PayByTraffic"          # Pay-by-traffic billing for the public bandwidth
  internet_max_bandwidth_out = 30                      # 30 Mbit/s outbound public bandwidth
  instance_charge_type       = "PostPaid"              # Billing type (pay-as-you-go or subscription)
  user_data                  = file("${path.cwd}/user-data.sh")  # Loads the initialization script

  data_disks {              # Data disk configuration
    size     = 100          # Data disk size
    category = "cloud_essd" # Data disk type
  }
}

# Outputs the NGINX access URL
output "nginx_ip" {
  value = "http://${alicloud_instance.instance.public_ip}:80"
}

Pontos principais: Métodos de referência de variáveis do Terraform

Método de referência

Sintaxe

Descrição

Referência de variável

var.variable_name

Recupera o valor de um parâmetro definido em um bloco variable (demonstrado no modelo avançado)

Referência de propriedade de recurso

resource_type.resource_name.property

Recupera uma propriedade de saída de outro recurso, como alicloud_vpc.vpc.id ou alicloud_instance.instance.public_ip

Carregamento de arquivo

file("${path.cwd}/file_name")

Carrega o conteúdo de um arquivo no diretório de trabalho atual

Extensões e variantes do modelo:

  • O user_data carrega um arquivo de script externo usando a função file(), facilitando a manutenção e a reutilização do script.

  • A configuração internet_max_bandwidth_out = 30 define uma largura de banda de saída de 30 Mbit/s, e a instância ECS obtém um endereço IP público automaticamente.

  • O bloco data_disks pode adicionar vários discos de dados ou ser omitido caso nenhum disco de dados seja anexado.

  • Após o modelo criar os recursos, as informações de output podem consultar diretamente as propriedades internas desses recursos. Assim, defina um bloco output para retornar o endereço de acesso público da instância ECS, que corresponde ao endereço de acesso do service NGINX.

Modelo básico completo

O modelo do Terraform possui a seguinte estrutura.

Conteúdo do arquivo 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"
}

# Basic security group configuration
resource "alicloud_security_group" "security_group" {
  name        = "sg-for-nginx"
  description = "nginx scg"
  vpc_id      = alicloud_vpc.vpc.id
}

# Inbound rule 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
}

# Inbound rule 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
}

# Outbound rule: all traffic allowed
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
}

# Basic instance configuration
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>"  # Replace with the actual password at deployment
  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"
  }
}

# Returns the NGINX access URL
output "nginx_ip" {
  value = "http://${alicloud_instance.instance.public_ip}:80"
}

Conteúdo do arquivo user-data.sh:

#!/bin/bash -v
# Mount the 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
# Install NGINX
yum install -y nginx
# Start NGINX
/usr/sbin/nginx

O modelo a seguir é a versão completa e pronta para uso, combinando os três passos anteriores. Para implantar um modelo do Terraform usando o ROS, encapsule o modelo no formato ROS Workspace.

Modelo completo no formato 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"
    }

    # Basic security group configuration
    resource "alicloud_security_group" "security_group" {
      name        = "sg-for-nginx"
      description = "nginx scg"
      vpc_id      = alicloud_vpc.vpc.id
    }

    # Inbound rule 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
    }

    # Inbound rule 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
    }

    # Outbound rule: all traffic allowed
    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
    }

    # Basic instance configuration
    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"
      }
    }

    # Returns the NGINX access URL
    output "nginx_ip" {
      value = "http://${alicloud_instance.instance.public_ip}:80"
    }
  user-data.sh: |-
    #!/bin/bash -v
    # Mount the 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
    # Install NGINX
    yum install -y nginx
    # Start NGINX
    /usr/sbin/nginx

Etapa 2: Modelo avançado — parametrização e configuração dinâmica

O modelo básico não define blocos variable nem as configurações de filtragem dinâmica, como description e default, suportadas por variable. Ao usar o modelo básico no console ROS, os parâmetros não são vinculados entre si, permitindo a seleção de combinações inválidas, como um tipo de instância indisponível na zona selecionada.

As otimizações a seguir melhoram significativamente a experiência no console e a reutilização do modelo:

  • Filtragem dinâmica de parâmetros (AssociationProperty): Configure AssociationProperty em formato JSON na description de uma variable para que o console filtre as opções disponíveis automaticamente.

  • Visibilidade condicional (Visible.Condition): Mostre ou oculte dinamicamente os parâmetros de duração da assinatura com base no tipo de faturamento.

  • Agrupamento de parâmetros (arquivo .metadata): Configure ParameterGroups no arquivo .metadata para que o console exiba os parâmetros em grupos lógicos.

  • Restrições de parâmetros (ResourcesForParameterConstraints): Defina restrições de recursos no arquivo .metadata para garantir que as combinações de parâmetros sejam válidas.

Gráfico de dependência de parâmetros

pay_type (billing type)
  ├── pay_period_unit (period unit, displayed only for PrePaid)
  └── pay_period (subscription duration, displayed only for PrePaid)

zone_id (zone, the core filter parameter)
  ├── instance_type (instance type, filtered by zone + billing type)
  │    ├── system_disk_category (system disk type, filtered by zone + instance type)
  │    └── data_disk_category (data disk type, filtered by zone + instance type)

Abordagem principal: Selecione primeiro a zona e o tipo de faturamento da ECS e, em seguida, filtre os tipos de instância ECS correspondentes (se o faturamento por assinatura for selecionado, também será necessário escolher a unidade de período e a duração da assinatura). Por fim, filtre os tipos de disco com base na zona e no tipo de instância ECS. Cada etapa mostra apenas as opções disponíveis sob as condições atuais, evitando combinações inválidas.

Como funciona o AssociationProperty

1. zone_id — zona (parâmetro base)

Defina AssociationProperty como ALIYUN::ECS::ZoneId para listar todas as zonas na região atual para seleção. Exemplo:

variable "zone_id" {
  type        = string
  description = <<EOT
  {
    # AssociationProperty specifies the resource property type that the parameter is associated with
    # The ROS console lists the available values based on this configuration
    "AssociationProperty": "ALIYUN::ECS::ZoneId",
    "Label": {
      "zh-cn": "VSwitch Availability Zone",
      "en": "VSwitch Availability Zone"
    },
    "Description": {
      "zh-cn": "Select availability zone for subsequent parameter filtering",
      "en": "Select availability zone for resource filtering"
    }
  }
  EOT
}

Este parâmetro serve como base de filtragem para todos os parâmetros subsequentes. Após selecionar uma zona, as listas de opções dos outros parâmetros são atualizadas conforme necessário.

2. pay_type — tipo de pagamento da ECS

Defina o parâmetro pay_type e use AssociationPropertyMetadata.Visible.Condition para alternar os parâmetros dinamicamente com base em uma condição: os parâmetros de duração da assinatura aparecem apenas quando o tipo de faturamento por assinatura (PrePaid) é selecionado. Exemplo:

variable "pay_type" {
  type    = string
  default = "PostPaid"
  description = <<EOT
  {
    "Label": { "en": "ECS Instance Charge Type", "zh-cn": "Payment Type" },
    "AllowedValues": ["PostPaid", "PrePaid"],
    "AssociationProperty": "ChargeType"
  }
  EOT
}
variable "pay_period_unit" {
  type    = string
  default = "Month"
  description = <<EOT
  {
    "Label": { "zh-cn": "Purchase 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", "zh-cn": "Purchase Period" },
    "AllowedValues": [1, 2, 3, 4, 5, 6, 7, 8, 9],
    "AssociationProperty": "PayPeriod",
    "AssociationPropertyMetadata": {
      "Visible": {
        "Condition": {
          "Fn::Not": { "Fn::Equals": ["$${pay_type}", "PostPaid"] }
        }
      }
    }
  }
  EOT
}

Quando o tipo de faturamento conforme o uso (PostPaid) é selecionado no console ROS, os parâmetros de duração da assinatura são ocultados automaticamente. Esses parâmetros aparecem somente quando o tipo de faturamento por assinatura (PrePaid) é escolhido.

3. instance_type — tipo de instância ECS

Defina AssociationProperty como ALIYUN::ECS::Instance::InstanceType para listar os tipos de instância ECS disponíveis e associe ${zone_id} e ${pay_type} para filtrar os tipos de instância disponíveis na zona especificada para o tipo de faturamento indicado. Exemplo:

variable "instance_type" {
  type = string
  description = <<EOT
  {
    "Label": { "zh-cn": "Instance Type", "en": "Instance Type" },
    "AssociationProperty": "ALIYUN::ECS::Instance::InstanceType",
    "AssociationPropertyMetadata": {
      "ZoneId": "$${zone_id}",
      "InstanceChargeType": "$${pay_type}"
    }
  }
  EOT
}

O estoque de tipos de instância varia por zona. Sem filtragem, pode-se selecionar um tipo de instância indisponível na zona, causando falha na criação.

4. system_disk_category — tipo de disco do sistema

Defina AssociationProperty como ALIYUN::ECS::Disk::SystemDiskCategory para listar os tipos de disco do sistema disponíveis e associe ${zone_id} e ${instance_type} para filtrar os tipos de disco do sistema ECS suportados pela zona e pelo tipo de instância ECS especificados. Exemplo:

variable "system_disk_category" {
  type = string
  description = <<EOT
  {
    "Label": { "zh-cn": "System Disk Type", "en": "System Disk Type" },
    "Description": {
      "zh-cn": "Options: cloud_efficiency, cloud_ssd, cloud_essd",
      "en": "Options: cloud_efficiency, cloud_ssd, cloud_essd"
    },
    "AssociationProperty": "ALIYUN::ECS::Disk::SystemDiskCategory",
    "AssociationPropertyMetadata": {
      "ZoneId": "$${zone_id}",
      "InstanceType": "$${instance_type}"
    }
  }
  EOT
}

A disponibilidade de um tipo de disco do sistema depende tanto da zona (algumas zonas não suportam ESSD) quanto do tipo de instância (alguns tipos de instância suportam apenas tipos específicos de disco).

5. data_disk_category — tipo de disco de dados

Defina AssociationProperty como ALIYUN::ECS::Disk::DataDiskCategory para listar os tipos de disco de dados disponíveis. O mecanismo de filtragem é idêntico ao do tipo de disco do sistema: ${zone_id} e ${instance_type} são associados para filtrar os tipos de disco de dados suportados tanto pela zona atual quanto pelo tipo de instância. Exemplo:

variable "data_disk_category" {
  type = string
  description = <<EOT
  {
    "Label": { "zh-cn": "Data Disk Type", "en": "Data Disk Type" },
    "Description": {
      "zh-cn": "Options: cloud_efficiency, cloud_ssd, cloud_essd",
      "en": "Options: cloud_efficiency, cloud_ssd, cloud_essd"
    },
    "AssociationProperty": "ALIYUN::ECS::Disk::DataDiskCategory",
    "AssociationPropertyMetadata": {
      "ZoneId": "$${zone_id}",
      "InstanceType": "$${instance_type}"
    }
  }
  EOT
}

Modelo de filtragem dinâmica de parâmetros

variable "zone_id" {
  type        = string
  description = <<EOT
  {
    "AssociationProperty": "ALIYUN::ECS::ZoneId",
    "Label": {
      "zh-cn": "VSwitch Availability Zone",
      "en": "VSwitch Availability Zone"
    },
    "Description": {
      "zh-cn": "Select availability zone for subsequent parameter filtering",
      "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": "Payment Type" },
    "AllowedValues": ["PostPaid", "PrePaid"],
    "AssociationProperty": "ChargeType"
  }
  EOT
}
variable "pay_period_unit" {
  type    = string
  default = "Month"
  description = <<EOT
  {
    "Label": { "zh-cn": "Purchase 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", "zh-cn": "Purchase Period" },
    "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": "Instance Type", "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": "System Disk Type", "en": "System Disk Type" },
    "Description": {
      "zh-cn": "Options: cloud_efficiency, cloud_ssd, cloud_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": "Data Disk Type", "en": "Data Disk Type" },
    "Description": {
      "zh-cn": "Options: cloud_efficiency, cloud_ssd, cloud_essd",
      "en": "Options: cloud_efficiency, cloud_ssd, cloud_essd"
    },
    "AssociationProperty": "ALIYUN::ECS::Disk::DataDiskCategory",
    "AssociationPropertyMetadata": {
      "ZoneId": "$${zone_id}",
      "InstanceType": "$${instance_type}"
    }
  }
  EOT
}

Como funciona a filtragem em cascata do AssociationProperty**

Ao criar uma pilha no console ROS, os parâmetros são selecionados em uma sequência em cascata:

  • Selecione uma zona (zone_id).

  • Escolha um tipo de faturamento ECS (pay_type).

  • A lista suspensa de tipos de instância ECS é atualizada automaticamente, mostrando apenas os tipos de instância que suportam o tipo de faturamento selecionado e estão disponíveis na zona escolhida.

  • Após selecionar um tipo de instância ECS, as listas suspensas de tipo de disco do sistema e tipo de disco de dados são atualizadas automaticamente, exibindo apenas os tipos de disco suportados tanto pela zona selecionada quanto pelo tipo de instância escolhido.

    Dessa forma, cada etapa apresenta apenas as opções viáveis nas condições atuais, prevenindo falhas de implantação causadas por combinações inválidas de parâmetros desde o início.

Agrupamento de parâmetros de metadados

A configuração ALIYUN::ROS::Interface em Metadata divide os parâmetros em vários grupos lógicos, cada um com um título. O console exibe os parâmetros por grupo, o que melhora significativamente a experiência de especificação.

Estrutura de sintaxe de metadados

Crie um arquivo .metadata na aba Terraform e configure o agrupamento de parâmetros (ParameterGroups) e as restrições de parâmetros (ResourcesForParameterConstraints):

{
  "ALIYUN::ROS::Interface": {
    "ResourcesForParameterConstraints": {
      "resource": {
        "Type": "ALIYUN::ECS::Instance",
        "Properties": {
        }
      }
    },
    "ParameterGroups": [
      {
        "Parameters": ["parameter_name_1", "parameter_name_2", "parameter_name_3"],
        "Label": { "default": { "zh-cn": "XXXX Configuration", "en": "Configuration" } }
      }
    ]
  }
}

Regras de sintaxe de metadados:

  • Tanto Parameters quanto Label são obrigatórios.

  • Os nomes de parâmetros listados em Parameters devem ser exatamente iguais aos nomes dos parâmetros variable.

  • Um parâmetro não incluído em nenhum grupo é exibido na área sem grupo no console.

Design de agrupamento de parâmetros para este cenário

Este modelo divide os 12 parâmetros em 3 grupos por tipo de recurso:

┌─────────────────────────────────────────────────────┐
│  Network configuration                              │
│  ├── VSwitch zone (zone_id)                         │
│  ├── VPC CIDR block (vpc_cidr_block)                │
│  └── VSwitch CIDR block (vswitch_cidr_block)        │
├─────────────────────────────────────────────────────┤
│  Payment configuration                              │
│  ├── ECS billing type (pay_type)                    │
│  ├── ECS subscription period unit (pay_period_unit) │
│  └── ECS subscription duration (pay_period)         │
├─────────────────────────────────────────────────────┤
│  ECS instance configuration                         │
│  ├── ECS instance type (instance_type)              │
│  ├── System disk type (system_disk_category)        │
│  ├── System disk size (system_disk_size)            │
│  ├── Data disk type (data_disk_category)            │
│  ├── Data disk size (data_disk_size)                │
│  └── ECS instance password (instance_password)      │
└─────────────────────────────────────────────────────┘

Configuração do arquivo .metadata

Crie um arquivo .metadata na aba Terraform e configure o agrupamento de parâmetros e as restrições de parâmetros:

{
  "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": "Network Configuration", "en": "Network Configuration" } }
      },
      {
        "Parameters": ["pay_type", "pay_period_unit", "pay_period"],
        "Label": { "default": { "zh-cn": "Payment Configuration", "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 Instance Configuration", "en": "ECS Instance Configuration" } }
      }
    ]
  }
}

Pontos principais:

  • Um recurso virtual ALIYUN::ECS::Instance é definido para associar os parâmetros do modelo às propriedades do recurso ECS.

  • O console ROS valida a eficácia da combinação de parâmetros com base nessa definição, verificando, por exemplo, se a zona especificada suporta o tipo de instância e os tipos de disco selecionados.

  • A sintaxe Ref referencia o nome da variável do Terraform sem o prefixo var..

Modelo avançado completo

O modelo a seguir é a versão avançada completa, encapsulada no formato ROS Workspace, pronta para implantação direta no console 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": "Network Configuration", "en": "Network Configuration" } }
          },
          {
            "Parameters": ["pay_type", "pay_period_unit", "pay_period"],
            "Label": { "default": { "zh-cn": "Payment Configuration", "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 Instance Configuration", "en": "ECS Instance Configuration" } }
          }
        ]
      }
    }
  main.tf: |-
    variable "pay_type" {
      type    = string
      default = "PostPaid"
      description = <<EOT
      {
        "Label": { "en": "ECS Instance Charge Type", "zh-cn": "Payment 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", "zh-cn": "Purchase 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", "zh-cn": "Purchase Period" },
        "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": "VSwitch Availability Zone", "en": "VSwitch Availability Zone" },
        "Description": {
          "zh-cn": "Select availability zone. Instance types and disk categories will be filtered accordingly.",
          "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": "VPC CIDR Block", "en": "VPC CIDR Block" },
        "Description": {
          "zh-cn": "VPC IP range. Recommended: 10.0.0.0/8, 172.16.0.0/12, or 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": "VSwitch CIDR Block", "en": "VSwitch CIDR Block" },
        "Description": {
          "zh-cn": "Must be a subnet of VPC CIDR and not overlap with other VSwitches",
          "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": "Instance Type", "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": "System Disk Type", "en": "System Disk Type" },
        "Description": {
          "zh-cn": "Options: cloud_efficiency, cloud_ssd, cloud_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": "System Disk Size", "en": "System Disk Size" },
        "Description": {
          "zh-cn": "System disk size, range: 40~500 GB",
          "en": "System disk size, range: 40~500 GB"
        }
      }
      EOT
    }
    variable "data_disk_category" {
      type = string
      description = <<EOT
      {
        "Label": { "zh-cn": "Data Disk Type", "en": "Data Disk Type" },
        "Description": {
          "zh-cn": "Options: cloud_efficiency, cloud_ssd, cloud_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": "Data Disk Space", "en": "Data Disk Space" },
        "Description": {
          "zh-cn": "ECS data disk size, range: 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": "Logon Password", "en": "Instance Password" },
        "Description": {
          "zh-cn": "Length 8-30, must contain at least 3 of: uppercase, lowercase, digits, special characters",
          "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
    }

    # 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
    }

    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
    # Mount the 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
    # Install NGINX
    yum install -y nginx
    # Start NGINX
    /usr/sbin/nginx

Referência rápida de sintaxe de modelos do Terraform

Sintaxe

Exemplo

Finalidade neste modelo

var.variable_name

var.zone_id

Referencia um valor de parâmetro de entrada definido por uma variável

local.variable_name

local.new_host_name

Referencia uma variável local definida em um bloco locals

resource_type.name.property

alicloud_vpc.vpc.id

Referencia uma propriedade de saída de outro recurso e estabelece a dependência automaticamente

file("path")

file("${path.cwd}/user-data.sh")

Carrega o conteúdo de um arquivo externo como valor de propriedade

"${expression}"

"sg-for-${local.production_name}"

Interpolação de string, que incorpora um valor de variável em uma string

<<EOT ... EOT

description = <<EOT {...} EOT

String multilinha, usada para incorporar configurações JSON

$${variable_name}

"$${pay_type}"

Referencia o valor atual de outra variável no JSON da descrição

Implantação

Parâmetros de implantação

Parâmetros de entrada obrigatórios (devem ser especificados na implantação)

Parâmetro

Tipo

Descrição

Restrição

zone_id

String

Zona do vSwitch

Seleção dinâmica no console

instance_type

String

Tipo de instância ECS

Filtrado automaticamente por zona

system_disk_category

String

Tipo de disco do sistema

Filtrado automaticamente por zona + tipo de instância

data_disk_category

String

Tipo de disco de dados

Filtrado automaticamente por zona + tipo de instância

instance_password

String

Senha de login da ECS

Comprimento de 8 a 30 caracteres, devendo conter letra maiúscula, letra minúscula, dígito e caractere especial

Parâmetros opcionais (possuem valores padrão, podem ser mantidos inalterados)

Parâmetro

Padrão

Descrição

pay_type

PostPaid

Tipo de faturamento (PostPaid para pagamento conforme o uso, PrePaid para assinatura)

pay_period_unit

Month

Unidade de duração da assinatura (exibido apenas para PrePaid)

pay_period

1

Duração da assinatura (exibido apenas para PrePaid)

vpc_cidr_block

192.168.0.0/16

Intervalo de bloco CIDR da VPC

vswitch_cidr_block

192.168.0.0/24

Bloco CIDR da sub-rede do vSwitch

system_disk_size

40

Tamanho do disco do sistema (GB), valores válidos: 40 a 500

data_disk_size

100

Tamanho do disco de dados (GiB), valores válidos: 20 a 32768

Métodos de implantação

Método 1: Implantar através do console ROS

  1. Acesse o console ROS.

  2. No painel de navegação à esquerda, escolha Templates > My Templates > Create Template.

  3. Para o tipo de modelo, selecione o modelo Terraform.

  4. Crie um arquivo main.tf e cole o conteúdo do main.tf do modelo avançado.

  5. Crie um arquivo user-data.sh e cole o conteúdo do script user-data.sh.

  6. Crie um arquivo .metadata e cole a configuração JSON do .metadata.

  7. Após salve o modelo, acesse Stacks > Create Stack > Select an existing template > My Templates e selecione o modelo.

  8. Especifique os parâmetros de configuração por grupo e clique em Create.

  9. Aguarde até que o status da pilha mude para CREATE_COMPLETE e visualize a URL de acesso do NGINX na aba Outputs.

Método 2: Implantar através do ROS IaC Code

O IaC Code é um assistente de IA para infraestrutura como código (IaC) voltado para infraestrutura em cloud, capaz de gerar, implantar e gerenciar modelos de infraestrutura por meio de prompts em linguagem natural. Sua arquitetura foi projetada para fluxos de trabalho multicloud. O prompt a seguir serve como referência para esta solução:

# Prompt

Help me create an ECS instance and deploy the NGINX service by using a Terraform template.
Requirements:
1. Create a new VPC and `vSwitch` as the basic network.
2. The security group allows inbound access on port 22 (SSH) and ports 80 to 443 (web access).
3. The ECS instance requires a public IP address, with an outbound bandwidth of 30 Mbit/s.
4. Attach a 100 GB data disk, format it, and mount it to /disk1.
5. Install and start NGINX automatically through a user_data script.
6. zone_id, instance_type, system_disk_category, and data_disk_category all require AssociationProperty dynamic filtering.
7. The billing type parameter requires conditional visibility (the subscription duration is displayed only for subscription billing).

Perguntas frequentes

P1: A implantação falha com a mensagem de erro "The specified InstanceType is not available in the zone"

Causa: O tipo de instância ECS selecionado está indisponível na zona especificada.

Solução:

  • No modelo avançado, o AssociationProperty trabalha em conjunto com ResourcesForParameterConstraints para filtrar automaticamente os tipos de instância disponíveis, prevenindo esse problema.

  • Se você estiver usando o modelo básico, verifique a disponibilidade de estoque do tipo de instância na zona alvo na página de Preços do Elastic Compute Service (ECS).

P2: A instância ECS foi criada, mas a página do NGINX não está acessível

Passos para solução de problemas:

  • Verifique se a regra do grupo de segurança permite acesso de entrada na porta 80 (verifique a regra allow_web).

  • Login to the ECS instance e execute systemctl status nginx para verificar se o NGINX está funcionando conforme esperado.

  • Confira se o script user_data foi executado com sucesso: visualize cat /var/log/messages | grep cloud-init.

  • Verifique se a instância ECS possui um endereço IP público (um IP público é atribuído automaticamente quando internet_max_bandwidth_out > 0).

P3: O script user_data falhou ao executar e o disco de dados não foi montado

Causa: A imagem pode ser incompatível ou o nome do dispositivo do disco de dados pode não corresponder.

Solução:

  • O caminho /dev/vdb usado no script user_data é o nome de dispositivo padrão do disco de dados. Certifique-se de que o bloco data_disks esteja configurado no modelo.

  • Se você utilizar uma imagem diferente do CentOS, talvez seja necessário ajustar o comando de particionamento (por exemplo, usar parted em vez de fdisk).

  • Caso não seja necessário um disco de dados, remova o bloco data_disks e a parte de montagem de disco do script user_data.

P4: Como converto um modelo do Terraform para um modelo do ROS?

Método 1: Converter no console

  • No console ROS, escolha Templates > My Templates > Create Template.

  • Escreva o modelo primeiro na aba de modelo Terraform.

  • Mude para a aba de modelo ROS e selecione YAML no canto superior direito. O sistema converte automaticamente o modelo do Terraform para o seguinte formato:

ROSTemplateFormatVersion: '2015-09-01'
Transform: Aliyun::Terraform-v1.2
Workspace:
  .metadata: |-
    { ... }  # Parameter grouping and constraint configuration
  main.tf: |-
    ...      # Terraform template content
  user-data.sh: |-
    ...      # Initialization script content

Método 2: Usar o Template Transformer

rostran transform templates/terraform/alicloud/main.tf --target-format json

P5: Como implanto outro service web, como Apache ou Tomcat?

Pontos de modificação:

  • Modifique os comandos de instalação e inicialização no arquivo user-data.sh:

    • Apache: yum install -y httpd && systemctl start httpd

    • Tomcat: instale o JDK e, em seguida, baixe e inicie o Tomcat.

  • Ajuste o intervalo de portas da regra do grupo de segurança (por exemplo, o Tomcat usa a porta 8080 por padrão).

  • Modifique o número da porta na saída.

P6: Como uso uma VPC existente em vez de criar uma nova?

Solução: Altere a VPC e o vSwitch para selecionar recursos existentes:

variable "vpc_id" {
  type = string
  description = <<EOT
  {
    "Label": { "zh-cn": "Existing VPC" },
    "AssociationProperty": "ALIYUN::ECS::VPC::VPCId"
  }
  EOT
}
variable "vswitch_id" {
  type = string
  description = <<EOT
  {
    "Label": { "zh-cn": "Existing VSwitch" },
    "AssociationProperty": "ALIYUN::VPC::VSwitch::VSwitchId",
    "AssociationPropertyMetadata": {
      "VpcId": "$${vpc_id}"
    }
  }
  EOT
}

Em seguida, altere vswitch_id em alicloud_instance para var.vswitch_id e exclua os blocos de recursos alicloud_vpc e alicloud_vswitch.

Para mais informações sobre problemas de implantação de recursos, consulte FAQ.