s3e23
Модульная застройка
Такс… Чтож такое эти ваши модули? Если на простом: модуль нужен, чтобы не копировать один и тот же код, а использовать его много раз.
Создаем модуль:
terraform-project/
├── main.tf
├── providers.tf
├── variables.tf
├── modules/
│ └── vm_volume_boot/
│ ├── main.tf
│ ├── variables.tf
│ └── outputs.tf
И заполняем файлы модуля:
modules/main.tf
data "openstack_images_image_v2" "image" {
name = var.image_name
most_recent = true
visibility = "public"
}
resource "openstack_blockstorage_volume_v3" "root" {
name = "${var.name}-root"
size = var.root_volume_size
image_id = data.openstack_images_image_v2.image.id
}
resource "openstack_compute_instance_v2" "vm" {
name = var.name
flavor_id = var.flavor_id
block_device {
uuid = openstack_blockstorage_volume_v3.root.id
source_type = "volume"
destination_type = "volume"
boot_index = 0
delete_on_termination = true
}
}
modules/variables.tf
variable "name" {
description = "VM name"
type = string
}
variable "image_name" {
description = "OS image name"
type = string
default = "Ubuntu 24.04 LTS 64-bit"
}
variable "flavor_id" {
description = "Flavor ID (diskless)"
type = string
}
variable "root_volume_size" {
description = "Root volume size in GB"
type = number
validation {
condition = var.root_volume_size >= 10
error_message = "Root volume must be at least 10 GB"
}
}
А в корневом main.tf делаем так:
module "vm1" {
source = "./modules/vm_volume_boot"
name = "linuxfactory-1-20"
flavor_id = "1"
root_volume_size = 20
}
Готовые IDшники flavors можно подсмотреть в официальной документации. Для примера выше, я взял ID=1 что соответствует 1 CPU / 512 RAM и 0 диска. Диск мы создаем с помощью модуля и цепляем к этому серверу.

Запускаем:
Проверяем и видим, что сервер успешно создан:

Теперь добавляем в корневой main.tf еще один сервер, но с другими параметрами:
module "vm1" {
source = "./modules/vm_volume_boot"
name = "linuxfactory-1-20"
flavor_id = "1"
root_volume_size = 20
}
module "vm2" {
source = "./modules/vm_volume_boot"
name = "linuxfactory-2-10"
flavor_id = "2"
root_volume_size = 10
}
Запускаем и смотрим что получилось:

А ведь всё правильно!
Модуль это что-то вроде шаблона, по которому ты будешь создавать ресурсы. Terraform модуль это функция. Ты прячешь сложную логику внутрь модуля, а в основном коде пишешь просто и понятно.
Если еще проще — Каждый раз готовишь бургер с нуля: месишь тесто, жаришь котлету, нарезаешь овощи. Каждый раз одно и то же.
А с модулями будет так — Сделай бургер с говядиной, сделай бургер с курицей. Рецепт один — параметры разные.
Если у тебя маленький проект, с модулями можно не заморачиваться, не нужно стрелять по воробьям из пушки. Но если у тебя огромная инфраструктура, то тут невольно сам придешь к модульному подходу. Это как ООП в программировании, для себя пишешь функции, а в компании всякие инкапсуляции, вьюшки и т.п.
При первом запуске с модулем, ты можешь наступить на грабли:

Пофикси эту проблему. Подсказывать не буду, там всё достаточно просто.
С модулями ты стандартизируешь создание инфраструктуры, у тебя одинаковые диски, одинаковые Security Group, одинаковые user_data и т.п. Изменяешь в одном месте один параметр и все ресурсы в корневом main.tf это подхватывают.
Тема конечно замороченная, но если в ней разобраться, то будешь силён и могуч. Повторюсь, что для маленьких проектов это избыточно. Выбирай инструмент под задачу и как я сказал ранее — не стреляй по воробьям из пушки.
Домашнее задание
- Создай подобный модуль, добавь туда сети и security group. Пусть твоя инфраструктура создается на модульной основе.