我尝试使用Terraform锁定状态

首先

第一次接触到Terraform的时候,我得到了这样一个建议:”因为v0.9以上版本有一个叫做state lock的功能,建议使用它”。(其实,”state”到底是什么呢?)

当我第一次接触Terraform时,由于仅仅依靠官方文档,我感到非常不知所措。为了留下痕迹,我将记录下来。

作为结果,我仍然不够熟练。实际上,我使用的方式是否正确呢?
所以,可能会有信息不足,但暂时我会把它留作备忘录。
如果我有了新的认识,我会做更新。

首先, “State Lock” 是什么?

我完全不理解,但Terraform似乎采用了一个策略,即「只涉及我知道的资源(如EC2或S3)」,并通过一个名为tfstate的JSON文件来管理自己处理的资源。

这个tfstate文件在一个人使用Terraform时没有问题,但当需要多个人使用Terraform进行操作时会有问题。为了解决这个问题,他们似乎开始使用了”backend”模块。然而,当在相同的时间进行terraform操作时,似乎无法完全控制那部分。

所以,从v0.9以上的版本开始,似乎实现了一个“在执行计划/应用时进行锁定”的功能。既然有这个机会,我就尝试引入了它。

官方网站:https://www.terraform.io/docs/state/locking.html

备办

手動準備的内容包括:
– 执行Terraform的用户凭据信息
→ 因为很麻烦,所以另外创建了一个名为test-terraform的用户。
– 创建S3 Bucket
→ 建议以terraform-s3-state为名进行创建。
– 创建DynamoDB
→ 名称可以随意,建议使用terraform-state-lock。
→ 请将主键设置为”LockID”,其他键无效。
→ 创建后,建议将读写容量单位设置为最低的1。

在中国,最好不要使用terraform来管理S3和DynamoDB。
无论如何,第一次执行时Terraform都会抱怨”没有这样的资源!”。

直到运动

由于这次主要讨论State Lock,所以可以使用任何资源来创建。
我们将以与地区无关的Route53为题材。

# 適当に1ゾーン作ります。

resource "aws_route53_zone" "test_zone" {
    name    =   "test.lockstate.com"
}
# ネーミングよくないですが、providerとbackendの設定します

provider "aws" {
    access_key = "ACCESS_KEY"
    private_key = "PRIVATE_KEY"
}

terraform {
    backend "s3" {
        bucket     = "terraform-s3-state"
        key        = "terraform.tfstate"
        region     = "s3とdynamoがいるregion"
        lock_table = "terraform-state-lock"
    }
}

请在该目录下执行命令 “$ terraform plan”。(否则会被训斥。)

Backend reinitialization required. Please run "terraform init".
Reason: Initial configuration of the requested backend "s3"

The "backend" is the interface that Terraform uses to store state,
perform operations, etc. If this message is showing up, it means that the
Terraform configuration you're using is using a custom configuration for
the Terraform backend.

我被告知说,先执行 terraform init ,所以我就按照被告知的去做。

$ 使用 Terraform 进行初始化

不过,按照以下方式,认证信息没了!会被怒斥。真是什么玩意儿。

Initializing the backend...

Error configuring the backend "s3": No valid credential sources found for AWS Provider.
  Please see https://terraform.io/docs/providers/aws/index.html for more information on
  providing credentials for the AWS Provider

Please update the configuration in your Terraform files to fix this error
then run this command again.

虽然对这个问题还不是很了解,但是有两种方法可以解决这个问题。
A. 将access_key/secret_key这两个凭据以明文的形式传递给settings.tf的backend。
-> 我本来觉得用变量会更好!但是当我用变量传递时,Terraform会在”之前”找到一个方式来启动后端,
并且我收到了一条不满的消息。

% terraform init 
Initializing the backend...
Error loading backend config: 1 error(s) occurred:

* terraform.backend: configuration cannot contain interpolations

The backend configuration is loaded by Terraform extremely early, before
the core of Terraform can be initialized. This is necessary because the backend
dictates the behavior of that core. The core is what handles interpolation
processing. Because of this, interpolations cannot be used in backend
configuration.

If you'd like to parameterize backend configuration, we recommend using
partial configuration with the "-backend-config" flag to "terraform init".

B. 目前正在使用的方法是将access_key/secret_key这两个环境变量传递进来。

在执行init或plan时,可能会根据情况询问是否要”将本地的State复制到S3或从S3复制State文件到本地”。
如果是第一次(或测试),可以选择Yes;如果已经执行了几次,可以选择No。

当您执行terraform plan(或apply)时,将写入有关谁正在使用DynamoDB LockDB的锁信息,并在完成后进行释放。

打开多个终端或者shell,并在大致相同的时间点上执行terraform plan(或apply)命令,只有成功获取锁的命令才能顺利运行,其他命令会因为错误而退出。然而,如果在锁释放之前被强制终止(例如,使用Ctrl-C),锁将继续存在,所以请注意。您可以使用命令$ terraform force-unlock ID信息来强制解锁。

目前还没有解决的问题

根据官方文档显示,“terraform remote 命令已被替换为 terraform init 命令!”而且,在使用 backend、修改 backend 之类的操作后,也会要求执行 terraform init。

然而,terraform init命令将会在执行的目录下生成一个 .terraform/terraform.tfstate 文件,并且如果没有该文件,命令将会报错。
尽管我还没有尝试过,但是如果我们的tf文件布局如下所示:
即使在根目录下执行init命令,它也会报错说找不到tf文件,因此我们必须移动到tf文件所在的目录才能执行init命令。

如果执行 `terraform init ./route53/tf`,那么tf文件将被复制到根目录下。
因此,无法很好地对资源进行分隔,比如按资源进行分割,按环境进行分割等等。
从另一个角度来看,是不是HashiCorp告诉我们应该在每个环境中使用一个目录来管理所有资源!
这是用来尝试新实施的环境吗……?

听说有一个叫BackendConfig的东西,我想试一试。

根目录
├── 设置
│ └── tf
│ └── 设置.tf
├── 路由53
│ └── tf
│ └── 路由53.tf
└── 亚马逊云电脑
└── tf
└── 亚马逊云电脑.tf

不太清楚如何使用Terraform