Быстрый старт с Terraform

Опубликовано

На все данные актуальны

В этом разделе мы на примерах покажем, как развернуть простую инфраструктуру в облаке Сервер Молл Cloud, создадим инстансы, назначим им плавающие (внешние) IP, создадим и подключим к ним дополнительные диски.

Предварительные требования

  1. Учетная запись Сервер Молл Cloud.
    У вас должна быть зарегистрирована учётная запись в личном кабинете Сервер Молл Cloud. Подробности в руководстве: “Регистрация аккаунта”.
  2. Подключена услуга “Облачная инфраструктура”.
    Услуга “Облачная инфраструктура” должна быть заказана и готова к работе. Как получить услугу, см. в инструкции ”Как заказать облачную инфраструктуру”.
  3. Terraform установлен.
    На компьютере должен быть установлен Terraform. Чтобы проверить, установлен ли он, выполните команду: terraform version. Если Terraform установлен, команда выведет его версию. В противном случае установите его по инструкции “Установка Terraform”.
  4. Настроена авторизация Terraform в облаке.
    Создайте конфигурационный файл и настройте авторизацию Terraform в облаке Сервер Молл Cloud по инструкции: “Аутентификация в облачной инфраструктуре через Terraform”.

Перед тем, как начать

В процессе создания конфигурации вам могут понадобиться данные о необходимых ресурсах и параметрах. Получить их можно через панель управления облачной инфраструктурой (облачная консоль) или с помощью CLI:

Важно: во всех примерах конфигурации заменяйте шаблонные значения (плейсхолдеры) в угловых скобках <…> на реальные параметры вашего проекта без самих скобок:

  • Строковое значение:
        # Исходный шаблон из примера
    instance_id = "<instance_id>"
    
    # После замены — конкретное значение в кавычках
    instance_id = "45fb7597-50db-4a39-b0f2-b6ce2eca773a"
  • Ссылка на Terraform-ресурс или переменную:
        # Исходный шаблон из примера
    instance_id = "<instance_id>"
    
    # После замены — ссылка на ресурс, без кавычек
    instance_id = openstack_compute_instance_v2.tf_instance_1.id
  • Числовое значение:
        # Исходный шаблон из примера 
    volume_size = <volume_size_in_gb>
    
    # После замены — просто число, без кавычек
    volume_size = 30

Для более глубокого изучения настройки OpenStack Provider в Terraform вы можете обратиться к официальной документации HashiCorp, доступной на их официальном сайте по ссылке.

I. Создание инстанса через Terraform

В этом разделе мы рассмотрим создание одного и нескольких инстансов в облачной инфраструктуре Сервер Молл Cloud через Terraform. Мы покажем как создать инстанс, дополнив файл конфигурации Terraform, который мы создали, когда настраивали  авторизацию Terraform в облаке, согласно инструкции: “Аутентификация в облачной инфраструктуре через Terraform”.

Создание одного инстанса

  1. Добавьте в файл конфигурации блок создания инстанса:
        # Блок создания одного инстанса в OpenStack через Terraform
    resource "openstack_compute_instance_v2" "tf_instance_1" {
      name            = "<instance_name>"                                   # Имя создаваемого инстанса
      image_id        = "<os_image_id>"                                     # Идентификатор используемого образа ОС
      flavor_id       = "<instance_flavor_id>"                              # Тип инстанса (определяет ресурсы CPU, RAM)
      key_pair        = "<key_pair_name>"                                   # Имя ключевой пары для SSH-доступа
      security_groups = ["default"]                                         # Список групп безопасности, применяемых к инстансу
    
      # Подключение файла с пользовательскими данными (cloud-init)
      user_data = file("${path.module}/<cloud-init.yaml>")                  # Путь к cloud-init YAML-файлу
    
      # Блок настройки основного (загрузочного) диска инстанса
      block_device {
        uuid                  = "<os_image_id>"                             # Идентификатор образа, используемого для создания диска
        source_type           = "image"                                     # Тип источника данных для создания диска (образ)
        destination_type      = "volume"                                    # Назначение (создание диска-тома)
        volume_size           = <volume_size_in_gb>                         # Размер создаваемого диска в гигабайтах
        volume_type           = "<volume_type_id>"                          # Тип дискового хранилища
        boot_index            = 0                                           # Порядок загрузки (0 — основной загрузочный диск)
        delete_on_termination = true                                        # Удалять диск после удаления инстанса
      }
    
      # Блок сетевых настроек подключения инстанса
      network {
        uuid = "<network_id>"                                               # Идентификатор сети, к которой подключается инстанс
      }
    }
    
  1. Замените значения-заполнители в угловых скобках <...> на реальные значения вашего проекта, исключая сами скобки, для следующих параметров:
    1. name — Уникальное имя инстанса (в рамках проекта).
    2. image_id — идентификатор образа операционной системы.
      Узнать id образа доступные проекту можно, через облачную консоль ("Compute" > "Images" в поле "ID/Name") или через CLI (openstack image list).
    3. flavor_id — идентификатор конфигурации инстанса, определяющий ресурсы (CPU, RAM). Узнать доступные id конфигураций можно через облачную консоль ("Compute" > "Flavors" в поле "ID/Name") или CLI (openstack flavor list).
    4. key_pair — имя существующей ключевой пары для SSH-подключения. Узнать доступные имена ключевых пар можно через облачную консоль ("Compute" > "Key Pairs" в поле "Name") или CLI (openstack keypair list). Если ключевой пары ещё нет, создайте её по инструкции «Создание ключевой пары».
    5. user_data — путь к файлу с пользовательскими данными (cloud-init или Ignition), который используется для автоматической настройки инстанса при его первом запуске.

      Важно: Обязательно используйте пользовательские данные для автоматической настройки — как минимум для создания пользователя, назначения прав доступа и установки пароля. Без этого вы можете не получить доступ к инстансу для управления им.

      Рекомендуется: Использовать относительный путь, основанный на переменной "
      ${path.module}" — она возвращает путь к директории, где находится текущий .tf-файл. Это делает конфигурацию переносимой и надёжной в разных окружениях.
      Пример указания пути к файлу пользовательских данных:
      user_data = file("${path.module}/cloud-init.yaml")

      Не рекомендуется: Указывать абсолютный путь, так как он жёстко привязан к конкретной системе и может не работать при переносе конфигурации, например:
      user_data = file("/home/user/project/cloud-init.yaml") # Linux/macOS  user_data = file("C:/Users/admin/project/cloud-init.yaml") # Window

      Примечание: Для указания пути в Windows рекомендуется использовать прямые слэши (/) в пути. Обратные слэши (\) требуют двойного экранирования (\\) и могут привести к ошибкам.
  1. uuid (block_device) — идентификатор образа, указанный в поле “image_id”.
  2. volume_size — размер создаваемого диска в гигабайтах, вводится целым числом (например, 30).
  3. volume_type — id типа диска:
    • 25c82f52-dc3b-4337-a939-a73ec1a58d2a — Hybrid-Datastore.
    • a462fa3a-8e23-492c-97bd-d493b1a8d0a4 — All-Flash-Datastore.
      Доступные id типов диска можно узнать через CLI (openstack volume type list).
  1. uuid (network) — идентификатор внутренней сети, к которой будет подключён инстанс. Узнать его можно через облачную консоль ("Network" > "Networks" > "Current Project Networks" в поле "ID/Name") или CLI (openstack network list --internal).

    "tf_instance_1" — это наименование инстанса внутри конфигурации Terraform, его вы можете произвольно изменить. Однако все упоминания инстанса должны совпадать, например, при создании инстанса, подключении дополнительного диска или плавающего IP-адреса.

    Поля "security_groups", "source_type", "destination_type", "boot_index" и “delete_on_termination” не требуют изменений.

    Когда изменения внесены, этот блок может выглядеть так:
        # Блок создания одного инстанса в OpenStack через Terraform
    resource "openstack_compute_instance_v2" "tf_instance_1" {
      name            = "test_instance"                                     # Имя создаваемого инстанса
      image_id        = "os_image_id45fb7597-50db-4a39-b0f2-b6ce2eca773a"   # Идентификатор используемого образа ОС
      flavor_id       = "07050101-11d1-4916-a31d-153405676deb"              # Тип инстанса (определяет ресурсы CPU, RAM)
      key_pair        = "test_key_pair"                                     # Имя ключевой пары для SSH-доступа
      security_groups = ["default"]                                         # Список групп безопасности, применяемых к инстансу
    
    # Подключение файла с пользовательскими данными (cloud-init)
      user_data = file("${path.module}/cloud-init.yaml")                    # Путь к cloud-init YAML-файлу
    
    
      # Блок настройки основного (загрузочного) диска инстанса
      block_device {
        uuid                  = "45fb7597-50db-4a39-b0f2-b6ce2eca773a"      # Идентификатор образа, используемого для создания диска
        source_type           = "image"                                     # Тип источника данных для создания диска (образ)
        destination_type      = "volume"                                    # Назначение (создание диска-тома)
        volume_size           = 30                                          # Размер создаваемого диска в гигабайтах
        volume_type           = "a462fa3a-8e23-492c-97bd-d493b1a8d0a4"      # Тип дискового хранилища
        boot_index            = 0                                           # Порядок загрузки (0 — основной загрузочный диск)
        delete_on_termination = true                                        # Удалять диск после удаления инстанса
      }
    
      # Блок сетевых настроек подключения инстанса
      network {
        uuid = "7c63ba21-958b-4856-b1da-764ed077b4df"                       # Идентификатор сети, к которой подключается инстанс
      }
    }
  1. Сохраните изменения в файле.

Создание нескольких инстансов

Вы можете создать сразу группу из нескольких инстансов с идентичными или различными характеристиками. Основное отличие от создания одного инстанса — наличие в блоке параметра "count", указывающего количество создаваемых инстансов. Параметры инстансов могут быть заданы как единым значением для всех инстансов группы, так и в виде списков в отдельном блоке локальных переменных "locals", для каждого инстанса индивидуально. Также возможно использовать динамические значения параметров, например, добавляя порядковый номер к имени каждого инстанса, как это показано в примере ниже, в параметре “name”.

При создании нескольких инстансов имя ресурса (например, "tf_instances" из примера, приведенного ниже), используемое Terraform, является именем группы. Это имя группы мы будем использовать далее при подключении дополнительных дисков или плавающих IP-адресов.

  1. Добавьте в файл конфигурации следующего блока создания инстансов:
        # Блок локальных переменных, укажите свои значения списком или единичным значением
    locals {
      image_ids        = ["<image-id-1>", "<image-id-2>", ..., "<image-id-n>"]                     # Вставьте свои id образов
      volume_sizes     = [<vol-size-1>, <vol-size-2>, ..., <vol-size-n>]                           # Вставьте размеры дисков (числами)
      flavor_ids       = ["<flavor-id-1>", "<flavor-id-2>", ..., "<flavor-id-n>"]                 # Вставьте свои id flavor (типов инстансов)
      volume_types     = ["<volume-type-id-1>", "<volume-type-id-2>", ..., "<volume-type-id-n>"]  # Вставьте свои типы дисков
      key_pair         = "<my-single-keypair>"                                                    # Вставьте имя своей ключевой пары
      user_data_files  = ["${path.module}/<cloud-init-1.yaml>", "${path.module}/<cloud-init-2.yaml>", ..., "${path.module}/<cloud-init-n.yaml>"] # Пути к cloud-init файлам
    }
    
    # Блок создания нескольких инстансов
    resource "openstack_compute_instance_v2" "tf_instances" {
      count           = length(local.image_ids)                          # Количество инстансов равно количеству образов (image_ids) в списке из locals.
      name            = "instance-${count.index + 1}"                    # Автоматическое присвоение имени инстанса с номером
      image_id        = local.image_ids[count.index]                     # id образа из списка
      flavor_id       = local.flavor_ids[count.index]                    # id flavor из списка
      key_pair        = local.key_pair                                   # Ключевая пара (единая для всех)
      user_data       = file(local.user_data_files[count.index])         # Индивидуальный файл пользовательских данных
      security_groups = ["default"]                                      # Группа безопасности единая для всех)
    
    # Блок создания загрузочного диска
      block_device {
        uuid                  = local.image_ids[count.index]             # id образа ОС (должен совпадать с image_id)
        source_type           = "image"                                  # Тип источника данных
        destination_type      = "volume"                                 # Назначение (диск)
        volume_size           = local.volume_sizes[count.index]          # Размер диска
        volume_type           = local.volume_types[count.index]          # Тип диска
        boot_index            = 0                                        # Индекс загрузочного диска
        delete_on_termination = true                                     # Удалять при удалении инстанса
      }
    
    # Сетевая конфигурация
      network {
        uuid = "<network-id>"                                            # Вставьте id своей сети
      }
    }
  1. Измените этот блок в соответствии с вашими потребностями и внесите свои данные, изменив следующие поля и разделы:
  1. locals — блок локальных переменных. Здесь указываются списки параметров или единичные значения, используемые для всех инстансов. Обращение к элементу списка осуществляется через locals.<имя_параметра>[<индекс>], например, flavor_id = local.flavor_ids[count.index] (для списка) или key_pair = local.key_pair (для единичного значения).
  2. count — количество создаваемых инстансов. Можно задать целым числом или вычислить на основе длины списка параметров, например, count = length(local.image_ids).
  3. name — уникальное имя инстанса. Может задаваться динамически (например, name = "My-instance-${count.index + 1}") или списком в “locals”.
  4. image_id — идентификатор образа ОС, доступный из облачной консоли ("Compute" > "Images" в поле "ID/Name") или CLI (openstack image list).
  5. flavor_id — идентификатор конфигурации ресурсов (CPU, RAM), доступный через облачную консоль ("Compute" > "Flavors" в поле "ID/Name") или CLI (openstack flavor list)
  6. key_pair — имя существующей ключевой пары, доступно через облачную консоль ("Compute" > "Key Pairs" в поле "Name") или CLI (openstack keypair list).
  7. user_data — путь к файлу с пользовательскими данными (cloud-init или Ignition), который используется для автоматической настройки инстанса при его первом запуске. Если требуется индивидуальная настройка каждого инстанса, пути к файлам можно указать списком в разделе "locals".
    Подробнее о том, как задать путь к файлу пользовательских данных, см. в разделе выше: “Создание одного инстанса”.
  8. uuid (шт block_device) — должен совпадать с “image_id”.
  9. volume_size — размер диска в ГБ, может задаваться числом или списком в “locals”.
  10. volume_type — id типа диска:
    • 25c82f52-dc3b-4337-a939-a73ec1a58d2a — Hybrid-Datastore.
    • a462fa3a-8e23-492c-97bd-d493b1a8d0a4 — All-Flash-Datastore.

id типа диска доступен через CLI (openstack volume type list).

  1. uuid (network) — идентификатор сети, доступный через облачную консоль ("Network" > "Networks" > "Current Project Networks" в поле "ID/Name") или CLI (openstack network list --internal).

Поля “security_groups”, “source_type”, “destination_type”, “boot_index” и “delete_on_termination” также могут быть заданы единичными значениями или списками для каждого инстанса группы.

Когда изменения внесены, этот блок может выглядеть, например, так:

# Блок локальных переменныхlocals {  image_ids      = ["5890aa4d-05a2-4a58-a23b-bd7affc72770", "45fb7597-50db-4a39-b0f2-b6ce2eca773a", "5890aa4d-05a2-4a58-a23b-bd7affc72770"] # id образов  volume_sizes   = [30, 40, 30]                                                                                                          # Размеры дисков (числами)  flavor_ids     = ["07050101-11d1-4916-a31d-153405676deb", "2dadfd90-dd24-411b-b4ae-94da79404886", "07050101-11d1-4916-a31d-153405676deb"] # id flavor (типов инстансов)  volume_types   = ["25c82f52-dc3b-4337-a939-a73ec1a58d2a", "a462fa3a-8e23-492c-97bd-d493b1a8d0a4", "25c82f52-dc3b-4337-a939-a73ec1a58d2a"] # Типы дисков  key_pair       = "test-keypair"                                                                                                        # Вставьте имя своей ключевой пары  user_data_files = [                                                                                                                    # Пути к cloud-init файлам    "${path.module}/cloud-init-1.yaml",    "${path.module}/cloud-init-2.yaml",    "${path.module}/cloud-init-3.yaml"  ]}
# Блок создания нескольких инстансовresource "openstack_compute_instance_v2" "tf_instances" {  count           = length(local.image_ids)                          # Количество инстансов равно количеству образов (image_ids) в списке из locals.  name            = "My-instance-${count.index + 1}"                 # Автоматическое присвоение имени инстанса с номером  image_id        = local.image_ids[count.index]                     # id образа из списка  flavor_id       = local.flavor_ids[count.index]                    # id flavor из списка  key_pair        = local.key_pair                                   # Ключевая пара (единая для всех)  user_data       = file(local.user_data_files[count.index])         # Индивидуальный cloud-init файл для каждого инстанса  security_groups = ["default"]                                      # Группа безопасности (единая для всех)
  # Блок создания загрузочного диска  block_device {    uuid                  = local.image_ids[count.index]             # id образа ОС (должен совпадать с image_id)    source_type           = "image"                                  # Тип источника данных    destination_type      = "volume"                                 # Назначение (диск)    volume_size           = local.volume_sizes[count.index]          # Размер диска    volume_type           = local.volume_types[count.index]          # Тип диска    boot_index            = 0                                        # Индекс загрузочного диска    delete_on_termination = true                                     # Удалять при удалении инстанса  }
  # Сетевая конфигурация  network {    uuid = "7c63ba21-958b-4856-b1da-764ed077b4df"                                              # id внутренней сети проекта  }}
  1. Сохраните изменения в файле.

II. Выделение инстансу плавающего IP

При создании инстанса в OpenStack ему автоматически назначается внутренний IP-адрес для связи внутри облачной инфраструктуры. Однако для доступа к инстансу из интернета требуется назначение внешнего (плавающего) IP-адреса.

Хотя в OpenStack существует пул внешних IP-адресов, в новом проекте по умолчанию не выделено ни одного плавающего IP-адреса для использования. В этом руководстве мы рассмотрим процесс выделения плавающих IP-адресов из общего пула и их назначения как отдельным инстансам, так и группам инстансов, что обеспечит доступ к вашим виртуальным машинам из внешних сетей.

Основываться будем на файлах конфигурации из раздела I. “Создание инстанса в Terraform”, предполагая, что наша конфигурация дополнит их.

Выделение IP-адреса из пула и его последующее присвоение инстансу

  1. Добавьте в файл конфигурации шаблон блока выделения плавающего адреса и присвоения его инстансу:
# Выделение плавающего IP из пула облачной инфраструктурыresource "openstack_networking_floatingip_v2" "float_ip" {  pool = "<External_IP_pool_name>"  # Укажите имя внешней сети, из пула которой будет выделен плавающий IP}
# Подключение выделенного плавающего IP к созданному инстансуresource "openstack_compute_floatingip_associate_v2" "associate_float_ip" {  floating_ip = openstack_networking_floatingip_v2.float_ip.address  instance_id = openstack_compute_instance_v2.tf_instance_1.id }
  1. Укажите параметр pool — имя внешней сети из пула которой будет выделен плавающий IP.
    Узнать имена внешних сетей проекта вы можете через облачную консоль ("Network" > "Networks" > "External Networks" в поле "ID/Name") или CLI (openstack network list --external).

    Если имя ресурса инстанса не "tf_instance_1" (не из нашего примера по созданию инстанса), замените его на ваше в строке "instance_id".

    После изменений этот блок может выглядеть, например, так:
# Выделение плавающего IP из пула облачной инфраструктурыresource "openstack_networking_floatingip_v2" "float_ip" {  pool = "Floating_IP59"  # Имя внешней сети из пула которой будет выделен плавающий IP}
# Подключение выделенного плавающего IP к созданному инстансуresource "openstack_compute_floatingip_associate_v2" "associate_float_ip" {  floating_ip = openstack_networking_floatingip_v2.float_ip.address  instance_id = openstack_compute_instance_v2.tf_instance_1.id }
  1. Сохраните изменения.

Присвоение ранее выделенного плавающего IP 

  1. Добавьте в файл конфигурации блок присвоения плавающего адреса инстансу:
resource "openstack_compute_floatingip_associate_v2" "associate_float_ip" {  floating_ip = "<Выделенный_ip>" # Укажите выделенный из пула плавающий IP  instance_id = "<id_Инстанса>" # Укажите id инстанса или ссылку на него в конфигурации Terraform}
  1. Укажите свои значения следующих параметров:
    1. floating_ip — IPv4 адрес, выделенный из пула внешней сети и не привязанный ни к одному из инстансов.
      Узнать доступные свободные плавающие IP-адреса в вашем проекте вы можете через облачную консоль ("Network" > "Floating IPs" в поле "ID/Floating IP", статус "DOWN") или через CLI (openstack floating ip list --status DOWN).
    2. instance_id — id инстанса вашего проекта или ссылка на имя инстанса в конфигурации Terraform.
      Узнать id инстансов вашего проекта вы можете через облачную консоль ("Compute" > "Instances" в поле "ID/Name") или через CLI (openstack server list).

Например, блок добавления плавающего IP-адреса для инстанса "tf_instance_1" из примера “Создание одного инстанса” из раздела 1 будет выглядеть следующим образом:

resource "openstack_compute_floatingip_associate_v2" "associate_float_ip" {  floating_ip = "198.51.100.101" # Уже выделенный из пула плавающий IP  instance_id = openstack_compute_instance_v2.tf_instance_1.id # ссылка на инстанс в конфигурации Terraform}

В этом случае указывается ссылка на имя инстанса в конфигурации Terraform.

Или так, если id инстанса указан напрямую:

resource "openstack_compute_floatingip_associate_v2" "associate_float_ip" {  floating_ip = "198.51.100.101" # Уже выделенный из пула плавающий IP  instance_id = "ea6ddfe0-fadf-4c96-aa64-77a61b639112" # id инстанса}
  1. Сохраните изменения конфигурации в файле.

Выделение нескольких плавающих IP и присвоение их группе инстансов

Выделение плавающих IP также возможно сразу для группы инстансов. И здесь мы рассмотрим выделение плавающих IP из пула внешних адресов и присвоение их инстансам из группы. Основываться будем на конфигурации, используя которую мы создавали группу инстансов "tf_instances", описанную в разделе I. “Создание инстанса через Terraform. Создание нескольких инстансов”. 

  1. Добавьте в файл конфигурации шаблон блока выделения плавающего адреса и присвоения его инстансу:
# Выделение плавающих IP-адресов из пула для каждого инстансаresource "openstack_networking_floatingip_v2" "fip" {  count = length(openstack_compute_instance_v2.tf_instances)  pool  = "<external_network_name>" # Укажите название внешней сети, которая будет пулом плавающих IP }
# Привязка выделенных плавающих IP-адресов к инстансамresource "openstack_compute_floatingip_associate_v2" "fip_associate" {  count       = length(openstack_compute_instance_v2.tf_instances)  floating_ip = openstack_networking_floatingip_v2.fip[count.index].address  instance_id = openstack_compute_instance_v2.tf_instances[count.index].id}


Этот код выполняет следующие действия:

  • Выделяет из пула внешних IP-адресов (указанного в параметре "pool") количество адресов, заданное параметром "count".
  • Последовательно назначает выделенные IP-адреса инстансам из группы "tf_instances".
  1. Укажите в параметре “pool” наименование внешней сети, которая будет выступать пулом внешних IP-адресов.
    Узнать имена доступных внешних сетей вы можете, через облачную консоль (“Network” > “Networks” > “External Networks” в поле “ID/Name”) или через CLI (openstack network list --external).

Если имя ресурса группы инстансов не "tf_instances" (не из нашего примера по созданию инстансов), замените его на ваше в строке "instance_id".

После добавления имени внешней сети этот блок может выглядеть, например, так:

# Выделение плавающих IP-адресов из пула для каждого инстансаresource "openstack_networking_floatingip_v2" "fip" {  count = length(openstack_compute_instance_v2.tf_instances)  pool  = "Floating_IP59" # Название внешней сети (пула плавающих IP)}
# Привязка выделенных плавающих IP-адресов к инстансамresource "openstack_compute_floatingip_associate_v2" "fip_associate" {  count       = length(openstack_compute_instance_v2.tf_instances)  floating_ip = openstack_networking_floatingip_v2.fip[count.index].address  instance_id = openstack_compute_instance_v2.tf_instances[count.index].id}
  1. Сохраните изменения.

III. Подключение дополнительного диска к инстансу

К инстансу можно подключить дополнительный диск. Это может быть как новый диск, так и существующий.

Подключить к инстансу дополнительный диск можно на этапе создания инстанса, продублировав блок конфигурации "block_device" и указав в нём параметры: "boot_index = -1" (диск не участвует в загрузке) и source_type = "blank" (пустой).

Но если вам нужно добавить диск уже после создания инстанса, то ниже мы покажем как это сделать на примере конфигураций из раздела I., дополнив их.

Подключение нового диска к создаваемому инстансу

  1. Добавьте в файл конфигурации из раздела I. “Создание инстанса в Terraform. Создание одного инстанса” блоки создания диска и подключения его к  новому инстансу:
# Создание дополнительного диска (volume)resource "openstack_blockstorage_volume_v3" "additional_volume" {  name        = "<volume_name>"  # Укажите имя создаваемого диска  size        = <volume_size>  # Укажите размер создаваемого диска                              volume_type = "<volume_type>"  # Укажите тип создаваемого диска}
# Подключение вновь созданного дополнительного диска к инстансуresource "openstack_compute_volume_attach_v2" "volume_attachment" {  instance_id = openstack_compute_instance_v2.tf_instance_1.id  volume_id   = openstack_blockstorage_volume_v3.additional_volume.id}
  1. Внесите в этот блок свои данные, изменив следующие поля:
  1. volume_name — Произвольное и уникальное в вашем проекте имя диска (например, my-additional-volume-01).
  2. volume_size — Размер создаваемого диска в гигабайтах, вводится целым числом (например, 20).
  3. volume_type — id типа диска:
    • 25c82f52-dc3b-4337-a939-a73ec1a58d2a — Hybrid-Datastore.
    • a462fa3a-8e23-492c-97bd-d493b1a8d0a4 — All-Flash-Datastore.

id доступных вашему проекту типов диска вы можете узнать через CLI  (openstack volume type list).

Если имя ресурса инстанса не "tf_instance_1" (не из нашего примера по созданию инстанса), замените его на ваше в строке "instance_id".

После внесения изменений этот блок может выглядеть так:

# Создание дополнительного диска (volume)resource "openstack_blockstorage_volume_v3" "additional_volume" {  name        = "my-additional-volume" # Имя создаваемого диска  size        = 20 # Размер создаваемого диска                              volume_type = "25c82f52-dc3b-4337-a939-a73ec1a58d2a" # Тип создаваемого диска }
# Подключение дополнительного диска к инстансуresource "openstack_compute_volume_attach_v2" "volume_attachment" {  instance_id = openstack_compute_instance_v2.tf_instance_1.id  volume_id   = openstack_blockstorage_volume_v3.additional_volume.id}
  1. Сохраните изменения.

Если нужно подключить существующий диск к инстансу

  1. Добавьте в файл конфигурации шаблон блок подключения диска к  новому инстансу:
# Подключение существующего диска к инстансу в качестве дополнительного resource "openstack_compute_volume_attach_v2" "existing_volume_attachment" {  instance_id = "<instance_id>" # Укажите id инстанса  volume_id   = "<existing_volume_id_here>" # Укажите id существующего диска}
  1. Внесите в этот блок свои значения параметров:
    1. instance_id — id инстанса вашего проекта или ссылка на имя инстанса в конфигурации Terraform.
      Узнать id инстансов, доступных вашему проекту, вы можете через облачную консоль, перейдя по вкладкам  “Compute” > “Instances” в поле “ID/Name”использовав команду CLI: “openstack server list” или через панель управления .
    2. volume_id — id существующего диска, который вы хотите подключить к создаваемому инстансу.
      Узнать id дисков, доступных вашему проекту и свободных для подключения, вы можете через облачную консоль (“Storage” > “Volumes” диск со статусом: “available”, в поле “ID/Name”) или через CLI (openstack volume list --status available).

Например, блок подключения дополнительного диска к создаваемому инстансу из примера “Создание одного инстанса” раздела 1 может выглядеть следующим образом:

# Подключение существующего диска к создаваемому инстансу в качестве дополнительного resource "openstack_compute_volume_attach_v2" "existing_volume_attachment" {  instance_id = openstack_compute_instance_v2.tf_instance_1.id # ссылка на id инстанса внутри конфигурации Terraform  volume_id   = "9874221b-018d-40ef-a717-183cdc6e30d3" # id существующего диска}


Или так, если вы прямо указываете id существующего инстанса:

# Подключение существующего диска к существующему инстансу в качестве дополнительногоresource "openstack_compute_volume_attach_v2" "existing_volume_attachment" {  instance_id = "ea6ddfe0-fadf-4c96-aa64-77a61b639114"  # id существующего инстанса  volume_id   = "9874221b-018d-40ef-a717-183cdc6e30d3"                          # id существующего диска}
  1. Сохраните изменения.

Подключение нескольких новых дисков к группе инстансов

  1. Добавьте в файл конфигурации из раздела I. “Создание инстанса в Terraform. Создание нескольких инстансов” блоки создания дисков и их подключения к  новым инстансам:
# Блок создания дополнительных дисков для каждого инстансаresource "openstack_blockstorage_volume_v3" "extra_volumes" {  count        = length(openstack_compute_instance_v2.tf_instances)           # Количество дополнительных томов равно количеству инстансов  name         = local.extra_volume_names[count.index]                        # Имя дополнительного тома из списка  size         = local.extra_volume_sizes[count.index]                        # Размер дополнительного тома из списка  volume_type  = local.extra_volume_types[count.index]                        # Тип дополнительного тома из списка}
# Блок подключения дополнительных дисков к соответствующим инстансамresource "openstack_compute_volume_attach_v2" "extra_attachments" {  count       = length(openstack_compute_instance_v2.tf_instances)            # Количество подключений равно количеству инстансов  instance_id = openstack_compute_instance_v2.tf_instances[count.index].id    # ID соответствующего инстанса  volume_id   = openstack_blockstorage_volume_v3.extra_volumes[count.index].id # ID соответствующего дополнительного тома}


Примечание:
Вставьте блоки после основного блока "resource "openstack_compute_instance_v2", но до "output" или "network"-секции (если такие имеются).

А блок "locals" дополните данными о параметрах создаваемых дисков:

# Блок локальных переменных для дополнительных дисков. Укажите здесь свои значения параметровlocals {  extra_volume_names = ["<extra-volume-name-1>", "<extra-volume-name-2>", …, "<extra-volume-name-n>"] # Вставьте имена дополнительных дисков  extra_volume_sizes = [<extra-size-1>, <extra-size-2>,…, <extra-size-n>] # Вставьте размеры дополнительных дисков (целыми числами)  extra_volume_types = ["<extra-volume-type-1>", "<extra-volume-type-2>",…,"<extra-volume-type-n>"] # Вставьте id типов дополнительных дисков}


Примечание:

Если вы хотите указать уникальные значения для каждого диска — например, разные имена или размеры — укажите соответствующие списки в блоке "locals" и используйте их в ресурсах.

Если же значения параметров одинаковы для всех дисков (например, одинаковый размер) или могут быть сгенерированы динамически (например, имя с порядковым номером), тогда эти параметры не нужно указывать в "locals". Вместо этого укажите их напрямую внутри ресурса.

  1. Внесите в блок "locals" свои данные для каждого из дисков, изменив значения параметров в следующих списках:
  1. extra_volume_names — Произвольные и уникальные в вашем проекте имена дисков.
  2. extra_volume_sizes — Размеры создаваемых дисков в гигабайтах, вводится целым числом (например, 20).
  3. extra_volume_types — id типов дисков:
    • 25c82f52-dc3b-4337-a939-a73ec1a58d2a — Hybrid-Datastore.
    • a462fa3a-8e23-492c-97bd-d493b1a8d0a4 — All-Flash-Datastore.

Узнать id доступных вашему проекту типов диска вы можете через CLI  (openstack volume type list).

Если имя ресурса группы инстансов не "tf_instances" (не из нашего примера по созданию инстансов), замените его на ваше в строке "instance_id".

Если все параметры дисков заданы индивидуально, то содержание блоков, которые вы добавили выше не изменится, а блок "locals" будет дополнен, например,  следующими данными:

# Дополнение в блок локальных переменныхlocals {
  # Параметры дополнительных дисков  extra_volume_names = ["extra-disk-1", "extra-disk-2", "extra-disk-3"]  extra_volume_sizes = [10, 20, 15]  extra_volume_types = ["25c82f52-dc3b-4337-a939-a73ec1a58d2a", "a462fa3a-8e23-492c-97bd-d493b1a8d0a4", "25c82f52-dc3b-4337-a939-a73ec1a58d2a"]}


В случае, если, например, указать один размер для всех дисков, а их имена генерировать динамически, то блок создания дополнительных дисков будет выглядеть так:

# Создание дополнительных дисков для каждого инстансаresource "openstack_blockstorage_volume_v3" "extra_volumes" {  count        = length(openstack_compute_instance_v2.tf_instances)       # Количество томов = количеству инстансов  name         = "extra-volume-${count.index + 1}"                         # Автоматическое имя тома с номером  size         = 10                                                        # Единый размер для всех дисков (в ГБ)  volume_type  = local.extra_volume_types[count.index]                    # Тип диска — индивидуальный для каждого}


Блок подключения дополнительных дисков к инстансам в этом случае останется неизменным, как в изначальном  шаблоне.

В этом случае в блоке "locals" нужно указать только типы дисков:

# Дополнение в блок локальных переменныхlocals {  extra_volume_types = ["25c82f52-dc3b-4337-a939-a73ec1a58d2a", "a462fa3a-8e23-492c-97bd-d493b1a8d0a4", "25c82f52-dc3b-4337-a939-a73ec1a58d2a"] # Типы дополнительных дисков}
  1. Сохраните изменения.

IV. Вывод информации о созданных ресурсах: использование блока "output"

После создания элементов облачной инфраструктуры может быть полезно получить информацию об идентификаторах созданных ресурсов — инстансов, дисков, плавающих IP-адресов и т.д. Для этого в Terraform используется специальный блок "output", который выводит нужные данные в терминал после выполнения операций. Блок "output" также позволяет использовать выводимые параметры в CI/CD пайплайнах, внешних скриптах и для доступа к данным из других модулей.

Блоки "output" добавляются в конец файла конфигурации и не влияют на саму инфраструктуру. 

Структура блока "output"

Блок "output" имеет следующую структуру:

output "<имя_вывода>" {  value       = <значение или ссылка на параметр>  description = "<необязательное описание>"  sensitive   = <true|false> # скрывает значение в терминале}

Здесь:

  • output "<имя_вывода>" — произвольное название, под которым будет отображаться результат. По этому названию можно получить доступ к выводу из других модулей.
  • value — значение или ссылка на параметр. Формирование этого параметра описано ниже.
  • description — описание выводимого параметра. Это необязательный параметр.
  • sensitive — необязательный параметр. Если указать "true", значение не будет выведено в терминал при выполнении "terraform apply", но останется доступным программно (в том числе для других модулей). По умолчанию считается "false" и обычно его не указывают.

Формирование значения параметра "value" блока "output"

Значение параметра "value" формируется следующим образом:

value = <тип_ресурса>.<имя_ресурса>.<параметр>

где:

  • <тип_ресурса> — тип ресурса Terraform. Ресурсы доступные для отображения приведены ниже;
  • <имя_ресурса> — имя ресурса, заданное вами в блоке "resource";
  • <параметр> — параметр, который нужно вывести: "id", "address", "name" и т.д.

Если значение не нужно передавать в другой модуль, но вы хотите отобразить его с пояснением в терминале, то параметр "value" можно сформировать следующим образом:

value = "<текст пояснения>${<тип_ресурса>.<имя_ресурса>.<параметр>}"

Например:

value = "ID инстанса: ${openstack_compute_instance_v2.tf_instance_1.id}"

Основные типы ресурсов OpenStack в Terraform

  • openstack_compute_instance_v2 — виртуальная машина (инстанс);
  • openstack_blockstorage_volume_v3 — дополнительный диск (том);
  • openstack_compute_volume_attach_v2 — подключение диска к инстансу;
  • openstack_networking_floatingip_v2 — выделение внешнего IP-адреса;
  • openstack_compute_floatingip_associate_v2 — назначение IP инстансу;
  • openstack_networking_port_v2 — создание сетевого порта;
  • openstack_keypair_v2 — импорт или генерация SSH-ключа;
  • openstack_security_group_v2 — создание группы безопасности.

Полный список доступных ресурсов приведён в официальной документации Terraform-провайдера для OpenStack.

Межмодульное использование "output"

Если вы используете модульную структуру, блок "output" позволяет передавать значения из одного модуля в другой. Это полезно при разделении логики: один модуль может создавать инфраструктуру, а другой — использовать полученные ресурсы для настройки, мониторинга или подключения.

Например, модуль может возвращать IP-адрес, пароль или идентификатор ресурса, а модуль, который его вызывает, может получить это значение через конструкцию:

module.<имя_модуля>.<имя_output_блока>

где:

  • module — ключевое слово Terraform, обозначающее доступ к модулю;
  • <имя_модуля> — имя, присвоенное модулю в конфигурации;
  • <имя_output_блока> — имя выходного параметра, заданное в модуле через блок "output".

Например:

module.vm_setup.instance_ip

Эта конструкция возвращает IP-адрес из блока "output" с именем "instance_ip", определённого в модуле "vm_setup", который внутри может выглядеть так:

# Внутри модуля vm_setupoutput "instance_ip" {  value = openstack_networking_floatingip_v2.fip.address}

Примеры оформления блоков "output"

Один инстанс:

output "instance_id" {  value       = openstack_compute_instance_v2.tf_instance_1.id  description = "ID созданного инстанса"}

Вывод:

instance_id = "ea6ddfe0-fadf-4c96-aa64-77a61b639112"

Группа инстансов:

output "instance_ids" {  value       = [for instance in openstack_compute_instance_v2.tf_instances : instance.id]  description = "Список ID всех созданных инстансов"}

Вывод:

instance_ids = [  "f01fa473-e7d5-4a2e-bf8e-45e4bd1aa622",  "e24e2875-8fb1-45d7-9d53-1fd94d89f02c"]


Один плавающий IP:

output "floating_ip" {  value       = openstack_networking_floatingip_v2.float_ip.address  description = "Плавающий IP-адрес, назначенный инстансу"}

Вывод:

floating_ip = "198.51.100.101"

Группа плавающих IP:

output "floating_ips" {  value       = [for fip in openstack_networking_floatingip_v2.fip : fip.address]  description = "Список всех назначенных плавающих IP-адресов"}

Вывод:

floating_ips = [  "198.51.100.201",  "198.51.100.202"]

Один дополнительный диск:

output "volume_id" {  value       = openstack_blockstorage_volume_v3.additional_volume.id  description = "ID дополнительного диска"}

Вывод:

volume_id = "4f6c2340-63d4-4b64-84c3-3aa3f8b0cf12"

Несколько дополнительных дисков:

output "volume_ids" {  value       = [for vol in openstack_blockstorage_volume_v3.extra_volumes : vol.id]  description = "Список ID всех созданных дополнительных дисков"}

Вывод:

volume_ids = [  "b90a4304-90c8-42b3-8c84-0c5a2f0aa3d3",  "3f2c8896-1e72-4a38-8053-d3e7e6c4bbff"]

V. Применение изменений в инфраструктуре

После того как файл конфигурации готов, его нужно применить к облачной инфраструктуре. Для этого выполните следующие шаги:

  1. Откройте терминал:
    • Для Windows: PowerShell или CMD;
    • Для macOS/Linux: Bash, Zsh или другой терминал.
  1. Перейдите в каталог с конфигурационным файлом:
    • Для Linux и macOS, например:
cd /home/user/terraform/conf
  • Для Windows (PowerShell или CMD), например:
cd "C:\Program Files\terraform\conf"
  1. Инициализируйте Terraform, если ещё не сделали этого:
terraform init


При успешной инициализации вы увидите сообщение:

Terraform has been successfully initialized!
  1. Проверьте конфигурационные файлы на наличие ошибок:
terraform validate


Если проверка прошла успешно, то вы увидите следующее сообщение:

Success! The configuration is valid.


Если в ходе проверки выявлены ошибки — устраните их до перехода к следующему шагу.

  1. Отформатируйте .tf-файлы в текущем каталоге согласно официальным рекомендациям HashiCorp:
terraform fmt


Это улучшит читаемость кода и обеспечит единообразие конфигурации.

  1. Отобразите и проверьте план изменений в инфраструктуре:
terraform plan


Если планируемые изменения не соответствуют вашим ожиданиям — внесите соответствующие изменения до перехода к следующему шагу.

  1. Примените изменения в облачной инфраструктуре:
terraform apply

При этом Terraform выведет запрос на подтверждение:

Do you want to perform these actions?  Terraform will perform the actions described above.  Only 'yes' will be accepted to approve.
  Enter a value: 
  1. Введите: "yes" и нажмите "Enter", чтобы подтвердить выполнение изменений.

После успешного применения вы увидите сообщения о созданных ресурсах и итоговое уведомление, например:

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.