企业级ECS集群构建

课程简介

欢迎来到“企业级ECS集群构建”本课程是“弹性计算Clouder系列认证”中的阶段六课程,本课程主要讲解了如何使用资源编排服务进行云上资源创建和管理。相较于使用其他方式管理云上资源,使用资源编排服务时,云上用户可以方便的使用资源模板文件的方式,创建和管理云上资源。这种IaC(基础设计即代码)的资源管理方式,让资源的创建和运维变得标准化,规范化。杜绝了人为创建资源带来的潜在风险。


课程目标

学习完本课程之后,您将能够:

  1. 了解IaC的基本概念以及Terraform资源模板
  2. 掌握resource,variable,output,data等Terraform中常见概念的用法
  3. 使用Terraform创建基础网络环境,以及安全组和安全组规则配置
  4. 使用Terraform创建包含云服务器ECS和负载均衡CLB的LAMP生产环境集群


课程场景

(提示:本课程为场景化教学,旨在帮助学员展示更加真实的应用场景。该场景讲述了一个虚构人物小云如何利用阿里云资源编排服务完成企业ECS集群的构建。)

经过前面的学习,小云已经可以熟练的进行云网络、云服务器、以及云上应用架构的搭建和配置。这一天下午,小云公司的资深云架构师老王在为云上测试集群的构建忙碌着,于是主动请缨来帮忙。

老王看到信心满满的小云,于是将项目测试集群中ECS部分的需求发给了小云:

  1. 应用采用分布式服务架构设计,大部分服务集群都是LAMP架构。
  2. 每个服务都放在单独的ECS里面运行,在ECS上层提供统一的CLB访问接口。
  3. 不同服务集群的负载并不一致,因此需要分配不同的ECS镜像和计算资源。
  4. 由于需要经常测试,每天可能会重复部署很多次。因此希望部署工作能控制在10分钟之内完成。

小云看到需求后,心里开始犯难,虽然已经可以熟练的创建和配置ECS云服务器。但是看到真实的项目需求吃了一惊。心里开始泛起了嘀咕:“不同的服务集群都要配置不同硬件配置,有的需要高内存,有的需要高CPU,还有的需要GPU;不同的组件所在网络交换机不同,安全组也不同;这么多工作如果每次都去手动部署,每部署一次至少需要半个小时到一个小时。而且每天要部署很多的次,万一环境部署出错,影响了项目的测试进度,项目不能按时上线,对公司的损失就太大了。”

看到了小云犯难的神情,坐在小云旁边的老王把椅子划了过来:"小云同学,运维工作有时候就是非常繁琐和枯燥的,我们当年在IDC机房里面做应用上线前的测试时,经常遇到这样的问题。基本上总结起来基本有这么几个难点:

  1. 硬件配置繁琐
  2. 网络配置繁琐
  3. 镜像版本复杂
  4. 部署时间紧迫

不过好在我们现在上云了,可以使用IaC的方式来创建和管理云资源了。"

1、什么是IaC(基础设施即代码)?

“IaC方式?这个概念我之前没有听说过啊。”小云好奇的问到。

老王笑了笑继续说到:“IaC方式是基础设施即代码的意思,也就是把我们运维人员复杂的部署工作写成一份配置文件,然后通过配置文件来创建环境。

“用配置文件管理资源,听起来是一个不错的方式啊!那我是不是就是通过Python或者bash来编写创建ECS资源的脚本,然后每次需要创建ECS的时候就执行脚本就可以了呢?”小云兴奋的说到。

“用脚本来自动创建是一个管理资源方式,可以解决部署速度慢的问题。但是它本身也存在着一些问题:

首先Python,bash这样的编程语言是为了实现逻辑计算设计的,并不是为了管理资源而设计的。因此使用编程语言会让代码非常的冗余。

其次使用编写脚本管理资源的时候,每个人都有自己的编写习惯,这样就使得资源管理脚本不容易阅读,一旦维护人员更换,接手的同学往往会对留下来的脚本无从下手。甚至就算是自己编写的脚本,但是由于搁置太久,连自己都忘了最初的逻辑。因此使用脚本管理资源不能算是基础设施即代码”老王认真的解释道。

“那IaC到底是什么呢?”小云疑惑的挠了挠头。

“其实也没有那么复杂,一般来说在云上使用IaC的时候,我们会使用配置文件而不是脚本文件来管理资源。在配置文件中我们只需要描述资源的类型、属性、相互关系之类的信息就可以了”老王答道。

“可是如果我们只是在配置文件里写了资源的信息,那又是谁去负责具体创建资源呢?”小云继续问道。

“你这就问到点子上了!为了能让IaC的配置文件转化成IT资源,就需要用到云平台的能力了。在阿里云上有一个专门的产品叫资源编排服务ROS(Resource Orchestration Service),就是负责完成这个工作的。”老王笑道。

紧接着老王开始带着小云学习如何使用资源编排服务……

2、资源编排服务快速入门

“ROS入门稍微有点复杂,正好我今天没有什么紧急的事。就先带着你一步一步的上手吧。”老王说完通过钉钉给小云发送了一段操作指南。

  1. 打开ROS控制台https://rosnext.console.aliyun.com/overview
  2. 在左侧选择资源栈选项,并在上方导航条选择资源地域


企业级ECS集群构建_配置文件

添加图片注释,不超过 140 字(可选)


  1. 在资源栈列表中选择创建资源栈 > 使用Terraform


企业级ECS集群构建_ci_02

添加图片注释,不超过 140 字(可选)


  1. 在使用新资源页面中选择如下选项:选择已有模板, 输入模板,Terraform,main.tf


企业级ECS集群构建_配置文件_03

添加图片注释,不超过 140 字(可选)


  1. 在模板内容中输入如下内容,然后点击下一步按钮。
resource "alicloud_vpc" "ros_vpc" {
  vpc_name = "ROS_VPC"
  cidr_block = "192.168.0.0/16"
}

resource "alicloud_vswitch" "ros_vsw" {
  vswitch_name = "ROS_VSWITCH"
  zone_id = "cn-hangzhou-b"
  vpc_id = alicloud_vpc.ros_vpc.id
  cidr_block = "192.168.1.0/24"
}


企业级ECS集群构建_输入框_04

添加图片注释,不超过 140 字(可选)


  1. 点击创建按钮


企业级ECS集群构建_配置文件_05

添加图片注释,不超过 140 字(可选)



  1. 在资源栈信息页面中,打开自动刷新选项。等待一段时间后资源栈状态变为创建成功。


企业级ECS集群构建_配置文件_06

添加图片注释,不超过 140 字(可选)


小云按照老王的操作指南,在ROS控制台中进行了操作。等资源栈状态变为创建成功后。进入了专有网络控制台。

https://vpc.console.aliyun.com/vpc/cn-hangzhou/vpcs

在控制台中发现已经自动创建了一个名为ROS_VPC的专有网络。


企业级ECS集群构建_配置文件_07

添加图片注释,不超过 140 字(可选)


在专有网络中,还包含了一个名为ROS_VSWITCH的交换机。


企业级ECS集群构建_输入框_08

添加图片注释,不超过 140 字(可选)


老王看到小云操作完成后,给小云讲解起了ROS的基本概念。


在ROS中资源栈是基本的资源管理单元



资源栈中又包含了模板文件和云上资源



模板文件可以使用ROS模板或Terraform模板



ROS模板文件又可以使用JSON格式或者YAML格式



Terraform模板采用特有的TF格式



运行模板文件可以创建相应的云上资源


  • e data-draft-node="block" data-draft-type="table" data-size="normal" data-row-style="normal">


  • e data-draft-node="block" data-draft-type="table" data-size="normal" data-row-style="normal">



在ROS中资源栈是基本的资源管理单元



资源栈中又包含了模板文件和云上资源



模板文件可以使用ROS模板或Terraform模板



ROS模板文件又可以使用JSON格式或者YAML格式



Terraform模板采用特有的TF格式



运行模板文件可以创建相应的云上资源




“一般来说,在使用的ROS的时候,我们先创建资源栈,然后在资源栈中创建模板文件,最后通过模板文件生成对应的云上资源。”老王继续解释道。


企业级ECS集群构建_ci_09

添加图片注释,不超过 140 字(可选)


3、Terraform文件格式

小云听完老王对ROS基本概念的讲解说到:“我对ROS也有了大概的了解。那么模板文件的格式您能再讲一下吗?”

“在ROS中模板文件有两种形式,一种是阿里云自有的ROS模板,可以使用JSON格式或YAML格式书写。另一种是比较通用的Terraform模板,这种形式的解析引擎开源,同时也被多个主流云平台支持,同时其文件格式也比较便于阅读,因此比较推荐使用。”老王解释道。


看小云认真的聆听和记笔记,老王继续说到:

“当我们使用Terraform创建资源栈的时候,我们需要注意以下几点:


Terraform格式的配置采用文件和文件夹的方式管理。配置文件的后缀名是.tf



Terraform的默认配置文件入口是main.tf



Terraform配置文件中又包含了:资源,变量,输出等元素


  • ta-draft-type="table" data-size="normal" data-row-style="normal">


Terraform格式的配置采用文件和文件夹的方式管理。配置文件的后缀名是.tf



Terraform的默认配置文件入口是main.tf



Terraform配置文件中又包含了:资源,变量,输出等元素



  • a-draft-node="block" data-draft-type="table" data-size="normal" data-row-style="normal">


Terraform格式的配置采用文件和文件夹的方式管理。配置文件的后缀名是.tf



Terraform的默认配置文件入口是main.tf



Terraform配置文件中又包含了:资源,变量,输出等元素




Terraform中元素的常见描述格式为:

元素种类 "元素类型" "元素名"{
	属性名1 = 属性值1
	属性名2 = 属性值2
  ...
}

例如刚才我让你输入的内容中,下面的段落就描述了一个VPC。其中 resource 表示这一段描述了一个资源,“alicloud_vpc”表示这一段描述了一个VPC,“ros_vpc”是这个资源在Terraform中的名字。vpc_name cidr_block 是元素的属性。

resource "alicloud_vpc" "ros_vpc" {
  vpc_name = "ROS_VPC"
  cidr_block = "192.168.0.0/16"
}

在描述元素的时候,有的元素的属性会依赖到另一个元素或者另一个元素的属性。当我们需要从另一个元素中引用属性的时候,我们可以使用元素类型.元素名.属性名的格式。例如刚才的输入内容中,配置交换机的时候需要一个交换机id的属性vpc_id。这个属性就需要从VPC中进行获取。这时候我们就可以使用alicloud_vpc.ros_vpc.id的方式来引用。”

resource "alicloud_vswitch" "ros_vsw" {
  vswitch_name = "ROS_VSWITCH"
  zone_id = "cn-hangzhou-b"
  vpc_id = alicloud_vpc.ros_vpc.id
  cidr_block = "192.168.1.0/24"
}


企业级ECS集群构建_输入框_10

添加图片注释,不超过 140 字(可选)



“这么看来Terraform脚本倒是不难。如果我想继续在资源栈里面添加新的资源,是不是在main.tf文件中继续添加对元素的描述就行了?如果我添加了新的元素,我怎么查询元素的类型和元素的属性名呢?”小云问到。

“如果你想查询Terraform支持的元素和属性可以参考Terraform的官方网站:https://registry.terraform.io/providers/aliyun/alicloud/latest/docs

在官方网站的右侧是Terraform最新版本支持的所有元素的列表。

当我们选择了一个元素之后,即可从右侧查找到这个元素的相关属性。”


企业级ECS集群构建_输入框_11

添加图片注释,不超过 140 字(可选)

1、如何在模板中输入动态参数?

“看来Terraform模板,用起来倒是挺简单的。不过我发现了一个问题,我们刚才创建的资源都是把所有的参数都配置好,但是在管理资源的时候,并不是所有的资源的属性都可以预先确定的,比如VPC的地址每次部署的时候可能都是不一样的。这种情况应该怎么办呢?"小云问道。

“这时候我们就可以在Terrform中添加 variable 段落来解决。我给你演示一下如何实现这个功能。”

  1. 在资源栈列表中选择创建资源栈 > 使用Terraform,选择已有模板, 输入模板,Terraform,在main.tf编辑器中输入如下内容。
variable "vpc_cidr" {
  type        = string
  default     = "192.168.0.0/16"
}

resource "alicloud_vpc" "ros_vpc" {
  vpc_name = "ROS_VPC"
  cidr_block = var.vpc_cidr
}


企业级ECS集群构建_ci_12

添加图片注释,不超过 140 字(可选)



  1. 文件编辑完成后,点击下一步按钮,这时候我们会看到在配置模板参数阶段,出现了输入编辑框,同时输入框的默认值为192.168.0.0/16。


企业级ECS集群构建_ci_13

添加图片注释,不超过 140 字(可选)


  1. 我们在输入框中修改一下内容,修改为192.168.1.0/24。然后点击创建按钮。等待资源创建成功


企业级ECS集群构建_ci_14

添加图片注释,不超过 140 字(可选)


企业级ECS集群构建_ci_15

添加图片注释,不超过 140 字(可选)



企业级ECS集群构建_ci_16

添加图片注释,不超过 140 字(可选)



  1. 等待资源创建完毕后,我们去VPC控制台查看创建结果,会发现这次创建的VPC已经使用了我们输入的网段


企业级ECS集群构建_输入框_17

添加图片注释,不超过 140 字(可选)



2、variable的配置

“原来Terraform模板还可以在页面输入参数。”小云感叹。

“Terraform的variable参数功能除了可以显示标准的输入框之外,还支持配置输入框。”老王说到。

  1. 在资源栈控制台中,使用Terraform创建资源栈。在main.tf编辑器中输入如下内容。
variable "vpc_cidr" {
  type        = string
  default     = "192.168.0.0/16"
  description = <<EOT
    {
      "Label": {
        "en": "VPC cidr",
        "zh-cn": "VPC 网段"
      },
      "AllowedValues": [
        "10.0.0.0/16",
        "172.16.0.0/16",
        "192.168.0.0/16"
      ]
    }
  EOT
}

resource "alicloud_vpc" "ros_vpc" {
  vpc_name = "ROS_VPC"
  cidr_block = var.vpc_cidr
}
  1. 文件编辑完成后,点击下一步按钮,会看到输入框的标题变成了VPC网段,同时VPC网段只能选择三个网络地址。


企业级ECS集群构建_配置文件_18

添加图片注释,不超过 140 字(可选)


  1. 我们按上一步按钮,回到模板编辑界面。继续修改main.tf文件为如下内容
variable "vpc_name" {
  type        = string
  default     = "VPC名称"
  description = <<EOT
    {
      "Label": {
        "en": "VPC Name",
        "zh-cn": "VPC名称"
      },
      "MinLength": 2,
      "MaxLength": 8
    }
  EOT
}

variable "vpc_cidr" {
  type        = string
  default     = "192.168.0.0/16"
  description = <<EOT
    {
      "Label": {
        "en": "VPC cidr",
        "zh-cn": "VPC CIDR"
      },
      "AllowedValues": [
        "10.0.0.0/16",
        "172.16.0.0/16",
        "192.168.0.0/16"
      ]
    }
  EOT
}

resource "alicloud_vpc" "ros_vpc" {
  vpc_name = var.vpc_name
  cidr_block = var.vpc_cidr
}
  1. 编辑结束后,按下一步按钮之后,会看到配置模板参数阶段,出现了两个控件,在VPC名称输入框中输入超过8个字符,会发现出现错误提示。


企业级ECS集群构建_配置文件_19

添加图片注释,不超过 140 字(可选)


  1. 我们将VPC名称修改为符合要求的长度。然后点击创建。等待一段时间后发现,资源将按照指定的参数成功创建。


3、variable显示系统界面

“有了输入参数界面,模板的使用就灵活多了。这样就可以适应很多不同的部署场合了。不过我想到了一个场景,当我部署网络环境的时候,经常会遇到可用区的选择,可是每个地域的可用区都不同。遇到这种情况我应该怎么处理呢?”小云说道。

“这也是一种非常常见的情况,遇到这种情况,可以调用通过variable来调用系统的界面进行输入。接下来我们来修改一下刚才创建的资源栈,为它添加。”老王说到。

  1. 我们回到资源栈列表,找到刚才创建的资源栈条目,点击条目后面的更新按钮。


企业级ECS集群构建_ci_20

添加图片注释,不超过 140 字(可选)


  1. 进入更新状态后,会跳到配置模板参数页面,此时我们需要修改模板的文件内容,因此我们先点击上一步按钮。


企业级ECS集群构建_输入框_21

添加图片注释,不超过 140 字(可选)


  1. 在选择模板页面,我们选择替换当前模板和选择已有模板两个选项。


企业级ECS集群构建_配置文件_22

添加图片注释,不超过 140 字(可选)


  1. 在模板录入方式中,选择输入模板选项。会看到页面回到了文件编辑界面。


企业级ECS集群构建_配置文件_23

添加图片注释,不超过 140 字(可选)


  1. 我们打开main.tf文件,在文件中追加如下内容
variable "vswitch_name" {
  type        = string
  default     = "交换机名称"
  description = <<EOT
  {
    "Label": {
      "en": "VSwitch Name",
      "zh-cn": "交换机名称"
    },
    "MinLength": 2,
    "MaxLength": 8
  }
  EOT
}

variable "zone_id" {
  type        = string
  description = <<EOT
  {
    "Label": {
      "en": "Availability Zone",
      "zh-cn": "交换机可用区"
    },
    "AssociationProperty": "ALIYUN::ECS::Instance::ZoneId"
  }
  EOT
}

resource "alicloud_vswitch" "ros_vsw" {
  vswitch_name = var.vswitch_name
  zone_id = var.zone_id
  vpc_id = alicloud_vpc.ros_vpc.id
  cidr_block = var.vpc_cidr
}
  1. 编辑完毕后,我们点击下一步按钮。我们在配置模板参数页面,会看到可用区的选择控件。


企业级ECS集群构建_配置文件_24

添加图片注释,不超过 140 字(可选)


  1. 我们选择一个可用区,然后再尝试修改一下VPC的名称和VPC网段。选择完毕后,我们点击确认修改按钮。等待一段时候之后发现资源栈更新成功了。


企业级ECS集群构建_配置文件_25

添加图片注释,不超过 140 字(可选)



企业级ECS集群构建_输入框_26

添加图片注释,不超过 140 字(可选)



  1. 我们进入VPC控制台,会发现经过更新之后,VPC的名称和网段已经更新成功,同时在VPC中也也创建了新的交换机。


企业级ECS集群构建_输入框_27

添加图片注释,不超过 140 字(可选)



企业级ECS集群构建_配置文件_28

添加图片注释,不超过 140 字(可选)



小云仔细的阅读了一下老王提供的variable代码。做了如下的工作总结:


添加variable段落可以为模板提供用户输入参数的界面



variable段落的格式为variable 参数名称{属性名1=属性值1...}



variable段落中可以定义type和default等属性



resource引用variable时可以使用var.参数名称的格式



variable的description的属性可以使用JSON格式进行更加详细的配置



variable的description的JSON格式配置的前后需要添加<<EOT和EOT



description中的Label属性可以为输入界面定义提示



description中的MinLength和MaxLength可以对输入框进行限制



description中的AllowedValues属性可以将输入框改为单选框



description中的AssociationProperty属性可以调用系统的输入控件



添加variable段落可以为模板提供用户输入参数的界面



variable段落的格式为variable 参数名称{属性名1=属性值1...}



variable段落中可以定义type和default等属性



resource引用variable时可以使用var.参数名称的格式



variable的description的属性可以使用JSON格式进行更加详细的配置



variable的description的JSON格式配置的前后需要添加<<EOT和EOT



description中的Label属性可以为输入界面定义提示



description中的MinLength和MaxLength可以对输入框进行限制



description中的AllowedValues属性可以将输入框改为单选框



description中的AssociationProperty属性可以调用系统的输入控件




添加variable段落可以为模板提供用户输入参数的界面



variable段落的格式为variable 参数名称{属性名1=属性值1...}



variable段落中可以定义type和default等属性



resource引用variable时可以使用var.参数名称的格式



variable的description的属性可以使用JSON格式进行更加详细的配置



variable的description的JSON格式配置的前后需要添加<<EOT和EOT



description中的Label属性可以为输入界面定义提示



description中的MinLength和MaxLength可以对输入框进行限制



description中的AllowedValues属性可以将输入框改为单选框



description中的AssociationProperty属性可以调用系统的输入控件




添加variable段落可以为模板提供用户输入参数的界面



variable段落的格式为variable 参数名称{属性名1=属性值1...}



variable段落中可以定义type和default等属性



resource引用variable时可以使用var.参数名称的格式



variable的description的属性可以使用JSON格式进行更加详细的配置



variable的description的JSON格式配置的前后需要添加<<EOT和EOT



description中的Label属性可以为输入界面定义提示



description中的MinLength和MaxLength可以对输入框进行限制



description中的AllowedValues属性可以将输入框改为单选框



description中的AssociationProperty属性可以调用系统的输入控件




添加variable段落可以为模板提供用户输入参数的界面



variable段落的格式为variable 参数名称{属性名1=属性值1...}



variable段落中可以定义type和default等属性



resource引用variable时可以使用var.参数名称的格式



variable的description的属性可以使用JSON格式进行更加详细的配置



variable的description的JSON格式配置的前后需要添加<<EOT和EOT



description中的Label属性可以为输入界面定义提示



description中的MinLength和MaxLength可以对输入框进行限制



description中的AllowedValues属性可以将输入框改为单选框



description中的AssociationProperty属性可以调用系统的输入控件




添加variable段落可以为模板提供用户输入参数的界面



variable段落的格式为variable 参数名称{属性名1=属性值1...}



variable段落中可以定义type和default等属性



resource引用variable时可以使用var.参数名称的格式



variable的description的属性可以使用JSON格式进行更加详细的配置



variable的description的JSON格式配置的前后需要添加<<EOT和EOT



description中的Label属性可以为输入界面定义提示



description中的MinLength和MaxLength可以对输入框进行限制



description中的AllowedValues属性可以将输入框改为单选框



description中的AssociationProperty属性可以调用系统的输入控件




添加variable段落可以为模板提供用户输入参数的界面



variable段落的格式为variable 参数名称{属性名1=属性值1...}



variable段落中可以定义type和default等属性



resource引用variable时可以使用var.参数名称的格式



variable的description的属性可以使用JSON格式进行更加详细的配置



variable的description的JSON格式配置的前后需要添加<<EOT和EOT



description中的Label属性可以为输入界面定义提示



description中的MinLength和MaxLength可以对输入框进行限制



description中的AllowedValues属性可以将输入框改为单选框



description中的AssociationProperty属性可以调用系统的输入控件




添加variable段落可以为模板提供用户输入参数的界面



variable段落的格式为variable 参数名称{属性名1=属性值1...}



variable段落中可以定义type和default等属性



resource引用variable时可以使用var.参数名称的格式



variable的description的属性可以使用JSON格式进行更加详细的配置



variable的description的JSON格式配置的前后需要添加<<EOT和EOT



description中的Label属性可以为输入界面定义提示



description中的MinLength和MaxLength可以对输入框进行限制



description中的AllowedValues属性可以将输入框改为单选框



description中的AssociationProperty属性可以调用系统的输入控件




添加variable段落可以为模板提供用户输入参数的界面



variable段落的格式为variable 参数名称{属性名1=属性值1...}



variable段落中可以定义type和default等属性



resource引用variable时可以使用var.参数名称的格式



variable的description的属性可以使用JSON格式进行更加详细的配置



variable的description的JSON格式配置的前后需要添加<<EOT和EOT



description中的Label属性可以为输入界面定义提示



description中的MinLength和MaxLength可以对输入框进行限制



description中的AllowedValues属性可以将输入框改为单选框



description中的AssociationProperty属性可以调用系统的输入控件




添加variable段落可以为模板提供用户输入参数的界面



variable段落的格式为variable 参数名称{属性名1=属性值1...}



variable段落中可以定义type和default等属性



resource引用variable时可以使用var.参数名称的格式



variable的description的属性可以使用JSON格式进行更加详细的配置



variable的description的JSON格式配置的前后需要添加<<EOT和EOT



description中的Label属性可以为输入界面定义提示



description中的MinLength和MaxLength可以对输入框进行限制



description中的AllowedValues属性可以将输入框改为单选框



description中的AssociationProperty属性可以调用系统的输入控件




添加variable段落可以为模板提供用户输入参数的界面



variable段落的格式为variable 参数名称{属性名1=属性值1...}



variable段落中可以定义type和default等属性



resource引用variable时可以使用var.参数名称的格式



variable的description的属性可以使用JSON格式进行更加详细的配置



variable的description的JSON格式配置的前后需要添加<<EOT和EOT



description中的Label属性可以为输入界面定义提示



description中的MinLength和MaxLength可以对输入框进行限制



description中的AllowedValues属性可以将输入框改为单选框



description中的AssociationProperty属性可以调用系统的输入控件



如何根据动态参数创建云网络资源?

小云仔细阅读了老王给的Terraform脚本后说到:“这样就可以使用Terraform来调用系统界面,从零创建云上资源了,不过根据我以前的运维经验,大部分的情况下VPC资源都是创建好的,有没有什么办法可以在已有的VPC上创建交换机呢?”

“其实在生产环境中使用脚本,要考虑各种各样的情况,你刚才提到的VPC就是一个最典型的例子。为了能兼容不同的环境。Terrform提供了表达式来做一些简单的逻辑判断,通过逻辑判断就可以让脚本根据用户的不同输入执行不同的流程。”老王说到。

“以你今天的部署任务来说,就需要考虑是否创建VPC,然后需要在VPC中创建交换机。为接下来创建ECS做准备。在这种情况下我们可以总结一下脚本的编写要求。”


为了兼容不同的网络环境,我们设置一个开关来选择是创建VPC还是使用现有VPC



在新创建VPC模式中,根据输入的cidr创建交换机



在选定已有VPC模式中,根据VPC的cidr创建交换机



为了兼容不同的网络环境,我们设置一个开关来选择是创建VPC还是使用现有VPC



在新创建VPC模式中,根据输入的cidr创建交换机



在选定已有VPC模式中,根据VPC的cidr创建交换机




为了兼容不同的网络环境,我们设置一个开关来选择是创建VPC还是使用现有VPC



在新创建VPC模式中,根据输入的cidr创建交换机



在选定已有VPC模式中,根据VPC的cidr创建交换机




为了兼容不同的网络环境,我们设置一个开关来选择是创建VPC还是使用现有VPC



在新创建VPC模式中,根据输入的cidr创建交换机



在选定已有VPC模式中,根据VPC的cidr创建交换机




创建是否创建VPC按钮

  1. 在资源栈中页面中,使用新资源创建资源栈,选择Terrform模板格式
  2. 首先创建一个bool类型的变量whether_create_vpc。我们在main.tf文件中输入如下内容:
variable "whether_create_vpc" {
  type        = bool
  description = <<EOT
  {
    "Label": {
      "zh-cn": "是否新建VPC",
      "en": "WhetherCreateVpc"
    }
  }
  EOT
  default     = true
}
  1. 输入完毕后,按下一步按钮。会发现bool类型的变量,可以生成一个开关类型的控件。


企业级ECS集群构建_输入框_29

添加图片注释,不超过 140 字(可选)



2. 创建VPC选择控件

  1. 接下来创建一个string类型的变量vpc_id,按上一步按钮返回编辑界面。继续编辑main.tf
  2. 然后通过AssociationProperty属性,将这个变量和界面ALIYUN::ECS::VPC::VPCId结合
  3. 我们在main.tf文件中继续编辑,追加如下内容:
variable "vpc_id" {
  type        = string
  default     = null
  description = <<EOT
  {
    "Type": "String",
    "Default": "",
    "Label": {
      "en": "VPC ID",
      "zh-cn": "专有网络VPC实例ID"
    },    
    "AssociationProperty": "ALIYUN::ECS::VPC::VPCId"
  }
  EOT
}
  1. 输入完毕后,按下一步按钮。会发现通过下拉框可以选择已经存在的VPC:


企业级ECS集群构建_输入框_30

添加图片注释,不超过 140 字(可选)



3. 创建新VPC控件

  1. 接下来我们将vpc_id变量和whether_create_vpc变量进行关联,只有在whether_create_vpc为false的时候才显示vpc_id控件。
  2. 控件的关联可以使用AssociationPropertyMetadata.Visible.Condition属性来控制是否显示。
  3. 使用Fn::Equals函数可以对变量的值进判断。
  4. 在嵌入的ROS模板中,如果需要引用variable变量,可以使用$${变量名}的方式。
  5. 我们在main.tf文件中继续编辑,修改vpc_id变量的定义。
variable "vpc_id" {
  type        = string
  default     = null
  description = <<EOT
  {
    "Type": "String",
    "Default": "",
    "Label": {
      "en": "VPC ID",
      "zh-cn": "专有网络VPC实例ID"
    },    
    "AssociationProperty": "ALIYUN::ECS::VPC::VPCId",
    "AssociationPropertyMetadata": {
      "Visible": {
        "Condition": {
          "Fn::Equals": [
            "$${whether_create_vpc}",
            false
          ]
        }
      }
    }
  }
  EOT
}
  1. 输入完毕后,按下一步按钮。会发现我们可以根据whether_create_vpc来控制是否显示vpc_id控件。


企业级ECS集群构建_输入框_31

添加图片注释,不超过 140 字(可选)



4. 创建选择已有VPC控件

  1. 在上一个步骤中我们创建了一个VPC选择控件,接下来我们再来添加新建VPC时所需要的控件。
  2. 新建VPC需要vpc_cidr和vpc_name两个变量,这两个变量也需要和whether_create_vpc关联。
  3. 我们在main.tf文件中继续编辑,添加vpc_cidr和vpc_name变量的定义。
variable "vpc_name" {
  type        = string
  default     = "VPC名称"
  description = <<EOT
    {
      "Label": {
        "en": "VPC Name",
        "zh-cn": "VPC名称"
      },
      "MinLength": 2,
      "MaxLength": 128,
      "AssociationPropertyMetadata": {
        "Visible": {
          "Condition": {
            "Fn::Equals": [
              "$${whether_create_vpc}",
              true
            ]
          }
        }
      }
    }
  EOT
}

variable "vpc_cidr" {
  type        = string
  default     = "192.168.0.0/16"
  description = <<EOT
    {
      "Label": {
        "en": "VPC cidr",
        "zh-cn": "VPC CIDR"
      },
      "AllowedValues": [
        "10.0.0.0/8",
        "172.16.0.0/12",
        "192.168.0.0/16"
      ],
      "AssociationPropertyMetadata": {
        "Visible": {
          "Condition": {
            "Fn::Equals": [
              "$${whether_create_vpc}",
              true
            ]
          }
        }
      }
    }
  EOT
}

resource "alicloud_vpc" "ros_vpc" {
  vpc_name = var.vpc_name
  cidr_block = var.vpc_cidr
}
  1. 输入完毕后,按下一步按钮。会发现我们可以根据whether_create_vpc来进行控件的切换


企业级ECS集群构建_输入框_32

添加图片注释,不超过 140 字(可选)



5. 创建交换机控件

  1. 添加交换机地域和命令控件。
  2. 我们在main.tf文件中继续编辑,添加vswitch_name和zone_id变量的定义。
variable "zone_id" {
  type        = string
  description = <<EOT
  {
    "Label": {
      "en": "Availability Zone",
      "zh-cn": "可用区"
    },
    "AssociationProperty": "ALIYUN::ECS::Instance::ZoneId"
  }
  EOT
}

variable "vswitch_name" {
  type        = string
  default     = "交换机名称"
  description = <<EOT
  {
    "Label": {
      "en": "VSwitch Name",
      "zh-cn": "交换机名称"
    },
    "MinLength": 2,
    "MaxLength": 128
  }
  EOT
}
  1. 接下来来添加交换机cidr输入控件,这时可以使用ALIYUN::VPC::VSwitch::CidrBlock属性控件。
  2. 在使用交换机cidr控件时,需要设置地域属性RegionId。这时我们可以使用ALIYUN::Region来获得地域信息。
  3. 除了地域之外,交换机cidr控件还需要设置VpcId和VpcCidrBlock。这两个属性,可以从vpc_id和vpc_cidr两个参数中获得。
  4. 由于新建VPC和选择已有VPC时,交换机cidr的合规性检查逻辑不同,因此此处我们创建两个控件。然后根据whether_create_vpc来进行控件的切换。
  5. 我们在main.tf文件中继续编辑,添加两个交换机cird控件。create_vswitch_cidr和exist_vswitch_cidr
variable "create_vswitch_cidr" {
  type        = string
  description = <<EOT
  {
    "Label": {
      "en": "VSwitch cidr",
      "zh-cn": "交换机CIDR"
    },
    "Default": "192.168.0.0/24",
    "AssociationProperty": "ALIYUN::VPC::VSwitch::CidrBlock",
    "AssociationPropertyMetadata": {
      "RegionId": "$${ALIYUN::Region}",
      "VpcCidrBlock": "$${vpc_cidr}",
      "Visible": {
        "Condition": {
          "Fn::Equals": [
            "$${whether_create_vpc}",
            true
          ]
        }
      }
    }
  }
  EOT
}

variable "exist_vswitch_cidr" {
  type        = string
  description = <<EOT
  {
    "Label": {
      "en": "VSwitch cidr",
      "zh-cn": "交换机CIDR"
    },
    "Default": "192.168.0.0/24",
    "AssociationProperty": "ALIYUN::VPC::VSwitch::CidrBlock",
    "AssociationPropertyMetadata": {
      "RegionId": "$${ALIYUN::Region}",
      "VpcId": "$${vpc_id}",
      "VpcCidrBlock": "$${vpc_cidr}",
      "Visible": {
        "Condition": {
          "Fn::Equals": [
            "$${whether_create_vpc}",
            false
          ]
        }
      }
    }
  }
  EOT
}

resource "alicloud_vswitch" "ros_vsw" {
  vswitch_name = var.vswitch_name
  zone_id = var.zone_id
  vpc_id = var.whether_create_vpc ? alicloud_vpc.ros_vpc.id : var.vpc_id
  cidr_block = var.whether_create_vpc ? var.create_vswitch_cidr : var.exist_vswitch_cidr
}

6. 配置参数创建资源

  1. 模板文件创建完成后,我们点击下一步按钮。可以看到VPC和交换机的配置页面。


企业级ECS集群构建_配置文件_33

添加图片注释,不超过 140 字(可选)



企业级ECS集群构建_输入框_34

添加图片注释,不超过 140 字(可选)


  1. 完成属性配置之后,点击创建按钮。稍等片刻即可创建资源。


小云仔细的阅读了一下代码老王提供的variable代码。做了如下的工作总结:


为variable指定不同的type类型,可以更改输入控件的类型



在variable的description属性的JSON配置中,可以使用$${参数名}的方式来引用其他的variable



description属性的JSON配置中,可以在AssociationPropertyMetadata属性中,做进一步的配置



如果description指定了AssociationProperty调用系统界面,AssociationPropertyMetadata可以对系统界面进行配置



在AssociationPropertyMetadata属性中,还可以使用Visible来控制该控件是否被显示



在Visible属性中,可以使用Fn::Equals方式进行逻辑判断。实现根据属性值选择是否显示控件



在terraform中可以使用?:三项算符进行逻辑判断



为variable指定不同的type类型,可以更改输入控件的类型



在variable的description属性的JSON配置中,可以使用$${参数名}的方式来引用其他的variable



description属性的JSON配置中,可以在AssociationPropertyMetadata属性中,做进一步的配置



如果description指定了AssociationProperty调用系统界面,AssociationPropertyMetadata可以对系统界面进行配置



在AssociationPropertyMetadata属性中,还可以使用Visible来控制该控件是否被显示



在Visible属性中,可以使用Fn::Equals方式进行逻辑判断。实现根据属性值选择是否显示控件



在terraform中可以使用?:三项算符进行逻辑判断




为variable指定不同的type类型,可以更改输入控件的类型



在variable的description属性的JSON配置中,可以使用$${参数名}的方式来引用其他的variable



description属性的JSON配置中,可以在AssociationPropertyMetadata属性中,做进一步的配置



如果description指定了AssociationProperty调用系统界面,AssociationPropertyMetadata可以对系统界面进行配置



在AssociationPropertyMetadata属性中,还可以使用Visible来控制该控件是否被显示



在Visible属性中,可以使用Fn::Equals方式进行逻辑判断。实现根据属性值选择是否显示控件



在terraform中可以使用?:三项算符进行逻辑判断




为variable指定不同的type类型,可以更改输入控件的类型



在variable的description属性的JSON配置中,可以使用$${参数名}的方式来引用其他的variable



description属性的JSON配置中,可以在AssociationPropertyMetadata属性中,做进一步的配置



如果description指定了AssociationProperty调用系统界面,AssociationPropertyMetadata可以对系统界面进行配置



在AssociationPropertyMetadata属性中,还可以使用Visible来控制该控件是否被显示



在Visible属性中,可以使用Fn::Equals方式进行逻辑判断。实现根据属性值选择是否显示控件



在terraform中可以使用?:三项算符进行逻辑判断




为variable指定不同的type类型,可以更改输入控件的类型



在variable的description属性的JSON配置中,可以使用$${参数名}的方式来引用其他的variable



description属性的JSON配置中,可以在AssociationPropertyMetadata属性中,做进一步的配置



如果description指定了AssociationProperty调用系统界面,AssociationPropertyMetadata可以对系统界面进行配置



在AssociationPropertyMetadata属性中,还可以使用Visible来控制该控件是否被显示



在Visible属性中,可以使用Fn::Equals方式进行逻辑判断。实现根据属性值选择是否显示控件



在terraform中可以使用?:三项算符进行逻辑判断




为variable指定不同的type类型,可以更改输入控件的类型



在variable的description属性的JSON配置中,可以使用$${参数名}的方式来引用其他的variable



description属性的JSON配置中,可以在AssociationPropertyMetadata属性中,做进一步的配置



如果description指定了AssociationProperty调用系统界面,AssociationPropertyMetadata可以对系统界面进行配置



在AssociationPropertyMetadata属性中,还可以使用Visible来控制该控件是否被显示



在Visible属性中,可以使用Fn::Equals方式进行逻辑判断。实现根据属性值选择是否显示控件



在terraform中可以使用?:三项算符进行逻辑判断




为variable指定不同的type类型,可以更改输入控件的类型



在variable的description属性的JSON配置中,可以使用$${参数名}的方式来引用其他的variable



description属性的JSON配置中,可以在AssociationPropertyMetadata属性中,做进一步的配置



如果description指定了AssociationProperty调用系统界面,AssociationPropertyMetadata可以对系统界面进行配置



在AssociationPropertyMetadata属性中,还可以使用Visible来控制该控件是否被显示



在Visible属性中,可以使用Fn::Equals方式进行逻辑判断。实现根据属性值选择是否显示控件



在terraform中可以使用?:三项算符进行逻辑判断




为variable指定不同的type类型,可以更改输入控件的类型



在variable的description属性的JSON配置中,可以使用$${参数名}的方式来引用其他的variable



description属性的JSON配置中,可以在AssociationPropertyMetadata属性中,做进一步的配置



如果description指定了AssociationProperty调用系统界面,AssociationPropertyMetadata可以对系统界面进行配置



在AssociationPropertyMetadata属性中,还可以使用Visible来控制该控件是否被显示



在Visible属性中,可以使用Fn::Equals方式进行逻辑判断。实现根据属性值选择是否显示控件



在terraform中可以使用?:三项算符进行逻辑判断




如何通过更改集更新模板?

小云认真的看完了老王给的模板案例之后说:“掌握了输入参数和表达式的能力。我应该有信心来用Terraform进行资源管理了。不过还有一些小地方感觉用起来不是很友好。比如刚才的资源栈案例有6个输入控件,但是控件之间的顺序好像是随机的,也没有分类管理。看起来很乱。这有什么办法可以解决吗?”

“你提的问题非常好,刚才的例子里面,其实参数并不算多,一些复杂的模板可能会有几十个参数。如果没有分类配置起来会非常的痛苦。所以Terraform在设计的时候也考虑到了这个问题。我们可以通过ParameterGroups来对参数进行分组”老王笑道。

“另外,更新资源栈的操作中,除了刚才我给你演示的直接更新资源栈的方法,还有一种使用更改集的方法来升级资源栈。这次我用这种方式来给你演示。”老王补充道。

更改集入门

  1. 在资源栈列表中点击已经创建的资源栈。在资源栈详情中,选择更改集选项卡,然后我们点击创建更改集按钮。会进入创建更改集页面。


企业级ECS集群构建_配置文件_35

添加图片注释,不超过 140 字(可选)



企业级ECS集群构建_配置文件_36

添加图片注释,不超过 140 字(可选)



企业级ECS集群构建_ci_37

添加图片注释,不超过 140 字(可选)



  1. 我们继续点击选择已有模板。然后点击输入模板。这时我就能看到之前创建的资源模板了。接下来你就可以在这里进行修改。


企业级ECS集群构建_输入框_38

添加图片注释,不超过 140 字(可选)



2. 创建.metadata文件

接下来我们在Terrform中添加一个.metadata文件,通过这个文件来指定输入参数的顺序。

  1. 我们点击文件目录旁边的+,然后点击创建文件菜单项。


企业级ECS集群构建_输入框_39

添加图片注释,不超过 140 字(可选)


  1. 在弹出的对话框中输入.metadata。然后点击确认按钮。


企业级ECS集群构建_ci_40

添加图片注释,不超过 140 字(可选)


  1. 文件创建成功后,在目录栏中会看到生成了新的文件。我们点击该文件,在编辑框会打开该文件的编辑内容。


企业级ECS集群构建_ci_41

添加图片注释,不超过 140 字(可选)


  1. 我们在.metadata文件的编辑框中,输入如下内容。
{
  "ALIYUN::ROS::Interface": {
    "ParameterGroups": [
      {
        "Parameters": [
          "whether_create_vpc",
          "vpc_id",
          "vpc_name",
          "vpc_cidr"
        ],
        "Label": {
          "default": {
            "zh-cn": "VPC属性配置"
          }
        }
      },
      {
        "Parameters": [
          "vswitch_name",
          "zone_id",
          "create_vswitch_cidr",
          "exist_vswitch_cidr"
        ],
        "Label": {
          "default": {
            "zh-cn": "交换机属性配置"
          }
        }
      }
    ]
  }
}
  1. 文件编辑完成之后,点击下一步按钮。会进入配置模板参数页面。在界面中我们发现输入控件已经进行了排序和分类。同时每一个分类都有自己的标签


企业级ECS集群构建_配置文件_42

添加图片注释,不超过 140 字(可选)


小云仔细分析了代码后说到:“我明白了,是Metadata.ALIYUN::ROS::Interface.ParameterGroups属性将输入参数进行了分组。”

3. 创建更改集

“接下来我们来真正的通过更改集来更新资源栈。”老王说到

  1. 我们在参数编辑框中,对VPC和交换机的名称做一个修改。修改完毕后,我们点击创建更改集按钮


企业级ECS集群构建_配置文件_43

添加图片注释,不超过 140 字(可选)


  1. 在等待一段时间后,回到更改集选项卡,点击刷新按钮之后,会出现一个新的更改集。


企业级ECS集群构建_ci_44

添加图片注释,不超过 140 字(可选)


  1. 更新集创建完成后,我们回到VPC控制台,会发现VPC和交换机的名称都没有改变。


企业级ECS集群构建_输入框_45

添加图片注释,不超过 140 字(可选)



企业级ECS集群构建_输入框_46

添加图片注释,不超过 140 字(可选)


4. 执行更改集

更改集创建之后,小云发现VPC和交换机的名称并没有改变。于是向老王问道:“更改集的作用是什么呢?更改集创建了,资源也没有修改,为什么不接直接更新脚本呢?”

老王回答道:“更改集创建后还需要执行更改集才可以完成资源的更新,更改集的好处是可以将编写和执行操作分开,使用新模板更新资源栈前,通过更改集查看即将产生的变更(比如新增了哪些资源、删除了哪些资源、对哪些资源的特定属性做了修改),确认无误后再执行,更好的保障更新能够顺利安全的进行。”

  1. 小云点击了更改集列表后面的执行按钮。


企业级ECS集群构建_输入框_47

添加图片注释,不超过 140 字(可选)


  1. 等待一段时候后,刷新资源栈信息,会发现资源栈的状态变更为更新成功。


企业级ECS集群构建_输入框_48

添加图片注释,不超过 140 字(可选)


  1. 这时再回到更改集页面,发现执行成功的更改集已经消失


企业级ECS集群构建_输入框_49

添加图片注释,不超过 140 字(可选)


  1. 回到VPC控制台,发现VPC和交换机的名称都已经更新了


企业级ECS集群构建_配置文件_50

添加图片注释,不超过 140 字(可选)



企业级ECS集群构建_ci_51

添加图片注释,不超过 140 字(可选)



“通过更改集确实可以减少架构升级的焦虑,这样可以先通过更改集做好调试。确认无误后,再执行更新操作。”小云感叹道。

如何创建安全组和安全组规则?

小云仔细阅读了老王写的脚本后说到:“看来通过表达式和显示控制功能,基本上就可以应付绝大多数的场景了。接下来我也尝试自己写一些简单的脚本吧。您看我先从什么地方入手比较合适?”

“你可以先在我的脚本的基础上,添加一些稍微复杂的内容,比如安全组和安全组规则。”,老王说到。

创建安全组名称控件

小云首先准备安全组的相关变量和资源。在添加安全组时,只需要设一个安全组名称变量security_group_name,安全组资源则使用security_group_name类型

  1. 小云打开了main.tf文件,输入如下内容,创建VPC和交换机资源。
variable "vpc_name" {
  type        = string
  default     = "VPC名称"
  description = <<EOT
  {
    "Label": {
      "en": "VPC Name",
      "zh-cn": "VPC名称"
    },
    "MinLength": 2,
    "MaxLength": 128
  }
EOT
}

variable "vpc_cidr" {
  type        = string
  default     = "192.168.0.0/16"
  description = <<EOT
    {
      "Label": {
        "en": "VPC cidr",
        "zh-cn": "VPC CIDR"
      },
      "AllowedValues": [
        "10.0.0.0/8",
        "172.16.0.0/12",
        "192.168.0.0/16"
      ]
    }
  EOT
}

resource "alicloud_vpc" "ros_vpc" {
  vpc_name = var.vpc_name
  cidr_block = var.vpc_cidr
}

variable "zone_id" {
  type        = string
  description = <<EOT
  {
    "Label": {
      "en": "Availability Zone",
      "zh-cn": "可用区"
    },
    "AssociationProperty": "ALIYUN::ECS::Instance::ZoneId"
  }
  EOT
}

variable "vswitch_name" {
  type        = string
  default     = "交换机名称"
  description = <<EOT
  {
    "Label": {
      "en": "VSwitch Name",
      "zh-cn": "交换机名称"
    },
    "MinLength": 2,
    "MaxLength": 128
  }
  EOT
}

variable "vswitch_cidr" {
  type        = string
  description = <<EOT
  {
    "Label": {
      "en": "VSwitch cidr",
      "zh-cn": "交换机CIDR"
    },
    "Default": "192.168.0.0/24",
    "AssociationProperty": "ALIYUN::VPC::VSwitch::CidrBlock",
    "AssociationPropertyMetadata": {
      "RegionId": "$${ALIYUN::Region}",
      "VpcCidrBlock": "$${vpc_cidr}"
    }
  }
  EOT
}

resource "alicloud_vswitch" "ros_vsw" {
  vswitch_name = var.vswitch_name
  zone_id = var.zone_id
  vpc_id = alicloud_vpc.ros_vpc.id
  cidr_block = var.vswitch_cidr
}
  1. 小云继续编辑main.tf文件,并在该文件中追加了如下内容。
variable "security_group_name" {
  type        = string
  default     = "安全组名称"
  description = <<EOT
  {
    "Label": {
      "en": "VSwitch Name",
      "zh-cn": "安全组名称"
    },
    "MinLength": 2,
    "MaxLength": 128
  }
  EOT
}

resource "alicloud_security_group" "ros_sg" {
  vpc_id = alicloud_vpc.ros_vpc.id
  name   = var.security_group_name
}

2. 列表界面实现安全组规则输入

接下来小云又准备为安全组添加规则。默认的安全组规则开放22,80,443三个端口。一条安全组规则的配置选项很多,包括协议、端口、cidr、优先级等。一个安全组中又可以包含多条安全组规则。

小云仔细的阅读了Terraform的文档,发现对于复杂配项目可以使用嵌套类型来定义。对于多条安全规则的编辑,可使用列表编辑界面进行编辑。

  1. 小云继续编辑main.tf文件,并在该文件中追加了如下内容。
variable "security_group_rules" {
  description = <<EOT
  {
    "Label": {
      "en": "security group rules",
      "zh-cn": "安全组规则"
    },
    "Type": "Json",
    "AssociationProperty": "List[Parameters]",
    "AssociationPropertyMetadata": {
      "Parameters": {
        "accept": {
          "Type": "Boolean",
          "Label": {
            "zh-cn": "是否允许访问"
          }
        },
        "port": {
          "Type": "Number",
          "Label": {
            "zh-cn": "端口号"
          },
          "MinValue": 1,
          "MaxValue": 65535,
          "AllowedPattern": "\\d"
        },
        "description": {
          "Type": "String",
          "Label": {
            "zh-cn": "规则表述"
          },
          "MinLength": 0,
          "MaxLength": 64
        }
      },
      "ListMetadata": {
        "ShowHeader": true,
        "ShowRemove": true,
        "ShowAddition": true,
        "Order": [
          "accept",
          "port",
          "description"
        ]
      }
    },
    "Default": [
      {
        "accept": true,
        "port": 22,
        "description": "SSH"
      },
      {
        "accept": true,
        "port": 80,
        "description": "HTTP"
      },
      {
        "accept": true,
        "port": 443,
        "description": "HTTPS"
      }
    ]
  }
  EOT
}

resource "alicloud_security_group_rule" "ros_sg_rule" {
  security_group_id = alicloud_security_group.ros_sg.id
  count             = length(var.security_group_rules)
  type              = "ingress"
  priority          = 1
  ip_protocol       = "tcp"
  nic_type          = "intranet"
  cidr_ip           = "0.0.0.0/0"
  policy            = var.security_group_rules[count.index].accept ? "accept" : "drop"
  port_range        = join("/", [var.security_group_rules[count.index].port, var.security_group_rules[count.index].port])
  description       = var.security_group_rules[count.index].description
}

3. 修改.metadata并配置编辑界面

  1. main.tf文件编辑完成之后,小云继续添加安全组的显示分组,新建.metadata文件,然后修改文件内容为如下
{
  "ALIYUN::ROS::Interface": {
    "ParameterGroups": [
      {
        "Parameters": [
          "vpc_name",
          "vpc_cidr"
        ],
        "Label": {
          "default": {
            "zh-cn": "VPC属性配置"
          }
        }
      },
      {
        "Parameters": [
          "vswitch_name",
          "zone_id",
          "vswitch_cidr"
        ],
        "Label": {
          "default": {
            "zh-cn": "交换机属性配置"
          }
        }
      },
      {
        "Parameters": [
          "security_group_name",
          "security_group_rules"
        ],
        "Label": {
          "default": {
            "zh-cn": "安全组属性配置"
          }
        }
      }
    ]
  }
}
  1. 文件修改完毕后,小云点击下一步按钮。出现了模板配置界面。


企业级ECS集群构建_配置文件_52

添加图片注释,不超过 140 字(可选)



企业级ECS集群构建_输入框_53

添加图片注释,不超过 140 字(可选)



企业级ECS集群构建_ci_54

添加图片注释,不超过 140 字(可选)



小云总结了列表控件的几个常见的用法:


将AssociationProperty设置为List[Parameters]可以显示列表控件



AssociationPropertyMetadata中的Parameters可以用来具体定义列表中参数的类型



AssociationPropertyMetadata中的ListMetadata可以用来定义列表的显示形式



AssociationPropertyMetadata中的Default可以用来定义界面的默认值,默认值为数组类型



在terraform的resource段落中,可以使用count函数来获取List类型的数据长度



使用count函数之后,可以使用类似var.security_group_rules[count.index]的语法来获得List中的一个元素



terraform还提供了join字符串函数。可以将不同类型的参数组合成字符串。



将AssociationProperty设置为List[Parameters]可以显示列表控件



AssociationPropertyMetadata中的Parameters可以用来具体定义列表中参数的类型



AssociationPropertyMetadata中的ListMetadata可以用来定义列表的显示形式



AssociationPropertyMetadata中的Default可以用来定义界面的默认值,默认值为数组类型



在terraform的resource段落中,可以使用count函数来获取List类型的数据长度



使用count函数之后,可以使用类似var.security_group_rules[count.index]的语法来获得List中的一个元素



terraform还提供了join字符串函数。可以将不同类型的参数组合成字符串。




将AssociationProperty设置为List[Parameters]可以显示列表控件



AssociationPropertyMetadata中的Parameters可以用来具体定义列表中参数的类型



AssociationPropertyMetadata中的ListMetadata可以用来定义列表的显示形式



AssociationPropertyMetadata中的Default可以用来定义界面的默认值,默认值为数组类型



在terraform的resource段落中,可以使用count函数来获取List类型的数据长度



使用count函数之后,可以使用类似var.security_group_rules[count.index]的语法来获得List中的一个元素



terraform还提供了join字符串函数。可以将不同类型的参数组合成字符串。




将AssociationProperty设置为List[Parameters]可以显示列表控件



AssociationPropertyMetadata中的Parameters可以用来具体定义列表中参数的类型



AssociationPropertyMetadata中的ListMetadata可以用来定义列表的显示形式



AssociationPropertyMetadata中的Default可以用来定义界面的默认值,默认值为数组类型



在terraform的resource段落中,可以使用count函数来获取List类型的数据长度



使用count函数之后,可以使用类似var.security_group_rules[count.index]的语法来获得List中的一个元素



terraform还提供了join字符串函数。可以将不同类型的参数组合成字符串。




将AssociationProperty设置为List[Parameters]可以显示列表控件



AssociationPropertyMetadata中的Parameters可以用来具体定义列表中参数的类型



AssociationPropertyMetadata中的ListMetadata可以用来定义列表的显示形式



AssociationPropertyMetadata中的Default可以用来定义界面的默认值,默认值为数组类型



在terraform的resource段落中,可以使用count函数来获取List类型的数据长度



使用count函数之后,可以使用类似var.security_group_rules[count.index]的语法来获得List中的一个元素



terraform还提供了join字符串函数。可以将不同类型的参数组合成字符串。




将AssociationProperty设置为List[Parameters]可以显示列表控件



AssociationPropertyMetadata中的Parameters可以用来具体定义列表中参数的类型



AssociationPropertyMetadata中的ListMetadata可以用来定义列表的显示形式



AssociationPropertyMetadata中的Default可以用来定义界面的默认值,默认值为数组类型



在terraform的resource段落中,可以使用count函数来获取List类型的数据长度



使用count函数之后,可以使用类似var.security_group_rules[count.index]的语法来获得List中的一个元素



terraform还提供了join字符串函数。可以将不同类型的参数组合成字符串。




将AssociationProperty设置为List[Parameters]可以显示列表控件



AssociationPropertyMetadata中的Parameters可以用来具体定义列表中参数的类型



AssociationPropertyMetadata中的ListMetadata可以用来定义列表的显示形式



AssociationPropertyMetadata中的Default可以用来定义界面的默认值,默认值为数组类型



在terraform的resource段落中,可以使用count函数来获取List类型的数据长度



使用count函数之后,可以使用类似var.security_group_rules[count.index]的语法来获得List中的一个元素



terraform还提供了join字符串函数。可以将不同类型的参数组合成字符串。




将AssociationProperty设置为List[Parameters]可以显示列表控件



AssociationPropertyMetadata中的Parameters可以用来具体定义列表中参数的类型



AssociationPropertyMetadata中的ListMetadata可以用来定义列表的显示形式



AssociationPropertyMetadata中的Default可以用来定义界面的默认值,默认值为数组类型



在terraform的resource段落中,可以使用count函数来获取List类型的数据长度



使用count函数之后,可以使用类似var.security_group_rules[count.index]的语法来获得List中的一个元素



terraform还提供了join字符串函数。可以将不同类型的参数组合成字符串。



如何查看和输出资源栈资源的信息?

1. 查看模板关联的资源

“还有另一个问题,现在模板文件得内容包含得资源越来越多了,我有什么办法可以看到模板关联的资源有哪些吗?”小云问道。

“这种情况可以使用资源栈的资源列表,接下来我来给你演示一下”老王说道。

老王点击了资源栈的资源选项卡。这里面显示了模板相关的所有资源,同时在资源的资源状态栏显示着创建成功。

企业级ECS集群构建_输入框_55

添加图片注释,不超过 140 字(可选)



“这种方式倒是非常简单,如果是使用已有的VPC会出现什么情况呢?”小云问道。

“等我创建一个克隆资源,给你演示一下”老王回答道。

2. 克隆资源栈

  1. 老王回到了资源栈的列表页面,点击创建好的资源栈的后面菜单展开按钮。然后点击克隆选项。


企业级ECS集群构建_配置文件_56

添加图片注释,不超过 140 字(可选)


  1. 在克隆页面中,ROS会根据之前的资源栈的模板生成新的资源栈,并进入配置页面。


企业级ECS集群构建_ci_57

添加图片注释,不超过 140 字(可选)



  1. 在配置界面中,我们选择不创建新的VPC,然后再VPC ID控件中选择一个已有的VPC。然后根据已有VPC的网段,配置交换机的网段,然后点击创建按钮。


企业级ECS集群构建_输入框_58

添加图片注释,不超过 140 字(可选)



企业级ECS集群构建_输入框_59

添加图片注释,不超过 140 字(可选)



企业级ECS集群构建_配置文件_60

添加图片注释,不超过 140 字(可选)



企业级ECS集群构建_ci_61

添加图片注释,不超过 140 字(可选)


  1. 等克隆的资源栈创建成功后,点击资源选项卡。会看到资源中并没有包含已有的VPC资源。


企业级ECS集群构建_输入框_62

添加图片注释,不超过 140 字(可选)


3. 执行结果输出

“有些资源虽然不是由模板创建的,但是和模板的关系还是很密切的,比如像刚才引用的VPC的信息。所以除了资源页面,还有没有什么办法可以输出这些资源的信息呢?”小云问道。

“这种情况,可以在Terraform脚本中使用output进行信息输出。”老王回答道。

  1. 我们在原有资源栈的添加一个更改集,在创建更改集中选择输入模板,然后打开main.tf文件。


企业级ECS集群构建_输入框_63

添加图片注释,不超过 140 字(可选)


  1. 在terraform中我们可以使用output段落来输入定制化的内容,我们在main.tf中追加如下内容。
output "vswitch_name" {
  value       = var.vswitch_name
  description = <<EOT
  {
    "Description": {
      "en": "VSwitch Name",
      "zh-cn": "交换机名称"
    }
  }
  EOT
}

output "vswitch_id" {
  value       = alicloud_vswitch.ros_vsw.id
  description = <<EOT
  {
    "Description": {
      "en": "VSwitch ID",
      "zh-cn": "交换机ID"
    }
  }
  EOT
}

output "vswitch_zone" {
  value       = alicloud_vswitch.ros_vsw.zone_id
  description = <<EOT
  {
    "Description": {
      "en": "VSwitch zone",
      "zh-cn": "交换机可用区"
    }
  }
  EOT
}
  1. 编辑完毕后按创建按钮,创建更改集,等更改集创建完毕后,再选择执行更改集。更改完成后,进入输出选项卡。这时我们可以看到交换机相关的配置信息了。


企业级ECS集群构建_配置文件_64

添加图片注释,不超过 140 字(可选)


4. output表达式的用法

“有output输出就方便很多了,这样可以把模板生成的资源的结构都输出出来,但是对于一些比较复杂的资源,比如创建VPC或者使用已有VPC,output有什么好办法吗?”小云问道。

“output同样支持表达式和函数,通过表达式就可以将复杂的模板配置解析成便于理解的文字了”老王说道。

  1. 在原有资源栈中继续添加更改集,在main.tf中追加如下内容。
output "vpc_mode" {
  value       = var.whether_create_vpc ? "创建新的VPC" : "使用已有VPC"
  description = <<EOT
  {
    "Description": {
      "en": "VPC ID",
      "zh-cn": "VPC ID"
    }
  }
  EOT
}

output "vpc_id" {
  value       = var.whether_create_vpc ? alicloud_vpc.ros_vpc[0].id : var.vpc_id
  description = <<EOT
  {
    "Description": {
      "en": "VPC ID",
      "zh-cn": "VPC ID"
    }
  }
  EOT
}

output "vswitch_cidr" {
  value       = var.whether_create_vpc ? var.create_vswitch_cidr : var.exist_vswitch_cidr
  description = <<EOT
  {
    "Description": {
      "en": "VSwitch CIDR",
      "zh-cn": "交换机网段"
    }
  }
  EOT
}
  1. 编辑完毕后,创建更改集,执行更改集。更改完成后,进入输出选项卡。这时我们可以看到交换机相关的配置信息了。


企业级ECS集群构建_配置文件_65

添加图片注释,不超过 140 字(可选)



小云总结了output的使用方式:


output段落的格式为output 名称{属性1=值}。



在output中,最重要的属性是value,该属性负责指定要输出的内容



value属性的值,可以引用variable,也可以引用resource。



description属性可以和variable一样,嵌入ROS模板。



在output中可以使用:三项目算符根据变量来进行逻辑判断。



output段落的格式为output 名称{属性1=值}。



在output中,最重要的属性是value,该属性负责指定要输出的内容



output段落的格式为output 名称{属性1=值}。



在output中,最重要的属性是value,该属性负责指定要输出的内容



value属性的值,可以引用variable,也可以引用resource。



description属性可以和variable一样,嵌入ROS模板。



在output中可以使用:三项目算符根据变量来进行逻辑判断。



output段落的格式为output 名称{属性1=值}。



在output中,最重要的属性是value,该属性负责指定要输出的内容




output段落的格式为output 名称{属性1=值}。



在output中,最重要的属性是value,该属性负责指定要输出的内容



value属性的值,可以引用variable,也可以引用resource。



description属性可以和variable一样,嵌入ROS模板。



在output中可以使用:三项目算符根据变量来进行逻辑判断。



output段落的格式为output 名称{属性1=值}。



在output中,最重要的属性是value,该属性负责指定要输出的内容




output段落的格式为output 名称{属性1=值}。



在output中,最重要的属性是value,该属性负责指定要输出的内容



value属性的值,可以引用variable,也可以引用resource。



description属性可以和variable一样,嵌入ROS模板。



在output中可以使用:三项目算符根据变量来进行逻辑判断。



output段落的格式为output 名称{属性1=值}。



在output中,最重要的属性是value,该属性负责指定要输出的内容




output段落的格式为output 名称{属性1=值}。



在output中,最重要的属性是value,该属性负责指定要输出的内容



value属性的值,可以引用variable,也可以引用resource。



description属性可以和variable一样,嵌入ROS模板。



在output中可以使用:三项目算符根据变量来进行逻辑判断。



output段落的格式为output 名称{属性1=值}。



在output中,最重要的属性是value,该属性负责指定要输出的内容




output段落的格式为output 名称{属性1=值}。



在output中,最重要的属性是value,该属性负责指定要输出的内容



value属性的值,可以引用variable,也可以引用resource。



description属性可以和variable一样,嵌入ROS模板。



在output中可以使用:三项目算符根据变量来进行逻辑判断。



output段落的格式为output 名称{属性1=值}。



在output中,最重要的属性是value,该属性负责指定要输出的内容




output段落的格式为output 名称{属性1=值}。



在output中,最重要的属性是value,该属性负责指定要输出的内容



value属性的值,可以引用variable,也可以引用resource。



description属性可以和variable一样,嵌入ROS模板。



在output中可以使用:三项目算符根据变量来进行逻辑判断。



output段落的格式为output 名称{属性1=值}。



在output中,最重要的属性是value,该属性负责指定要输出的内容




output段落的格式为output 名称{属性1=值}。



在output中,最重要的属性是value,该属性负责指定要输出的内容



value属性的值,可以引用variable,也可以引用resource。



description属性可以和variable一样,嵌入ROS模板。



在output中可以使用:三项目算符根据变量来进行逻辑判断。



output段落的格式为output 名称{属性1=值}。



在output中,最重要的属性是value,该属性负责指定要输出的内容




5. data段落的用法

“这样显示的内容就丰富多了,但是还有一个小问题,当我使用指定VPC的时候,变量中只有VPC的id,如果我想显示指定VPC的时候,有什么办法可以显示出来吗?”小云问道。

“这种情况,可以使用data段落来实现,data段落可以用来查询云上已经存在的资源。”,老王说道。

  1. 我们继续创建更改集,打开main.tf,并追加如下内容。
data "alicloud_vpcs" "vpcs_ds" {
  ids = [var.whether_create_vpc ? alicloud_vpc.ros_vpc[0].id : var.vpc_id]
}
  1. 在main.tf中继续追加如下内容。
output "vpc_name" {
  value       = data.alicloud_vpcs.vpcs_ds.names.0
  description = <<EOT
  {
    "Description": {
      "en": "VPC name",
      "zh-cn": "VPC 名称"
    }
  }
  EOT
}

output "vpc_cidr" {
  value       = data.alicloud_vpcs.vpcs_ds.vpcs.0.cidr_block
  description = <<EOT
  {
    "Description": {
      "en": "VPC CIDR",
      "zh-cn": "VPC 网段"
    }
  }
  EOT
}
  1. 保存,执行更改集之后。在输出选项卡中,出现了VPC的相关信息


企业级ECS集群构建_输入框_66

添加图片注释,不超过 140 字(可选)



小云总结了data的使用方式:


data的格式为data 类型 名称{筛选属性=筛选属性值}



不同的data数据类型指向一个类型的数据集,例如alicloud_vpcs指向当前地域的所有vpc。



通过data的筛选属性,可以筛选出数据集中的指定内容。例如使用ids=[id1, id2]的格式筛选出指定id的vpc



在data的筛选属性值中同样可以使用表达式。



在output中引用data时,使用data.类型.名称.子属性的方式。



data的属性一般都是数组。因此当我们需要访问其中一个元素时可以使用类似于data.alicloud_vpcs.vpcs_ds.vpcs.0.cidr_block的语法。



data的格式为data 类型 名称{筛选属性=筛选属性值}



不同的data数据类型指向一个类型的数据集,例如alicloud_vpcs指向当前地域的所有vpc。



通过data的筛选属性,可以筛选出数据集中的指定内容。例如使用ids=[id1, id2]的格式筛选出指定id的vpc



在data的筛选属性值中同样可以使用表达式。



在output中引用data时,使用data.类型.名称.子属性的方式。



data的属性一般都是数组。因此当我们需要访问其中一个元素时可以使用类似于data.alicloud_vpcs.vpcs_ds.vpcs.0.cidr_block的语法。




data的格式为data 类型 名称{筛选属性=筛选属性值}



不同的data数据类型指向一个类型的数据集,例如alicloud_vpcs指向当前地域的所有vpc。



通过data的筛选属性,可以筛选出数据集中的指定内容。例如使用ids=[id1, id2]的格式筛选出指定id的vpc



在data的筛选属性值中同样可以使用表达式。



在output中引用data时,使用data.类型.名称.子属性的方式。



data的属性一般都是数组。因此当我们需要访问其中一个元素时可以使用类似于data.alicloud_vpcs.vpcs_ds.vpcs.0.cidr_block的语法。




data的格式为data 类型 名称{筛选属性=筛选属性值}



不同的data数据类型指向一个类型的数据集,例如alicloud_vpcs指向当前地域的所有vpc。



通过data的筛选属性,可以筛选出数据集中的指定内容。例如使用ids=[id1, id2]的格式筛选出指定id的vpc



在data的筛选属性值中同样可以使用表达式。



在output中引用data时,使用data.类型.名称.子属性的方式。



data的属性一般都是数组。因此当我们需要访问其中一个元素时可以使用类似于data.alicloud_vpcs.vpcs_ds.vpcs.0.cidr_block的语法。




data的格式为data 类型 名称{筛选属性=筛选属性值}



不同的data数据类型指向一个类型的数据集,例如alicloud_vpcs指向当前地域的所有vpc。



通过data的筛选属性,可以筛选出数据集中的指定内容。例如使用ids=[id1, id2]的格式筛选出指定id的vpc



在data的筛选属性值中同样可以使用表达式。



在output中引用data时,使用data.类型.名称.子属性的方式。



data的属性一般都是数组。因此当我们需要访问其中一个元素时可以使用类似于data.alicloud_vpcs.vpcs_ds.vpcs.0.cidr_block的语法。




data的格式为data 类型 名称{筛选属性=筛选属性值}



不同的data数据类型指向一个类型的数据集,例如alicloud_vpcs指向当前地域的所有vpc。



通过data的筛选属性,可以筛选出数据集中的指定内容。例如使用ids=[id1, id2]的格式筛选出指定id的vpc



在data的筛选属性值中同样可以使用表达式。



在output中引用data时,使用data.类型.名称.子属性的方式。



data的属性一般都是数组。因此当我们需要访问其中一个元素时可以使用类似于data.alicloud_vpcs.vpcs_ds.vpcs.0.cidr_block的语法。




data的格式为data 类型 名称{筛选属性=筛选属性值}



不同的data数据类型指向一个类型的数据集,例如alicloud_vpcs指向当前地域的所有vpc。



通过data的筛选属性,可以筛选出数据集中的指定内容。例如使用ids=[id1, id2]的格式筛选出指定id的vpc



在data的筛选属性值中同样可以使用表达式。



在output中引用data时,使用data.类型.名称.子属性的方式。



data的属性一般都是数组。因此当我们需要访问其中一个元素时可以使用类似于data.alicloud_vpcs.vpcs_ds.vpcs.0.cidr_block的语法。