代码编写阶段的术语和概念
在了解了模板编写、Terraform 配置文件目录和 HashiCorp 语言 HCL 之后,本文主要介绍在 Terraform 工作流的代码编写阶段你会遇到的一些常见术语和概念。
资源(Resources)
资源(Resources)是定义基础设施组件的代码块,通常定义在 main.tf 文件中。资源通过关键字 resource 来标识,其后跟具体的资源类型和自定义名称。资源类型取决于你在配置文件中定义的提供商(Provider)。在花括号内是指定资源类型的参数,你需要在这里指定资源配置所需的输入。
resource "resource_type" "resource_name" {
# 指定资源类型的参数(Argument)
}
Terraform 使用资源类型和资源名称来标识一个基础设施元素。关键字 resource 将代码块识别为云基础设施的组件。资源类型是 alicloud_oss_bucket,这代表阿里云的资源。术语 resource 是 Terraform 特有的,不能自定义;资源类型根据定义的提供商而变化;example-bucket 代表在当前 Terraform 配置中的资源名称。Terraform 使用资源类型和资源名称一起作为资源在当前 Terraform 配置中的标识符。
resource "alicloud_oss_bucket" "example-bucket" {
bucket = "my-bucket-xxxx" # 指定一个全局唯一的 Bucket 名称
}
下面这个示例声明了阿里云为提供者,并展示了两个阿里云的资源块:一个 OSS Bucket 和一个虚拟交换机。参数根据定义的资源类型而不同。对于资源 alicloud_oss_bucket,你只需指定 Bucket 名称即可成功创建资源。对于 alicloud_vswitch 资源,你必须指定所属 VPC 的 ID(vpc_id)、网段(cidr_block)、所属可用区(zone_id),名称,标签等其他参数是可选的。
resource "alicloud_oss_bucket" "example-bucket" {
bucket = "my-bucket-xxxxx"
}
resource "alicloud_vswitch" "main_vswitch" {
vpc_id = "vpc-abc12345"
cidr_block = "10.0.1.0/24"
zone_id = "cn-hangzhou-k"
vswitch_name = "main-vswitch"
}
如果资源复杂,资源配置代码较长,可以按照资源类型单独使用一个独立的 .tf 文件来存放,例如,用于 ECS 实例、OSS Bucket 和数据库的配置可以分别放在 instance.tf,oss.tf 和 database.tf 中。
提供商(Provider)
提供商实现了每一种可配置的资源类型;如果没有提供商,Terraform 将无法管理任何类型的基础设施。提供商通常定义在 providers.tf 文件中,你需要指定包含提供商定义的 Terraform 块。当声明了提供商后,Terraform 通过 init 命令自动下载提供商插件。
terraform {
required_providers {
alicloud = {
source = "aliyun/alicloud"
version = "1.225.0"
}
}
}
provider "alicloud" {
# 配置你的阿里云凭据和地域信息
# 出于安全考虑,建议不要在这个文件中直接包含你的阿里云AccessKey和SecretKey,推荐使用环境变量或其它安全方式设置凭据:
# export ALICLOUD_ACCESS_KEY="<你的阿里云Access Key>"
# export ALICLOUD_SECRET_KEY="<你的阿里云Secret Key>"
region = "cn-hangzhou"
}
提供商将具体的管理资源的 API 编排为 Terraform 资源,并管理资源与 API 之间的交互。提供商配置属于 Terraform 配置的根模块。alicloud 是要配置的本地提供商名称,为了确保本地名称配置正确,必须在 required_providers 块中包含提供商。source 参数用于指定你打算使用的提供商的全局源地址。在上面的示例中,source 参数被赋值为 Terraform Registry 站点的地址 aliyun/alicloud。version 参数用于指定提供商的其中一个版本,该参数是可选的,但建议使用。version 参数将提供商限制在特定版本或版本范围内,以防止下载可能包含非兼容更改的新提供商。如果未指定版本,Terraform 会在初始化期间自动下载最新版本的提供商。
值得注意的是,由于历史原因,阿里云提供商 alicloud 支持两个 source 值:aliyun/alicloud 和 hashicorp/alicloud。两者的实现完全一致。更多信息,详见Terraform 概览。
access_key,secret_key,region 等参数是专用于配置阿里云 Provider 的。如果 Terraform 配置中没有包含 provider 块,Terraform 会假定一个空的默认配置,并且 access_key,secret_key,region 默认会从环境变量中获取。如果环境变量中没有指定 region,默认将使用 cn-beijing。更多阿里云 Provider 的配置参数,详见 Provider 官网。
变量(Variables)
变量用于参数化你的 Terraform 配置。输入变量作为参数供给 Terraform 使用,使其允许在无需更改源配置代码的情况下轻松定制和共享配置。一旦定义了变量,在 Terraform 运行时可以有多种不同的方式来设置其值:环境变量、CLI 参数、键值文件等。你可以在运行时或在一个以 .tfvars 扩展名结尾的文件中以 K-V 的形式定义资源属性。
借助参数,你可以轻松地将属性与 Terraform 执行计划分离。在这个示例中,main.tf 声明了一个专有网络 VPC,vpc_name 属性在 variables.tf 文件中被声明为变量,因此该属性已经被参数化,你可以在运行时定义这些变量的值或者将其定义到一个 tfvars 文件中。更多关于变量的内容,详见Variable 介绍。
输出(Outputs)
outputs.tf 文件保存了资源的输出值。由 Terraform 管理的每个资源实例都可以导出属性,这些属性的值可在 Terraform 配置的其他地方被引用。如果需要,输出值是用来暴露这些信息的方法。
一些资源属性在创建时被计算出来。例如,某些资源的连接地址或者 VSwitch 的 ID 会在资源创建时生成。VSwitch 的计算属性 ID 是创建其他资源(如 ECS 实例,RDS 实例等)对象所需的。通过输出值,你可以输出这些信息并使其可访问。
output "vswitch_id" {
value = alicloud_vswitch.main_vswitch.id
}
output 关键字后的标签是名称,必须是一个有效的标识符。在根模块中,此名称会显示给查看者。在子模块中,它可以用于访问该值。value 参数接受一个表达式,该表达式返回结果给用户。
状态(State)
Terraform 在状态文件中保存它管理的资源的状态。默认情况下,状态文件是存储在本地,但它也可以远端存储。在团队协作场景中,远端存储通常是首选方法。
{
"version": 4,
"terraform_version": "1.7.1",
"serial": 168,
"lineage": "46c0889c-f4ff-d1fd-2109-364f97e55c06",
"outputs": {
"vswitch_id": {
"value": "vsw-bp1ev5ei73c7y5ib887v1",
"type": "string"
}
},
"resources": [
{
"mode": "managed",
"type": "alicloud_vswitch",
"name": "main_vswitch",
"provider": "provider[\"registry.terraform.io/hashicorp/alicloud\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"availability_zone": "cn-hangzhou-k",
"cidr_block": "10.0.1.0/24",
"create_time": "2024-06-23T07:53:48Z",
"description": "",
"enable_ipv6": null,
"id": "vsw-bp1ev5ei73c7y5ib887v1",
...
需要注意的是,不要修改或触碰此文件,它是自动创建和更新的,一旦状态文件损坏,将会导致继续执行 Terraform 失败或者重复创建新的资源。更多状态介绍,详见Terraform State 介绍。
模块(Modules)
Terraform 模块是一组位于单个目录中的 Terraform 配置文件,即使是一个包含了一个或多个 .tf 文件的单一目录的简单配置也被视为一个模块。模块是 Terraform 中代码复用的主要方法,它们通过指定可以检索代码的源来重复使用。源可以是本地的也可以是远程的。你可以使用来自 HashiCorp 模块注册中心的开源模块或创建你自己的模块。