Terraform的分层部署

phy*_*man 1 terraform terraform-template-file terraform-provider-azure

我是Terraform的新手,所以甚至不确定这样的事情是否可行。举例来说,假设我有一个模板,该模板中部署了一个Azure资源组和一个密钥库。然后说我有另一个模板,可以将虚拟机部署到同一资源组中。是否可以在不破坏密钥库和资源组的情况下使用虚拟机模板进行破坏?我们试图将大型解决方案的各个部分划分开来,而不必将其全部放在一个模板中,并且我们希望能够独立管理每个部分而又不影响其他部分。

在相关说明中...我们将状态文件存储在Azure存储帐户中。如果我们将部署分解为多个分区的部署...每个部署应该有自己的状态文件还是应该都使用相同的状态文件?

Mar*_*ins 5

对于较大的系统,通常将基础结构拆分为多个单独的配置,然后分别应用每个配置。这与使用共享模块是一个独立的想法(并且是对它们的补充):模块允许许多不同的配置对一组特定的基础结构拥有自己的单独“副本”,而以下所述的模式则允许由一个配置管理的对象通过引用传递给另一个。

如果某些配置将取决于其他配置的结果,则必须将这些结果存储在某些数据存储中,该数据存储可由其生产者写入并由其消费者读取。在其中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 ...
}
Run Code Online (Sandbox Code Playgroud)

在此示例中resource_group_nameterraform_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}"
  }
}
Run Code Online (Sandbox Code Playgroud)

然后将单独的配置(一个或多个)使用的集中管理的资源组和密钥保管库将使用读取它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 ...
}
Run Code Online (Sandbox Code Playgroud)

作为运行另一项服务来存储这些中间值的额外复杂性的回报,这两个配置现在除了对Consul中键的约定命名方案有所了解外,彼此之间一无所知,例如,如果将来您决定重构这些Terraform配置,以便密钥库也具有自己的单独配置。使用像Consul这样的通用数据存储,还可能会例如通过consul-template使这些数据对应用程序本身可用。

领事只是一个数据存储的例子,恰好在Terraform中得到了很好的支持。使用Terraform可以读取和写入的任何其他数据存储,也可以实现类似的结果。例如,您甚至可以将值存储在DNS区域中的TXT记录中,并使用DNS提供程序读取“开箱即用”的解决方案,从而避免运行其他服务。


像往常一样,这里需要在简单性(最简单的“所有配置”)和灵活性(使用单独的配置存储)之间进行权衡,因此您需要评估以下哪种方法是最好的适合您的情况。

作为其他一些上下文:我已经记录了成功用于中等复杂度系统的模式。在那种情况下,我们使用Consul和DNS的混合来创建“环境”抽象,该抽象使我们能够分别为登台环境,生产等部署相同的应用程序。尽管如此,使用的确切技术并不重要。这种方法不会完全适用于所有其他情况,但是希望其中有一些想法可以帮助其他人思考如何在他们的环境中最佳利用Terraform。