Создание ВМ в Proxmox через Terraform

Буквально на выходных разобрал интересный для меня кейс и не могу не поделиться с вами тем, что мне удалось по итогу получить на выходе. Может быть кому то это пригодится или, как минимум, ляжет в основу дальнейшего проекта или кейса. По большей части статья будет рассказывать про создание ВМ в Proxmox через Terraform.

Если нужно что-то пояснить дополнительно, то пишите в комментариях – постараюсь помочь.

Предыстория

Я готовлю очень много демо стендов. Иногда это одна ВМ, иногда две, а иногда и пять. Процесс подготовки, скажем, пяти ВМ очень утомительный. Я решил озадачиться тем, что в каком-то виде автоматизировать этот процесс. После изучения текущих практик я пришел к использованию Proxmox + Terraform. Хотя можно исключить Terraform и ограничиться только Proxmox. Почему я оставил Terraform в этой связке? Во-первых, готовый план Terrafoorm можно будет применить на другом сервере. Во-вторых, это практика с Terraform.

Первоисточники

В процессе подготовки решения и статьи я использовал следующие материалы.

  1. 5 Steps for Creating Templates and Virtual Machines on Proxmox using Linux Distro’s Cloud Images.
  2. Cloud-Init Support.
  3. Create Proxmox cloud-init templates.
  4. Terraform provider plugin for Proxmox.

Описание окружения

Ниже я привожу схему моего окружения.

Гипервизор – Proxmox VE 8.2.2.

Инфраструктура в коде – Terraform 1.8.3.

Плагин Proxmox для Terraform – telmate/proxmox 3.0.1-rc2.

Процесс автоматизации создания ВМ

Весь процесс выглядит следующим образом:

  1. Загрузка Linux Cloud Image нужного дистрибутива.
  2. Создание ВМ в Proxmox.
  3. При необходимости дополнительная настройка ВМ.
  4. Создание шаблона из ВМ.
  5. Создание ВМ из шаблона через модуль Proxmox для Terraform.

Я опишу весь процесс в разделах ниже, но некоторые шаги объединю в один раздел.

Подготовка образов

Linux Cloud Image – это образы, которые оптимизированы для работы в публичных или частных облаках. Для моего сценария это именно то, что нужно. У этих образов более гибкие и удобные инструменты для кастомизации. Но сначала такой образ нужно подготовить. Большинство из Linux дистрибутивов предоставляют такие образы.

Например, вот таким небольшим скриптом на Proxmox сервере я подготовил образ Ubuntu Server 22.04, создал из него ВМ и конвертировал её в шаблон:

# Source guide - https://gist.github.com/zidenis/dfc05d9fa150ae55d7c87d870a0306c5

# SSH to Proxmox Server
ssh user@your-proxmox-server
su - root

# Install required tools on Proxmox Server
apt update
apt install -y libguestfs-tools

# Install qemu quest agent on Ubuntu 22.04 Cloud Image
virt-customize --install qemu-guest-agent -a "${IMAGES_PATH}/jammy-server-cloudimg-amd64.img"

export IMAGES_PATH="/mnt/pve/HDD_local" # defines the path where the images will be stored and change the path to it.

cd ${IMAGES_PATH}
wget https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img

export QEMU_CPU_MODEL="host"
export VM_CPU_CORES=2
export VM_CPU_SOCKETS=2
export VM_MEMORY=4098
export VM_STORAGE_NAME="HDD500"
export VM_BRIDGE_NAME="vmbr0"

export CLOUD_INIT_USER="roman"
export CLOUD_INIT_PASSWORD="Qwerty123"
#export CLOUD_INIT_SSHKEY="/home/user/.ssh/id_rsa.pub" # Provides the path to the SSH public key for the user.
export CLOUD_INIT_IP="dhcp"
# export CLOUD_INIT_IP="192.168.10.20/24,gw=192.168.10.1" # Static example
export CLOUD_INIT_NAMESERVER="8.8.8.8"
export CLOUD_INIT_SEARCHDOMAIN="itproblog.ru"

export TEMPLATE_ID=2000
#export TEMPLATE_ID=$(pvesh get /cluster/nextid)

export VM_NAME="Ubuntu2204"
export VM_DISK_IMAGE="${IMAGES_PATH}/jammy-server-cloudimg-amd64.img"

# Create VM. Change the cpu model 
qm create ${TEMPLATE_ID} --name ${VM_NAME} --cpu ${QEMU_CPU_MODEL} --sockets ${VM_CPU_SOCKETS} --cores ${VM_CPU_CORES} --memory ${VM_MEMORY} --numa 1 --net0 virtio,bridge=${VM_BRIDGE_NAME} --ostype l26 --agent 1 --scsihw virtio-scsi-single

# Import Disk
qm set ${TEMPLATE_ID} --virtio0 ${VM_STORAGE_NAME}:0,import-from=${VM_DISK_IMAGE}

# Add Cloud-Init CD-ROM drive. This enables the VM to receive customization instructions during boot.
qm set ${TEMPLATE_ID} --ide2 ${VM_STORAGE_NAME}:cloudinit --boot order=virtio0

# Cloud-init network-data
qm set ${TEMPLATE_ID} --ipconfig0 ip=${CLOUD_INIT_IP} --nameserver ${CLOUD_INIT_NAMESERVER} --searchdomain ${CLOUD_INIT_SEARCHDOMAIN}

# Cloud-init user-data
qm set ${TEMPLATE_ID} --ciupgrade 1 --ciuser ${CLOUD_INIT_USER} --cipassword ${CLOUD_INIT_PASSWORD}

# Cloud-init regenerate ISO image, ensuring that the VM will properly initialize with the desired parameters.
qm cloudinit update ${TEMPLATE_ID}

qm set ${TEMPLATE_ID} --name "${VM_NAME}-Template"

qm template ${TEMPLATE_ID}

Для подготовки образа этих действий достаточно.

Аналогичным образом подготовлю шаблон для Rocky Linux 9.

Все примеры подготовки я выложил на GitHub. По мере необходимости буду расширять пул примеров.

По итогу у меня получилось два вот таких шаблона:

Создание ВМ в Proxmox через Terraform

Сразу отмечу, что провайдер telmate/proxmox довольно специфичен. Довольно много откровенно негативных отзывов про него. Мне тоже не сразу удалось подружить его в том виде, в каком я планировал. Поэтому я не уверен, что он подойдет для боевого окружения. Как пишу на Хабре – этим инструментом инфраструктуру можно скорее завалить, чем построить. Но для моих тестовых сред этот инструмент вполне себе даже ничего.

Второй момент, который я бы хотел отметить – это версии Proxmox и версии провайдера telmate/proxmox для Terraform. Пока я не обновил оба продукта до версий, которые указаны на схеме выше я так и не смог заставить эту связку либо работать вообще, либо работала так, как мне нужно. Учитывайте этот момент.

Создание токена доступа на Proxmox

Для работы провайдера Proxmox для Terraform я буду использовать доступ через токен. Для этого на сервере Proxmox я сгенерирую соответствующий токен. С точки зрения безопасности лучше создать отдельную учетную запись. Поскольку я буду применять решение в моем тестовом контуре, то я создам токен для пользователя root.

Скопируйте значения Token ID и Secret:

В последующем я укажу эти значения в переменных для подключения к API Proxmox.

Установка Terraform

Я не буду подробно расписывать этот процесс, т.к. это не является основной целью данной публикации. Инструкция по установке Terraform доступна вот по этой ссылке.

Есть еще альтернативный вариант использования форва Terraform – OpenTofu. Но я дальше в примерах буду использовать Terraform.

Подготовка плана инфраструктуры в Terraform

1. Сначала я создам отдельную директорию для хранения всех необходимых файлов Terraform:

mkdir SimpleVM
cd SimpleVM

2. Теперь я создам файл с определение переменных. В основном это переменные для подключения к Proxmox:

nano credentials.auto.tfvars
proxmox_api_url = "https://10.10.10.61:8006/api2/json"
proxmox_api_token_id = "root@pam!terraform-token"
proxmox_api_token_secret = "e4849c31-6071-448f-aa51-8a7b07057529"
storage_name = "HDD500"

3. Следующим шагом я подключу провайдера:

nano provider.tf
terraform {
  required_providers {
    proxmox = {
        source = "telmate/proxmox"
        version = "3.0.1-rc2"
    }
  }
}
provider "proxmox" {
  pm_api_url = var.proxmox_api_url
  pm_api_token_id = var.proxmox_api_token_id
  pm_api_token_secret = var.proxmox_api_token_secret
  pm_tls_insecure = true
}

4. Теперь подготовим план нашей инфраструктуры для Terraform.

nano vm-ubuntu2204.tf
resource "proxmox_vm_qemu" "ubuntu2204" {
    name = "Ununtu2204"
    desc = "A test for using terraform and cloudinit"

    # Node name has to be the same name as within the cluster
    # this might not include the FQDN
    target_node = "px01"

    # The template name to clone this vm from
    clone = "Ubuntu2204-Template"

    # Activate QEMU agent for this VM
    agent = 1

    os_type = "cloud-init"
    cores = 2
    sockets = 2
    vcpus = 0
    cpu = "host"
    memory = 2048
    scsihw = "virtio-scsi-single"

    # Setup the disk
    disks {
        ide {
            ide3 {
                cloudinit {
                    storage = var.storage_name
                }
            }
        }
        virtio {
            virtio0 {
                disk {
                    size            = "2252M"
                    storage         = var.storage_name
                    replicate       = true
                }
            }
        }
    }

    # Setup the network interface and assign a vlan tag: 256
    network {
        model = "virtio"
        bridge = "vmbr0"
    }

    # Setup the ip address using cloud-init.
    boot = "order=virtio0"
    # Keep in mind to use the CIDR notation for the ip.
    ipconfig0 = "ip=dhcp"
    nameserver = "8.8.8.8"
    ciuser = "roman"
}

5. Также я создал аналогичное определение ресурса и для Rocky Linux 9.

6. Проверим синтаксис нашего определения инфраструктуры:

terraform validate

7. Проверим, что Terraform создаст в Proxmox на основе нашего плана:

terraform plan

8. Все именно так, как мне нужно. Запускаем процесс создания инфраструктуры:

terraform apply

9. Дожидаемся окончания процедуры создания инфраструктуры.

Как видно выше процесс подготовки двух ВМ занял две минуты. Вручную мне бы потребовалось гораздо больше времени.

Все файлы с примерами я выложил на GitHub.

Можно также одномоментно уничтожить все ВМ:

terraform destroy

Немного особенностей

Как я уже говорил выше провайдер telmate/proxmox для Terraform довольно специфичен. Например, определение типа SCSI контроллера и интерфейсов подключения дисков должны совпадать в шаблоне ВМ и в определении ресурса в Terraform. Даже размер диска должен совпадать. Иначе Terraform создаст новый дополнительный пустой диск и Proxmox будет пытаться загрузить ВМ с этого диска.

т.е. вот эти параметры должны совпадать:

Итоговая проверка

По итогу у меня получилась вот такая иерархия объектов в Proxmox.

Надеюсь, что материал данной статьи будет вам полезен.

Создание ВМ в Proxmox через Terraform: 5 комментариев

    1. Да, спасибо, я почитал документацию. Там действительно больше ресурсов, примеров и документации. Я переписываю пример на этот провайдер, но пока я почему то не могу подружить его с моим Proxmox 8.2.2. Клонирование ВМ завешается успешно, но при обновлении свойства ВМ генерировалась ошибка “Error: error updating VM: the requested resource does not exist”. Пробовал разные подключения провайдера – по текену, логину/паролю, SSH. Попозже попробую добить примеры выше на этом провайдере.

  1. Хм, по идее должен, если версия терраформ выше 1.5 и провайдер самый свежий ну или с версиями поиграться…

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *