Terraform
定位资源
当你将更改应用于 Terraform 项目时,Terraform 会生成一个计划,其中包含你的配置和项目当前管理资源之间的所有差异(如果有)。 当你应用计划时,Terraform 将添加、删除和修改计划中提出的资源。
在典型的 Terraform 工作流程中,你一次性应用整个计划。 有时你可能只想应用部分计划,例如当 Terraform 的状态与你的资源因网络故障、上游云平台问题或 Terraform 或其提供程序中的错误而不同步时。 为了支持这一点,Terraform 允许你在计划、应用或销毁你的基础设施时,定位特定的资源。 定位单个资源对于故障排除错误很有用,但不应成为你的正常工作流程的一部分。
你可以使用 Terraform 的 -target 选项来定位特定的资源、模块或资源集合。 在本教程中,你将预置一个带有其中一些对象的 S3 存储桶,然后使用 -target 逐步应用更改。
先决条件
您可以使用 Terraform Community Edition 或 HCP Terraform 以相同的流程完成本教程。HCP Terraform 是一个平台,可用于管理和执行您的 Terraform 项目。它包含远程状态和执行、结构化计划输出、工作区资源摘要等功能。
选择 HCP Terraform 标签页以使用 HCP Terraform 完成本教程。
本教程假定您熟悉 Terraform 工作流程。如果您是 Terraform 新手,请先完成 入门系列。
为了完成本教程,您需要以下条件
- 本地安装的 Terraform v1.2+ 。
- 一个配置了本地凭证的AWS 账户,这些凭证已配置为与 Terraform 一起使用。
创建基础设施
克隆 本教程的示例配置,该配置定义了一个具有随机名称的 S3 存储桶和四个 S3 存储桶对象。
$ git clone https://github.com/hashicorp-education/learn-terraform-resource-targeting
导航到仓库目录。
$ cd learn-terraform-resource-targeting
初始化此配置。
$ terraform init
Initializing the backend...
##...
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
应用此配置以创建您的 S3 存储桶和对象。 通过键入 yes 来确认该操作。
$ terraform apply
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
##...
Plan: 12 to add, 0 to change, 0 to destroy.
Changes to Outputs:
+ bucket_arn = (known after apply)
+ bucket_name = (known after apply)
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
##...
Apply complete! Resources: 12 added, 0 changed, 0 destroyed.
Outputs:
bucket_arn = "arn:aws:s3:::learning-specially-tender-fawn"
bucket_name = "learning-specially-tender-fawn"
定位 S3 存储桶名称
在 main.tf 中,找到 random_pet.bucket_name 资源。 存储桶模块使用此资源为 S3 存储桶分配一个随机名称。 将 length 的值更新为 5。
main.tf
resource "random_pet" "bucket_name" {
- length = 3
+ length = 5
separator = "-"
prefix = "learning"
}
规划此更改。
$ terraform plan
##...
Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
-/+ destroy and then create replacement
Terraform will perform the following actions:
# aws_s3_object.objects[0] must be replaced
-/+ resource "aws_s3_object" "objects" {
~ bucket = "learning-newly-still-gibbon" -> (known after apply) # forces replacement
~ bucket_key_enabled = false -> (known after apply)
~ etag = "fd1573fb94f296502600f23b95493cf4" -> (known after apply)
~ id = "learning_gladly_incredibly_deeply_growing_condor.txt" -> (known after apply)
+ kms_key_id = (known after apply)
- metadata = {} -> null
+ server_side_encryption = (known after apply)
~ storage_class = "STANDARD" -> (known after apply)
- tags = {} -> null
+ version_id = (known after apply)
# (6 unchanged attributes hidden)
}
##...
# module.s3_bucket.aws_s3_bucket_public_access_block.this[0] must be replaced
-/+ resource "aws_s3_bucket_public_access_block" "this" {
~ bucket = "learning-newly-still-gibbon" -> (known after apply) # forces replacement
~ id = "learning-newly-still-gibbon" -> (known after apply)
# (4 unchanged attributes hidden)
}
Plan: 8 to add, 0 to change, 8 to destroy.
Changes to Outputs:
~ bucket_arn = "arn:aws:s3:::learning-newly-still-gibbon" -> (known after apply)
~ bucket_name = "learning-newly-still-gibbon" -> (known after apply)
------------------------------------------------------------------------
请注意,Terraform 计划更改 random_pet 资源以及依赖于它的任何资源。
再次规划变更,但仅针对 random_pet.bucket_name 资源。
$ terraform plan -target="random_pet.bucket_name"
random_pet.bucket_name: Refreshing state... [id=learning-specially-tender-fawn]
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
-/+ destroy and then create replacement
Terraform will perform the following actions:
# random_pet.bucket_name must be replaced
-/+ resource "random_pet" "bucket_name" {
~ id = "learning-specially-tender-fawn" -> (known after apply)
~ length = 3 -> 5 # forces replacement
# (2 unchanged attributes hidden)
}
Plan: 1 to add, 0 to change, 1 to destroy.
Changes to Outputs:
~ bucket_name = "learning-specially-tender-fawn" -> (known after apply)
Warning: Resource targeting is in effect
##...
Terraform 将计划仅替换目标资源。
现在创建一个针对模块的计划,这将适用于模块内的所有资源。
$ terraform plan -target="module.s3_bucket"
random_pet.bucket_name: Refreshing state... [id=learning-specially-tender-fawn]
module.s3_bucket.aws_s3_bucket.this[0]: Refreshing state... [id=learning-specially-tender-fawn]
module.s3_bucket.aws_s3_bucket_public_access_block.this[0]: Refreshing state... [id=learning-specially-tender-fawn]
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
-/+ destroy and then create replacement
Terraform will perform the following actions:
# random_pet.bucket_name must be replaced
-/+ resource "random_pet" "bucket_name" {
~ id = "learning-specially-tender-fawn" -> (known after apply)
~ length = 3 -> 5 # forces replacement
# (2 unchanged attributes hidden)
}
# module.s3_bucket.aws_s3_bucket.this[0] must be replaced
-/+ resource "aws_s3_bucket" "this" {
+ acceleration_status = (known after apply)
~ arn = "arn:aws:s3:::learning-specially-tender-fawn" -> (known after apply)
~ bucket = "learning-specially-tender-fawn" -> (known after apply) # forces replacement
~ bucket_domain_name = "learning-specially-tender-fawn.s3.amazonaws.com" -> (known after apply)
~ bucket_regional_domain_name = "learning-specially-tender-fawn.s3.eu-west-1.amazonaws.com" -> (known after apply)
~ hosted_zone_id = "Z1BKCTXD74EZPE" -> (known after apply)
~ id = "learning-specially-tender-fawn" -> (known after apply)
~ region = "eu-west-1" -> (known after apply)
~ request_payer = "BucketOwner" -> (known after apply)
- tags = {} -> null
+ website_domain = (known after apply)
+ website_endpoint = (known after apply)
# (2 unchanged attributes hidden)
~ versioning {
~ enabled = false -> (known after apply)
~ mfa_delete = false -> (known after apply)
}
}
##...
Plan: 4 to add, 0 to change, 4 to destroy.
Changes to Outputs:
~ bucket_arn = "arn:aws:s3:::learning-specially-tender-fawn" -> (known after apply)
~ bucket_name = "learning-specially-tender-fawn" -> (known after apply)
Warning: Resource targeting is in effect
##...
Terraform 确定 module.s3_bucket 依赖于 random_pet.bucket_name,并且存储桶名称配置已更改。由于此依赖关系,Terraform 将更新上游存储桶名称和您为此操作针对的模块。资源定位会更新目标所依赖的资源,但不更新依赖于目标的资源。
仅应用对存储桶名称的更改。对确认提示回复 yes。
$ terraform apply -target="random_pet.bucket_name"
random_pet.bucket_name: Refreshing state... [id=learning-specially-tender-fawn]
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
-/+ destroy and then create replacement
Terraform will perform the following actions:
# random_pet.bucket_name must be replaced
-/+ resource "random_pet" "bucket_name" {
~ id = "learning-specially-tender-fawn" -> (known after apply)
~ length = 3 -> 5 # forces replacement
# (2 unchanged attributes hidden)
}
Plan: 1 to add, 0 to change, 1 to destroy.
Changes to Outputs:
~ bucket_name = "learning-specially-tender-fawn" -> (known after apply)
Warning: Resource targeting is in effect
##...
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
random_pet.bucket_name: Destroying... [id=learning-specially-tender-fawn]
random_pet.bucket_name: Destruction complete after 0s
random_pet.bucket_name: Creating...
random_pet.bucket_name: Creation complete after 0s [id=learning-optionally-violently-apparently-equal-skylark]
Warning: Applied changes may be incomplete
The plan was created with the -target option in effect, so some changes
requested in the configuration may have been ignored and the output values may
not be fully updated. Run the following command to verify that no other
changes are pending:
terraform plan
Note that the -target option is not suitable for routine use, and is provided
only for exceptional situations such as recovering from errors or mistakes, or
when Terraform specifically suggests to use it as part of an error message.
Apply complete! Resources: 1 added, 0 changed, 1 destroyed.
Outputs:
bucket_arn = "arn:aws:s3:::learning-specially-tender-fawn"
bucket_name = "learning-optionally-violently-apparently-equal-skylark"
请注意,bucket_name 输出已更改,不再与存储桶 ARN 匹配。打开 outputs.tf 并注意存储桶名称输出值引用随机宠物资源,而不是存储桶本身。
outputs.tf
output "bucket_name" {
description = "Randomly generated bucket name."
value = random_pet.bucket_name.id
}
在使用 Terraform 的正常工作流程并将更改应用于整个工作目录时,存储桶名称修改将应用于所有下游依赖项。由于您针对的是随机宠物资源,Terraform 更新了存储桶名称的输出值,但没有更新存储桶本身。资源定位可能会引入不一致性,因此您仅应在故障排除场景中使用它。
更新 bucket_name 输出以引用实际的存储桶名称。
outputs.tf
output "bucket_name" {
description = "Randomly generated bucket name."
- value = random_pet.bucket_name.id
+ value = module.s3_bucket.s3_bucket_id
}
由于您在上一次操作中仅针对配置的一部分,因此您的现有资源与原始配置或新配置都不匹配。将更改应用于整个工作目录,以使 Terraform 更新您的基础设施以匹配当前配置,包括您对 bucket_name 输出所做的更改。在提示符处输入 yes 确认操作。
$ terraform apply
##...
Plan: 7 to add, 0 to change, 7 to destroy.
Changes to Outputs:
~ bucket_arn = "arn:aws:s3:::learning-newly-still-gibbon" -> (known after apply)
~ bucket_name = "learning-seriously-lately-hugely-pleasing-newt" -> (known after apply)
------------------------------------------------------------------------
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
##...
Apply complete! Resources: 7 added, 0 changed, 7 destroyed.
Outputs:
bucket_arn = "arn:aws:s3:::learning-seriously-lately-hugely-pleasing-newt"
bucket_name = "learning-seriously-lately-hugely-pleasing-newt"
在使用资源定位修复 Terraform 项目中的问题后,请务必将更改应用于整个配置,以确保所有资源之间的一致性。请记住,您可以使用 terraform plan 查看任何剩余的计划更改。
目标特定的存储桶对象
打开 main.tf 并更新存储桶对象的内容。示例配置使用单行示例文本来表示包含有用数据的对象。按照以下所示的方式更改对象内容。
main.tf
resource "aws_s3_object" "objects"
count = 4
acl = "public-read"
key = "${random_pet.object_names[count.index].id}.txt"
bucket = module.s3_bucket.s3_bucket_id
- content = "Example object #${count.index}"
+ content = "Bucket object #${count.index}"
content_type = "text/plain"
}
你可以传递多个 -target 选项来一次性定位多个资源。将此更改应用于其中两个存储桶对象,并用 yes 确认。
$ terraform apply -target="aws_s3_object.objects[2]" -target="aws_s3_object.objects[3]"
##...
Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
~ update in-place
Terraform will perform the following actions:
# aws_s3_object.objects[2] will be updated in-place
~ resource "aws_s3_object" "objects" {
~ content = "Example object #2" -> "Bucket object #2"
id = "learning_overly_subtly_suitably_flexible_goldfish.txt"
tags = {}
+ version_id = (known after apply)
# (10 unchanged attributes hidden)
}
# aws_s3_object.objects[3] will be updated in-place
~ resource "aws_s3_object" "objects" {
~ content = "Example object #3" -> "Bucket object #3"
id = "learning_informally_blatantly_jolly_worthy_crappie.txt"
tags = {}
+ version_id = (known after apply)
# (10 unchanged attributes hidden)
}
Plan: 0 to add, 2 to change, 0 to destroy.
╷
│ Warning: Resource targeting is in effect
│
│ You are creating a plan with the -target option, which means that the
│ result of this plan may not represent all of the changes requested by the
│ current configuration.
│
│ The -target option is not for routine use, and is provided only for
│ exceptional situations such as recovering from errors or mistakes, or when
│ Terraform specifically suggests to use it as part of an error message.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
aws_s3_object.objects[2]: Modifying... [id=learning_overly_subtly_suitably_flexible_goldfish.txt]
aws_s3_object.objects[2]: Modifications complete after 1s [id=learning_overly_subtly_suitably_flexible_goldfish.txt]
aws_s3_object.objects[3]: Modifications complete after 1s [id=learning_informally_blatantly_jolly_worthy_crappie.txt]
╷
│ Warning: Applied changes may be incomplete
│
│ The plan was created with the -target option in effect, so some changes
│ requested in the configuration may have been ignored and the output values
│ may not be fully updated. Run the following command to verify that no other
│ changes are pending:
│ terraform plan
│
│ Note that the -target option is not suitable for routine use, and is
│ provided only for exceptional situations such as recovering from errors or
│ mistakes, or when Terraform specifically suggests to use it as part of an
│ error message.
╵
Apply complete! Resources: 0 added, 2 changed, 0 destroyed.
Outputs:
bucket_arn = "arn:aws:s3:::learning-seriously-lately-hugely-pleasing-newt"
bucket_name = "learning-seriously-lately-hugely-pleasing-newt"
Terraform 更新了选定的存储桶对象,并通知你对基础设施的更改可能不完整。
目标存储桶对象名称
如上所示,你可以使用 count 或 for_each 元参数创建的集合的各个实例。但是,Terraform 为整个资源计算资源依赖关系。在某些情况下,这可能会导致令人惊讶的结果。
从 main.tf 中的 random_pet.object_names 资源中删除 prefix 参数。
main.tf
resource "random_pet" "object_names" {
count = 4
length = 5
separator = "_"
- prefix = "learning"
}
尝试将此更改应用于单个存储桶对象。
$ terraform apply -target="aws_s3_object.objects[2]"
##...
Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
-/+ destroy and then create replacement
Terraform will perform the following actions:
# aws_s3_object.objects[2] must be replaced
-/+ resource "aws_s3_object" "objects" {
~ bucket_key_enabled = false -> (known after apply)
~ etag = "ac6265d2157e71b8e8470b465ddb45db" -> (known after apply)
~ id = "learning_overly_subtly_suitably_flexible_goldfish.txt" -> (known after apply)
~ key = "learning_overly_subtly_suitably_flexible_goldfish.txt" -> (known after apply) # forces replacement
+ kms_key_id = (known after apply)
- metadata = {} -> null
+ server_side_encryption = (known after apply)
~ storage_class = "STANDARD" -> (known after apply)
- tags = {} -> null
+ version_id = (known after apply)
# (6 unchanged attributes hidden)
}
# random_pet.object_names[0] must be replaced
-/+ resource "random_pet" "object_names" {
~ id = "learning_gladly_incredibly_deeply_growing_condor" -> (known after apply)
- prefix = "learning" -> null # forces replacement
# (2 unchanged attributes hidden)
}
# random_pet.object_names[1] must be replaced
-/+ resource "random_pet" "object_names" {
~ id = "learning_nationally_carefully_firstly_huge_whippet" -> (known after apply)
- prefix = "learning" -> null # forces replacement
# (2 unchanged attributes hidden)
}
# random_pet.object_names[2] must be replaced
-/+ resource "random_pet" "object_names" {
~ id = "learning_overly_subtly_suitably_flexible_goldfish" -> (known after apply)
- prefix = "learning" -> null # forces replacement
# (2 unchanged attributes hidden)
}
# random_pet.object_names[3] must be replaced
-/+ resource "random_pet" "object_names" {
~ id = "learning_informally_blatantly_jolly_worthy_crappie" -> (known after apply)
- prefix = "learning" -> null # forces replacement
# (2 unchanged attributes hidden)
}
Plan: 5 to add, 0 to change, 5 to destroy.
Warning: Resource targeting is in effect
You are creating a plan with the -target option, which means that the result
of this plan may not represent all of the changes requested by the current
configuration.
The -target option is not for routine use, and is provided only for
exceptional situations such as recovering from errors or mistakes, or when
Terraform specifically suggests to use it as part of an error message.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value:
请注意,Terraform 更新了所有五个 random_pet.object_name 资源,而不仅仅是你针对的对象的名称。 random_pet.object_name 和 aws_s3_object.object 都使用 count 来配置多个资源,并且每个存储桶对象都引用相同索引的名称。但是,由于整个 aws_s3_bucket_objects.objects 资源依赖于整个 random_pet.object_names 资源,Terraform 更新了所有名称。
用 yes 接受更改。
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
aws_s3_bucket_object.objects[2]: Destroying... [id=learning_brightly_strangely_naturally_willing_aardvark.txt]
aws_s3_bucket_object.objects[2]: Destruction complete after 1s
random_pet.object_names[2]: Destroying... [id=learning_brightly_strangely_naturally_willing_aardvark]
##...
Apply complete! Resources: 5 added, 0 changed, 5 destroyed.
Outputs:
bucket_arn = "arn:aws:s3:::learning-optionally-violently-apparently-equal-skylark"
bucket_name = "learning-optionally-violently-apparently-equal-skylark"
销毁你的基础设施
Terraform 的 destroy 命令也接受资源定位。在上面的示例中,你使用方括号中的索引来引用单个存储桶对象,例如 aws_s3_bucket_object.objects[2]。你还可以一次性引用整个资源集合。销毁存储桶对象,并用 yes 回应确认提示。
$ terraform destroy -target="aws_s3_object.objects"
##...
Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
- destroy
Terraform will perform the following actions:
# aws_s3_object.objects[0] will be destroyed
##...
Plan: 0 to add, 0 to change, 4 to destroy.
Warning: Resource targeting is in effect
You are creating a plan with the -target option, which means that the result
of this plan may not represent all of the changes requested by the current
configuration.
The -target option is not for routine use, and is provided only for
exceptional situations such as recovering from errors or mistakes, or when
Terraform specifically suggests to use it as part of an error message.
Do you really want to destroy all resources?
Terraform will destroy all your managed infrastructure, as shown above.
There is no undo. Only 'yes' will be accepted to confirm.
Enter a value: yes
aws_s3_bucket_object.objects[3]: Destroying... [id=learning_rationally_lately_slowly_careful_warthog.txt]
aws_s3_bucket_object.objects[1]: Destroying... [id=learning_partially_eminently_intensely_elegant_worm.txt]
aws_s3_bucket_object.objects[2]: Destroying... [id=mostly_manually_certainly_cheerful_quetzal.txt]
aws_s3_bucket_object.objects[0]: Destroying... [id=learning_firmly_smoothly_firmly_dashing_bonefish.txt]
aws_s3_bucket_object.objects[2]: Destruction complete after 1s
aws_s3_bucket_object.objects[3]: Destruction complete after 1s
aws_s3_bucket_object.objects[0]: Destruction complete after 1s
aws_s3_bucket_object.objects[1]: Destruction complete after 1s
Warning: Applied changes may be incomplete
The plan was created with the -target option in effect, so some changes
requested in the configuration may have been ignored and the output values may
not be fully updated. Run the following command to verify that no other
changes are pending:
terraform plan
Note that the -target option is not suitable for routine use, and is provided
only for exceptional situations such as recovering from errors or mistakes, or
when Terraform specifically suggests to use it as part of an error message.
Destroy complete! Resources: 4 destroyed.
现在销毁你的剩余基础设施。用 yes 回应确认提示。
$ terraform destroy
Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
- destroy
Terraform will perform the following actions:
##...
Plan: 0 to add, 0 to change, 8 to destroy.
Changes to Outputs:
- bucket_arn = "arn:aws:s3:::learning-seriously-lately-hugely-pleasing-newt" -> null
- bucket_name = "learning-seriously-lately-hugely-pleasing-newt" -> null
Do you really want to destroy all resources?
Terraform will destroy all your managed infrastructure, as shown above.
There is no undo. Only 'yes' will be accepted to confirm.
Enter a value: yes
##...
Apply complete! Resources: 0 added, 0 changed, 8 destroyed.
如果你使用 HCP Terraform 完成本教程,在销毁资源后,请从你的 HCP Terraform 组织中删除 learn-terraform-resource-targeting 工作区。
后续步骤
在本教程中,您使用了 Terraform 的资源定位来指定将给定的更改应用于哪些资源。资源定位在某些情况下是一个有用的工具,但您应避免在日常操作中使用它,因为它可能导致您的基础设施变得不一致。
- 阅读 Terraform 文档关于资源定位。
- 跟随教程了解如何 管理资源漂移。
- 了解如何 排查 Terraform 中的常见问题。
- 跟随我们的 管理 Terraform 状态教程,学习其他操作 Terraform 状态的方法。