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-ти машин, мне пригодился вариант с динамическими зависимостями, который очень сильно сократил и оптимизировал код. Надеюсь, данное решение пригодится тебе в работе.

Автор: Алексей Цветков.

Комментарии (0)