Каждое обновление = даунтайм: переводим хостинг на Ceph для live migration

Задача клиента: даунтайм при каждом обслуживании

Летом 2025 года к нам обратился небольшой хостинг-провайдер HostLine из Екатеринбурга. Компания предоставляла VPS-хостинг для малого бизнеса: 50 клиентских виртуальных серверов на базе Proxmox VE, размещённых на 5 физических нодах в двух стойках дата-центра.

Критическая проблема: диски виртуальных машин хранились локально на каждой ноде. Это означало:

  • Нет live migration — перенос VM между нодами требовал остановки, копирования диска и запуска
  • Каждое обновление = даунтайм — обновление ядра ноды требовало остановки всех VM на ней (до 10 штук)
  • Нет отказоустойчивости хранилища — при выходе диска из строя клиентские данные терялись
  • Неравномерная утилизация — на одних нодах 90% диска занято, на других 30%
«Каждый месяц — окно обслуживания. Мы предупреждаем клиентов за неделю, но они всё равно жалуются. Двое ушли к конкурентам, которые обещают 99.99% uptime» — директор HostLine.

За последний год было 3 инцидента с дисками. В одном случае RAID-массив на ноде деградировал, и восстановление заняло 8 часов. Клиенты подняли волну негатива на хостинг-форумах. Инженеры АйТи Фреш предложили развернуть Ceph — распределённое хранилище, которое решает все описанные проблемы разом.

Почему Ceph, а не NFS или GlusterFS

Мы рассмотрели три варианта распределённого хранилища:

КритерийNFSGlusterFSCeph
Block storage (RBD для VM)НетЧерез gluster-blockНативный
Интеграция с ProxmoxЕсть, но медленноОграниченнаяНативная, в ядре
Live migrationРаботает, но с лагамиНенадёжноБесшовно
Производительность IOPSНизкая (NFS overhead)СредняяВысокая (kernel RBD)
СамовосстановлениеНетЧастичноеПолное автоматическое
МасштабированиеВертикальноеГоризонтальноеГоризонтальное

Ceph победил по всем критериям для нашего кейса. Нативная интеграция с Proxmox VE означала, что после развёртывания Ceph live migration будет работать «из коробки» — без дополнительных плагинов и костылей.

Архитектура Ceph для хостинга

Мы спроектировали кластер с учётом существующего оборудования клиента (5 нод) и бюджета:

# Архитектура Ceph-кластера

# Ноды (5 серверов, dual Xeon E5-2680v4, 128 GB RAM)
Node1 (10.0.10.1): MON + MGR + OSD × 4  (4 × 2TB NVMe)
Node2 (10.0.10.2): MON + MGR + OSD × 4  (4 × 2TB NVMe)
Node3 (10.0.10.3): MON + OSD × 4        (4 × 2TB NVMe)
Node4 (10.0.10.4): OSD × 4              (4 × 2TB NVMe)
Node5 (10.0.10.5): OSD × 4              (4 × 2TB NVMe)

# Сеть
Public network:  10.0.10.0/24 (клиентский трафик, 10 Gbit)
Cluster network: 10.0.20.0/24 (репликация Ceph, 10 Gbit, отдельный VLAN)

# Итого
OSD: 20 дисков × 2 TB = 40 TB raw
Usable (replication × 3): ~13 TB
Usable (replication × 2): ~20 TB

Мы выбрали фактор репликации 3 для пула VM-дисков (любые 2 ноды могут выйти из строя без потери данных) и фактор 2 для пула бэкапов (экономия места при допустимом риске).

Развёртывание Ceph через cephadm

Cephadm — современный инструмент развёртывания Ceph, пришедший на смену ceph-deploy и ceph-ansible. Он управляет демонами Ceph через контейнеры (Podman/Docker) и SSH.

Подготовка нод и сетевой инфраструктуры

Перед развёртыванием мы подготовили все 5 серверов:

# На всех нодах (Node1-Node5):

# 1. Обновляем систему
sudo apt-get update && sudo apt-get upgrade -y

# 2. Настраиваем NTP (критично для Ceph!)
sudo apt-get install -y chrony
sudo systemctl enable chrony
chronyc tracking
# Reference ID    : A29FC801 (ntp1.vniiftri.ru)
# System time     : 0.000000231 seconds fast of NTP time

# 3. Настраиваем отдельную сеть для кластерного трафика
# /etc/netplan/01-cluster.yaml
sudo tee /etc/netplan/01-cluster.yaml > /dev/null <<'EOF'
network:
  version: 2
  ethernets:
    ens4:
      addresses:
        - 10.0.20.X/24    # X = номер ноды (1-5)
      mtu: 9000           # Jumbo frames для производительности
EOF
sudo netplan apply

# 4. Проверяем MTU 9000 между нодами
ping -M do -s 8972 10.0.20.2
# PING 10.0.20.2 (10.0.20.2) 8972(9000) bytes of data.
# 8980 bytes from 10.0.20.2: icmp_seq=1 ttl=64 time=0.154 ms

# 5. Настраиваем SSH без пароля с Node1 на все ноды
ssh-keygen -t ed25519 -N '' -f ~/.ssh/id_ed25519
for i in 1 2 3 4 5; do
  ssh-copy-id root@10.0.10.$i
done

Инициализация кластера Ceph

Cephadm bootstrap создаёт первый монитор и менеджер на Node1:

# На Node1: установка cephadm
curl --silent --remote-name --location \
  https://download.ceph.com/rpm-squid/el9/noarch/cephadm
chmod +x cephadm
sudo mv cephadm /usr/local/bin/

# Bootstrap кластера
sudo cephadm bootstrap \
  --mon-ip 10.0.10.1 \
  --cluster-network 10.0.20.0/24 \
  --initial-dashboard-user admin \
  --initial-dashboard-password 'S3cur3D4sh!' \
  --dashboard-password-noupdate \
  --allow-fqdn-hostname

# Вывод:
# Ceph Dashboard is now available at:
#          URL: https://node1:8443/
#         User: admin
#     Password: S3cur3D4sh!
# You can access the Ceph CLI with:
#     sudo /usr/local/bin/cephadm shell -- ceph -s

# Установка CLI-утилит на хост
sudo cephadm install ceph-common

# Проверяем статус кластера
sudo ceph -s
# cluster:
#   id:     a1b2c3d4-e5f6-7890-abcd-ef1234567890
#   health: HEALTH_WARN
#           OSD count 0 < osd_pool_default_size 3
#
# services:
#   mon: 1 daemons, quorum node1
#   mgr: node1.abcdef(active)

Добавление нод и OSD

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

# Добавляем ноды в кластер
sudo ceph orch host add node2 10.0.10.2
sudo ceph orch host add node3 10.0.10.3
sudo ceph orch host add node4 10.0.10.4
sudo ceph orch host add node5 10.0.10.5

# Назначаем роли мониторов (нечётное количество — 3)
sudo ceph orch apply mon --placement="node1,node2,node3"

# Назначаем роли менеджеров (2 для отказоустойчивости)
sudo ceph orch apply mgr --placement="node1,node2"

# Проверяем, что ноды добавлены
sudo ceph orch host ls
# HOST   ADDR        LABELS  STATUS
# node1  10.0.10.1
# node2  10.0.10.2
# node3  10.0.10.3
# node4  10.0.10.4
# node5  10.0.10.5

# Смотрим доступные диски
sudo ceph orch device ls --wide
# HOST   PATH      TYPE  SIZE   AVAIL
# node1  /dev/nvme0n1  ssd  2.0T  Yes
# node1  /dev/nvme1n1  ssd  2.0T  Yes
# node1  /dev/nvme2n1  ssd  2.0T  Yes
# node1  /dev/nvme3n1  ssd  2.0T  Yes
# ... (ещё 16 дисков на нодах 2-5)

# Добавляем все доступные диски как OSD
sudo ceph orch apply osd --all-available-devices

# Ждём 2-3 минуты и проверяем
sudo ceph osd tree
# ID  CLASS  WEIGHT    TYPE NAME        STATUS  REWEIGHT
# -1         36.37999  root default
# -3          7.27600      host node1
#  0    ssd   1.81900          osd.0      up     1.00000
#  1    ssd   1.81900          osd.1      up     1.00000
#  2    ssd   1.81900          osd.2      up     1.00000
#  3    ssd   1.81900          osd.3      up     1.00000
# -5          7.27600      host node2
# ... (ещё 16 OSD)

# Финальная проверка здоровья
sudo ceph -s
# cluster:
#   health: HEALTH_OK
#
# services:
#   mon: 3 daemons, quorum node1,node2,node3
#   mgr: node1.abcdef(active, standbys: node2.ghijkl)
#   osd: 20 osds: 20 up, 20 in

Настройка пулов и интеграция с Proxmox

После развёртывания кластера нужно создать пулы хранения и подключить их к Proxmox VE.

Создание RADOS-пулов с CRUSH-правилами

Мы создали три пула для разных задач:

# Пул для VM-дисков (replication factor 3)
sudo ceph osd pool create vm-disks 128
sudo ceph osd pool set vm-disks size 3
sudo ceph osd pool set vm-disks min_size 2
sudo ceph osd pool application enable vm-disks rbd

# Пул для ISO-образов и шаблонов (replication factor 2)
sudo ceph osd pool create templates 32
sudo ceph osd pool set templates size 2
sudo ceph osd pool set templates min_size 1
sudo ceph osd pool application enable templates rbd

# Пул для бэкапов (replication factor 2, erasure coding в будущем)
sudo ceph osd pool create backups 64
sudo ceph osd pool set backups size 2
sudo ceph osd pool set backups min_size 1
sudo ceph osd pool application enable backups rbd

# Инициализируем RBD на пулах
sudo rbd pool init vm-disks
sudo rbd pool init templates
sudo rbd pool init backups

# Проверяем пулы
sudo ceph osd lspools
# 1 vm-disks
# 2 templates
# 3 backups

# Проверяем распределение placement groups
sudo ceph pg stat
# 224 pgs: 224 active+clean; 0 B data, 945 MiB used, 36.4 TiB / 36.4 TiB avail

Интеграция Ceph с Proxmox VE

Proxmox VE имеет нативную поддержку Ceph RBD. Мы создали пользователя и настроили подключение на всех Proxmox-нодах:

# Создаём пользователя для Proxmox
sudo ceph auth get-or-create client.proxmox \
  mon 'profile rbd' \
  osd 'profile rbd pool=vm-disks, profile rbd pool=templates, profile rbd pool=backups' \
  mgr 'profile rbd pool=vm-disks, profile rbd pool=templates, profile rbd pool=backups'

# Получаем ключ
sudo ceph auth get client.proxmox
# [client.proxmox]
#     key = AQBz1abc2DEFghi3JKLmno4PQRstu5VWXyz6==

# На каждой Proxmox-ноде: сохраняем ключ
sudo mkdir -p /etc/pve/priv/ceph
echo 'AQBz1abc2DEFghi3JKLmno4PQRstu5VWXyz6==' > /etc/pve/priv/ceph/vm-disks.keyring

# Копируем ceph.conf на все Proxmox-ноды
sudo scp /etc/ceph/ceph.conf root@proxmox-node1:/etc/ceph/
sudo scp /etc/ceph/ceph.conf root@proxmox-node2:/etc/ceph/
# ... (на все 5 нод)

Добавляем хранилище через Proxmox CLI:

# Добавляем Ceph RBD storage в Proxmox
pvesm add rbd ceph-vm \
  --pool vm-disks \
  --monhost 10.0.10.1,10.0.10.2,10.0.10.3 \
  --username proxmox \
  --content images,rootdir \
  --krbd 1

pvesm add rbd ceph-templates \
  --pool templates \
  --monhost 10.0.10.1,10.0.10.2,10.0.10.3 \
  --username proxmox \
  --content iso,vztmpl

pvesm add rbd ceph-backups \
  --pool backups \
  --monhost 10.0.10.1,10.0.10.2,10.0.10.3 \
  --username proxmox \
  --content backup

# Проверяем доступность хранилищ
pvesm status
# Name            Type   Status  Total       Used      Avail
# ceph-vm         rbd    active  13421772    0         13421772
# ceph-templates  rbd    active  20132659    0         20132659
# ceph-backups    rbd    active  20132659    0         20132659
# local           dir    active  102400      5120      97280

Миграция существующих VM на Ceph

Ключевой этап — перенос 50 клиентских VM с локальных дисков на Ceph RBD. Мы делали это поочерёдно, в ночные окна:

# Миграция диска VM с локального хранилища на Ceph
# Для каждой VM (пример: VM ID 101)

# 1. Проверяем текущее хранилище
qm config 101 | grep -E '^(scsi|virtio|ide|sata)'
# scsi0: local-lvm:vm-101-disk-0,size=50G

# 2. Переносим диск на Ceph (online, но с замедлением I/O)
qm move-disk 101 scsi0 ceph-vm --delete 1

# Прогресс:
# Moving disk 'local-lvm:vm-101-disk-0' to 'ceph-vm'
# creating full clone of drive scsi0 (local-lvm:vm-101-disk-0)
#  Logical volume "vm-101-disk-0" successfully removed.
# drive mirror is complete

# 3. Проверяем, что диск теперь на Ceph
qm config 101 | grep scsi0
# scsi0: ceph-vm:vm-101-disk-0,size=50G

# 4. Проверяем RBD-образ в Ceph
rbd ls vm-disks
# vm-101-disk-0

rbd info vm-disks/vm-101-disk-0
# rbd image 'vm-101-disk-0':
#     size 50 GiB in 12800 objects
#     order 22 (4 MiB objects)
#     block_name_prefix: rbd_data.abc123
#     format: 2
#     features: layering, exclusive-lock, object-map, fast-diff, deep-flatten

Для автоматизации мы написали скрипт массовой миграции:

#!/bin/bash
# migrate-all-vms.sh — перенос всех VM на Ceph

for VMID in $(qm list | awk 'NR>1 {print $1}'); do
    echo "=== Миграция VM $VMID ==="
    DISKS=$(qm config $VMID | grep -oP '(scsi|virtio)\d+' | sort -u)
    for DISK in $DISKS; do
        STORAGE=$(qm config $VMID | grep "^${DISK}:" | grep -oP '^[^:]+:\K[^,]+')
        if [[ "$STORAGE" == local* ]]; then
            echo "  Перенос $DISK с $STORAGE на ceph-vm"
            qm move-disk $VMID $DISK ceph-vm --delete 1
            echo "  $DISK перенесён успешно"
        else
            echo "  $DISK уже на Ceph, пропускаем"
        fi
    done
    echo ""
done

Live migration: нулевой даунтайм при обслуживании

После переноса всех VM на Ceph RBD стала доступна live migration — перенос работающей VM между нодами без остановки.

Тестирование live migration

Мы провели тестирование в присутствии клиента:

# Проверяем, на какой ноде работает VM 101
qm status 101 --verbose | grep node
# node: node1

# Запускаем непрерывный ping к VM изнутри
# (с отдельной машины)
ping -i 0.1 10.0.1.101

# Выполняем live migration на node3
qm migrate 101 node3 --online

# Вывод:
# Starting migration of VM 101 to node 'node3'
# Volume 'scsi0': skipped (on shared storage 'ceph-vm')
# migration active, transferred 256 MiB of 8192 MiB VM RAM...
# migration active, transferred 1024 MiB of 8192 MiB VM RAM...
# migration active, dirty: 12 MiB, transferred 7680 MiB...
# migration completed, downtime: 45 ms
# TASK OK

# Результат ping:
# 64 bytes from 10.0.1.101: icmp_seq=842 time=0.3 ms
# 64 bytes from 10.0.1.101: icmp_seq=843 time=0.3 ms
# 64 bytes from 10.0.1.101: icmp_seq=844 time=12.1 ms  ← момент переключения
# 64 bytes from 10.0.1.101: icmp_seq=845 time=0.4 ms
# 64 bytes from 10.0.1.101: icmp_seq=846 time=0.3 ms

Даунтайм при live migration: 45 миллисекунд. Даже SSH-сессия не прерывалась.

Автоматическая эвакуация при обслуживании ноды

Мы написали скрипт для безопасного обслуживания ноды — он мигрирует все VM на соседние ноды:

#!/bin/bash
# evacuate-node.sh — эвакуация всех VM с ноды

NODE=$1
if [ -z "$NODE" ]; then
    echo "Использование: $0 "
    exit 1
fi

# Получаем список VM на ноде
VMs=$(pvesh get /nodes/${NODE}/qemu --output-format json | jq -r '.[].vmid')
VM_COUNT=$(echo "$VMs" | wc -w)

echo "Найдено $VM_COUNT VM на ноде $NODE"
echo "Начинаем эвакуацию..."

# Получаем список целевых нод (все ноды кроме текущей)
TARGET_NODES=($(pvesh get /nodes --output-format json | jq -r '.[].node' | grep -v "$NODE"))
TARGET_COUNT=${#TARGET_NODES[@]}
IDX=0

for VMID in $VMs; do
    TARGET=${TARGET_NODES[$((IDX % TARGET_COUNT))]}
    echo "  VM $VMID → $TARGET (live migration)"
    qm migrate $VMID $TARGET --online 2>&1 | tail -1
    IDX=$((IDX + 1))
done

echo "Эвакуация завершена. Нода $NODE свободна для обслуживания."
echo "После обслуживания запустите: $0 --return $NODE"
# Пример использования
./evacuate-node.sh node2
# Найдено 10 VM на ноде node2
# Начинаем эвакуацию...
#   VM 101 → node1 (live migration)
#   migration completed, downtime: 38 ms
#   VM 102 → node3 (live migration)
#   migration completed, downtime: 52 ms
# ...
# Эвакуация завершена. Нода node2 свободна для обслуживания.

# Теперь можно безопасно обновить ядро на node2
ssh root@node2 'apt-get upgrade -y && reboot'

Мониторинг и обслуживание Ceph-кластера

Ceph-кластер требует постоянного мониторинга. Мы настроили несколько инструментов.

Ceph Dashboard и Prometheus

Ceph имеет встроенный Dashboard на порту 8443. Дополнительно мы включили Prometheus-экспорт:

# Включаем модуль Prometheus в Ceph MGR
sudo ceph mgr module enable prometheus

# Проверяем метрики
curl -s http://10.0.10.1:9283/metrics | head -20
# # HELP ceph_cluster_total_bytes Cluster total bytes
# ceph_cluster_total_bytes 4.0007767e+13
# # HELP ceph_cluster_total_used_bytes Cluster total used bytes
# ceph_cluster_total_used_bytes 1.2345678e+12

# Ключевые алерты для Ceph в Prometheus
# /etc/prometheus/rules/ceph_alerts.yml
# /etc/prometheus/rules/ceph_alerts.yml
groups:
  - name: ceph
    rules:
      - alert: CephHealthWarning
        expr: ceph_health_status == 1
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Ceph кластер в состоянии HEALTH_WARN"

      - alert: CephHealthError
        expr: ceph_health_status == 2
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "Ceph кластер в состоянии HEALTH_ERR"

      - alert: CephOSDDown
        expr: ceph_osd_up == 0
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "OSD {{ $labels.ceph_daemon }} не работает"

      - alert: CephClusterNearFull
        expr: ceph_cluster_total_used_bytes / ceph_cluster_total_bytes > 0.75
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "Ceph кластер заполнен на {{ $value | humanizePercentage }}"

Performance tuning для NVMe

Для максимальной производительности на NVMe-дисках мы применили ряд оптимизаций:

# Оптимизация Ceph для NVMe
# Устанавливаем в ceph.conf через cephadm

sudo ceph config set osd bluestore_cache_size_ssd 4294967296  # 4 GB cache per OSD
sudo ceph config set osd bluestore_min_alloc_size_ssd 4096
sudo ceph config set osd osd_memory_target 4294967296          # 4 GB RAM per OSD
sudo ceph config set osd osd_op_num_threads_per_shard_ssd 2

# Увеличиваем количество PG для лучшего распределения
sudo ceph osd pool set vm-disks pg_num 256
sudo ceph osd pool set vm-disks pgp_num 256

# Включаем compression для пула бэкапов
sudo ceph osd pool set backups compression_mode aggressive
sudo ceph osd pool set backups compression_algorithm zstd

# Бенчмарк после оптимизации
sudo rados bench -p vm-disks 30 write --no-cleanup
# Total writes made:      8942
# Write size:             4194304
# Object size:            4194304
# Bandwidth (MB/sec):     1192.34
# Average IOPS:           298
# Stddev IOPS:            42
# Max IOPS:               367
# Min IOPS:               198

sudo rados bench -p vm-disks 30 rand
# Total reads made:       15234
# Read size:              4194304
# Average IOPS:           507
# Bandwidth (MB/sec):     2030.12

Результаты бенчмарка: 1.2 GB/s на запись и 2 GB/s на чтение — более чем достаточно для 50 VPS с типичными нагрузками хостинга.

Результаты внедрения

Проект занял 3 недели: 1 неделя на развёртывание кластера, 1 неделя на миграцию VM, 1 неделя на тестирование и оптимизацию. Вот что получил хостинг-провайдер HostLine после внедрения Ceph специалистами АйТи Фреш:

МетрикаДо CephПосле Ceph
Даунтайм при обслуживании ноды30–60 минут (остановка VM)0 (live migration за 45 мс)
Время восстановления при отказе диска4–8 часов (ручное)Автоматическое (rebalance)
Окна обслуживания в месяц1–2 (плановые)0 (всё прозрачно для клиентов)
Потеря данных при отказе дискаВозможна (RAID rebuild)Исключена (3× репликация)
Утилизация дискового пространства30–90% (неравномерно)Равномерная по всем нодам
Отток клиентов за квартал3–5 клиентов0 клиентов

Через месяц после внедрения на Node4 вышел из строя один NVMe-диск. Ceph автоматически запустил recovery: данные с повреждённого OSD были восстановлены на оставшихся дисках за 40 минут. Ни один клиент не заметил проблемы. Инженеры HostLine заменили диск в рабочее время без какого-либо воздействия на клиентские VM.

«До Ceph каждый выход диска — это ночной аврал. Сейчас мы получаем уведомление в Telegram, заказываем замену и меняем диск в удобное время. Клиенты даже не знают, что что-то произошло» — системный администратор HostLine.

Часто задаваемые вопросы

Минимум — 3 сервера (для кворума мониторов и replication factor 3). Однако для продакшн-нагрузок мы рекомендуем 5+ нод: это позволяет терять до 2 серверов одновременно без потери данных и обеспечивает более равномерное распределение нагрузки. Каждый сервер должен иметь минимум один выделенный SSD/NVMe-диск для OSD.

При использовании NVMe и 10 Gbit сети разница в производительности минимальна: задержка Ceph RBD на NVMe составляет 0.2–0.5 мс (локальный NVMe — 0.05–0.1 мс). Для типичных серверных нагрузок (веб-серверы, базы данных среднего размера) разница незаметна. Критически важно выделить отдельную сеть для кластерного трафика Ceph (cluster network) и использовать Jumbo Frames (MTU 9000).

С replication factor 3 данные сохранятся — каждый объект хранится в 3 копиях на разных нодах. Кластер перейдёт в состояние HEALTH_WARN, часть placement groups будет в degraded-состоянии, но все данные останутся доступными для чтения и записи. Ceph автоматически начнёт recovery, распределяя данные по оставшимся 3 нодам. При min_size=2 запись будет работать, пока доступны хотя бы 2 копии каждого объекта.

Да, горизонтальное масштабирование — одно из главных преимуществ Ceph. Добавление новой ноды: ceph orch host add node6 10.0.10.6, затем ceph orch apply osd --all-available-devices. Ceph автоматически начнёт rebalance — перенос части данных на новые OSD. Процесс полностью прозрачен для клиентов. В нашем проекте HostLine через 3 месяца добавил шестую ноду за 30 минут.

Нужна помощь с настройкой?

Специалисты АйТи Фреш помогут с внедрением и настройкой — 15+ лет опыта, обслуживание от 15 000 ₽/мес

📞 Связаться с нами
#Ceph кластер настройка#распределённое хранилище#Ceph RBD Proxmox#CephFS настройка#cephadm развёртывание#live migration VPS#Ceph OSD#Ceph мониторинг