Буквально на выходных разобрал интересный для меня кейс и не могу не поделиться с вами тем, что мне удалось по итогу получить на выходе. Может быть кому то это пригодится или, как минимум, ляжет в основу дальнейшего проекта или кейса. По большей части статья будет рассказывать про создание ВМ в Proxmox через Terraform.
Если нужно что-то пояснить дополнительно, то пишите в комментариях – постараюсь помочь.
Предыстория
Я готовлю очень много демо стендов. Иногда это одна ВМ, иногда две, а иногда и пять. Процесс подготовки, скажем, пяти ВМ очень утомительный. Я решил озадачиться тем, что в каком-то виде автоматизировать этот процесс. После изучения текущих практик я пришел к использованию Proxmox + Terraform. Хотя можно исключить Terraform и ограничиться только Proxmox. Почему я оставил Terraform в этой связке? Во-первых, готовый план Terrafoorm можно будет применить на другом сервере. Во-вторых, это практика с Terraform.
Первоисточники
В процессе подготовки решения и статьи я использовал следующие материалы.
- 5 Steps for Creating Templates and Virtual Machines on Proxmox using Linux Distro’s Cloud Images.
- Cloud-Init Support.
- Create Proxmox cloud-init templates.
- Terraform provider plugin for Proxmox.
Описание окружения
Ниже я привожу схему моего окружения.
Гипервизор – Proxmox VE 8.2.2.
Инфраструктура в коде – Terraform 1.8.3.
Плагин Proxmox для Terraform – telmate/proxmox 3.0.1-rc2.
Коллеги в комментариях еще посоветовали модуль bpg/terraform-provider-proxmox. В целом поддержу – в этом модуле довольно много парамтеров, но я смог заставить его работать только с Proxmox VE 8.3.
Процесс автоматизации создания ВМ
Весь процесс выглядит следующим образом:
- Загрузка Linux Cloud Image нужного дистрибутива.
- Создание ВМ в Proxmox.
- При необходимости дополнительная настройка ВМ.
- Создание шаблона из ВМ.
- Создание ВМ из шаблона через модуль 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
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
virt-customize --install qemu-guest-agent -a "${IMAGES_PATH}/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="local-lvm"
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=2001
#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: 8 комментариев
Все круто, только для proxmox нужно использовать plugin pbg
Добрый день! Спасибо за комментарий, обязательно протестирую кейс с провайдеров pbg.
У него гораздо шире возможности
Да, спасибо, я почитал документацию. Там действительно больше ресурсов, примеров и документации. Я переписываю пример на этот провайдер, но пока я почему то не могу подружить его с моим Proxmox 8.2.2. Клонирование ВМ завешается успешно, но при обновлении свойства ВМ генерировалась ошибка “Error: error updating VM: the requested resource does not exist”. Пробовал разные подключения провайдера – по текену, логину/паролю, SSH. Попозже попробую добить примеры выше на этом провайдере.
Комментарий для тех, кто столкнулся с такой же ошибкой. Молуль bpg/terraform-provider-proxmox. Я ошибся с версией в комментарии выше – у меня была версия 7.2.2. С Версией 8.x модуль заработал корректно.
Хм, по идее должен, если версия терраформ выше 1.5 и провайдер самый свежий ну или с версиями поиграться…
Да, я наконец то добрался до этой задачи 🙂 У меня была версия 7.2.2 – странно, что я вообще проглядел её. С версией 8.x (как в документации и указано) модуль заработал корректно.
Насколько я понял провайдер для 8.2 проксмокса очень не очень) проблемы с ним