使用 Terraform 进行分层部署
Layered deployments with Terraform
我是 Terraform 的新手,所以甚至不确定这样的事情是否可行。例如,假设我有一个模板,用于在其中部署 Azure 资源组和密钥保管库。然后假设我有另一个模板将虚拟机部署到同一个资源组中。是否可以在不破坏 Key Vault 和资源组的情况下使用虚拟机模板进行破坏?我们正在尝试划分大型解决方案的各个部分,而不必将其全部放在一个模板中,我们希望能够单独管理每个部分而不影响其他部分。
相关说明...我们将状态文件存储在 Azure 存储帐户中。如果我们将部署分解为多个分隔的部署……每个部署应该有自己的状态文件还是应该都使用相同的状态文件?
您可以使用 terraform destroy -target path.to.resource
销毁特定资源。 Docs
大型解决方案的不同部分可以拆分为 modules,这些模块甚至不必是同一代码库的一部分,可以远程引用。根据您的解决方案,您可能希望将部署分解为模块并从包含所有内容的 "master" 状态文件中引用它们。
对于较大的系统,通常将基础架构拆分为多个单独的 配置 并分别应用它们中的每一个。这是与使用共享 模块 不同的想法(并且是对其的补充):模块允许许多不同的配置拥有自己独立的 "copy" 一组特定的基础设施,而下面描述的模式允许将一个配置管理的对象通过引用传递给另一个。
如果某些配置将依赖于其他配置的结果,则有必要将这些结果存储在一些数据存储中,该数据存储可以由其生产者写入并由其消费者读取。在 Terraform 状态远程存储且可广泛读取的环境中,the terraform_remote_state
data source 是一种常见的入门方式:
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 ...
}
此示例中由 terraform_remote_state
数据源导出的 resource_group_name
属性假定该名称的值由使用 output 管理资源组的配置公开。
这将两个配置解耦,使它们具有完全独立的生命周期。您首先在创建资源组的配置中 terraform apply
,然后在包含上面显示的 terraform_remote_state
数据资源的配置中 terraform apply
。然后,您可以根据需要多次应用后一种配置,而不会给共享资源组或密钥保管库带来风险。
虽然 terraform_remote_state
数据源对于任何已经使用 remote state (which is recommended), some organizations prefer to decouple configurations further by introducing an intermediate data store like Consul 的组织来说都可以快速上手,但它允许更明确地在配置之间传递数据。
为此,"producing" 配置(管理您的资源组的配置)使用 the consul_key_prefix
resource 在众所周知的位置将有关它创建的内容的必要信息发布到 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}"
}
}
然后使用集中管理的资源组和密钥保管库的单独配置将使用 the consul_keys
data source:
读取它
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 ...
}
在 return 中,由于 运行 另一个存储这些中间值的服务的额外复杂性,除了 Consul 中商定的键命名方案之外,这两个配置现在彼此一无所知,这提供了灵活性,例如,如果您将来决定重构这些 Terraform 配置,以便 Key Vault 也有自己的单独配置。使用像 Consul 这样的 generic 数据存储也可能使这些数据可供应用程序本身使用,例如通过 consul-template.
Consul 只是数据存储的一个例子,它恰好在 Terraform 中得到了很好的支持。使用 Terraform 可以读取和写入的任何其他数据存储也可以实现类似的结果。例如,您甚至可以将 TXT
条记录中的值存储在 a DNS zone and use the DNS provider 中以供读取,作为避免 运行 额外服务的 "outside the box" 解决方案。
像往常一样,这里需要在简单性("everything in one configuration" 是最简单的)和灵活性(使用单独的配置存储)之间进行权衡,因此您需要评估其中的哪一个方法最适合您的情况。
作为一些额外的上下文:我已经为中等复杂度的系统记录了 a pattern I used successfully。在那种情况下,我们混合使用了 Consul 和 DNS 来创建一个 "environment" 抽象,允许我们为暂存环境、生产环境等单独部署相同的应用程序。所使用的确切技术不如模式重要,尽管.这种方法不会完全适用于所有其他情况,但希望其中有一些想法可以帮助其他人思考如何在他们的环境中最好地利用 Terraform。
我是 Terraform 的新手,所以甚至不确定这样的事情是否可行。例如,假设我有一个模板,用于在其中部署 Azure 资源组和密钥保管库。然后假设我有另一个模板将虚拟机部署到同一个资源组中。是否可以在不破坏 Key Vault 和资源组的情况下使用虚拟机模板进行破坏?我们正在尝试划分大型解决方案的各个部分,而不必将其全部放在一个模板中,我们希望能够单独管理每个部分而不影响其他部分。
相关说明...我们将状态文件存储在 Azure 存储帐户中。如果我们将部署分解为多个分隔的部署……每个部署应该有自己的状态文件还是应该都使用相同的状态文件?
您可以使用 terraform destroy -target path.to.resource
销毁特定资源。 Docs
大型解决方案的不同部分可以拆分为 modules,这些模块甚至不必是同一代码库的一部分,可以远程引用。根据您的解决方案,您可能希望将部署分解为模块并从包含所有内容的 "master" 状态文件中引用它们。
对于较大的系统,通常将基础架构拆分为多个单独的 配置 并分别应用它们中的每一个。这是与使用共享 模块 不同的想法(并且是对其的补充):模块允许许多不同的配置拥有自己独立的 "copy" 一组特定的基础设施,而下面描述的模式允许将一个配置管理的对象通过引用传递给另一个。
如果某些配置将依赖于其他配置的结果,则有必要将这些结果存储在一些数据存储中,该数据存储可以由其生产者写入并由其消费者读取。在 Terraform 状态远程存储且可广泛读取的环境中,the terraform_remote_state
data source 是一种常见的入门方式:
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 ...
}
此示例中由 terraform_remote_state
数据源导出的 resource_group_name
属性假定该名称的值由使用 output 管理资源组的配置公开。
这将两个配置解耦,使它们具有完全独立的生命周期。您首先在创建资源组的配置中 terraform apply
,然后在包含上面显示的 terraform_remote_state
数据资源的配置中 terraform apply
。然后,您可以根据需要多次应用后一种配置,而不会给共享资源组或密钥保管库带来风险。
虽然 terraform_remote_state
数据源对于任何已经使用 remote state (which is recommended), some organizations prefer to decouple configurations further by introducing an intermediate data store like Consul 的组织来说都可以快速上手,但它允许更明确地在配置之间传递数据。
为此,"producing" 配置(管理您的资源组的配置)使用 the consul_key_prefix
resource 在众所周知的位置将有关它创建的内容的必要信息发布到 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}"
}
}
然后使用集中管理的资源组和密钥保管库的单独配置将使用 the consul_keys
data source:
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 ...
}
在 return 中,由于 运行 另一个存储这些中间值的服务的额外复杂性,除了 Consul 中商定的键命名方案之外,这两个配置现在彼此一无所知,这提供了灵活性,例如,如果您将来决定重构这些 Terraform 配置,以便 Key Vault 也有自己的单独配置。使用像 Consul 这样的 generic 数据存储也可能使这些数据可供应用程序本身使用,例如通过 consul-template.
Consul 只是数据存储的一个例子,它恰好在 Terraform 中得到了很好的支持。使用 Terraform 可以读取和写入的任何其他数据存储也可以实现类似的结果。例如,您甚至可以将 TXT
条记录中的值存储在 a DNS zone and use the DNS provider 中以供读取,作为避免 运行 额外服务的 "outside the box" 解决方案。
像往常一样,这里需要在简单性("everything in one configuration" 是最简单的)和灵活性(使用单独的配置存储)之间进行权衡,因此您需要评估其中的哪一个方法最适合您的情况。
作为一些额外的上下文:我已经为中等复杂度的系统记录了 a pattern I used successfully。在那种情况下,我们混合使用了 Consul 和 DNS 来创建一个 "environment" 抽象,允许我们为暂存环境、生产环境等单独部署相同的应用程序。所使用的确切技术不如模式重要,尽管.这种方法不会完全适用于所有其他情况,但希望其中有一些想法可以帮助其他人思考如何在他们的环境中最好地利用 Terraform。