对于较大的系统,通常将基础架构拆分为多个单独的配置并分别应用它们。这是一个与使用共享模块不同的想法(并且是对使用共享模块的补充):模块允许许多不同的配置拥有自己单独的一组特定基础设施的“副本”,而下面描述的模式允许由一个配置管理的对象通过引用传递给另一个。
如果某些配置将依赖于其他配置的结果,则有必要将这些结果存储在某个数据存储中,该数据存储可以由其生产者写入并由其消费者读取。在 Terraform 状态被远程存储和广泛可读的环境中,数据terraform_remote_state
源是一种常用的入门方式:
data "terraform_remote_state" "resource_group" {
# The settings here should match the "backend" settings in the
# configuration that manages the network resources.
backend = "s3"
config {
bucket = "mycompany-terraform-states"
region = "us-east-1"
key = "azure-resource-group/terraform.tfstate"
}
}
resource "azurerm_virtual_machine" "example" {
resource_group_name = "${data.terraform_remote_state.resource_group.resource_group_name}"
# ... etc ...
}
此示例中数据源导出的resource_group_name
属性terraform_remote_state
假定该名称的值已由使用输出管理资源组的配置公开。
这将两种配置解耦,使它们具有完全独立的生命周期。您首先terraform apply
在创建资源组的配置中,然后terraform apply
在包含terraform_remote_state
上面显示的数据资源的配置中。然后,您可以根据需要多次应用后一种配置,而不会对共享资源组或密钥保管库造成风险。
虽然对于已经使用远程状态terraform_remote_state
(推荐)的任何组织来说,数据源都可以快速上手,但一些组织更喜欢通过引入像Consul这样的中间数据存储来进一步解耦配置,这样就可以更明确地在配置之间传递数据.
为此,“生产”配置(管理您的资源组的配置)使用以下consul_key_prefix
资源将有关其创建内容的必要信息发布到 Consul 的知名位置:
resource "consul_key_prefix" "example" {
path_prefix = "shared/resource_group/"
subkeys = {
name = "${azurerm_resource_group.example.name}"
id = "${azurerm_resource_group.example.id}"
}
resource "consul_key_prefix" "example" {
path_prefix = "shared/key_vault/"
subkeys = {
name = "${azurerm_key_vault.example.name}"
id = "${azurerm_key_vault.example.id}"
uri = "${azurerm_key_vault.example.uri}"
}
}
然后,使用集中管理的资源组和密钥保管库的单独配置将使用数据consul_keys
源读取它:
data "consul_keys" "example" {
key {
name = "resource_group_name"
path = "shared/resource_group/name"
}
key {
name = "key_vault_name"
path = "shared/key_vault/name"
}
key {
name = "key_vault_uri"
path = "shared/key_vault/uri"
}
}
resource "azurerm_virtual_machine" "example" {
resource_group_name = "${data.consul_keys.example.var.resource_group_name}"
# ... etc ...
}
作为运行另一个服务来存储这些中间值的额外复杂性的回报,这两种配置现在除了在 Consul 中商定的键命名方案之外,彼此一无所知,这提供了灵活性,例如,如果将来您决定重构这些 Terraform 配置,以便密钥库也有自己的单独配置。使用像 Consul 这样的通用数据存储也可能使这些数据对应用程序本身可用,例如通过consul-template。
Consul 只是恰好已经在 Terraform 中得到很好支持的数据存储的一个示例。使用 Terraform 可以读写的任何其他数据存储也可以实现类似的结果。例如,您甚至可以将值存储在DNS 区域TXT
中的记录中,并使用DNS 提供程序进行读取,这是一种“开箱即用”的解决方案,可以避免运行额外的服务。
像往常一样,这里需要在简单性(“一个配置中的所有内容”是最简单的)和灵活性(使用单独的配置存储)之间进行权衡,因此您需要评估哪些方法是最好的适合你的情况。
作为一些额外的背景:我已经记录了我成功用于中等复杂度系统的模式。在这种情况下,我们混合使用 Consul 和 DNS 来创建“环境”抽象,允许我们为暂存环境、生产环境等单独部署相同的应用程序。不过,使用的确切技术不如模式重要。这种方法并不完全适用于所有其他情况,但希望其中有一些想法可以帮助其他人思考如何在他们的环境中最好地利用 Terraform。