- OpenTofu 语言
- 状态
- OpenTofu 状态的目的
OpenTofu 状态的目的
状态是 OpenTofu 正常运行的必要条件。人们经常问 OpenTofu 是否可以在没有状态的情况下工作,或者 OpenTofu 是否可以不使用状态而只是在每次运行时检查现实世界的资源。本页将帮助解释为什么 OpenTofu 状态是必需的。
正如你在下面原因中看到的那样,状态是必需的。在 OpenTofu 能够在没有状态的情况下正常工作的情况下,这样做将需要将大量的复杂性从一个地方(状态)转移到另一个地方(替换概念)。
映射到现实世界
OpenTofu 需要某种数据库来将 OpenTofu 配置映射到现实世界。例如,当你的配置中有一个资源 resource "aws_instance" "foo"
时,OpenTofu 会使用此映射来知道资源 resource "aws_instance" "foo"
表示一个现实世界中的对象,该对象在远程系统上具有实例 ID i-abcd1234
。
对于像 AWS 这样的某些提供者,OpenTofu 理论上可以使用类似于 AWS 标签的东西。OpenTofu 的早期原型实际上没有状态文件,并使用这种方法。然而,我们很快遇到了问题。第一个主要问题很简单:并非所有资源都支持标签,并且并非所有云提供者都支持标签。
因此,为了将配置映射到现实世界中的资源,OpenTofu 使用它自己的状态结构。
OpenTofu 预期每个远程对象只绑定到配置中的一个资源实例。如果一个远程对象绑定到多个资源实例,那么从配置到状态中的远程对象的映射就会变得模棱两可,OpenTofu 的行为可能会出乎意料。OpenTofu 可以保证在创建对象并将它们的标识记录到状态时进行一对一的映射。在导入 OpenTofu 之外创建的对象时,你必须确保每个不同的对象只导入到一个资源实例。
元数据
除了资源和远程对象之间的映射之外,OpenTofu 还必须跟踪元数据,例如资源依赖关系。
OpenTofu 通常使用配置来确定依赖关系顺序。但是,当你从 OpenTofu 配置中删除资源时,OpenTofu 必须知道如何从远程系统中删除该资源。OpenTofu 可以看到状态文件中存在一个映射,用于不在你的配置中的资源,并计划将其销毁。但是,由于配置不再存在,因此无法仅从配置中确定顺序。
为了确保正确操作,OpenTofu 会在状态中保留最近一组依赖关系的副本。现在,当你从配置中删除一个或多个项目时,OpenTofu 仍然可以从状态中确定销毁的正确顺序。
避免这种情况的一种方法是让 OpenTofu 知道资源类型之间的必要顺序。例如,OpenTofu 可以知道服务器必须在删除它们所属的子网之前被删除。但是,这种方法的复杂性会迅速增加:除了 OpenTofu 必须理解每个提供者的每个资源的排序语义之外,OpenTofu 还必须理解跨提供者的排序。
OpenTofu 还出于类似原因存储其他元数据,例如指向提供者配置的指针,该配置在存在多个别名提供者的情况下最近与资源一起使用。
性能
除了基本映射之外,OpenTofu 还存储所有资源在状态中的属性值的缓存。这是 OpenTofu 状态中最可选的功能,仅作为性能改进。
在运行 tofu plan
时,OpenTofu 必须知道资源的当前状态,才能有效地确定需要进行哪些更改才能达到你所需的配置。
对于小型基础设施,OpenTofu 可以查询你的提供者并同步所有资源的最新属性。这是 OpenTofu 的默认行为:对于每个计划和应用,OpenTofu 都将同步状态中的所有资源。
对于大型基础设施,查询每个资源太慢了。许多云提供者不提供一次查询多个资源的 API,并且每个资源的往返时间为数百毫秒。最重要的是,云提供者几乎总是具有 API 速率限制,因此 OpenTofu 只能在一段时间内请求一定数量的资源。OpenTofu 的大型用户大量使用 -refresh=false
标志以及 -target
标志来解决这个问题。在这种情况下,缓存状态被视为真实记录。
同步
在默认配置中,OpenTofu 将状态存储在运行 OpenTofu 的当前工作目录中的一个文件中。这对于入门来说还可以,但在团队中使用 OpenTofu 时,重要的是让每个人使用相同的状态,这样操作才能应用于相同的远程对象。
远程状态 是解决此问题的推荐方案。借助功能完备的状态后端,OpenTofu 可以使用远程锁定作为一种措施,避免两个或多个不同的用户在同一时间意外运行 OpenTofu,从而确保每次 OpenTofu 运行都从最新的更新状态开始。