关于 Terraform 需要了解的一点是,它只能管理它创建的配置,或者是在事后被明确告知的配置。这种限制的原因是 Terraform 期望对其管理的资源具有权威性。它依赖于两种类型的文件来了解它控制哪些资源以及这些资源处于什么状态。Terraform 通过以下内容决定何时以及如何进行更改:
- 一个定义要由 Terraform 管理的资源配置的配置文件 ↗(以
.tf结尾)。这是您在教程步骤中使用的文件。 - 一个本地状态文件 ↗,它将您的配置文件中定义的资源名称(例如,
cloudflare_load_balancer.www-lb)映射到 Cloudflare 中存在的资源。
当 Terraform 如教程中所述调用 Cloudflare API 创建新资源时,它会将这些 ID 持久化到状态文件中。默认情况下,Terraform 使用目录中的 terraform.tfstate 文件,但它也可以是远程位置 ↗。稍后当您调用 terraform plan 和 terraform apply 时,将查找并刷新这些 ID。
如果您通过其他方式配置了 Cloudflare,例如,通过登录 Cloudflare 仪表板或对 api.cloudflare.com 进行 curl 调用,则 Terraform 尚未在状态文件中拥有这些资源 ID。要管理这个先前存在的配置,您首先需要在配置文件中重现该配置,然后通过提供其 ID 和资源名称单独导入资源。
cf-terraforming ↗ 帮助现有的 Cloudflare 客户开始使用 Terraform。目前,cf-terraforming 通过从您选择的账户和/或区域中获取指定类型的所有资源来帮助生成 Terraform 配置状态。
开始之前,您必须安装 cf-terraforming。
如果您在 macOS 上使用 Homebrew,请打开终端并运行以下命令:
brew tap cloudflare/cloudflare
brew install cloudflare/cloudflare/cf-terraforming如果您使用的是其他操作系统,请从 cf-terraforming GitHub 存储库下载最新版本 ↗。
要查看帮助文件,请运行 cf-terraforming 或 cf-terraforming -h。
要使用 cf-terraforming,请指定以下项目:
- 要执行的命令(例如,
generate或import)。 - 您的 Cloudflare 用户电子邮件 -
--email或-e。 - 您的 Cloudflare API 令牌 -
--token或-t。 - 从中提取资源的账户和/或区域 -
--account/--zone或-a/-z。 - 用于生成配置的 Cloudflare 资源。
支持的资源列表在 Terraform README ↗ 中提供。
要开始在 Terraform 中管理现有的 Cloudflare 资源(例如 DNS 记录),您需要:
- 该资源的 Terraform 配置(在
.tf文件中定义) - 伴随该资源状态的 Terraform 状态文件(在
.tfstate文件中定义)
如果尚未定义 Terraform 配置文件,则需要如下定义 provider 块:
provider 'cloudflare' {
# Cloudflare email saved in $CLOUDFLARE_EMAIL
# Cloudflare API token saved in $CLOUDFLARE_API_TOKEN
}切记将您的凭证保存在未检入源文件的环境变量或 terraform autovars 中。
首先调用 cf-terraforming generate 来为您想使用 Terraform 管理的区域中的 DNS 记录生成 Terraform 配置。
cf-terraforming generate --email $CLOUDFLARE_EMAIL --token $CLOUDFLARE_API_TOKEN -z 1109d899a5ff5fd74bc01e581693685b --resource-type cloudflare_record > importing-example.tf如果您没有将输出重定向到 importing-example.tf 文件,那么在标准输出(您的终端窗口)中显示的结果将如下所示:
resource "cloudflare_record" "terraform_managed_resource_3c0b456bc2aa443089c5f40f45f51b31" {
name = "@"
type = "A"
ttl = 1
proxied = true
value = "192.0.2.1"
zone_id = "1109d899a5ff5fd74bc01e581693685b"
}
resource "cloudflare_record" "terraform_managed_resource_5e10399a590a45279f09aa8fb1163354" {
name = "www"
type = "CNAME"
ttl = 1
proxied = true
value = "mitigateddos.net"
zone_id = "1109d899a5ff5fd74bc01e581693685b"
}
resource "cloudflare_record" "terraform_managed_resource_de1cb74bae184b569bb7f83fefe72248" {
name = "a123"
type = "NS"
ttl = 300
proxied = false
value = "rafe.ns.cloudflare.com"
zone_id = "1109d899a5ff5fd74bc01e581693685b"
}
resource "cloudflare_record" "terraform_managed_resource_5799bb01054843eea726758f935d2aa2" {
name = "a123"
type = "NS"
ttl = 300
proxied = false
value = "terin.ns.cloudflare.com"
zone_id = "1109d899a5ff5fd74bc01e581693685b"
}此时调用 terraform plan 会尝试创建这些资源,就像它们不存在一样,因为它们不存在于本地状态文件中:
terraform planTerraform used the selected providers to generate the following execution plan.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# cloudflare_record.terraform_managed_resource_3c0b456bc2aa443089c5f40f45f51b31 will be created
+ resource "cloudflare_record" "terraform_managed_resource_3c0b456bc2aa443089c5f40f45f51b31" {
+ id = (known after apply)>
+ created_on = (known after apply)
+ domain = "mitigateddos.net"
+ hostname = (known after apply)
+ metadata = (known after apply)
+ modified_on = (known after apply)
+ name = "mitigateddos.net"
+ proxiable = (known after apply)
+ proxied = true
+ ttl = 1
+ type = "A"
+ value = "192.0.2.1"
+ zone_id = "1109d899a5ff5fd74bc01e581693685b"
}
# cloudflare_record.terraform_managed_resource_5e10399a590a45279f09aa8fb1163354 will be created
+ resource "cloudflare_record" "terraform_managed_resource_5e10399a590a45279f09aa8fb1163354" {
+ id = (known after apply)
+ created_on = (known after apply)
+ domain = "mitigateddos.net"
+ hostname = (known after apply)
+ metadata = (known after apply)
+ modified_on = (known after apply)
+ name = "www.mitigateddos.net"
+ proxiable = (known after apply)
+ proxied = true
+ ttl = 1
+ type = "CNAME"
+ value = "mitigateddos.net"
+ zone_id = "1109d899a5ff5fd74bc01e581693685b"
}
# cloudflare_record.terraform_managed_resource_de1cb74bae184b569bb7f83fefe72248 will be created
+ resource "cloudflare_record" "terraform_managed_resource_de1cb74bae184b569bb7f83fefe72248" {
+ id = (known after apply)
+ created_on = (known after apply)
+ domain = "mitigateddos.net"
+ hostname = (known after apply)
+ metadata = (known after apply)
+ modified_on = (known after apply)
+ name = "a123.mitigateddos.net"
+ proxiable = (known after apply)
+ proxied = false
+ ttl = 300
+ type = "NS"
+ value = "rafe.ns.cloudflare.com"
+ zone_id = "1109d899a5ff5fd74bc01e581693685b"
}
# cloudflare_record.terraform_managed_resource_5799bb01054843eea726758f935d2aa2 will be created
+ resource "cloudflare_record" "terraform_managed_resource_5799bb01054843eea726758f935d2aa2" {
+ id = (known after apply)
+ created_on = (known after apply)
+ domain = "mitigateddos.net"
+ hostname = (known after apply)
+ metadata = (known after apply)
+ modified_on = (known after apply)
+ name = "a123.mitigateddos.net"
+ proxiable = (known after apply)
+ proxied = false
+ ttl = 300
+ type = "NS"
+ value = "terin.ns.cloudflare.com"
+ zone_id = "1109d899a5ff5fd74bc01e581693685b"
}
Plan: 4 to add, 0 to change, 0 to destroy.
------------------------------------------------------------------------
Note: You didn't use the -out option to save this plan, so Terraform can't
guarantee to take exactly these actions if you run "terraform apply" now.要解决此问题,您必须将 Cloudflare 中这些资源的真实状态导入到 Terraform 状态文件(.tfstate)中。
cf-terraforming 允许您为配置期间导入的相同资源导入本地状态(.tfstate 文件)。
当您运行 cf-terraforming import ... 时,您将获得一个 terraform import ... 命令列表,您必须在此之后手动运行这些命令以将这些资源导入 Terraform 状态。这目前是一个手动过程,但将来可能会实现自动化。
-
运行以下命令:
cf-terraforming import --resource-type "cloudflare_record" --email $CLOUDFLARE_EMAIL --key $CLOUDFLARE_API_KEY --zone $CLOUDFLARE_ZONE_ID -
复制输出中包含的每个
terraform import ...命令并运行它。Terraform 将分别将每个资源导入 Terraform 状态。
例如,如果第一个命令(cf-terraforming import ...)的输出包含以下 terraform 命令:
terraform import cloudflare_record.terraform_managed_resource_3c0b456bc2aa443089c5f40f45f51b31 1109d899a5ff5fd74bc01e581693685b/3c0b456bc2aa443089c5f40f45f51b31
terraform import cloudflare_record.terraform_managed_resource_5e10399a590a45279f09aa8fb1163354 1109d899a5ff5fd74bc01e581693685b/d09d916d059aa9fc8cb54bdd49deea5f
terraform import cloudflare_record.terraform_managed_resource_de1cb74bae184b569bb7f83fefe72248 1109d899a5ff5fd74bc01e581693685b/8d6ec0d02c5b22212ff673782c816ef8
terraform import cloudflare_record.terraform_managed_resource_5799bb01054843eea726758f935d2aa2 1109d899a5ff5fd74bc01e581693685b/3766b952a2dda4c47e71952aeef33c77您需要在终端中单独运行每个命令:
terraform import cloudflare_record.terraform_managed_resource_3c0b456bc2aa443089c5f40f45f51b31 1109d899a5ff5fd74bc01e581693685b/3c0b456bc2aa443089c5f40f45f51b31cloudflare_record.terraform_managed_resource_3c0b456bc2aa443089c5f40f45f51b31: Importing from ID "1109d899a5ff5fd74bc01e581693685b/3c0b456bc2aa443089c5f40f45f51b31"...
cloudflare_record.terraform_managed_resource_3c0b456bc2aa443089c5f40f45f51b31: Import complete!
Imported cloudflare_record [id=3c0b456bc2aa443089c5f40f45f51b31]
cloudflare_record.terraform_managed_resource_3c0b456bc2aa443089c5f40f45f51b31: Refreshing state... [id=3c0b456bc2aa443089c5f40f45f51b31]
Import successful!
The resources that were imported are shown above. These resources are now in
your Terraform state and will henceforth be managed by Terraform.terraform import cloudflare_record.terraform_managed_resource_5e10399a590a45279f09aa8fb1163354 1109d899a5ff5fd74bc01e581693685b/d09d916d059aa9fc8cb54bdd49deea5fcloudflare_record.terraform_managed_resource_5e10399a590a45279f09aa8fb1163354: Importing from ID "1109d899a5ff5fd74bc01e581693685b/d09d916d059aa9fc8cb54bdd49deea5f"...
cloudflare_record.terraform_managed_resource_5e10399a590a45279f09aa8fb1163354: Import complete!
Imported cloudflare_record [id=d09d916d059aa9fc8cb54bdd49deea5f]
cloudflare_record.terraform_managed_resource_5e10399a590a45279f09aa8fb1163354: Refreshing state... [id=d09d916d059aa9fc8cb54bdd49deea5f]
Import successful!
The resources that were imported are shown above. These resources are now in
your Terraform state and will henceforth be managed by Terraform.terraform import cloudflare_record.terraform_managed_resource_de1cb74bae184b569bb7f83fefe72248 1109d899a5ff5fd74bc01e581693685b/8d6ec0d02c5b22212ff673782c816ef8cloudflare_record.terraform_managed_resource_de1cb74bae184b569bb7f83fefe72248: Importing from ID "1109d899a5ff5fd74bc01e581693685b/8d6ec0d02c5b22212ff673782c816ef8"...
cloudflare_record.terraform_managed_resource_de1cb74bae184b569bb7f83fefe72248: Import complete!
Imported cloudflare_record [id=8d6ec0d02c5b22212ff673782c816ef8]
cloudflare_record.terraform_managed_resource_de1cb74bae184b569bb7f83fefe72248: Refreshing state... [id=8d6ec0d02c5b22212ff673782c816ef8]
Import successful!
The resources that were imported are shown above. These resources are now in
your Terraform state and will henceforth be managed by Terraform.terraform import cloudflare_record.terraform_managed_resource_5799bb01054843eea726758f935d2aa2 1109d899a5ff5fd74bc01e581693685b/3766b952a2dda4c47e71952aeef33c77cloudflare_record.terraform_managed_resource_5799bb01054843eea726758f935d2aa2: Importing from ID "1109d899a5ff5fd74bc01e581693685b/3766b952a2dda4c47e71952aeef33c77"...
cloudflare_record.terraform_managed_resource_5799bb01054843eea726758f935d2aa2: Import complete!
Imported cloudflare_record [id=3766b952a2dda4c47e71952aeef33c77]
cloudflare_record.terraform_managed_resource_5799bb01054843eea726758f935d2aa2: Refreshing state... [id=3766b952a2dda4c47e71952aeef33c77]
Import successful!
The resources that were imported are shown above. These resources are now in
your Terraform state and will henceforth be managed by Terraform.如果您现在运行 terraform plan,您将注意到 Terraform 将不再尝试重新创建 cloudflare_record 资源:
terraform plan | grep changesNo changes. Infrastructure is up-to-date.