Practical SRE & DevOps guides. Linux debugging. Lifestyle

Proxmox VE Cluster: від теорії до продакшену

Proxmox Virtual Environment — це платформа на базі Debian Linux, що поєднує KVM-віртуалізацію та LXC-контейнеризацію в єдиному веб-інтерфейсі. Поодинокий гіпервізор — це завжди single point of failure. Кластер вирішує цю проблему, але за умови що ти розумієш як він реально працює всередині.

Як Proxmox влаштований на низькому рівні

Перед тим як говорити про кластер — треба зрозуміти що відбувається на одній ноді.

Шар 1 — Залізо і ядро

Proxmox встановлюється прямо на bare metal. Ніякого гіпервізора між залізом і ядром немає. Це Debian з кастомним ядром pve-kernel, в яке вбудовано ZFS, KVM-модуль (/dev/kvm) і VFIO для PCI passthrough. KVM і є гіпервізор — але він живе як модуль Linux.

# Переконатись що KVM завантажений
lsmod | grep kvm
# kvm_intel або kvm_amd — залежно від процесора

Шар 2 — Процес на кожну VM

Коли ти запускаєш VM — Proxmox форкає окремий процес qemu-system-x86_64. Кожна VM = один Linux-процес. Цей процес через /dev/kvm просить ядро виконати guest-код напряму на CPU через VT-x/AMD-V — без емуляції. Тому KVM VM такі швидкі.

# Побачиш по одному процесу на кожну запущену VM
ps aux | grep qemu-system

LXC-контейнери — зовсім інша історія. Вони не емулюють залізо взагалі. Просто clone() системний виклик з новими namespace і cgroup. Контейнер бачить ізольований процесний простір і мережу, але ядро хоста спільне. Старт LXC — ~100ms. Старт KVM VM — кілька секунд.

Шар 3 — Системні сервіси

pvedaemon — мозок вузла. REST API сервер на внутрішньому порту 85. Він запускає і зупиняє VM, керує сховищем, виконує завдання. Якщо він падає — Web UI перестає відповідати, але вже запущені VM продовжують жити — їх процеси незалежні від pvedaemon.

pveproxy — тільки проксі. Приймає HTTPS на порт 8006, робить TLS-термінацію і передає запити до pvedaemon. Веб-інтерфейс (Ext.js) живе тут.

systemctl status pvedaemon pveproxy

Де живуть конфіги

/etc/pve/ — це не звичайна директорія. Це FUSE-файлова система pmxcfs, яка реплікується між усіма нодами кластера в реальному часі через Corosync. Змінив конфіг VM на node01 → через мілісекунди зʼявилось на node02 і node03.

/etc/pve/
├── qemu-server/       # конфіги KVM VM (101.conf, 102.conf...)
├── lxc/               # конфіги LXC контейнерів
├── storage.cfg        # визначення сховищ (cluster-wide)
├── datacenter.cfg     # глобальні налаштування кластера
├── corosync.conf      # конфіг кластеру
├── ha/
│   ├── resources.cfg  # які VM захищені HA
│   └── groups.cfg     # групи нод для HA
└── nodes/
    └── pve01/         # конфіги специфічні для ноди

Все що в /etc/pve — автоматично синхронізується. Те що поза ним (/etc/network/interfaces тощо) — ні.

Критичний нюанс: якщо кластер втратив кворум — /etc/pve переходить в read-only на всіх нодах. Ти не зможеш запустити нову VM, змінити мережу, нічого. Це навмисна поведінка — захист від split-brain.


Архітектура кластера

Що таке кворум і чому мінімум 3 ноди

Кворум — це стан коли більшість вузлів бачать один одного і можуть приймати рішення. Формула проста:

мінімально необхідна кількість голосів = floor(total_votes / 2) + 1

При 3 нодах: кворум = 2. Впала одна нода → лишилось 2/3 → кластер живий, HA спрацьовує.

При 2 нодах: кворум = 2. Впала одна нода → лишилось 1/2 → кворуму немає, кластер заморожує всі зміни, HA не мігрує VM.

Це не баг — це захист від split-brain.

Split-brain: чому це найгірше що може статись

Split-brain — коли мережа між нодами розривається і обидві частини вирішують що вони “живі”. Обидві намагаються змонтувати той самий диск спільного сховища в read-write. Результат — гарантована корупція файлової системи всередині VM. ZFS pool після цього не відновити.

Proxmox запобігає цьому через кворум: якщо у тебе менше половини голосів — ти нічого не робиш. Меншість мовчить, більшість керує.

Що робити якщо фізично тільки 2 сервери

QDevice (Corosync Qdevice) — зовнішній арбітр кворуму. Розгортається на окремій малесенькій машині (VPS, Raspberry Pi) — вона не несе VM, тільки голосує при розриві між нодами.

# На окремій машині (арбітр)
apt install corosync-qnetd
corosync-qnetd-certutil -i

# На мастер-ноді кластера
pvecm qdevice setup 192.168.1.100   # IP арбітра

Після цього pvecm status покаже Expected votes: 3 при двох фізичних нодах.

Важливо: QDevice і його хост мають бути в іншій мережі або локації. Якщо він в тій самій стійці що й обидві ноди — при відключенні стійки втрачаєш всі три голоси одночасно.


Мережева інфраструктура: де найчастіше все ламається

Що треба ізолювати фізично

ТрафікВимогиЧому окремо
Corosync heartbeat<2ms latency, low jitterОдин dropped packet = нода вважається мертвою
ZFS replication / Ceph10GbE+, high bandwidthFlooding цього трафіку вбиває Corosync latency
Live migration (VM RAM)висока пропускна здатністьПри великих VM може забити канал Corosync
VM traffic (public)залежить від задачіІзоляція безпеки та QoS
IPMI/BMCокремий management VLANПотрібен навіть коли ОС повністю впала

Якщо є тільки два фізичних порти — мінімум роби VLAN trunk і окремий VLAN для Corosync. Але краще — окремі NIC.

Migration network: нюанс який часто забувають

За замовчуванням трафік live migration VM іде через той самий інтерфейс що і Corosync. При міграції великої VM (64GB RAM) це може забити канал — Corosync пакети дропаються, нода виглядає мертвою, HA вирішує мігрувати ще більше VM. Каскадний збій.

Виправлення в /etc/pve/datacenter.cfg:

migration: type=insecure,network=10.0.1.0/24

Або через UI: Datacenter → Options → Migration Settings.

insecure означає відсутність додаткового шифрування поверх — якщо мережа фізично ізольована, це нормально. Для WAN — використовуй secure (SSH tunnel, але повільніше).


Corosync: налаштування таймаутів

Файл /etc/corosync/corosync.conf, секція totem:

totem {
    version: 2
    cluster_name: pve-prod
    transport: knet

    # Час очікування токену між нодами (мс). Дефолт: 1000.
    # На WAN між дата-центрами — збільш до 5000-20000.
    token: 5000

    # token * token_retransmits = реальний таймаут до оголошення ноди мертвою
    token_retransmits_before_loss_const: 10

    join: 100
    consensus: 1200
    max_messages: 20

    # Для WAN — обовʼязково knet з компресією
    knet_compression_model: lz4
    knet_compression_threshold: 100
}

Правило для token: має бути мінімум 10× максимальної RTT між нодами.

Після зміни — перезапуск через systemctl restart corosync тільки якщо кластер живий на більшості нод. Ніколи не роби це одночасно на всіх.


Що робити при high latency або нестабільному звʼязку між локаціями

Симптом: ноди постійно виходять і заходять у кластер

journalctl -u corosync --since "1 hour ago" | grep -E "FAILED|left|joined"

Якщо бачиш totem: FAILED to receive the leave message або node X left the cluster — latency перевищує token таймаут, або jitter вбиває пакети.

Алгоритм діагностики

1. Виміряй реальну latency саме на тому IP що в corosync.conf:

ping -c 100 -i 0.1 192.168.10.2 | tail -5
# avg > 5ms або mdev (jitter) > 2ms — треба тюнити

2. Перевір чи Corosync не ділить NIC з іншим трафіком:

# Ненульовий dropped — або buffer overflow, або collision
watch -n1 'ip -s link show eth0'

3. Збільш таймаути пропорційно latency — формула вище.

4. Як тимчасово зупинити автоматичні міграції:

Якщо між локаціями нестабільний звʼязок і ти не хочеш щоб Proxmox починав автоматично мігрувати VM при кожному кліпанні каналу — заморозь HA policy:

# Через CLI (заморожує прийняття рішень CRM)
pvesh set /cluster/ha/config --no-shutdown-policy freeze

Або через UI: Datacenter → HA → Resources → змінити policy на ignored для конкретних VM.

WARNING: Якщо вимкнеш фенсинг і при цьому нода “зависне” а не впаде — HA не зможе безпечно перезапустити VM на іншій ноді. Це trade-off між доступністю і безпекою даних.


Fencing і STONITH: як Proxmox переконується що нода мертва

Коли HA manager бачить що нода недоступна — він не одразу мігрує VM. Спочатку переконується що нода точно зупинила свої VM — інакше split-brain зі спільним сховищем.

Якщо фенсинг не налаштований — HA чекає і нічого не робить. Звідси і “VM не мігрує 10 хвилин після падіння ноди” — це не баг, це безпека.

Типи фенсинг агентів:

Hardware IPMI/iDRAC/iLO → fence_ipmilan  (найнадійніше)
PDU / розетка            → fence_apc_snmp
Proxmox API (self)       → fence_pve

Налаштування через UI: Datacenter → HA → Fencing → Add.

Перевірка без реального перезапуску:

fence_ipmilan -a 192.168.1.100 -u admin -p secret -o status

Watchdog: як нода вбиває сама себе

Коли HA активований, кожна нода відкриває /dev/watchdog. Якщо LRM перестає оновлювати watchdog (бо нода зависла, ОС крашнулась) — апаратний watchdog примусово перезавантажує сервер через кілька секунд. Це self-fencing — нода сама себе вбиває щоб CRM міг безпечно запустити її VM деінде.

cat /proc/sys/kernel/watchdog
ls /dev/watchdog*

Datacenter Manager: що він реально контролює

Datacenter у Proxmox Web UI — це не просто “група нод”. Тут зберігаються речі які автоматично розповсюджуються на всі ноди через pmxcfs:

Storage definitions — якщо додаєш NFS в Datacenter → Storage, він стає доступним на всіх нодах автоматично. Якщо додаєш storage тільки на одній ноді — він видимий тільки там.

HA Groups і Resources — тут визначаєш які VM є HA-захищеними і на які ноди вони можуть мігрувати. VM без HA-ресурсу не буде автоматично перезапущена при падінні ноди.

Resource Mapping (PVE 8+) — абстракція для PCI пристроїв (GPU, HBA, USB) на рівні кластера. Описуєш “GPU у slot 1” на кожній ноді під спільною назвою — тоді VM з GPU passthrough можна мігрувати між нодами.

SDN (Software Defined Networking) — VXLAN-зони, VNet, subnet. Замість того щоб вручну прописувати bridge на кожній ноді — робиш один раз у Datacenter, конфіг реплікується через pmxcfs.

Datacenter-level Firewall — ipsets, aliases, security groups. Правила з datacenter-рівня застосовуються до всіх VM і нод якщо увімкнені.


Покрокове створення кластера

Крок 1 — Ініціалізація на першій ноді

Datacenter → Cluster → Create Cluster

Крок 2 — Отримання Join Information

Datacenter → Cluster → Join Information → скопіюй весь текст (Information String).

Крок 3 — Приєднання другої і третьої ноди

На кожній ноді що додається: Datacenter → Cluster → Join Cluster

Застереження: під час join веб-інтерфейс ноди що додається перезавантажиться — відбувається заміна локального /etc/pve на кластерну pmxcfs. Нода що приєднується не повинна мати запущених VM з ID які вже є в кластері.

Перевірка після join

pvecm status        # загальний статус і кворум
pvecm nodes         # список нод з голосами
corosync-cfgtool -s # статус Corosync кілець

Що відбувається при падінні ноди: покроково

1. node02 перестає відповідати на Corosync heartbeat
2. Через token timeout (~5-6 сек дефолт) node01 і node03 оголошують node02 мертвою
3. Corosync перераховує голоси: 2/3 — кворум є
4. CRM отримує подію "node02 left"
5. CRM чекає grace period (60 сек) — раптом нода сама повернеться
6. Якщо фенсинг налаштований — CRM надсилає IPMI команду "вимкни node02"
7. Після підтвердження фенсингу — CRM дає команду LRM запустити VM з node02
8. LRM форкає нові qemu-system процеси для цих VM

Якщо фенсинг не налаштований — крок 6 пропускається, але CRM чекає набагато довше перш ніж мігрувати.


Сховище у кластері

Сам по собі кластер не переміщує дані дисків автоматично якщо у тебе локальні диски. Для live migration (без зупинки VM) потрібне правильне сховище.

ТипТехнологіяПлюсиМінуси
Локальне з реплікацієюZFS Storage ReplicationШвидкі локальні NVMe/SSDРеплікація за розкладом, при падінні ноди — втрата даних за останні N хвилин
Спільне мережевеNFS / iSCSIПростота, live migrationSingle point of failure (NFS сервер)
РозподіленеCephСправжній HA, live migration за секундиПотребує 10GbE+, мінімум 3 OSD ноди

Оновлення нод без downtime

# 1. Міграція всіх VM з ноди
for vmid in $(qm list | awk 'NR>1 {print $1}'); do
    qm migrate $vmid pve02 --online
done

# 2. Переводимо ноду в maintenance mode
ha-manager crm-command node-maintenance enable pve01

# 3. Оновлення
apt update && apt dist-upgrade -y

# 4. Перезавантаження якщо змінилось ядро
if [ -f /var/run/reboot-required ]; then reboot; fi

# 5. Перевірка після ребуту
pvecm status
ha-manager status

# 6. Виводимо з maintenance
ha-manager crm-command node-maintenance disable pve01

Діагностика: команди які завжди під рукою

# Загальний статус кластера і кворуму
pvecm status

# Список нод з голосами
pvecm nodes

# Детальний статус Corosync кілець
corosync-cfgtool -s

# Список нод з кількістю голосів
corosync-quorumtool -l

# HA статус всіх ресурсів
ha-manager status

# Статус реплікації ZFS
pvesr status

# Логи кластерних подій (де шукати проблеми першим ділом)
journalctl -u pve-cluster -u corosync --since "30 min ago"

# Перевірка синхронізації часу (різниця >5с = Corosync не зʼєднається)
chronyc tracking
timedatectl status

Чеклист перед запуском в продакшен

[ ] Мінімум 3 ноди або 2 ноди + QDevice в окремій локації
[ ] Окремий фізичний інтерфейс або VLAN для Corosync
[ ] Link 0 + Link 1 для Corosync (різні фізичні комутатори)
[ ] Окрема мережа для storage/replication трафіку
[ ] Окрема мережа для live migration (datacenter.cfg)
[ ] NTP/chrony синхронізований на всіх нодах
[ ] Фенсинг налаштований і протестований (IPMI або PDU)
[ ] HA Groups і Resources визначені для критичних VM
[ ] corosync token timeout відповідає реальній RTT мережі
[ ] Протестований failover: вимкни одну ноду і перевір HA
[ ] Proxmox Backup Server або VZDump з перевіреним відновленням

#Proxmox #Virtualization #Infrastructure #HA #Corosync #DevOps