Введение
Модули Terraform позволяют группировать отдельные ресурсы вашей инфраструктуры в один унифицированный ресурс. Вы можете использовать их повторно с возможными настройками, не повторяя определения ресурсов каждый раз, когда они вам нужны, что полезно для крупных проектов со сложной структурой. Вы можете настраивать экземпляры модулей, используя определяемые вами входные переменные, а также извлекать из них информацию с помощью выходных данных. Помимо создания собственных модулей, вы также можете использовать готовые модули, опубликованные в реестре Terraform. Разработчики могут использовать и настраивать их, используя входные данные, такие как создаваемые вами модули, но их исходный код хранится как в облаке, так и вне его. В этом руководстве вы создадите модуль Terraform, который запускает несколько дроплетов за балансировщиком нагрузки для обеспечения избыточности. Вы также будете использовать функции циклов for_each и count языка конфигурации Hashicorp (HCL) для одновременного развертывания нескольких настроенных экземпляров модулей.
Предпосылки
- Персональный код доступа DigitalOcean
- Terraform установлен в вашей системе и создан проект с поставщиком DO.
- Введение в типы данных и циклы HCL
- Введение в выходные данные Terraform и их использование
Структура модуля и преимущества
В этом разделе вы узнаете о преимуществах модулей, их обычном размещении в проекте и о том, как их следует структурировать. Пользовательские модули Terraform создаются для инкапсуляции связанных компонентов, которые часто используются в крупных проектах и развертываются совместно. Они самодостаточны и объединяют только необходимые им ресурсы, переменные и поставщики. Модули обычно хранятся в центральной папке в корне проекта, каждый в своей подпапке. Чтобы обеспечить чёткое разделение между модулями, всегда проектируйте их так, чтобы они имели одно назначение, и следите за тем, чтобы они никогда не содержали подмодулей. Упаковка одного ресурса в виде модуля может быть избыточной и постепенно снижать простоту общей архитектуры. Для небольших проектов разработки и тестирования объединение модулей необязательно, поскольку в таких случаях это не приводит к существенному прогрессу. Преимущество модулей заключается в том, что определения достаточно изменить только в одном месте, а затем это изменение распространяется на остальную инфраструктуру.
Далее вы определяете, используете и настраиваете модули в своих проектах Terraform.
Создать модуль
В этом разделе вы определите несколько дроплетов и балансировщик нагрузки как ресурсы Terraform и упакуете их в модуль. Вы также настроите получившийся модуль, используя настраиваемые входные данные.
Поместите модуль в каталог под названием капелька-фунт, вы сохраните их в каталоге modules. Предполагая, что вы находитесь в каталоге terraform-modules, созданном в рамках предварительных требований, установите оба одновременно, выполнив команду:
mkdir -p modules/droplet-lbАргумент -p указывает mkdir создать все каталоги по указанному пути.
Перейти к нему:
cd modules/droplet-lbКак упоминалось в предыдущем разделе, модули содержат используемые ими ресурсы и переменные. Начиная с Terraform 0.13, они также должны содержать определения используемых ими поставщиков. Модули не требуют специальной настройки для указания того, что код представляет собой модуль, поскольку Terraform считает модулем любой каталог, содержащий код HCL, даже корневой каталог проекта.
Переменные, определённые в модуле, доступны в качестве входных данных и могут использоваться в определениях ресурсов для их настройки. Создаваемый вами модуль будет иметь два входных данных: количество создаваемых дроплетов и имя их группы. Чтобы отредактировать файл с именем переменные.tf Создайте и откройте место, где вы будете хранить переменные:
nano variables.tfДобавьте следующие строки:
variable "droplet_count" {}
variable "group_name" {}Сохраните и закройте файл.
Вы определяете Droplet в файле, который называется капли.tf Сохраните его. Создайте и откройте для редактирования:
nano droplets.tf
Добавьте следующие строки:
resource "digitalocean_droplet" "droplets" {
count = var.droplet_count
image = "ubuntu-22-04-x64"
name = "${var.group_name}-${count.index}"
region = "fra1"
size = "s-1vcpu-1gb"
lifecycle {
precondition {
condition = var.droplet_count >= 2
error_message = "At least two droplets must be created."
}
}
}Для параметра считатьПередаётся переменная droplet_count, которая определяет количество создаваемых экземпляров ресурса. Её значение будет определено при вызове модуля из основного кода проекта. Имя каждого развёрнутого дроплета будет разным, что достигается добавлением индекса текущего дроплета к указанному имени группы. Развёртывание дроплетов в зоне fra1 Он будет работать под управлением Ubuntu 22.04.
Раздел Жизненный цикл Содержит Предварительное условие выполняется до фактического развёртывания ресурсов. Здесь проверяется, что будет создано не менее двух кластеров — наличие только одного кластера противоречит принципам балансировщика нагрузки. Другой пример валидации можно найти в репозитории k8s-bootstrapper, содержащем шаблоны для настройки кластера DigitalOcean Kubernetes с использованием Terraform. Там валидация используется для того, чтобы убедиться, что количество узлов в кластере находится в допустимых пределах.
Когда закончите, сохраните и закройте файл.
Определив дроплеты, можно перейти к созданию балансировщика нагрузки. Определите его источник в файле с именем фунт.тф Сохраните его. Создайте и откройте для редактирования, выполнив следующую команду:
nano lb.tfДобавьте определение источника:
resource "digitalocean_loadbalancer" "www-lb" {
name = "lb-${var.group_name}"
region = "fra1"
forwarding_rule {
entry_port = 80
entry_protocol = "http"
target_port = 80
target_protocol = "http"
}
healthcheck {
port = 22
protocol = "tcp"
}
droplet_ids = [
for droplet in digitalocean_droplet.droplets:
droplet.id
]
}Вы определяете балансировщик нагрузки, используя имя группы в названии, чтобы он был узнаваем. Вы определяете его вместе с точками сброса в зоне. fra1 В следующих двух разделах указываются целевые и мониторинговые порты и протоколы.
Выделенный блок droplet_ids получает идентификаторы дроплетов, которыми должен управлять балансировщик нагрузки. Поскольку дроплетов несколько, и их количество заранее неизвестно, используется цикл for для перебора коллекции дроплетов (digitalocean_droplet.droplets) и получения их идентификаторов. Цикл for заключается в квадратные скобки ([]), так что результирующая коллекция представляет собой список.
Сохраните и закройте файл.
Теперь, когда вы определили Droplet, Load Balancer и переменные для своего модуля, вам необходимо определить требования к провайдерам и указать, каких провайдеров будет использовать модуль, включая их версию и местоположение. Начиная с Terraform 0.13, модули должны явно указывать ресурсы провайдеров, не принадлежащих Hashicorp, которые они будут использовать. Это связано с тем, что они не будут наследовать их от родительского проекта.
Вы определяете требования к поставщику в файле, который называется провайдер.tf Вы сохраните его. Сделайте его доступным для редактирования, выполнив следующую команду:
nano provider.tfДобавьте следующие строки, чтобы потребовать поставщика Digitalocean:
terraform {
required_providers {
digitalocean = {
source = "digitalocean/digitalocean"
version = "~> 2.0"
}
}
}После завершения сохраните и закройте файл. Модуль капелька-фунт Теперь к провайдеру Digitalocean Потребности.
Модули также поддерживают выходные данные, которые можно использовать для извлечения внутренней информации о состоянии их ресурсов. Вы определяете выходные данные, отображающие IP-адрес балансировщика нагрузки, и сохраняете их в файле с именем выходы.tf Сохраните его. Создайте для редактирования:
nano outputs.tfДобавьте следующее определение:
output "lb_ip" {
value = digitalocean_loadbalancer.www-lb.ip
}Этот вывод вернет IP-адрес балансировщика нагрузки. Сохраните и закройте файл.
Модуль капелька-фунт Теперь он полностью функционален и готов к развертыванию. Вы будете вызывать его из основного кода, который будет храниться в корне проекта. Сначала перейдите к нему, дважды щёлкнув вверх в каталоге файлов:
cd ../..Затем файл называется main.tf Создайте и откройте для редактирования место, где вы будете использовать модуль:
nano main.tfДобавьте следующие строки:
module "groups" {
source = "./modules/droplet-lb"
droplet_count = 3
group_name = "group1"
}
output "loadbalancer-ip" {
value = module.groups.lb_ip
}В этом объявлении модуль капелька-фунт Вы вызываете исходный каталог, который находится в указанном каталоге. В качестве входных данных он предоставляет: droplet_count и имя_группы Вы настраиваете его на group1, чтобы иметь возможность различать экземпляры в дальнейшем.
Поскольку выходной IP-адрес балансировщика нагрузки определён в модуле, он не отображается автоматически при развёртывании проекта. Решение — создать другой выходной адрес, извлекая его значение (loadbalancer_ip).
По завершении сохраните и закройте файл.
Запустите модуль, выполнив:
terraform initРезультат будет следующим:
OutputInitializing modules...
- groups in modules/droplet-lb
Initializing the backend...
Initializing provider plugins...
- Finding digitalocean/digitalocean versions matching "~> 2.0"...
- Installing digitalocean/digitalocean v2.34.1...
- Installed digitalocean/digitalocean v2.34.1 (signed by a HashiCorp partner, key ID F82037E524B9C0E8)
...
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.Вы можете запланировать проект, чтобы увидеть, какие действия Terraform предпримет после выполнения:
terraform plan -var "do_token=${DO_PAT}"Вывод будет примерно таким:
Output...
Terraform used the selected providers to generate the following execution plan. Resource actions are
indicated with the following symbols:
+ create
Terraform will perform the following actions:
# module.groups.digitalocean_droplet.droplets[0] will be created
+ resource "digitalocean_droplet" "droplets" {
...
+ name = "group1-0"
...
}
# module.groups.digitalocean_droplet.droplets[1] will be created
+ resource "digitalocean_droplet" "droplets" {
...
+ name = "group1-1"
...
}
# module.groups.digitalocean_droplet.droplets[2] will be created
+ resource "digitalocean_droplet" "droplets" {
...
+ name = "group1-2"
...
}
# module.groups.digitalocean_loadbalancer.www-lb will be created
+ resource "digitalocean_loadbalancer" "www-lb" {
...
+ name = "lb-group1"
...
}
Plan: 4 to add, 0 to change, 0 to destroy.
...В этом выводе объясняется, что Terraform создает три дроплета с именами group1-0, group1-1 и group1-2, а также создает балансировщик нагрузки с именем group1-lb, который обрабатывает трафик к этим трем дроплетам и от них.
Вы можете развернуть проект в облаке, выполнив следующее:
terraform apply -var "do_token=${DO_PAT}"При появлении запроса введите «да». В результатах будут отображены все действия, а также IP-адрес балансировщика нагрузки:
Outputmodule.groups.digitalocean_droplet.droplets[1]: Creating...
module.groups.digitalocean_droplet.droplets[0]: Creating...
module.groups.digitalocean_droplet.droplets[2]: Creating...
...
Apply complete! Resources: 4 added, 0 changed, 0 destroyed.
Outputs:
loadbalancer-ip = ip_addressВы создали модуль, содержащий настраиваемое количество дроплетов и балансировщик нагрузки, который автоматически настраивается для управления входящим и исходящим трафиком.
Переименовать развернутые ресурсы
В предыдущем разделе вы развернули определённый вами модуль и назвали его Group. Если вы хотите изменить его имя, простое переименование вызова модуля не даст ожидаемого результата. Переименование вызова приведёт к уничтожению и повторному созданию ресурсов Terraform, что приведёт к чрезмерному простою.
Например, main.tf Откройте его для редактирования, выполнив:
nano main.tfПереименуйте модуль групп в group_renamed, как указано:
module "groups_renamed" {
source = "./modules/droplet-lb"
droplet_count = 3
group_name = "group1"
}
output "loadbalancer-ip" {
value = module.groups_renamed.lb_ip
}Сохраните и закройте файл. Затем снова инициализируйте проект:
terraform initТеперь вы можете планировать проект:
terraform plan -var "do_token=${DO_PAT}"Вывод будет длинным, но выглядеть будет примерно так:
Output...
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
- destroy
Terraform will perform the following actions:
# module.groups.digitalocean_droplet.droplets[0] will be destroyed
...
# module.groups_renamed.digitalocean_droplet.droplets[0] will be created
...Terraform требует уничтожения существующих экземпляров и создания новых. Это разрушительно, ненужно и может привести к непреднамеренным сбоям.
Вместо этого вы можете указать Terraform перенести старые ресурсы с новым именем, используя перенесённый блок. Откройте файл main.tf для редактирования и добавьте в конец следующие строки:
moved {
from = module.groups
to = module.groups_renamed
}Когда закончите, сохраните и закройте файл.
Теперь вы можете планировать проект:
terraform plan -var "do_token=${DO_PAT}"При программировании с перемещенным блоком в main.tf Terraform хочет переместить ресурсы вместо их пересоздания:
OutputTerraform will perform the following actions:
# module.groups.digitalocean_droplet.droplets[0] has moved to module.groups_renamed.digitalocean_droplet.droplets[0]
...
# module.groups.digitalocean_droplet.droplets[1] has moved to module.groups_renamed.digitalocean_droplet.droplets[1]
...Мобильные ресурсы изменяют свое местоположение в режиме Terraform, а это означает, что реальные облачные ресурсы не изменяются, не уничтожаются и не воссоздаются.
Поскольку на следующем этапе вам предстоит существенно изменить конфигурацию, обновите развернутые ресурсы, выполнив следующую команду:
terraform destroy -var "do_token=${DO_PAT}"Когда вас спросили, Да Введите . Вывод заканчивается:
Output...
Destroy complete! Resources: 4 destroyed.В этом разделе вы переименовали ресурсы в проекте Terraform, не уничтожая их. Теперь вы развернёте несколько экземпляров модуля из одного и того же кода, используя for_each и count.
Развертывание нескольких экземпляров модуля
В этом разделе вы будете использовать count и for_each для многократного развертывания модуля droplet-lb с возможностью настройки.
Использование счетчика
Один из способов одновременно развернуть несколько экземпляров модуля — передать значение параметра count, которое автоматически доступно для каждого модуля. Откройте main.tf для редактирования:
nano main.tfИзмените его на следующий, удалив существующее определение вывода и перемещенный блок:
module "groups" {
source = "./modules/droplet-lb"
count = 3
droplet_count = 3
group_name = "group1-${count.index}"
}Установив значение 3, вы дадите Terraform команду развернуть модуль три раза, каждый раз с разным именем группы. После завершения сохраните и закройте файл.
Запланируйте развертывание, выполнив:
terraform plan -var "do_token=${DO_PAT}"Вывод будет длинным и будет выглядеть так:
Output...
Terraform used the selected providers to generate the following execution plan. Resource actions are
indicated with the following symbols:
+ create
Terraform will perform the following actions:
# module.groups[0].digitalocean_droplet.droplets[0] will be created
...
# module.groups[0].digitalocean_droplet.droplets[1] will be created
...
# module.groups[0].digitalocean_droplet.droplets[2] will be created
...
# module.groups[0].digitalocean_loadbalancer.www-lb will be created
...
# module.groups[1].digitalocean_droplet.droplets[0] will be created
...
# module.groups[1].digitalocean_droplet.droplets[1] will be created
...
# module.groups[1].digitalocean_droplet.droplets[2] will be created
...
# module.groups[1].digitalocean_loadbalancer.www-lb will be created
...
# module.groups[2].digitalocean_droplet.droplets[0] will be created
...
# module.groups[2].digitalocean_droplet.droplets[1] will be created
...
# module.groups[2].digitalocean_droplet.droplets[2] will be created
...
# module.groups[2].digitalocean_loadbalancer.www-lb will be created
...
Plan: 12 to add, 0 to change, 0 to destroy.
...Terraform поясняет в выходных данных, что каждый из трех экземпляров модуля имеет три Droplet и связанный с ними балансировщик нагрузки.
Использование for_each
Вы можете использовать for_each для модулей, когда вам нужна более сложная настройка экземпляров или когда количество экземпляров зависит от сторонних данных (часто предоставляемых в виде карты), которые неизвестны на момент написания кода.
Теперь вы определяете карту, которая связывает имена групп с количеством дроплетов и реализует экземпляры droplet-lb на её основе. Откройте main.tf для редактирования, выполнив команду:
nano main.tfИзмените файл следующим образом:
variable "group_counts" {
type = map
default = {
"group1" = 1
"group2" = 3
}
}
module "groups" {
source = "./modules/droplet-lb"
for_each = var.group_counts
droplet_count = each.value
group_name = each.key
}Сначала вы определяете карту group_counts, содержащую количество дроплетов в данной группе. Затем вы вызываете модуль droplet-lb, но указываете, что цикл for_each должен работать с var.group_counts, картой, которую вы определили ранее. droplet_count принимает each.value — текущее значение пары, которое представляет собой количество дроплетов в текущей группе. group_name принимает имя группы.
По завершении сохраните и закройте файл.
Попробуйте применить конфигурацию, выполнив следующее:
terraform plan -var "do_token=${DO_PAT}"В выходных данных показаны подробности действий Terraform по созданию этих двух групп с дроплетами и балансировщиками нагрузки:
Output...
Terraform used the selected providers to generate the following execution plan. Resource actions are
indicated with the following symbols:
+ create
Terraform will perform the following actions:
# module.groups["group1"].digitalocean_droplet.droplets[0] will be created
...
# module.groups["group1"].digitalocean_loadbalancer.www-lb will be created
...
# module.groups["group2"].digitalocean_droplet.droplets[0] will be created
...
# module.groups["group2"].digitalocean_droplet.droplets[1] will be created
...
# module.groups["group2"].digitalocean_droplet.droplets[2] will be created
...
# module.groups["group2"].digitalocean_loadbalancer.www-lb will be created
...На этом этапе вы использовали count и for_each для развертывания нескольких настроенных экземпляров модуля из одного и того же кода.
Результат
В этом руководстве вы создали и реализовали модули Terraform. Вы использовали модули для группировки логически связанных ресурсов и настроили их для развёртывания нескольких различных экземпляров централизованного определения кода. Вы также использовали выходные данные для отображения свойств ресурсов в модуле.









