HomeLab

🧠 День 14 — Миграция узла в Proxmox-кластере: безопасный вывод ноды на обслуживание

15 мая 2026, 07:51
🧠 День 14 — Миграция узла в Proxmox-кластере: безопасный вывод ноды на обслуживание

В небольшом домашнем Proxmox-кластере одна из нод начала вести себя нестабильно и потребовала обслуживания.

Задача была «по-взрослому SRE», даже если это homelab:

  • вывести ноду из нагрузки без простоя сервисов;
  • перенести VM на новый узел;
  • укрепить хранилище (ZFS mirror);
  • дать критичному VPN-сервису репликацию и регулярный health-check;
  • сохранить план отката и пост-проверки.

Важно: материал обезличен. Нодам, VM, подсетям и внешним точкам я использую условные имена.


🗺️ Топология (как это выглядит в голове)

                +---------------------+
                |  Proxmox Cluster    |
                |  (3 nodes total)    |
                +----------+----------+
                           |
          +----------------+----------------+
          |                                 |
  +-------v-------+                 +-------v-------+
  |  node-A        |                 |  node-B        |
  |  (existing)    |                 |  (existing)    |
  |  storage: ...  |                 |  storage: ...  |
  +-------+--------+                 +-------+--------+
          |                                  \
          |                                   \
          |                                    \
  +-------v--------+                      +-----v------+
  |  node-C         |   <--- joined ---   |  NEW NODE   |
  |  (new in cluster)|                    |  ZFS mirror |
  |  storage: tank1  |                    |  2x1TB      |
  +------------------+                    +------------+

  Critical VM: vpn-gw  -> ZFS + replication q=5m

🎯 Контекст

Один из узлов (далее node-A) стал нестабилен и его нужно было вывести на обслуживание.
Но на нём жили VM, которые нельзя «просто выключить и потом разберёмся».

Решение: завести новый узел node-C, аккуратно ввести его в кластер и перенести нагрузку.


✅ Что было сделано (по шагам)

Схема: план миграции (Before → Move → After)

Before:
  node-A (unstable)  : [vm1][vm2][vpn-gw][...]
  node-B (stable)    : [vmX][...]
  node-C (new)       : (empty) + ZFS mirror + storage_id=tank1

Move (batched):
  backup -> migrate vm1 -> validate
        -> migrate vm2 -> validate
        -> migrate vpn-gw (separate window) -> validate

After:
  node-A             : [empty] (maintenance)
  node-B             : [vmX][...]
  node-C             : [vm1][vm2][vpn-gw][...]

1) Подготовили новый узел и безопасный админ-доступ

  • добавил SSH-доступ по ключам;
  • сделал алиасы для удобного администрирования;
  • переключил репозитории на no-subscription;
  • обновил систему и перешёл на актуальное ядро (с ребутом);
  • перед join проверил совместимость версий Proxmox/пакетов.
Admin plane:
  ssh-key -> aliases -> updates -> reboot -> version parity -> cluster join

2) Добавили новый узел в кластер

  • node-C вошёл в существующий кластер;
  • проверил кворум и видимость нод;
  • только после этого начал перенос нагрузок.

3) Подготовили хранилище

На новом узле поднял более надёжную схему:

  • ZFS mirror (2 диска одинакового объёма);
  • единый storage ID, чтобы Proxmox-репликация работала без сюрпризов.
Storage:
  disk1 + disk2  =>  ZFS mirror  =>  storage_id: tank1

Replication requires:
  source.storage_id == target.storage_id

4) Страховка: бэкапы перед миграцией

Перед переносом целевых VM сделал страховочные бэкапы.
Это не «оверкилл», это контроль:

  • если миграция пойдёт не так, есть понятный план отката;
  • проще принимать инженерные решения, когда есть подушка.

5) Перенесли VM с обслуживаемой ноды

  • основную массу VM перенёс в рабочем режиме;
  • «сетевую appliance VM» переносил в отдельное окно и с доп.проверками.

ASCII как процесс (упрощённо):

Before:
  node-A: [vm1][vm2][vpn-gw][...]
  node-B: [vmX][...]
  node-C: [empty]

Migrate:
  backup -> move vm1 -> validate -> move vm2 -> validate -> move vpn-gw -> validate

After:
  node-A: [empty / maintenance]
  node-B: [vmX][...]
  node-C: [vm1][vm2][vpn-gw][...]

6) Почистили «хвосты» репликации и выровняли версии

После миграций часто остаются старые replication jobs (особенно если VM меняли storage/узел).

Сделал:

  • отключил/удалил устаревшие задания;
  • выровнял версии пакетов и ядра между активными нодами.

7) Укрепили отказоустойчивость для VPN VM

Схема: репликация критичной VPN VM

          writes
vpn-gw VM  ----->  tank1 (ZFS mirror)  [node-C]
   |
   | (replication job, every 5m)
   v
tank1 (same storage_id) on target node

Fail case: node-C down
  -> promote replicated dataset
  -> start vpn-gw VM on another node
  -> restore admin access

Критичный сервис — это VPN-шлюз/точка доступа, на которую завязаны админ-доступы.

Сделал:

  • перевёл диски VPN VM на ZFS (tank1);
  • включил репликацию каждые 5 минут.
vpn-gw VM
  storage: tank1 (ZFS)
  replication: every 5m

Goal:
  "если node-C умер" -> быстро поднять vpn-gw на другой ноде

8) Выровняли сеть (чтобы после миграции не ловить фантомные баги)

Сверил между узлами:

  • DNS
  • статические маршруты
  • bridge-конфигурацию

Это важно: иногда VM «переезжает», а проблема оказывается не в VM, а в мелком различии сетевых параметров хоста.

9) Автообновления и health-check

  • настроил ночные автообновления пакетов;
  • добавил daily health-check с логированием и уведомлениями.

🧪 Технические нюансы (что всплыло)

  • Не все диски «просто мигрируются» между lvmthin и zfspool.
    Иногда нужен обходной сценарий (бэкап/restore или промежуточное хранилище).

  • После миграции остаются «хвосты» replication jobs.
    Их лучше пересоздавать, а не пытаться «починить по месту».

  • Для штатной Proxmox-репликации важен единый storage ID.
    Если на одной ноде tank1, а на другой tank-zfs — выстрелишь себе в ногу.

  • Проверки после ребута лучше делать с паузой.
    В переходном состоянии можно получить ложную картину и начать чинить то, что само бы поднялось.


✅ Итог

  • Нестабильная нода выведена из нагрузки без потери VM.
  • Сервисы продолжили работать на остальных узлах.
  • Хранилище стало надёжнее (ZFS mirror на активной ноде).
  • Критичный VPN получил репликацию и регулярный мониторинг.
  • Кластер стал более предсказуемым по версиям, сети и storage.

🧠 Практический вывод

Даже в небольшом homelab имеет смысл делать такие работы как в проде:

  • миграции только через бэкап + валидацию;
  • storage IDs проектировать заранее;
  • иметь ежедневный health-check;
  • работать с окном обслуживания и планом отката.

✅ Мини-чеклист (как шаблон на будущее)

[Before]
- confirm: backups exist
- confirm: cluster quorum ok
- confirm: versions aligned
- confirm: target storage_id matches

[Move]
- migrate in batches
- validate service after each move
- move critical VM in separate window

[After]
- cleanup replication jobs
- validate routes/DNS/bridges
- enable replication for critical VM
- enable health-check + alerts