Terraform State
什么是 Terraform State
Terraform State 是指 Terraform 状态,是 Terraform 生命周期过程中必不可少的元素。本质上讲,Terraform 状态是你的基础设施配置的元数据存储库,Terraform 把它管理的资源状态保存在一个状态文件中。
默认情况下,状态保存在一个名为 "terraform.tfstate" 的文件中,但也可以远程存储,在团队协作管理基础设施的场景下,推荐采用远程存储。
Terraform 使用状态来创建执行计划并更改您的基础设施。在任何操作之前,Terraform 会执行刷新操作以用基础设施的实际状态来更新状态。Terraform 状态的主要目的是存储远端系统(如云上)中的基础设施对象和配置文件中声明的资源实例之间的绑定关系,当 Terraform 通过配置文件创建或者更改了远端对象时,它会将该远端对象的标识记录在与之对应的资源实例中,并保存在状态文件中,之后,Terraform 可能会根据未来的配置更改更新或删除该对象。
每个在资源块中创建的基础设施资源都是通过其resource_name
在 Terraform 状态中进行标识的,其对资源的管理流程大致如下:
当第一次通过 terraform apply 应用 Terraform 配置时,会创建基础设施资源,同时自动生成一个状态文件,该文件引用资源块中声明的名称
如果一个资源已经在 Terraform 状态文件中有标识,那么 Terraform 会将配置文件与状态文件和当前的资源远端的实际状态进行比较,并根据比较结果,会生成一个执行计划
当执行该计划时,它会更新资源的状态以匹配配置文件中的定义,如果由于远端 API 限制无法实现就地更新参数,那么该执行计划将会先销毁资源,然后再重新创建新的资源;如果是一个资源销毁的计划,将发起资源的销毁操作
计划执行成功后,Terraform 状态文件会更新以反映当前的基础设施状态
如果某资源已从当前 Terraform 配置中移除但在状态文件中仍然存在,Terraform 则会比较配置文件并销毁不再存在的资源
存储 Terraform State
Terraform 默认将本地状态文件保存在当前工作目录中,扩展名为 .tfstate,因此它们不需要额外的维护。本地状态文件适用于只有一个开发人员工作的项目,当多个开发人员同时运行 Terraform 并且每台机器都有对当前基础设施的理解和配置时,默认的本地状态文件的配置方式就会变得棘手。
在团队协作开发场景中使用本地状态时主要存在以下几个问题:
本地状态没有共享访问权限
当使用 Terraform 更新你的基础设施,团队中的每个成员都需要访问相同的状态文件,这意味着这些文件必须存储在一个共享的位置,比如 ECS 实例特定的位置,而这无形增加了管理成本。
不能锁定本地状态文件
如果两个团队成员同时运行 Terraform,他们可能会遇到竞争条件,因为多个 Terraform 进程可能同时在更新状态文件。在这种情况下,可能带来导致冲突、数据丢失和状态文件损坏等风险。
本地状态文件不保密
当信息以明文形式存储在状态文件中时,敏感数据将存在被暴露的风险,例如数据库凭证,SSH 登录密码等。
因此,当一个团队中有多个开发人员通过编写代码来管理基础设施时,我们推荐你应该将状态文件存储在一个远端的中心位置。这样,当基础设施发生变化时,Terraform 状态文件会更新并同步,团队中的所有人员将始终使用最新的基础设施状态。
面对本地状态存在的问题,当使用远端状态存储时,这些问题将会得到解决:
远端状态文件会自动更新
当远程存储时,状态文件会自动更新,即一旦配置了远程后端,每次运行 plan 或 apply 命令时,Terraform 将自动从远端加载状态文件。除此之外,它还会在每次 apply 后自动将状态文件同步存储在远端中,因此不存在手动错误的情况。
远端状态文件支持状态锁定
当执行 Terraform 命令时,可以对远端状态文件进行加锁,这样如果多个开发人员同时运行 terraform apply,它不会因同时更新而损坏。
远端状态文件存储比本地存储更安全
OSS Bucket 支持本地传输加密和远端加密功能。此外,OSS Bucket 包括多种配置访问权限的方法,因此你可以以精细化的方式控制状态文件的访问权限。
配置远端状态存储
阿里云基于 OSS Bucket 提供了远端状态存储的能力,同时利用表格存储 OTS 支持了远端状态文件的加锁能力,因此在配置远端状态存储之前,首先需要准备好用于状态文件存储的 OSS Bucket 和 OTS 实例。我们展示如何在云存储桶中远程存储 Terraform 状态:
创建远端状态所依赖的资源
首先,将 alicloud_oss_bucket,alicloud_ots_instance,alicloud_ots_table 资源添加到 Terraform 配置文件中,例如 main.tf,并按照自身的需求对资源进行配置,如设置 Bucket 名称,OTS 实例名称,实例规格,表格名称等。完成配置后,运行 terraform apply 来创建 Bucket 以及其他资源。
配置远端状态
接下来,将代码配置添加到一个名为 backend.tf 的新 Terraform 配置文件中,接着运行 terraform init 来配置你的 Terraform 远端状态。此时,Terraform 检测到本地已经有一个状态文件,并提示你将其复制到新的 OSS Bucket 中。输入 yes,terraform init 运行成功后,你的 Terraform 状态将存储在 OSS Bucket 中。
为了更便捷的配置远端存储,可以使用阿里云提供的用于配置远端状态的 Terraform Module。
以下是来自 OSS Bucket 的状态文件片段:
{
"version": 4,
"terraform_version": "1.7.1",
"serial": 9,
"lineage": "5827f172-fc29-c293-cce7-7932f3537499",
"outputs": {},
"resources": [
{
"mode": "managed",
"type": "alicloud_oss_bucket",
"name": "this",
"provider": "provider[\"registry.terraform.io/hashicorp/alicloud\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"access_monitor": [
{
"status": "Disabled"
}
],
"acl": "private",
"bucket": "tf-oss-backend-for-demo",
状态包括了创建的资源的元数据,例如资源类型、资源名称和提供商名称等。
Terraform State 的最佳实践
针对 Terraform 状态文件,我们从状态优化和安全性方面给出如下建议:
团队协作场景使用远端状态
首先,在团队协作场景中应使用远程状态,以便锁定和版本控制状态文件。阿里云的客户应使用 OSS 作为远端状态存储后端,并使用 OTS 来锁定状态文件。将敏感信息与 Terraform 配置文件的版本控制分开,并确保只有构建系统和高权限管理员可以访问远程状态存储 Bucket。为了防止意外地将开发环境的状态文件提交到源代码版本控制系统中(如Github,Gitlab等),请为 Terraform 状态文件配置 gitignore。
不要在状态中存储敏感数据
许多资源和数据提供者会将敏感数据以明文形式存储在状态文件中,这是存在安全隐患的。如果可能,尽量避免在状态文件中存储敏感信息。
对状态进行加密
增加一层防御,始终对远端状态文件进行加密。阿里云 OSS 存储支持 KMS、AES256、SM4 三种加密方式的,客户可以通过自定义的 KMS 密钥对状态文件提供额外一层保护。
不要手动修改 Terraform 状态
状态文件是维护 Terraform 配置和阿里云基础设施资源之间的映射关系的关键,状态文件的损坏可能导致重大的基础设施问题。因此不要尝试手动修改 Terraform 状态文件内容。