Многоуровневое развертывание с помощью Terraform

Я новичок в Terraform, поэтому даже не уверен, что что-то подобное возможно. Например, допустим, у меня есть шаблон, который развертывает группу ресурсов Azure, и хранилище ключей в нем. А потом, скажем, у меня есть другой шаблон, который развертывает виртуальную машину в той же группе ресурсов. Можно ли выполнить уничтожение с помощью шаблона виртуальной машины, не разрушая хранилище ключей и группу ресурсов? Мы пытаемся разделить части большого решения, не помещая все это в один шаблон, и мы хотим иметь возможность управлять каждой частью отдельно, не затрагивая другие части.

В связи с этим... мы храним файлы состояния в учетной записи хранения Azure. Если мы разделим наше развертывание на несколько разделенных на части развертываний... должно ли каждое развертывание иметь свой собственный файл состояния или все они должны использовать один и тот же файл состояния?

2 ответа

Решение

Для более крупных систем принято разделять инфраструктуру на несколько отдельных конфигураций и применять каждую из них отдельно. Эта идея отличается от (и дополняет) использование общих модулей: модули позволяют нескольким различным конфигурациям иметь свою собственную "копию" определенного набора инфраструктуры, в то время как шаблоны, описанные ниже, позволяют объекту, управляемому одной конфигурацией, передаваться по ссылке на другого.

Если некоторые конфигурации будут зависеть от результатов других конфигураций, необходимо сохранить эти результаты в некотором хранилище данных, которое может быть записано его производителем и считано его потребителем. В среде, где состояние 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 ресурс:

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 ...
}

В ответ на дополнительную сложность запуска другого сервиса для хранения этих промежуточных значений, две конфигурации теперь ничего не знают друг о друге, кроме согласованной схемы именования ключей в Консуле, что дает гибкость, если, например, в будущем вы решите провести реорганизацию этих конфигураций Terraform, чтобы хранилище ключей имело свою собственную отдельную конфигурацию. Использование общего хранилища данных, такого как Consul, также потенциально делает эти данные доступными для самих приложений, например, через консул-шаблон.

Consul - это только один пример хранилища данных, которое уже хорошо поддерживается в Terraform. Также возможно достичь аналогичных результатов, используя любое другое хранилище данных, которое Terraform может и читать, и записывать. Например, вы можете даже хранить значения в TXT записи в зоне DNS и использование DNS-провайдера для чтения в качестве "нестандартного" решения, позволяющего избежать запуска дополнительной службы.


Как обычно, здесь необходимо найти компромисс между простотой ("простейшее из возможных решений - все в одной конфигурации") и гибкостью (с отдельным хранилищем конфигурации), поэтому вам необходимо оценить, какой из этих подходов является наилучшим подходит для вашей ситуации.

В качестве дополнительного контекста: я задокументировал шаблон, который успешно использовал для системы средней сложности. В этом случае мы использовали смесь Consul и DNS для создания абстракции "среды", которая позволяла нам развертывать одни и те же приложения отдельно для промежуточной среды, производства и т. Д. Точные используемые технологии менее важны, чем шаблон. Этот подход не будет применяться точно ко всем другим ситуациям, но, надеюсь, в нем есть некоторые идеи, которые помогут другим подумать о том, как наилучшим образом использовать Terraform в своей среде.

Вы можете уничтожить определенные ресурсы, используя terraform destroy -target path.to.resource, Документы

Различные части большого решения могут быть разделены на модули, эти модули даже не обязательно должны быть частью одной и той же кодовой базы и на них можно ссылаться удаленно. В зависимости от вашего решения вы можете разбить ваши развертывания на модули и ссылаться на них из "основного" файла состояния, который содержит все.

Другие вопросы по тегам