配置变量
实验步骤
创建 EC2 IAM 角色
导航到
IAM
在左侧菜单中,单击
角色
。单击创建角色
该按钮以创建新的 IAM 角色。在创建角色部分,为角色选择可信实体类型:
AWS 服务
使用案例:EC2
单击下一步
添加权限:现在,您可以看到策略列表。按名称
AdministratorAccess
搜索权限并添加。单击下一步
角色名称:输入
TERRAFORM_EC2
您已成功按名称 TERRAFORM_EC2 创建了一个 IAM 角色。
注意:您可以使用其他名称创建角色,然后将其附加到 EC2 实例
启动 EC2 实例
请确保您位于美国东部(弗吉尼亚北部)us-east-1 区域。
顶部菜单导航到 EC2
左侧面板,单击"实例",然后单击"启动新实例"。
(1)控制台启动实例
(2)选择系统镜像
(3)选择实例类型
(4)配置实例
实例数:输入
1
IAM角色:从列表中选择我们在上面创建的 IAM 角色。
将所有其他设置保留为默认值。单击"下一步:添加存储"
(5)添加存储
(6)添加标签
添加标签:点击添加标签按钮
键:
Name
值:
MyEC2Instance
点击
下一步:配置安全组
(7) 配置安全组
添加 SSH:
. 选择类型: 选择 SSH . 协议:TCP . 端口范围:22 . 源:选择"任何位置"
点击下一步
审核和启动
(8) 审核启动
检查所有选定的设置,无误点击启动
选择现有密钥对,确认并单击启动实例
环境配置
SSH 连接到 EC2 实例
以下命令切换到root权限。
sudo su
以下命令安装本实验所需软件。
yum install git -y
安装 Terraform: Install | Terraform | HashiCorp Developer
下载仓库代码模版部署
您需要使用
git clone https://github.com/hashicorp/learn-terraform-variables.git
命令将代码模版拉取到EC2实例中确保您这些文件在同一位置。
通过运行以下命令初始化 Terraform:
terraform init
注意:
terraform init
将检查所有插件依赖项并下载它们。查看生成计划,请运行以下命令:
terraform plan
创建在
main.tf
配置文件中声明的所有资源 ,请运行以下命令:
terraform apply
您将能够看到将要创建的资源,通过输入
yes
批准所有资源的创建。
terraform apply
命令最多可能需要 2 分钟才能创建资源。
参数配置
变量声明可以出现在配置文件中的任何位置。但是,我们建议将它们放入的单独文件中,以便用户更容易理解如何自定义配置。
要使用输入变量,首先在
variables.tf
中定义变量。
variable "aws_region" { description = "AWS region" type = string default = "us-west-2" }
变量块有三个可选参数。
说明:用于记录变量用途的简短说明。
类型:变量中包含的数据类型。
默认值:默认值。
我们建议为所有变量设置描述和类型,并在可行时设置默认值。
如果未为变量设置默认值,则必须先赋值,然后 Terraform 才能应用该配置。
Terraform 不支持未分配的变量。
变量值必须是文本值,并且不能使用资源属性、表达式或其他变量等计算值。
您可以使用
var.<variable_name>
引用配置中的变量。编辑提供程序块以使用新变量。
provider "aws" { - region = "us-west-2" + region = var.aws_region }
将变量的声明添加到
vpc_cidr_block
。
variable "vpc_cidr_block" { description = "CIDR block for VPC" type = string default = "10.0.0.0/16" }
现在,将 VPC CIDR 块的值替换为变量。
module "vpc" { source = "terraform-aws-modules/vpc/aws" version = "2.66.0" - cidr = "10.0.0.0/16" + cidr = var.vpc_cidr_block ## ... }
应用更新的配置。由于这些变量的默认值与替换它们的编码值相同,因此 Terraform 不会执行任何更改。
terraform apply
设置实例数
Terraform 还支持多种变量类型。
使用类型定义实例数。将以下内容添加到
variables.tf
variable "instance_count" { description = "Number of instances to provision." type = number default = 2 }
使用变量更新 EC2 实例。
module "ec2_instances" { source = "./modules/aws-instance" - instance_count = 2 + instance_count = var.instance_count ## ... }
切换 VPN 网关支持
使用类型变量控制您的 VPC 是否配置了 VPN 网关。将以下内容添加到
variables.tf
。
variable "enable_vpn_gateway" { description = "Enable a VPN gateway in your VPC." type = bool default = false }
编辑
main.tf
在 VPC 配置中使用此新变量,如下所示。
module "vpc" { source = "terraform-aws-modules/vpc/aws" version = "2.44.0" ## ... enable_nat_gateway = true - enable_vpn_gateway = false + enable_vpn_gateway = var.enable_vpn_gateway ## ... }
列出公有子网和私有子网
到目前为止,您使用的变量都是单个值。
Terraform将这些类型的变量称为简单变量。
Terraform 还支持包含多个值的集合变量类型。Terraform 支持多种集合变量类型。
List:相同类型的值的序列。
Map:键与值匹配,所有类型都相同。
Set:无序集合,所有值的类型都相同。
将以下变量声明添加到
variables.tf
。
variable "public_subnet_count" { description = "Number of public subnets." type = number default = 2 } variable "private_subnet_count" { description = "Number of private subnets." type = number default = 2 } variable "public_subnet_cidr_blocks" { description = "Available cidr blocks for public subnets." type = list(string) default = [ "10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24", "10.0.4.0/24", "10.0.5.0/24", "10.0.6.0/24", "10.0.7.0/24", "10.0.8.0/24", ] } variable "private_subnet_cidr_blocks" { description = "Available cidr blocks for private subnets." type = list(string) default = [ "10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24", "10.0.104.0/24", "10.0.105.0/24", "10.0.106.0/24", "10.0.107.0/24", "10.0.108.0/24", ] }
使用
slice()
函数来获取这些列表的子集。使用
terraform console
命令打开控制台。现在,使用 Terraform 控制台检查私有子网块的列表。
> var.private_subnet_cidr_blocks tolist([ "10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24", "10.0.104.0/24", "10.0.105.0/24", "10.0.106.0/24", "10.0.107.0/24", "10.0.108.0/24", ])
通过带方括号的索引从列表中检索第二个元素。
> var.private_subnet_cidr_blocks[1] "10.0.102.0/24"
现在使用
slice()
函数返回列表中的前三个元素。
> slice(var.private_subnet_cidr_blocks, 0, 3) tolist([ "10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24", ])
现在,在定义 VPC 的公有子网和私有子网配置时,使用 slice() 函数提取 cidr 列表的子集。
module "vpc" { source = "terraform-aws-modules/vpc/aws" version = "2.44.0" cidr = "10.0.0.0/16" azs = data.aws_availability_zones.available.names - private_subnets = ["10.0.101.0/24", "10.0.102.0/24"] - public_subnets = ["10.0.1.0/24", "10.0.2.0/24"] + private_subnets = slice(var.private_subnet_cidr_blocks, 0, var.private_subnet_count) + public_subnets = slice(var.public_subnet_cidr_blocks, 0, var.public_subnet_count) ## ... }
这样,此配置的用户可以指定所需的公有子网和私有子网的数量,而不必担心定义 CIDR 块。
资源标签
在
variables.tf
中的资源标签声明一个新变量。
variable "resource_tags" { description = "Tags to set for all resources" type = map(string) default = { project = "project-alpha", environment = "dev" } }
启动控制台。
terraform console
> var.resource_tags["environment"] "dev"
现在,将
main.tf
的tags
替换为对新变量的引用。
- tags = { - project = "project-alpha", - environment = "dev" - } + tags = var.resource_tags ## ... replace all five occurrences of `tags = {...}`
tags
在此配置中使用了五次,请务必全部替换它们。应用这些更改。
terraform apply
由于
tags
的值已更改,因此将应用更改。
为变量赋值
Terraform 要求为每个变量分配一个值。Terraform 支持多种分配变量值的方法。
在到目前为止的示例中,所有变量定义都包含默认值。将带缺省值的新变量添加到
variables.tf
。
variable "ec2_instance_type" { description = "AWS EC2 instance type." type = string }
替换
main.tf
中对 EC2 实例类型的引用。
module "ec2_instances" { source = "./modules/aws-instance" instance_count = var.instance_count - instance_type = "t2.micro" + instance_type = var.ec2_instance_type ## ... }
立即应用此配置。
terraform apply
Terraform 将提示您输入新变量的值。
输入:
t2.micro
由于您输入的值与旧值相同,因此不会应用任何更改。
使用terraform.tfvars
文件赋值
每当您执行计划、销毁或使用任何未分配的变量进行应用时,Terraform 都会提示您输入一个值。
手动输入变量值既耗时又容易出错,因此 Terraform 提供了几种其他方法来为变量赋值。
创建一个以以下内容命名的文件
terraform.tfvars
。
resource_tags = { project = "new-project", environment = "test", owner = "me@example.com" } ec2_instance_type = "t3.micro" instance_count = 3
Terraform 会自动加载当前目录中具有确切名称或匹配项的所有文件。
这些文件使用类似于 Terraform 配置文件 (HCL) 的语法,但它们不能包含资源定义等配置。
应用这些新值的配置。
terraform apply
您还可以通过环境变量和命令行设置输入变量。
在字符串中插值变量
Terraform 配置支持字符串插值,将表达式的输出插入到字符串中
更新安全组的名称
module "app_security_group" { source = "terraform-aws-modules/security-group/aws//modules/web" version = "3.12.0" - name = "web-sg-project-alpha-dev" + name = "web-sg-${var.resource_tags["project"]}-${var.resource_tags["environment"]}" ## ... } module "lb_security_group" { source = "terraform-aws-modules/security-group/aws//modules/web" version = "3.12.0" - name = "lb-sg-project-alpha-dev" + name = "lb-sg-${var.resource_tags["project"]}-${var.resource_tags["environment"]}" ## ... } module "elb_http" { source = "terraform-aws-modules/elb/aws" version = "2.4.0" # Ensure load balancer name is unique - name = "lb-${random_string.lb_id.result}-project-alpha-dev" + name = "lb-${random_string.lb_id.result}-${var.resource_tags["project"]}-${var.resource_tags["environment"]}" ## ... }
验证变量
此配置存在潜在问题。AWS 负载均衡器具有命名限制.它们的长度不得超过 32 个字符,并且只能包含一组有限的字符。
处理此问题的一种方法是使用变量验证来限制项目和环境标记的可能值。
替换以下代码段,其中包括用于实施字符限制和字符集的验证块。
variable "resource_tags" { description = "Tags to set for all resources" type = map(string) default = { project = "my-project", environment = "dev" } validation { condition = length(var.resource_tags["project"]) <= 16 && length(regexall("[^a-zA-Z0-9-]", var.resource_tags["project"])) == 0 error_message = "The project tag must be no more than 16 characters, and only contain letters, numbers, and hyphens." } validation { condition = length(var.resource_tags["environment"]) <= 8 && length(regexall("[^a-zA-Z0-9-]", var.resource_tags["environment"])) == 0 error_message = "The environment tag must be no more than 8 characters, and only contain letters, numbers, and hyphens." } }
regexall()
函数采用正则表达式和字符串来测试它,并返回在字符串中找到的匹配项的列表。这样,负载均衡器名称的最大长度将永远不会超过 32,并且不会包含无效字符。使用变量验证是尽早捕获错误配置的好方法。
应用此更改以向这两个变量添加验证。不会应用任何更改,因为您的基础结构配置尚未更改。
terraform apply
现在,通过指定长的环境标签来测试验证规则。请注意,该命令将失败并返回验证块中指定的错误消息。
terraform apply -var='resource_tags={project="my-project",environment="development"}' Error: Invalid value for variable on variables.tf line 69: 69: variable "resource_tags" { The environment tag must be no more than 8 characters, and only contain letters, numbers, and hyphens. This was checked by the validation rule at variables.tf:82,3-13.