Terraform — это Open source решение для управления IaC от компании Hashicorp, вышедшее в 2014 году. Terraform придерживается декларативного стиля управления инфраструктурой. Это значит, что вы описываете финальное состояние инфраструктуры в конфигурационном файле, а Terraform приводит её к нему. Достаточно написать конфигурацию, в которой будет изложено, как вы видите вашу будущую инфраструктуру, а главное, если описывать конфигурацию инфраструктуры в человеко-читаемом текстовом формате, то после применения данной конфигурации начинаются создаваться ресурсы в заранее определённых зависимостях.
Данный метод не позволяет использовать заранее определённую статическую конфигурацию разметки и подключения дисков.
Необходимо настроить подключение дисков в определённой последовательности, чтобы в дальнейшем с помощью Ansible, на дисках создать разделы и подмонтировать их в нужные папки.
Вариант без зависимостей
resource "vcd_vm_internal_disk" "server_disk_swap" {
vapp_name = vcd_vm.server.vapp_name
vm_name = vcd_vm.server.name
vdc = vcd_vm.server.vdc
bus_type = "paravirtual"
size_in_mb = 51200
bus_number = 0
unit_number = 1
storage_profile = "VC7-SSD"
}
resource "vcd_vm_internal_disk" "server_disk_app" {
vapp_name = vcd_vm.server.vapp_name
vm_name = vcd_vm.server.name
vdc = vcd_vm.server.vdc
bus_type = "paravirtual"
size_in_mb = 102500
bus_number = 0
unit_number = 2
storage_profile = "VC7-SSD"
}
resource "vcd_vm_internal_disk" "server_disk_db" {
vapp_name = vcd_vm.server.vapp_name
vm_name = vcd_vm.server.name
vdc = vcd_vm.server.vdc
bus_type = "paravirtual"
size_in_mb = 204800
bus_number = 0
unit_number = 3
storage_profile = "VC7-SSD"
}
Код для создания дисков без зависимостей
resource "vcd_vm_internal_disk" "disk_1" {
unit_number = 1
}
resource "vcd_vm_internal_disk" "disk_2" {
unit_number = 2
}
resource "vcd_vm_internal_disk" "disk_3" {
unit_number = 3
}
Если использовать подобную конструкцию, тогда диски будут создаваться в случайной последовательности. В свойствах виртуальной машины у дисков будут правильные Unit Number, но не правильный Index. На хосте так же имена дисков будут не в той последовательности, которая необходима.
Решение со статическими зависимостями
resource "vcd_vm_internal_disk" "server_disk_swap" {
vapp_name = vcd_vm.server.vapp_name
vm_name = vcd_vm.server.name
vdc = vcd_vm.server.vdc
bus_type = "paravirtual"
size_in_mb = 51200
bus_number = 0
unit_number = 1
storage_profile = "VC7-SSD"
depends_on = [vcd_vm.server]
}
resource "vcd_vm_internal_disk" "server_disk_app" {
vapp_name = vcd_vm.server.vapp_name
vm_name = vcd_vm.server.name
vdc = vcd_vm.server.vdc
bus_type = "paravirtual"
size_in_mb = 102500
bus_number = 0
unit_number = 2
storage_profile = "VC7-SSD"
depends_on = [vcd_vm_internal_disk.server_disk_swap]
}
resource "vcd_vm_internal_disk" "server_disk_db" {
vapp_name = vcd_vm.server.vapp_name
vm_name = vcd_vm.server.name
vdc = vcd_vm.server.vdc
bus_type = "paravirtual"
size_in_mb = 204800
bus_number = 0
unit_number = 3
storage_profile = "VC7-SSD"
depends_on = [vcd_vm_internal_disk.server_disk_app]
}
Решение со статическими зависимостями
resource "vcd_vm_internal_disk" "disk_1" {
unit_number = 1
depends_on = [vcd_vm.vm]
}
resource "vcd_vm_internal_disk" "disk_2" {
unit_number = 2
depends_on = [vcd_vm_internal_disk.disk_1]
}
resource "vcd_vm_internal_disk" "disk_3" {
unit_number = 3
depends_on = [vcd_vm_internal_disk.disk_2]
}
В данном решении указаны статические объекты, которые ссылаются на предыдущий элемент.
Если в переменную depends_on подставить какую-нибудь переменную, тогда получаем ошибку "A single static variable reference is
required: only attribute access and indexing with constant keys. No
calculations, function calls, template expressions, etc are allowed
here.". Использование
переменных depends_on запрещены из-за особенности построения структуры создания
ресурсов. Как видим на рисунке 2 диски создаются параллельно и ничего друг о
друге они не знают, т.к. находятся в параллельных ветках зависимостей.
depends_on = [vcd_vm.vm] - указывает, что необходимо ждать пока создастся виртуальная машина (можно эту зависимость не указывать, terraform сам распределяет очерёдность создания и он не создаст диск, пока не будет создана виртуальная машина
depends_on = [vcd_vm_internal_disk.disk_1] - указывает, что ждём пока не создастся ресурс vcd_vm_internal_disk.disk_1
depends_on = [vcd_vm_internal_disk.disk_2] - указывает, что ждём пока не создастся ресурс vcd_vm_internal_disk.disk_2
Это рабочий вариант, когда нам нужно создать не большое количество виртуальных машин, но когда их много, тогда код будет очень громоздкий и в нём будет очень сложно разобраться.
Решение с динамическими зависимостями
Для данного решения вынесем создание диска в отдельный модуль modules>disks>main.tf
resource "time_sleep" "wait" {
depends_on = [var.vms]
create_duration = "${var.sleep}s"
}
resource "vcd_vm_internal_disk" "disks" {
vapp_name = var.vapp_name
vm_name = var.vm_name
vdc = var.vdc
bus_type = var.bus_type
size_in_mb = var.size_in_mb
bus_number = 0
unit_number = var.unit_number
storage_profile = "VC7-SSD"
depends_on = [time_sleep.wait]
}
Код модуля для создания дисков
Основной код ./main.tf
module "disks" {
count = length(var.vcd_host.disks)
source = "../disks"
vapp_name = vcd_vm.vms.vapp_name
vm_name = vcd_vm.vms.name
vdc = vcd_vm.vms.vdc
vms = vcd_vm.vms
bus_type = var.vcd_host.disks[count.index].bus_type
size_in_mb = var.vcd_host.disks[count.index].size_in_mb
unit_number = count.index + 1
sleep = (30 * count.index) + 1
}
Решение с динамическими интервалами создания
Переменная откуда берётся список дисков (variables.tf)
disks = [
{bus_type = "paravirtual", size_in_mb = 51200},
{bus_type = "paravirtual", size_in_mb = 102400},
{bus_type = "paravirtual", size_in_mb = 204800}
]
Список необходимых дисков в определённой последовательности
Теперь с помощью цикла мы можем создать то количество дисков, которое нам необходимо, и в нужной последовательности. Если последовательность нарушается, тогда можно увеличить время ожидания с 30 до 60 и т.д.
module "disks" {
count = length(var.vcd_vm.disks)
size_in_mb = var.vcd_vm.disks[count.index]
unit_number = count.index + 1
sleep = (30 * count.index) + 1
}
В модуле с помощь переменной sleep мы регулируем, когда начинать создание диска. Для таймера мы так же указываем, чтобы он не начинал отсчёт, пока не будет создана машина, указанная в переменной vcd_vm.
resource "time_sleep" "wait" {
depends_on = [var.vcd_vm]
create_duration = "${var.sleep}s"
}
Заключение
Как видите, при создании ресурсов с помощью terraform есть определённые сложности для организации последовательности. Для разрешения этих сложностей можно использовать несколько вариантов. Для создания инфраструктуры, в которой более 50-ти машин, мне пригодился вариант с динамическими зависимостями, который очень сильно сократил и оптимизировал код. Надеюсь, данное решение пригодится тебе в работе.
Автор: Алексей Цветков.