📝 Данный материал подготовлен соавтором Вороньего сообщества 👨💻🐧.
Разберём, как корректно собирать Cloud-Init шаблоны в Proxmox VE при использовании ZFS. Материал основан на практическом опыте и типичных проблемах при переходе с классических схем хранения (mdadm + LVM) на ZFS.
🖐️Эй!
Подписывайтесь на наш телеграм @r4ven_me📱, чтобы не пропустить новые публикации на сайте😉. А если есть вопросы или желание пообщаться по тематике — заглядывайте в Вороний чат @r4ven_me_chat🧐.
Также в блоге теперь доступно соавторство 🐧🐧🐧.
Введение
Моё знакомство с Proxmox VE началось с 7-й версии, когда система часто разворачивалась поверх Debian вручную. Изначально я использовал mdadm + LVM - это было просто и предсказуемо. После перехода на серверное железо и миграции на ZFS (с восстановлением виртуальных машин из бэкапов) проявилась проблема: при развёртывании виртуальных машин (ВМ) через Terraform перестал корректно работать dynamic inventory в Ansible.
Причина оказалась не в Terraform или Ansible, а глубже - в несовместимости модели хранения ZFS (zvol) и формата qcow2. Этот разбор и лёг в основу статьи.
В статье рассмотрим:
- различия между
qcow2,raw,zvolиZFS dataset; - почему возникает конфликт на ZFS;
- правильный способ сборки Cloud-Init шаблонов;
- типовые ошибки;
- как добавить Cloud-Init в уже существующие шаблоны.
ПО, используемое в статье:
| ПО | Версия |
|---|---|
| Proxmox VE | 9.1 |
| Debian | 13 |
Для лучшего понимания сути заметки, важно озвучить теоретическую сторону данного кейса.
Проблематика: ZFS и QCOW2
Ключевая проблема - различие моделей хранения данных.
В Proxmox VE с ZFS:
- диски ВМ размещаются в zvol (блочное устройство);
- Cloud-Init образы в основном распространяются в формате qcow2 (файл).
Это создаёт архитектурный конфликт:
| Характеристика | qcow2 | zvol |
|---|---|---|
| Тип | Файл | Блочное устройство |
| Требует наличия ФС | Да | Нет |
| Copy-on-Write | Внутри файла | на уровне ZFS |
| Использование в Proxmox VE | directory storage | ZFS storage |
Различия между qcow2, raw, zvol и ZFS dataset
QCOW2
qcow2 - это файловый формат с поддержкой:
- Copy-on-Write (CoW);
- снапшотов;
- сжатия;
- thin provisioning.
Фактически это слой поверх файловой системы.
Проблема на ZFS - двойной CoW:
- qcow2 выполняет CoW внутри файла;
- ZFS выполняет CoW на уровне блоков.
Последствия:
- двойная запись (write amplification);
- рост задержек (latency);
- ухудшение производительности системы ввода-вывода (падение IOPS);
- дополнительная фрагментация.
Поэтому в документации Proxmox VE не рекомендуется использовать qcow2 на ZFS.
RAW
RAW - это линейный образ без дополнительной логики.
- нет метаданных;
- запись напрямую в блоки;
- CoW делегирован ZFS.
Преимущества: минимальные накладные расходы, предсказуемая производительность и оптимальность для ZFS.
ZVOL
ZVOL - это блочное устройство внутри ZFS.
- используется Proxmox VE по умолчанию для дисков ВМ;
- не требует файловой системы;
- управляется ZFS;
- поддерживает снапшоты и клонирование на уровне пула.
Ключевой параметр: volblocksize (размер блока). Размер блока напрямую влияет на производительность системы ввода-вывода, потому важно указать оптимальное значение.
Типичные значения:
- 8K–16K - диски ВМ или БД;
- 64K–128K - универсальный сценарий для файлового хранилища и резервных копий;
- 256K - изображения и фотографии;
- 512К-1М - медиафайлы (видео, фильмы, сериалы и т.п.).
В Proxmox VE по умолчанию создаётся zvol с размером блока 16K, что оптимально для дисков ВМ на ZFS.
ZFS Dataset
ZFS dataset - это файловая система внутри ZFS.
Используется для:
- хранения файлов (включая qcow2);
- directory storage в Proxmox.
Особенности:
- параметр
recordsizeвлияет на поведение записи; - появляется дополнительный слой (ФС → файл → ZFS);
- при использовании qcow2 возникает двойной CoW.
Почему возникает конфликт
Проблема появляется при попытке использовать файловый образ (qcow2) как источник для блочного устройства (zvol).
На практике это выглядит так:
- Proxmox импортирует qcow2;
- конвертирует в raw;
- записывает результат в zvol.
Типичная ошибка в инструкциях:
qm importdisk 7777 ./debian-13-generic-amd64.qcow2 storage --format qcow2Здесь явно задан qcow2, что некорректно для zvol.
Результат:
- диск импортируется с ошибками;
- Cloud-Init не инициализируется;
- ВМ в неконсистентном состоянии.
Варианты решения
Подход 1: ZFS Dataset (directory storage)
Создайте набор данных (dataset) с файловой системой, например:
rpool/data/imagesИ используйте его как каталог (directory storage).
Преимущества: простая настройка.
- совместимость с типовыми инструкциями в открытых источниках.
Недостатки: двойной CoW.
- лишний слой абстракции;
- заметная деградация производительности (особенно на HDD).
Вывод: допустимо, но не оптимально.
Подход 2 (рекомендуемый): использование RAW
На этапе импорта диска в пустую виртуальную машину укажите формат RAW вместо стандартного qcow2:
qm importdisk <VMID> <image> <storage> --format rawНапример, для машины с id 7777 из инструкции на сайте команда будет такой:
qm importdisk 7777 ./debian-13-generic-amd64.qcow2 storage --format rawВо время импорта qcow2 конвертируется в raw при импорте, raw записывается в zvol.
Преимущества: нет двойного CoW, максимальная производительность и Cloud-Init работает корректно.
Сборка Cloud-Init шаблона на ZFS
Информации не так много, но читатели не знакомые с ZFS, вероятно, успели запутаться. Поэтому предлагаю ещё раз последовательно разобрать типовой процесс создания шаблона виртуальной машины с использованием Cloud-Init, с учётом особенностей работы с ZFS.
1. Импорт образа
- Увеличиваем размер диска:
qemu-img resize ./debian-13-generic-amd64.qcow2 32GГде debian-13-generic-amd64.qcow2 - образ диска cloud-init, а 32G - итоговый размер (32ГБ).
- Создаём новую виртуальную машину без диска:
qm create 9998 --name "debian-13-ci" --memory 2048 --cores 2 --net0 virtio,bridge=vnet01Расшифровка:
9998- id новой ВМ;debian-13-ci- имя ВМ отображаемое в Proxmox VE;--memory 2048- объём выделенной оперативной памяти в МБ (2ГБ);--cores 2- число vCPU выделяемых машине;--net0- основной сетевой интерфейс с типомvirtio, использующий мостvnet01.
- Импортируем образ
qcow2в форматеraw(ключевое отличие):
qm importdisk 9998 debian-13-generic-amd64.qcow2 vm-hdd --format rawГде vm-hdd - имя вашего zvol в Proxmox VE.
- Устанавливаем SCSI контроллер и добавляем ранее импортированный диск:
qm set 9998 --scsihw virtio-scsi-single --scsi0 vm-hdd:vm-9998-disk-0,discard=on- Обновляем порядок загрузки:
qm set 9998 --boot order=scsi0- Добавляем Cloud-Init диск:
qm set 9998 --ide1 vm-hdd:cloudinit- Настраиваем пользователя, пароль и SSH для cloud-init:
# --- Пользователь ---
# Создаём пользователя:
qm set 9998 --ciuser ansible
qm set 9998 --cipassword <ПАРОЛЬ ПОЛЬЗОВАТЕЛЯ>
# Добавляем SSH ключ:
qm set 9998 --sshkeys ~/.ssh/id_ed25519.pub
# ------- СЕТЬ -------
# Настройка IP по DHCP:
qm set 9998 --ipconfig0 ip=dhcp
# Статический IP:
qm set 9998 --ipconfig0 ip=10.10.10.254/24,gw=10.10.10.1
# Установить адрес DNS-сервера 10.10.10.15:
qm set 9998 --nameserver 10.10.10.15
# Задать домен поиска infra.lan:
qm set 9998 --searchdomain infra.lan
# ----- Обновления -----
# Установка обновлений при запуске:
qm set 9998 --ciupgrade 1
# Не устанавливать обновления:
qm set 9998 --ciupgrade 0- Добавляем последовательный порт:
qm set 9998 --serial0 socket --vga serial0- Включаем QEMU Guest Agent для взаимодействия гипервизора с гостевой системой:
qm set 9998 --agent enabled=1- Сохраняем машину как шаблон:
qm template 9998- Создаём клон ранее собранного шаблона для проверки работы Cloud-Init:

- Запускаем тестовую машину и проверяем:

Готово! Теперь шаблон Cloud-Init работает корректно и хранится на вашем zvol.
2. Добавление Cloud-Init в готовый шаблон
Если вы не так давно узнали про Cloud-Init и уже успели собрать шаблоны типовых виртуальных машин под вашу инфраструктуру не расстраивайтесь!
Есть способ добавить поддержку Cloud-Init для уже существующих шаблонов, рассмотрим пример с Debian 13 Trixie.
- Сделайте полную копию шаблона (Full Clone).
- Подключитесь к терминалу новой машины через VNC или SSH.
- Переключитесь на пользователя
root(если используете пользовательскую учётную запись):
sudo -i- Обновите систему:
apt update && apt full-upgrade -y- Установите гоствевой агент (если не сделали этого ранее) и пакет
cloud-init:
apt install -y qemu-guest-agent cloud-init- Создайте новую конфигурацию Cloud-Init для Proxmox VE:
/etc/cloud/cloud.cfg.d/99-pve.cfgВ файл вставьте строку такого вида:
datasource_list: [ NoCloud, ConfigDrive ]Сохраните изменения и выйдите из текстового редактора.
- Выполните очистку журналов и machine-id:
cloud-init clean --logs
rm -f /etc/machine-id
truncate -s 0 /etc/machine-id- При желании можно почистить журналы в системе и кэш apt:
journalctl --rotate
journalctl --vacuum-time=1s
apt clean- Выключите машину:
poweroff- Переключитесь на терминал гипервизора и добавьте диск Cloud-Init к этой машине:
qm set <VMID> --ide2 <storage>:cloudinit- Затем добавьте последовательный порт:
qm set <VMID> --serial0 socket --vga serial0 - Включите агента:
qm set <VMID> --agent enabled=1- Сохраните данную машину как шаблон:
qm template <VMID>После этого можно добавить дополнительные параметры Cloud-Init и проверить работу обновлённого шаблона.
Типичные ошибки
Наиболее частые проблемы:
- использование qcow2 на ZFS в production-среде;
- импорт qcow2 в zvol без явной конвертации в raw;
- игнорирование параметра
volblocksizeпри создании zvol; - неочищенное состояние cloud-init (приводит к некорректному клонированию);
- отсутствие serial console (недоступны логи cloud-init);
- неправильно заданный datasource.
Эти ошибки часто проявляются не сразу, но создают проблемы при масштабировании.
Вывод
Если вы используете Proxmox VE с ZFS оптимальная схема будет такой:
- диски ВМ - zvol;
- формат диска - raw;
- Cloud-Init - отдельный диск.
ZFS уже реализует CoW, снапшоты и thin provisioning. Использование qcow2 поверх ZFS дублирует эти механизмы и приводит к деградации производительности и усложнению архитектуры.
👨💻Ну и…
Не забывайте про нашу телегу📱и чат 💬
Или может хотите стать соавтором? Тогда клик сюда🔗
Всех благ✌️
That should be it. If not, check the logs 🙂


