Proxmox — это специализированный дистрибутив для виртуализации и контейнеризации на базе Debian Linux.


Когда потребности перерастают один, ответственный за все, железный сервер, но еще не настолько велики, чтобы использовать Kubernetes, на помощь приходят разные решения, позволяющие управлять кластером из нескольких хостов, организовать High Availability, репликацию и централизованный бэкап контейнеров и виртуалок. Proxmox — одно из них.


С ним мы уже больше двух лет, и очень довольны: он сильно упрощает очень многое: нарезку и резервирование ресурсов, живую миграцию (qemu VM's only), централизованный сбор метрик (без необходимости впихивать экспортер/агент в каждого гостя), управление (через WebUI, api и ssh).


Наша сеть разрослась от трех серверов до дюжины, из них количество хостов Proxmox выросло от нуля до восьми, на текущий момент. Но иногда ломается и он.


Что может отказать у Proxmox?


На самом деле, немало. Сетевые маунты, corosync, неснявшийся lock…


Одни сбои потребуют ручного вмешательства, другие устраняются самостоятельно. Некоторые самоустраняются довольно неприятным образом, называемом fencing — особенно неприятным, если пострадавший сервис не имел собственной кластеризации. Иные сбои случаются только в кластере и никогда на одночном хосте, иные наоборот.


Отказы одиночных хостов (нод)


Залипший lock


Proxmox часто вешает замок на контейнер или VM — в интерфейсе это отображается, собственно, иконкой замка на соответствущем госте. Изменение конфигурации, снятие бэкапа, разворачивание/клонирование/миграция — любая из этих операций вешает замок и не всегда обратная команда исполняется корректно.


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


К счастью, с этим просто бороться. Нужно выполнить


  • pct unlock <CTid> для конейнеров
  • qm unlock <VMid> для виртуальных машин
    … на соответствующем хосте Proxmox

Критичность: невысокая
Этот вид отказов затрагивает лишь одного гостя и на функционировании его не сказывается.


Отказ сетевого хранилища


Как правило, обнаруживается по иконке с вопросительным знаком на хранилище. Proxmox с завидным упорством пытается примонтировать хранилище, если оно включено в конфигурации кластера для соответствующего хоста, но вот отмонтировать залипшее хранилище не пытается.
Решается просто:
umount -nlf <mountpoint>


Критичность: от низкой до высокой
В зависимости от типа хранилища и его назначения, этот отказ может быть как совершенно некритичным (инсталляционные образы и образы контейнеров), так и наоборот, если, например, у вас откажет хранилище бэкапов или nfs-шара с запущенными контейнерами.


Отказ внутренних сервисов самого Proxmox


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


Наилучший способ лечения — перезагрузка через ssh или с помощью KVM хостера.
Однако, если перезапуск неприемлем, можно попробовать остановить и запустить заново сервисы Proxmox:


for s in pveproxy spiceproxy pvestatd pve-cluster corosync; do systemctl stop $s; done
for s in corosync pve-cluster pvestatd spiceproxy pveproxy; do systemctl stop $s; done

Критичность: средняя
Несмотря на полную неуправляемость хоста через WebUI, запущенные гости продолжают работать.


Отказы уровня кластера


Несовпадение конфигурации Replication и HA


Proxmox может самостоятельно реплицировать гостей между хостами и переподнимать их если один из хостов выходит из строя. Однако, проверка когерентности этих настроек не выполняется — тем самым вы можете настроить репликацию на один хост, а HA — на другой, после чего попытка переместить гостя закончится невозможностью его запуска.
Очень неприятно, но достаточно легко исправить, пересоздав конфигурацию HA для гостя на включающую корректный хост или уничтожив ее и переместив /etc/pve/nodes/<host>/<lxc|qemu-server>/<guest>.conf в правильное место (в соответствующую папку активного хоста с валидной репликой) и запустив вручную.


Критичность: катастрофическая
Фактически это тайм-бомба, приводящая к DoS. Вы не хотите обнаружить такое.


Ошибки репликации ZFS


Встречались раз-два в месяц до перехода на 7 версию, обычно происходят если каким-то образом хост с репликой и хост-источник разошлись в снепшотах: репликация хранит только один снепшот для каждой цели репликации, и при несовпадении снепшотов на источнике и цели репликация падает.
Решение — удалить соответствующий dataset/volume.


Критичность: катастрофическая
Еще один вариант предудыщей таймбомбы


Отсутствие кворума в кластере


Неочевидное и труднодиагностируемое состояние. Гости при этом продолжают работать (Proxmox вообще довольно бережен к гостям) там, где они находились до распада кворума, но становятся невозможными любые операции с хостами или гостями включая авторизацию через WebUI. Происходит это потому что pmxcfs, хранящая — и реплицирующая между хостами! — настройки кластера, переходит в read-only при отсутствии кворума.
Может быть связано с отказом внутренних сервисов, потерями в сети, неправильной настройкой файрволла, или даже оказаться следствием продолжительной деградации сети в недавнем прошлом.


Проверить наличие кворума можно через ssh командой pvecm status. Нормальный вывод будет содержать следующий блок:


Votequorum information  
----------------------  
Expected votes:   7  
Highest expected: 7  
Total votes:      7  
Quorum:           4     
Flags:            Quorate

Это говорит о том, что в кластере семь хостов (Expected votes), из них для кворума необходимо не менее четырех (Quorum), и сейчас все семь хостов активны (Total votes), кворум соблюден (Flags: Quorate). Если количество голосов окажется меньше, чем требуется для кворума — кластер заблокируется до восстановления.


Решение — по обстоятельствам. Один раз, после долгих неполадок в сети хостера, нам помог перезапуск внутренних сервисов на хосте, никак не связанном с наблюдаемым эффектом (исправно входившего в кворум).


Критичность: катастрофическая
Перестают работать любые функции кластера, не запускаются задания, могут уйти в fencing хосты с HA.


Сетевые ошибки


В целом, Proxmox довольно толерантен к ошибкам сети, потерям пакетов и тому подобному, однако если udp-пакеты перестают нормально ходить, то события развиваются следующим образом:


  • из-за потерь пакетов нарушается обмен служебной информацией между нодами
  • перестраивается кворум corosync
  • один или несколько хостов теряют связь с кластером и пытаются заново к нему присоединиться
  • если для хоста сконфигурирован HA то он выполняет жесткую перезагрузку
    Выглядит это примерно так:
    systemd[1]: rsyslog.service: Sent signal SIGHUP to main process 3087 (rsyslogd) on client request.
    systemd[1]: logrotate.service: Succeeded.
    systemd[1]: Finished Rotate log files.
    systemd[1]: logrotate.service: Consumed 1.067s CPU time.
    spiceproxy[1503847]: worker exit
    spiceproxy[3908]: worker 1503847 finished
    pveproxy[777811]: worker exit
    pveproxy[1280387]: worker exit
    pveproxy[888694]: error AnyEvent::Util: Runtime error in AnyEvent::guard callback: Can't call method "_put_session" on an undefined value at /usr/lib/x86_64-linux-gnu/perl5/5.32/AnyEvent/Handle.pm line 2259 during global destruction.
    pveproxy[3902]: worker 777811 finished
    pveproxy[3902]: worker 888694 finished
    pveproxy[3902]: worker 1280387 finished
    // Link to another host is garbled 
    corosync[3813]:   [KNET  ] link: host: 8 link: 0 is down
    corosync[3813]:   [KNET  ] host: host: 8 (passive) best link: 0 (pri: 1)
    corosync[3813]:   [KNET  ] host: host: 8 has no active links
    corosync[3813]:   [KNET  ] rx: host: 8 link: 0 is up
    corosync[3813]:   [KNET  ] host: host: 8 (passive) best link: 0 (pri: 1)
    pveproxy[1643087]: got inotify poll request in wrong process - disabling inotify
    pveproxy[1643087]: worker exit
    // by corosync udp-packets disappearing
    corosync[3813]:   [TOTEM ] Token has not been received in 5266 ms 
    corosync[3813]:   [KNET  ] link: host: 1 link: 0 is down
    corosync[3813]:   [KNET  ] link: host: 8 link: 0 is down
    corosync[3813]:   [KNET  ] host: host: 1 (passive) best link: 0 (pri: 1)
    corosync[3813]:   [KNET  ] host: host: 1 has no active links
    corosync[3813]:   [KNET  ] host: host: 8 (passive) best link: 0 (pri: 1)
    corosync[3813]:   [KNET  ] host: host: 8 has no active links
    corosync[3813]:   [TOTEM ] Token has not been received in 12169 ms 
    corosync[3813]:   [KNET  ] rx: host: 1 link: 0 is up
    corosync[3813]:   [KNET  ] host: host: 1 (passive) best link: 0 (pri: 1)
    corosync[3813]:   [KNET  ] rx: host: 8 link: 0 is up
    corosync[3813]:   [KNET  ] host: host: 8 (passive) best link: 0 (pri: 1)
    corosync[3813]:   [TOTEM ] Token has not been received in 19848 ms 
    // Quorum disruption
    corosync[3813]:   [QUORUM] Sync members[1]: 5
    corosync[3813]:   [QUORUM] Sync left[4]: 1 3 4 8
    corosync[3813]:   [TOTEM ] A new membership (5.13620) was formed. Members left: 1 3 4 8
    corosync[3813]:   [TOTEM ] Failed to receive the leave message. failed: 1 3 4 8
    pmxcfs[3703]: [dcdb] notice: members: 5/3703
    pmxcfs[3703]: [status] notice: members: 5/3703
    // HA-hosts may do fencing there 
    corosync[3813]:   [QUORUM] This node is within the non-primary component and will NOT provide any services.
    corosync[3813]:   [QUORUM] Members[1]: 5
    // This cake is a lie, host is blocked
    corosync[3813]:   [MAIN  ] Completed service synchronization, ready to provide service.
    // Because of quorum absence
    pmxcfs[3703]: [status] notice: node lost quorum
    pmxcfs[3703]: [dcdb] crit: received write while not quorate - trigger resync
    pmxcfs[3703]: [dcdb] crit: leaving CPG group
    pve-ha-lrm[3910]: lost lock 'ha_agent_pve5_lock - cfs lock update failed - Operation not permitted
    pve-ha-lrm[3910]: status change active => lost_agent_lock
    // Quorum restoration
    corosync[3813]:   [QUORUM] Sync members[5]: 1 3 4 5 8
    corosync[3813]:   [QUORUM] Sync joined[4]: 1 3 4 8
    corosync[3813]:   [TOTEM ] A new membership (1.13624) was formed. Members joined: 1 3 4 8
    pmxcfs[3703]: [status] notice: members: 1/3409, 3/7179, 4/3856, 5/3703, 8/2042
    pmxcfs[3703]: [status] notice: starting data syncronisation
    // Host unbloked for this moment
    corosync[3813]:   [QUORUM] This node is within the primary component and will provide service.
    corosync[3813]:   [QUORUM] Members[5]: 1 3 4 5 8
    corosync[3813]:   [MAIN  ] Completed service synchronization, ready to provide service.
    pmxcfs[3703]: [status] notice: node has quorum
    pmxcfs[3703]: [status] notice: received sync request (epoch 1/3409/000000A6)
    pmxcfs[3703]: [status] notice: received sync request (epoch 1/3409/000000A7)
    pmxcfs[3703]: [dcdb] notice: start cluster connection
    // Problems persists
    pmxcfs[3703]: [dcdb] crit: cpg_join failed: 14
    pmxcfs[3703]: [dcdb] crit: can't initialize service
    pve-ha-crm[3900]: lost lock 'ha_manager_lock - cfs lock update failed - Device or resource busy
    pve-ha-crm[3900]: status change master => lost_manager_lock
    // Another place for fencing
    pve-ha-crm[3900]: watchdog closed (disabled)
    pve-ha-crm[3900]: status change lost_manager_lock => wait_for_quorum
    pmxcfs[3703]: [dcdb] crit: cpg_send_message failed: 9
    pmxcfs[3703]: [dcdb] crit: cpg_send_message failed: 9
    pmxcfs[3703]: [dcdb] crit: cpg_send_message failed: 9
    pmxcfs[3703]: [dcdb] crit: cpg_send_message failed: 9
    pmxcfs[3703]: [dcdb] crit: cpg_send_message failed: 9
    pmxcfs[3703]: [dcdb] crit: cpg_send_message failed: 9
    pmxcfs[3703]: [dcdb] crit: cpg_send_message failed: 9
    pmxcfs[3703]: [dcdb] crit: cpg_send_message failed: 9
    pmxcfs[3703]: [dcdb] crit: cpg_send_message failed: 9
    pmxcfs[3703]: [dcdb] crit: cpg_send_message failed: 9
    pmxcfs[3703]: [dcdb] crit: cpg_send_message failed: 9
    pmxcfs[3703]: [dcdb] crit: cpg_send_message failed: 9
    pmxcfs[3703]: [dcdb] crit: cpg_send_message failed: 9
    pmxcfs[3703]: [dcdb] crit: cpg_send_message failed: 9
    pmxcfs[3703]: [dcdb] crit: cpg_send_message failed: 9
    pmxcfs[3703]: [dcdb] crit: cpg_send_message failed: 9
    pmxcfs[3703]: [dcdb] crit: cpg_send_message failed: 9
    pmxcfs[3703]: [dcdb] crit: cpg_send_message failed: 9
    pmxcfs[3703]: [dcdb] crit: cpg_send_message failed: 9
    pmxcfs[3703]: [dcdb] crit: cpg_send_message failed: 9
    pmxcfs[3703]: [dcdb] crit: cpg_send_message failed: 9
    pmxcfs[3703]: [dcdb] crit: cpg_send_message failed: 9
    pmxcfs[3703]: [dcdb] crit: cpg_send_message failed: 9
    pmxcfs[3703]: [dcdb] crit: cpg_send_message failed: 9
    pve-ha-crm[3900]: status change wait_for_quorum => slave
    pmxcfs[3703]: [dcdb] crit: cpg_send_message failed: 9
    pmxcfs[3703]: [dcdb] crit: cpg_send_message failed: 9
    pvescheduler[1634357]: replication: cfs-lock 'file-replication_cfg' error: got lock request timeout
    corosync[3813]:   [TOTEM ] Token has not been received in 5396 ms 
    pmxcfs[3703]: [dcdb] crit: cpg_send_message failed: 9
    pmxcfs[3703]: [dcdb] crit: cpg_send_message failed: 9
    corosync[3813]:   [TOTEM ] Token has not been received in 12299 ms 
    corosync[3813]:   [TOTEM ] Retransmit List: b e 
    corosync[3813]:   [KNET  ] link: host: 8 link: 0 is down
    corosync[3813]:   [KNET  ] host: host: 8 (passive) best link: 0 (pri: 1)
    corosync[3813]:   [KNET  ] host: host: 8 has no active links
    corosync[3813]:   [KNET  ] rx: host: 8 link: 0 is up
    corosync[3813]:   [KNET  ] host: host: 8 (passive) best link: 0 (pri: 1)
    // All thing became good for now
    pmxcfs[3703]: [status] notice: received all states
    corosync[3813]:   [QUORUM] Sync members[5]: 1 3 4 5 8
    corosync[3813]:   [TOTEM ] A new membership (1.13630) was formed. Members
    corosync[3813]:   [QUORUM] Members[5]: 1 3 4 5 8
    corosync[3813]:   [MAIN  ] Completed service synchronization, ready to provide service.
    pmxcfs[3703]: [status] notice: cpg_send_message retried 1 times
    pmxcfs[3703]: [status] notice: all data is up to date
    pmxcfs[3703]: [status] notice: dfsm_deliver_queue: queue length 106
    pmxcfs[3703]: [dcdb] notice: members: 1/3409, 3/7179, 4/3856, 5/3703, 8/2042
    pmxcfs[3703]: [dcdb] notice: starting data syncronisation
    pmxcfs[3703]: [dcdb] notice: received sync request (epoch 1/3409/000000C2)
    pmxcfs[3703]: [dcdb] notice: received all states
    pmxcfs[3703]: [dcdb] notice: leader is 1/3409
    pmxcfs[3703]: [dcdb] notice: synced members: 1/3409, 3/7179, 4/3856, 8/2042
    pmxcfs[3703]: [dcdb] notice: waiting for updates from leader
    pmxcfs[3703]: [dcdb] notice: dfsm_deliver_queue: queue length 2
    pmxcfs[3703]: [dcdb] notice: update complete - trying to commit (got 7 inode updates)
    pmxcfs[3703]: [dcdb] notice: all data is up to date
    pmxcfs[3703]: [dcdb] notice: dfsm_deliver_queue: queue length 2
    pve-ha-lrm[3910]: successfully acquired lock 'ha_agent_pve5_lock'
    pve-ha-crm[3900]: successfully acquired lock 'ha_manager_lock'
    pve-ha-lrm[3910]: status change lost_agent_lock => active
    pve-ha-crm[3900]: watchdog active
    pve-ha-crm[3900]: status change slave => master
    // Bad again
    corosync[3813]:   [TOTEM ] Token has not been received in 5363 ms 
    corosync[3813]:   [TOTEM ] Token has not been received in 12264 ms 
    corosync[3813]:   [QUORUM] Sync members[5]: 1 3 4 5 8
    corosync[3813]:   [TOTEM ] A new membership (1.1363c) was formed. Members
    corosync[3813]:   [QUORUM] Members[5]: 1 3 4 5 8
    corosync[3813]:   [MAIN  ] Completed service synchronization, ready to provide service.
    pvescheduler[1653190]: jobs: cfs-lock 'file-jobs_cfg' error: got lock request timeout
    pvescheduler[1653189]: replication: cfs-lock 'file-replication_cfg' error: got lock request timeout
    pveproxy[1641105]: proxy detected vanished client connection
    corosync[3813]:   [TOTEM ] Token has not been received in 5399 ms 
    corosync[3813]:   [TOTEM ] Token has not been received in 12301 ms 
    corosync[3813]:   [QUORUM] Sync members[5]: 1 3 4 5 8
    corosync[3813]:   [TOTEM ] A new membership (1.13648) was formed. Members
    corosync[3813]:   [QUORUM] Members[5]: 1 3 4 5 8
    corosync[3813]:   [MAIN  ] Completed service synchronization, ready to provide service.
    corosync[3813]:   [TOTEM ] Token has not been received in 5402 ms 
    corosync[3813]:   [KNET  ] link: host: 8 link: 0 is down
    corosync[3813]:   [KNET  ] host: host: 8 (passive) best link: 0 (pri: 1)
    corosync[3813]:   [KNET  ] host: host: 8 has no active links
    corosync[3813]:   [TOTEM ] Token has not been received in 12303 ms 
    corosync[3813]:   [KNET  ] rx: host: 8 link: 0 is up
    corosync[3813]:   [KNET  ] host: host: 8 (passive) best link: 0 (pri: 1)
    corosync[3813]:   [QUORUM] Sync members[5]: 1 3 4 5 8
    corosync[3813]:   [TOTEM ] A new membership (1.13654) was formed. Members
    corosync[3813]:   [QUORUM] Members[5]: 1 3 4 5 8
    corosync[3813]:   [MAIN  ] Completed service synchronization, ready to provide service.

Критичность: от высокой до катастрофической
Проблемы с сетью это всегда неприятно, даже если они не ведут к деградации сервиса.
Обычные хосты будут продолжать попытки переподключения к кластеру до победного (и могут перейти в состояние отказа внутренних сервисов), в то время как если для хоста настроен HA то вы увидите…


Fencing (sudden reboot)!


Вообще, фенсинг (озаборивание, огораживание) работает на пользователя Proxmox. Его задача — до того как переподнять (по правилам HA) гостя на другом хосте — обеспечить надежную изоляцию сбойного хоста и не дать двум экземплярам гостя конфликтовать за один и тот же адрес, так как после перезапуска хост не запускает своих гостей пока не получит обновление текущей конфигурации кластера.


Это должно помогать, например, если у вас засбоила сетевая карта или порт в свитче, или поймали нестабильное (с данным железом) обновление.


Однако, если сама сеть испытывает проблемы — диагностика происходящего легко способна поставить в тупик.


Случается он (fencing) при потере кворума на хостах включенных в HA: каждый такой хост максимально жестко пытается восстановить соединение с кластером. При невозможности подключения к кластеру такие хосты выполняют жесткую перезагрузку, что принудительно тушит поднятые на них сервисы.


В syslog это выглядит как внезапная перезагрузка без выключения: вот были обычные рабочие записи, а вот сразу лог загрузки пошел.


Решение: лечить сеть, откатывать последнее обновление, переносить сеть кластера в физически отдельный контур — в зависимости от того, что вызывает fencing.


Особенно хорошо процесс виден на виртуалках: в физической консоли нет привычного лога выключения системы, сразу переход к загрузочной заставке, словно нажат Reset.


Критичность: катастрофическая, но штатная


Вместо злоключения


Как и с любой сложной системой, главное — знать три вещи: куда смотреть, за что держать и на что нажимать. Но опыт, дающий это знание, как всегда, приходит сразу после того как был нужен…


Бессбойного аптайма, господа!

Комментарии (21)