Ceph: знакомство с системой и разбор базовых операций

Ceph: базовые операции на примере интеграции с Hashicorp Nomad

Владимир Иванов Владимир Иванов Системный админиcтратор 8 мая 2024

В статье знакомимся с системой хранения данных Ceph и разбираем, как подключить ее к оркестратору Nomad, чтобы получить постоянное хранилище для контейнеров.

Изображение записи

Привет! Я Владимир Иванов, системный администратор выделенных серверов в Selectel. Мы довольно часто экспериментируем с подходами, процессами и решениями. В одном из экспериментов добрались до Ceph: сделали тренажер, в котором можно «потыкать» основной функционал хранилища, проверить гипотезы, что-то сломать/починить, не собирая при этом железный кластер. В случае фейла этот тренажер можно развернуть заново в пару консольных команд. Так и появилась идея написать эту статью.

Ceph — программно определяемая система хранения данных (SDS, Software Defined Storage). Если коротко, он объединяет несколько дисков обычной сетью, лучше от 10 GbE. Хранилище устойчиво к выходу из строя отдельных дисков, серверов, стоек или даже дата-центров. В отличие от большинства вендорных СХД, Ceph разворачивается почти на любом железе и поддерживает несколько протоколов доступа к данным: объектный, файловый и блочный. В рамках статьи я рассмотрю последний из них.

При подготовке этой статьи я исхожу из того, что вы знакомы с общепринятыми терминами и сокращениями. Архитектура хранилища Ceph подробно описана в документации, на Хабре есть статья с картинками, а у СЛЁРМ — классный курс.

Nomad — это планировщик для ваших приложений. Ближайший аналог — Kubernetes. В Nomad значительно легче вкатиться: он прост в установке и подготовке к работе. Разработчики, компания Hashicorp, поддерживают автоматическую интеграцию основных инструментов экосистемы между собой: Nomad, Consul, Vault и Terraform. Если у вас есть опыт работы с любым из этих инструментов, разобраться с синтаксисом заданий не составит большого труда.

Зачем подключать Ceph к Nomad

Nomad может работать с приложениями, контейнерами и виртуальными машинами в любом масштабе. А чтобы масштаб действительно был любым, нам необходимо перемещать наше приложение между хостами оркестратора. Тут-то и понадобится Ceph — благодаря ему хранилище можно перемещать вместе с приложением и не зависеть от локальных ресурсов хоста.

Общая схема взаимодействия компонентов между собой.
Общая схема взаимодействия компонентов между собой.

Вместо Nomad может быть K8s, выделенный сервер или платформа виртуализации. Отличаться будет только интерфейс предоставления блочного доступа к данным: CSI, RBD, iSCSI или NVME-OF. Nomad использует CSI Driver (Container Storage Interface Driver). Это унифицированный интерфейс, в котором описано взаимодействие между Nomad и системой хранения.

Ceph-CSI состоит из двух компонентов:

  • Ceph-CSI Controller — работает непосредственно с Ceph, создает и удаляет тома, назначает права доступа и т. д.;
  • Ceph-CSI Node — запускается на каждом узле и монтирует выделенные для задачи тома.

При подготовке этой статьи мы реализовали ChefCookbook, который автоматизирует деплой кластера Ceph и в несколько команд настраивает виртуальное окружение test-kitchen. С его помощью можно развернуть тестовый кластер у себя на ноутбуке в пару консольных команд. При запуске стенда развернем четыре виртуальные машины: три под кластер Ceph и одну для клиента кластера. У нас этим клиентом будет Nomad. Инструкция по настройке «тренажера» описана в репозитории.

Подготовка стенда

Вкратце, все сводится к установке необходимых зависимостей и запуску test-kitchen:


    # Деплой локального кластера
:~$ kitchen converge
# Логинимся на первую ноду кластера
:~$ kitchen login node1
# Разбираем кластер, удаляем данные виртуальных машин
:~$ kitchen destroy

Если все прошло удачно, мы сможем залогиниться на ноду и посмотреть состояние нашего кластера:


    vagrant@node1:~# ceph -s
  cluster:
    id:     6ba7d13c-642b-11ee-b8b2-c70be95e3c50
    health: HEALTH_WARN
            OSD count 0 < osd_pool_default_size 3
 
  services:
    mon: 3 daemons, quorum node1,node2,node3 (age 28m)
    mgr: node1.cauksk(active, since 44m), standbys: node2.ecffgz
    osd: 0 osds: 0 up, 0 in
 
  data:
    pools:   0 pools, 0 pgs
    objects: 0 objects, 0 B
    usage:   0 B used, 0 B / 0 B avail
    pgs: 

# Если вы не меняли адресацию в файле kitchen.yml Ceph Dashboard будет доступна с вашего локального хоста.
Ceph Dashboard - https://192.168.56.6:8443/ или https://192.168.56.5:8443/ (в зависимости от того, где работает сервис mgr)
Креды по умолчанию: login - ceph-admin, pass - pa$$w0rd

Из вывода выше мы видим, что кластер развернут и состоит из:

  • трех сервисов мониторов (mon), которые поддерживают кворум между собой;
  • двух сервисов менеджеров, один активен, второй «на подхвате»;
  • ноля сервисов OSD.

Данных в кластере нет, никакие сервисные флаги не установлены. А отсутствие сервисов OSD — причина, по которой кластер находится в состоянии warning.

Добавление OSD

Сервисы Ceph крутятся в контейнерах под управлением systemd. У хранилища есть инструмент ceph orch, с помощью которого можно настраивать практически все сервисы кластера, чем мы и займемся. В принципе, добавление OSD можно автоматизировать в рамках рецептов кукбука, но я намеренно этого не делаю, чтобы мы могли все потрогать и покрутить своими руками.

Кластер состоит из трех нод, у каждой помимо системного есть по два дополнительных диска. Мы можем инициализировать сервисы OSD на всех из них, выбрать некоторые из конкретных узлов или передать спецификацию YAML, указав в ней правило добавления дисков.

Мы используем все свободные диски кластера под сервисы OSD, потому что так быстрее, но в производственной среде стоит подумать, какие из них и по каким правилам будем добавлять в кластер. Так же инструмент ceph orch позволяет разворачивать и другие сервисы Ceph.


    # Вывести все диски кластера
root@node1:~# ceph orch device ls

HOST   PATH      TYPE  DEVICE ID                           SIZE  AVAILABLE  REFRESHED  REJECT REASONS  
node1  /dev/sdb  hdd   VBOX_HARDDISK_VBaa3afe84-dcde44b9  6000M  Yes        18m ago                    
node1  /dev/sdc  hdd   VBOX_HARDDISK_VB6cfb6cfd-cbfff2b2  6000M  Yes        18m ago                    
node2  /dev/sdb  hdd   VBOX_HARDDISK_VB9a0de133-d4c47481  6000M  Yes        2m ago                     
node2  /dev/sdc  hdd   VBOX_HARDDISK_VB17ff3e6d-ff3a778d  6000M  Yes        2m ago                     
node3  /dev/sdb  hdd   VBOX_HARDDISK_VBef988c66-7de380c8  6000M  Yes        24s ago                    
node3  /dev/sdc  hdd   VBOX_HARDDISK_VBb42afeb2-1643e145  6000M  Yes        24s ago                    

# Развернуть сервисы OSD на всех доступных дисках
root@node1:~# ceph orch apply osd --all-available-devices
Scheduled osd.all-available-devices update...

# Посмотреть состояние сервисов osd
root@node1:~# ceph orch ps --daemon_type osd
NAME   HOST   PORTS  STATUS         REFRESHED  AGE  MEM USE  MEM LIM  VERSION  IMAGE ID      CONTAINER ID  
osd.0  node3         running (1m)     1m ago  1m    26.9M    4096M  18.2.2   7b46ae09e5dc  c20a9a449e32  
osd.1  node2         running (1m)     1m ago  1m    35.5M    4096M  18.2.2   7b46ae09e5dc  d6a3d414084b  
osd.2  node1         running (1m)     1m ago  1m    23.8M    4096M  18.2.2   7b46ae09e5dc  baae22c434b9  
osd.3  node3         running (1m)     1m ago  1m    28.5M    4096M  18.2.2   7b46ae09e5dc  5cb04e5d04b4  
osd.4  node2         running (1m)     1m ago  1m    27.6M    4096M  18.2.2   7b46ae09e5dc  c2ad3d47caf5  
osd.5  node1         running (1m)     1m ago  1m    24.8M    4096M  18.2.2   7b46ae09e5dc  0c1ae30543fc

Создание и настройка пула хранения

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

Начнем с настройки политик. С их помощью мы можем, например, настроить распределение пулов на разных типах носителей, тем самым определить их производительность. В нашем кластере отсутствуют устройства SSD, поэтому переопределим класс некоторых дисков. Данная операция может потребоваться и на боевом кластере, если ваши SSD прячутся за HBA-контроллером и определяются ОС как HDD.


    root@node1:~# ceph osd crush rm-device-class osd.2 osd.1 osd.0
done removing class of osd(s): 0,1,2
root@node1:~# ceph osd crush set-device-class ssd osd.2 osd.1 osd.0
set osd(s) 0,1,2 to class 'ssd'
root@node1:~# ceph osd df tree
ID  CLASS  WEIGHT   REWEIGHT  SIZE     RAW USE  DATA     OMAP  META     AVAIL    %USE  VAR   PGS  STATUS  TYPE NAME     
-1         0.03415         -   35 GiB  266 MiB  3.8 MiB   0 B  262 MiB   35 GiB  0.74  1.00    -          root default  
-7         0.01138         -   12 GiB   89 MiB  1.3 MiB   0 B   88 MiB   12 GiB  0.74  1.00    -              host node1
 5    hdd  0.00569   1.00000  5.9 GiB   62 MiB  948 KiB   0 B   61 MiB  5.8 GiB  1.04  1.40    1      up          osd.5 
 2    ssd  0.00569   1.00000  5.9 GiB   26 MiB  368 KiB   0 B   26 MiB  5.8 GiB  0.44  0.60    0      up          osd.2 
-3         0.01138         -   12 GiB   89 MiB  1.3 MiB   0 B   88 MiB   12 GiB  0.74  1.00    -              host node2
 4    hdd  0.00569   1.00000  5.9 GiB   62 MiB  948 KiB   0 B   61 MiB  5.8 GiB  1.04  1.40    1      up          osd.4 
 1    ssd  0.00569   1.00000  5.9 GiB   26 MiB  356 KiB   0 B   26 MiB  5.8 GiB  0.44  0.60    0      up          osd.1 
-5         0.01138         -   12 GiB   89 MiB  1.3 MiB   0 B   88 MiB   12 GiB  0.74  1.00    -              host node3
 3    hdd  0.00569   1.00000  5.9 GiB   62 MiB  936 KiB   0 B   61 MiB  5.8 GiB  1.04  1.40    1      up          osd.3 
 0    ssd  0.00569   1.00000  5.9 GiB   26 MiB  356 KiB   0 B   26 MiB  5.8 GiB  0.44  0.60    0      up          osd.0 
                       TOTAL   35 GiB  266 MiB  3.8 MiB   0 B  262 MiB   35 GiB  0.74                                   
MIN/MAX VAR: 0.60/1.40  STDDEV: 0.30

В листинге выше видно, что OSD. [0-2] находятся на разных узлах в дереве с корнем default. Кстати, с помощью политик можно создавать несколько корней и за счет этого хранить данные в одном кластере, но на разных хостах, стойках или дата-центрах. Ниже создадим пул данных и применим к нему политику размещения «только на SSD», а далее укажем, что данный пул будем использовать под RBD-образы.

Создаем политику для реплицированных пулов с именем replicated_ssd. Данные будут иметь домен отказа host, а размещаться — на SSD.


    root@node1:~# ceph osd crush rule create-replicated replicated_ssd default host ssd

Посмотреть настройки политик можно этой командой:


    root@node1:~# ceph osd crush rule dump

Создаем реплицированный пул nomad, «нарезанный» на 32 кусочка (PG, или placement group).


    root@node1:~# ceph osd pool create nomad 32 32 replicated
pool 'nomad' created

Назначаем пулу crush правило SIC. Эту настройку необходимо выполнить до того, как залили пул клиентскими данными, иначе подобные действия приведут к их перемещению внутри кластера, что снизит производительность для клиентов.


    root@node1:~# ceph osd pool set nomad crush_rule replicated_ssd
set pool 2 crush_rule to replicated_ssd

Указываем, что данный пул будет использоваться под блочные устройства (RBD):


    root@node1:~# ceph osd pool application enable nomad rbd
enabled application 'rbd' on pool 'nomad'

Смотрим на дерево кластера. Видно, что OSD.[0-2] содержат по 32 PG:


    root@node1:~# ceph osd df tree
ID  CLASS  WEIGHT   REWEIGHT  SIZE     RAW USE  DATA      OMAP  META     AVAIL    %USE  VAR   PGS  STATUS  TYPE NAME     
-1         0.03415         -   35 GiB  267 MiB   4.3 MiB   0 B  262 MiB   35 GiB  0.74  1.00    -          root default  
-7         0.01138         -   12 GiB   89 MiB   1.4 MiB   0 B   88 MiB   12 GiB  0.74  1.00    -              host node1
 5    hdd  0.00569   1.00000  5.9 GiB   62 MiB  1020 KiB   0 B   61 MiB  5.8 GiB  1.04  1.40    1      up          osd.5 
 2    ssd  0.00569   1.00000  5.9 GiB   27 MiB   440 KiB   0 B   26 MiB  5.8 GiB  0.44  0.60   32      up          osd.2 
-3         0.01138         -   12 GiB   89 MiB   1.4 MiB   0 B   88 MiB   12 GiB  0.74  1.00    -              host node2
 4    hdd  0.00569   1.00000  5.9 GiB   62 MiB  1020 KiB   0 B   61 MiB  5.8 GiB  1.04  1.40    1      up          osd.4 
 1    ssd  0.00569   1.00000  5.9 GiB   27 MiB   440 KiB   0 B   26 MiB  5.8 GiB  0.44  0.60   32      up          osd.1 
-5         0.01138         -   12 GiB   89 MiB   1.4 MiB   0 B   88 MiB   12 GiB  0.74  1.00    -              host node3
 3    hdd  0.00569   1.00000  5.9 GiB   62 MiB  1020 KiB   0 B   61 MiB  5.8 GiB  1.04  1.40    1      up          osd.3 
 0    ssd  0.00569   1.00000  5.9 GiB   27 MiB   440 KiB   0 B   26 MiB  5.8 GiB  0.44  0.60   32      up          osd.0 
                       TOTAL   35 GiB  267 MiB   4.3 MiB   0 B  262 MiB   35 GiB  0.74                                   
MIN/MAX VAR: 0.60/1.40  STDDEV: 0.30

Детально посмотрим на настройку пулов и проверим, что все в порядке. Запись replicated size 3 — настройка по умолчанию, которая указывает, что все данные будут храниться в кластере в трех экземплярах. Ниже я ее называю «размер пула». Также обратите внимание, что у каждого пула есть свой id.


    root@node1:~# ceph osd pool ls detail
pool 1 '.mgr' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 1 pgp_num 1 autoscale_mode on last_change 21 flags hashpspool stripe_width 0 pg_num_max 32 pg_num_min 1 application mgr read_balance_score 6.00
pool 2 'nomad' replicated size 3 min_size 2 crush_rule 1 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode on last_change 43 flags hashpspool stripe_width 0 application rbd read_balance_score 1.22

Команда выводит служебную информацию о PG: где находятся primary- и secondary-данные, в каком состоянии PG, когда выполнялась проверка целостности. PG начинается с id пула, частью которого она является:


    root@node1:~# ceph pg ls
PG    OBJECTS  DEGRADED  MISPLACED  UNFOUND  BYTES   OMAP_BYTES*  OMAP_KEYS*  LOG  LOG_DUPS  STATE         SINCE  VERSION  REPORTED  UP         ACTING     SCRUB_STAMP                      DEEP_SCRUB_STAMP                 LAST_SCRUB_DURATION  SCRUB_SCHEDULING                                          
1.0         2         0          0        0  590368            0           0  413         0  active+clean     9h   27'413   43:1099  [3,5,4]p3  [3,5,4]p3  2024-04-04T23:01:31.874678+0000  2024-04-04T23:01:31.874678+0000                    0  periodic scrub scheduled @ 2024-04-05T23:57:41.643668+0000
...
...
2.1e        0         0          0        0       0            0           0    0         0  active+clean    18m      0'0     43:21  [1,2,0]p1  [1,2,0]p1  2024-04-05T17:34:39.443193+0000  2024-04-05T17:34:39.443193+0000                    0  periodic scrub scheduled @ 2024-04-07T05:09:41.113721+0000
2.1f        0         0          0        0       0            0           0    0         0  active+clean    18m      0'0     43:22  [2,0,1]p2  [2,0,1]p2  2024-04-05T17:34:39.443193+0000  2024-04-05T17:34:39.443193+0000                    0  periodic scrub scheduled @ 2024-04-06T18:34:58.287296+0000

Еще раз посмотрим на состояние кластера и проверим, что все в порядке:


    root@node1:~# ceph -s
  cluster:
    id:     6ba7d13c-642b-11ee-b8b2-c70be95e3c50
    health: HEALTH_OK
 
  services:
    mon: 3 daemons, quorum node1,node2,node3 (age 19h)
    mgr: node1.cauksk(active, since 20h), standbys: node2.ecffgz
    osd: 6 osds: 6 up (since 9h), 6 in (since 19h)
 
  data:
    pools:   2 pools, 33 pgs
    objects: 2 objects, 577 KiB
    usage:   267 MiB used, 35 GiB / 35 GiB avail
    pgs:     33 active+clean


Настройка авторизации клиента кластера

Авторизация в Ceph подробно описана в документации. Отмечу, что какой бы тип сервиса или клиента ни использовался, Ceph хранит в себе данные о них в виде объектов RADOS. У каждого из них есть определенный ряд возможностей (caps), а также определен уровень доступа к объектам и пулам хранения. Утилиты Ceph ищут файл с ключом авторизации по пути /etc/ceph/ceph.client.{name}.keyring.

Подготовим пользователя для клиента Nomad CSI:


     создаем клиента nomad с правами, определенными преднастроенным профилем rbd, с полным доступом к пулу nomad.
root@node1:~# ceph auth get-or-create client.nomad mon 'profile rbd' osd 'profile rbd pool=nomad' mgr 'profile rbd pool=nomad'
[client.nomad]
	key = AQA4PxBmD0uiARAAP5M3DrAyNNlr7CjjX6PnNw==

# вывести информацию о настроеных разрешениях клиента можно командой:
root@node1:~# ceph auth get client.nomad
[client.nomad]
	key = AQA4PxBmD0uiARAAP5M3DrAyNNlr7CjjX6PnNw==
	caps mgr = "profile rbd pool=nomad"
	caps mon = "profile rbd"
	caps osd = "profile rbd pool=nomad"

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

Если вам необходимо зашифровать данные, сделать это следует до их отправки в кластер.

Разворачиваем Nomad

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


    # кластер состоит из трех узлов.
root@node1:~# ceph orch host ls
HOST   ADDR          LABELS  STATUS  
node1  192.168.56.5  _admin          
node2  192.168.56.6                  
node3  192.168.56.7                  


# эта команда разместит ключ администратора на узле кластера node2 и предоставит возможности администратора.
root@node1:~# ceph orch host  label add node2 _admin
Added label _admin to host node2
root@node1:~# ceph orch host ls
HOST   ADDR          LABELS  STATUS  
node1  192.168.56.5  _admin          
node2  192.168.56.6  _admin          
node3  192.168.56.7                  
3 hosts in cluster

# С помощью служебных и пользовательских лейблов можно управлять деплоем сервисов Ceph. Следующая команда запретит размещать любые сервисы Ceph на ноде, кроме OSD. Может быть полезно при обслуживании узла.
root@node1:~# ceph orch host label add node3 _no_schedule 
Added label _no_schedule to host node3

root@node1:~# ceph orch ps node3
NAME   HOST   PORTS  STATUS        REFRESHED  AGE  MEM USE  MEM LIM  VERSION  IMAGE ID      CONTAINER ID  
osd.0  node3         running (3d)    40s ago   3d    42.5M    4096M  18.2.2   7b46ae09e5dc  c20a9a449e32  
osd.3  node3         running (3d)    40s ago   3d    31.2M    4096M  18.2.2   7b46ae09e5dc  5cb04e5d04b4  

root@node1:~# ceph orch ps node2
NAME                 HOST   PORTS             STATUS        REFRESHED  AGE  MEM USE  MEM LIM  VERSION  IMAGE ID      CONTAINER ID  
ceph-exporter.node2  node2                    running (4d)    48s ago   4d    7531k        -  18.2.2   7b46ae09e5dc  518802272a35  
crash.node2          node2                    running (4d)    48s ago   4d    2883k        -  18.2.2   7b46ae09e5dc  5e8b2fba0923  
mgr.node2.ecffgz     node2  *:8443,9283,8765  running (4d)    48s ago   4d     128M        -  18.2.2   7b46ae09e5dc  2b8bb882c8b0  
mon.node2            node2                    running (4d)    48s ago   4d    78.2M    2048M  18.2.2   7b46ae09e5dc  a42e6d5b346e  
node-exporter.node2  node2  *:9100            running (4d)    48s ago   4d    13.3M        -  1.5.0    0da6a335fe13  27be86a587c0  
osd.1                node2                    running (3d)    48s ago   3d    39.4M    4096M  18.2.2   7b46ae09e5dc  d6a3d414084b  
osd.4                node2                    running (3d)    48s ago   3d    27.7M    4096M  18.2.2   7b46ae09e5dc  c2ad3d47caf5  

# При этом сам кластер будет себя отлично чувствовать:
root@node1:~# ceph health detail
HEALTH_OK

Подробнее об управлении хостами, как всегда, написано в документации.

Перейдем к настройке Nomad. Для этого с локального хоста выполним вход на четвертый узел стенда. Установим Nomad и Consul, а также настроим их запуск в режиме разработчика как systemd-сервисы. Обратите внимание: мы разрешаем Nomad запускать контейнеры в привилегированном режиме. Это необходимо для работы Ceph-CSI Node. Consul — это инструмент от Hashicorp, который позволяет искать службы servicemesh и хранить данные в виде key/value.


    :~$kitchen login node4

# Установка репозиториев и пакетов Consul/Nomad
root@node4:~# wget -O- https://apt.releases.hashicorp.com/gpg | gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
root@node4:~# echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | tee /etc/apt/sources.list.d/hashicorp.list
root@node4:~# apt-get update && sudo apt-get install nomad consul
root@node4:~# cat <<EOF >>/etc/systemd/system/consul.service 
[Unit]
Description=consul agent
Requires=network-online.target
After=network-online.target

[Service]
User=root
Group=root
Restart=on-failure
ExecStart=/usr/bin/consul agent -dev
ExecReload=/bin/kill -HUP $MAINPID
KillSignal=SIGINT

[Install]
WantedBy=multi-user.target
EOF

root@node4:~# cat <<EOF >>/etc/systemd/system/nomad.service 
[Unit]
Description=nomad agent
Requires=network-online.target
After=network-online.target

[Service]
User=root
Group=root
Restart=on-failure
ExecStart=/usr/bin/nomad agent -dev -config=/etc/nomad.d/nomad.hcl
ExecReload=/bin/kill -HUP $MAINPID
KillSignal=SIGINT

[Install]
WantedBy=multi-user.target
EOF

# скачиваем набор драйверов CNI
root@node4:~# wget https://github.com/containernetworking/plugins/releases/download/v1.4.1/cni-plugins-linux-amd64-v1.4.1.tgz
root@node4:~# mkdir -p /opt/cni/bin && tar -C /opt/cni/bin -xvf ./cni-plugins-linux-amd64-v1.4.1.tgz
# Разрешаем запуск привилегированных контейнеров
root@node4:~# cat >>/etc/nomad.d/nomad.hcl<<EOF
plugin "docker" {
  config {
    allow_privileged = true
  }
}
EOF

# Включаем модуль ядра rbd
root@node4:~# modprobe rbd

root@node4:~# systemctl daemon-reload
root@noed4:~# systemctl start nomad consul

#Проверяем, что все работает.
root@node4:~# consul members
Node   Address         Status  Type    Build   Protocol  DC   Partition  Segment
node4  127.0.0.1:8301  alive   server  1.18.1  2         dc1  default    <all>
root@node4:~# nomad node status
ID        Node Pool  DC   Name   Class   Drain  Eligibility  Status
69e42712  default    dc1  node4  <none>  false  eligible     ready

# Если вы не меняли адресацию в файле kitchen.yml, веб-панель Nomad будет доступна с вашего локального хоста.
Nomad - http://192.168.56.8:4646

Теперь перейдем к настройке коннектора к Ceph. Создадим файлы плагинов Ceph-CSI и запустим их. Нам понадобится информация об адресах сервисов MON и UUID-кластера (поля clusterID, monitors). По сути, мы описываем в этих файлах, из каких контейнеров собрать задания плагинов, какие порты открыть, как подключиться к Ceph, какие драйверы использовать.

Итак, сперва создаем файл ceph-csi-plugin-controller.nomad с таким содержимым:


    job "ceph-csi-plugin-controller" {
  datacenters = ["dc1"]
  group "controller" {
    network {
      port "metrics" {}
    }
    task "ceph-controller" {
      template {
        data        = <<EOF
[{
    "clusterID": "6ba7d13c-642b-11ee-b8b2-c70be95e3c50",
    "monitors": [
        "192.168.56.5",
        "192.168.56.6",
        "192.168.56.7"
    ]
}]
EOF
        destination = "local/config.json"
        change_mode = "restart"
      }
      driver = "docker"
      config {
        image = "quay.io/cephcsi/cephcsi:v3.3.1"
        volumes = [
          "./local/config.json:/etc/ceph-csi-config/config.json"
        ]
        mounts = [
          {
            type     = "tmpfs"
            target   = "/tmp/csi/keys"
            readonly = false
            tmpfs_options = {
              size = 1000000 # size in bytes
            }
          }
        ]
        args = [
          "--type=rbd",
          "--controllerserver=true",
          "--drivername=rbd.csi.ceph.com",
          "--endpoint=unix://csi/csi.sock",
          "--nodeid=${node.unique.name}",
          "--instanceid=${node.unique.name}-controller",
          "--pidlimit=-1",
          "--logtostderr=true",
          "--v=5",
          "--metricsport=$${NOMAD_PORT_metrics}"
        ]
      }
      resources {
        cpu    = 500
        memory = 256
      }
      service {
        name = "ceph-csi-controller"
        port = "metrics"
        tags = [ "prometheus" ]
      }
      csi_plugin {
        id        = "ceph-csi"
        type      = "controller"
        mount_dir = "/csi"
      }
    }
  }
}

Затем — файл ceph-csi-plugin-nodes.nomad:


    job "ceph-csi-plugin-nodes" {
  datacenters = ["dc1"]
  type        = "system"
  group "nodes" {
    network {
      port "metrics" {}
    }
    task "ceph-node" {
      driver = "docker"
      template {
        data        = <<EOF
[{
    "clusterID": "6ba7d13c-642b-11ee-b8b2-c70be95e3c50",
    "monitors": [
        "192.168.56.5",
        "192.168.56.6",
        "192.168.56.7"
    ]
}]
EOF
        destination = "local/config.json"
        change_mode = "restart"
      }
      config {
        image = "quay.io/cephcsi/cephcsi:v3.3.1"
        volumes = [
          "./local/config.json:/etc/ceph-csi-config/config.json"
        ]
        mounts = [
          {
            type     = "tmpfs"
            target   = "/tmp/csi/keys"
            readonly = false
            tmpfs_options = {
              size = 1000000 # size in bytes
            }
          }
        ]
        args = [
          "--type=rbd",
          "--drivername=rbd.csi.ceph.com",
          "--nodeserver=true",
          "--endpoint=unix://csi/csi.sock",
          "--nodeid=${node.unique.name}",
          "--instanceid=${node.unique.name}-nodes",
          "--pidlimit=-1",
          "--logtostderr=true",
          "--v=5",
          "--metricsport=$${NOMAD_PORT_metrics}"
        ]
        privileged = true
      }
      resources {
        cpu    = 500
        memory = 256
      }
      service {
        name = "ceph-csi-nodes"
        port = "metrics"
        tags = [ "prometheus" ]
      }
      csi_plugin {
        id        = "ceph-csi"
        type      = "node"
        mount_dir = "/csi"
      }
    }
  }
}

Запускаем плагины ceph-csi и проверяем, что все работает:


    root@node4:~# nomad job run ceph-csi-plugin-controller.nomad
root@node4:~# nomad job run ceph-csi-plugin-nodes.nomad

root@node4:~# nomad plugin status ceph-csi
ID                   = ceph-csi
Provider             = rbd.csi.ceph.com
Version              = v3.3.1
Controllers Healthy  = 1
Controllers Expected = 1
Nodes Healthy        = 1
Nodes Expected       = 1

Allocations
ID        Node ID   Task Group  Version  Desired  Status   Created    Modified
e191676d  e895f83f  nodes       0        run      running  3m8s ago   2m57s ago
b1224cdf  e895f83f  controller  0        run      running  3m25s ago  3m14s ago

# в веб интерфейсе также появится информация об этих заданиях.
http://192.168.56.8:4646/ui/jobs

Теперь перейдем к volume.hcl. Данный конфигурационный файл описывает размер диска, параметры монтирования, а также где и под какой учетной записью создать сам диск.


    root@node4:~# cat ./prom-volume.hcl
id = "ceph-prometheus-volume"
name = "ceph-prometheus-volume"
type = "csi"
plugin_id = "ceph-csi"
capacity_max = "2G"
capacity_min = "1G"

capability {
  access_mode     = "single-node-writer"
  attachment_mode = "file-system"
}

secrets {
  userID  = "nomad"
  userKey = "AQA4PxBmD0uiARAAP5M3DrAyNNlr7CjjX6PnNw=="
}

parameters {
  clusterID = "6ba7d13c-642b-11ee-b8b2-c70be95e3c50"
  pool = "nomad"
  imageFeatures = "layering"
  mkfsOptions = "-t ext4"
}

# Создаем диск.
root@node4:~# nomad volume create ./prom-volume.hcl

Опишем файл задания. Выше мы использовали копипасту из документации Ceph, поэтому запускать будем Prometheus, а ходить за метриками в наш же кластер Ceph. Просто чтобы было не скучно.

Cephadm самостоятельно поднимает сервисы мониторинга и Prometheus. То есть значительную часть работы можно автоматизировать, но мы в этой статье проделаем все вручную, чтобы получше изучить функционал Ceph.


    # Собственно, сам файл задания. Подробно все описано в документации Nomad.
root@node4:~# cat ./prometheus.nomad 
job "prometheus-server" {
  datacenters = ["dc1"]
  type        = "service"
  group "prometheus-server" {
    count = 1
    //Наш volume, который описывали выше//
    volume "ceph-prometheus-volume" {
      type      = "csi"
      attachment_mode = "file-system"
      access_mode     = "single-node-writer"
      read_only = false
      source    = "ceph-prometheus-volume"
    }
    //Используем CNI драйвер и мапим порты//
    network {
      mode = "bridge"
      port "prometheus" {
        static = 9090
        to     = 9090
      }
    }
    //Параметры рестарта задания, если что-то идет не так//
    restart {
      attempts = 10
      interval = "5m"
      delay    = "25s"
      mode     = "delay"
    }
    //Настройки самой таски. Имя, драйвер, куда монтировать сетевой диск, из какого образа собрать, какие конфиги прокинуть внутрь, сколько ресурсов выделить//
    task "prometheus-server" {
      driver = "docker"
      volume_mount {
        volume      = "ceph-prometheus-volume"
        destination = "/prometheus"
        read_only   = false
      }

      env {
        MY_ENV_VARS = "HelloWorld"
      }
      config {
        image = "prom/prometheus:latest"
        args  = []
        ports = ["prometheus"]
        volumes = [ "local/prometheus.yml:/etc/prometheus/prometheus.yml" ]
      }
      template {
        data = file("/root/prometheus.yml")
        destination = "local/prometheus.yml"
      }
      resources {
        cpu    = 500
        memory = 256
      }
      service {
        name = "prometheus-server"
        port = "prometheus"
        check {
          path     = "/-/helthy"
          type     = "tcp"
          interval = "10s"
          timeout  = "2s"
        }
      }
    }
  }
}

# Файл конфига Prometheus. Указываем на наш кластер и экспортеры.
root@node4:~# cat prometheus.yml 
global:
  scrape_interval: 10s
  scrape_timeout: 10s
  evaluation_interval: 10s
scrape_configs:
- job_name: node
  honor_timestamps: true
  scrape_interval: 5s
  scrape_timeout: 5s
  metrics_path: /metrics
  scheme: http
  follow_redirects: true
  enable_http2: true
  http_sd_configs:
  - follow_redirects: true
    enable_http2: true
    refresh_interval: 1m
    url: http://192.168.56.6:8765/sd/prometheus/sd-config?service=node-exporter
- job_name: ceph
  scrape_interval: 5s
  scrape_timeout: 5s
  metrics_path: /metrics
  scheme: http
  follow_redirects: true
  enable_http2: true
  http_sd_configs:
  - follow_redirects: true
    enable_http2: true
    refresh_interval: 1m
    url: http://192.168.56.6:8765/sd/prometheus/sd-config?service=mgr-prometheus
- job_name: ceph-exporter
  scrape_interval: 5s
  scrape_timeout: 5s
  metrics_path: /metrics
  scheme: http
  follow_redirects: true
  enable_http2: true
  http_sd_configs:
  - follow_redirects: true
    enable_http2: true
    refresh_interval: 1m
    url: http://192.168.56.6:8765/sd/prometheus/sd-config?service=ceph-exporter

# Ну и, наконец, запускаем задание.
root@node4:~# nomad job run prometheus.nomad 
==> 2024-04-11T22:33:00Z: Monitoring evaluation "16580069"
    2024-04-11T22:33:00Z: Evaluation triggered by job "prometheus-server"
    2024-04-11T22:33:00Z: Evaluation within deployment: "fa62c7ea"
    2024-04-11T22:33:00Z: Allocation "0d02495c" created: node "e895f83f", group "prometheus-server"
    2024-04-11T22:33:00Z: Evaluation status changed: "pending" -> "complete"
==> 2024-04-11T22:33:00Z: Evaluation "16580069" finished with status "complete"
==> 2024-04-11T22:33:00Z: Monitoring deployment "fa62c7ea"
  ✓ Deployment "fa62c7ea" successful
    
    2024-04-11T22:33:18Z
    ID          = fa62c7ea
    Job ID      = prometheus-server
    Job Version = 0
    Status      = successful
    Description = Deployment completed successfully
    
    Deployed
    Task Group         Desired  Placed  Healthy  Unhealthy  Progress Deadline
    prometheus-server  1        1       1        0          2024-04-11T22:43:16Z


Нагляднее всего будет перейти в веб-интерфейс Nomad и посмотреть, как это все работает. Можете удалить это задание, а затем запустить его еще раз. Тем не менее, сам Prometheus будет писать данные в сетевое хранилище, что можно увидеть по росту количества объектов в кластере и числу метрик TSDB.


    http://192.168.56.8:4646/ui/jobs
http://192.168.56.8:9090/tsdb-status

root@node1:~# ceph -s
...
  data:
    pools:   2 pools, 33 pgs
    objects: 28 objects, 46 MiB
    usage:   499 MiB used, 35 GiB / 35 GiB avail
    pgs:     33 active+clean
 
  io:
    client:   27 KiB/s wr, 0 op/s rd, 4 op/s wr

Где хранятся настройки Ceph

Раньше все параметры и значения объявлялись в /etc/ceph/ceph.conf. Сейчас от этого подхода отказались, так как файл становится нечитаемым из-за большого количества этих параметров у каждого из сервиса Ceph.

Сейчас настройки принято хранить внутри базы сервисов монитора:


    # Команда вернет переопределенные параметры сервисов.
root@node1:~# ceph config dump
WHO     MASK  LEVEL     OPTION                                 VALUE                                                                                      RO
global        advanced  cluster_network                        192.168.56.0/24                                                                            * 
global        basic     container_image                        quay.io/ceph/ceph@sha256:06ddc3ef5b66f2dcc6d16e41842d33a3d7f497849981b0842672ef9014a96726  * 
mon           advanced  auth_allow_insecure_global_id_reclaim  false                                                                                        
mon           advanced  public_network                         192.168.56.0/24                                                                            * 
mgr           advanced  mgr/cephadm/container_init             True                                                                                       * 
mgr           advanced  mgr/cephadm/migration_current          6                                                                                          * 
mgr           advanced  mgr/dashboard/ALERTMANAGER_API_HOST    http://node1:9093                                                                          * 
mgr           advanced  mgr/dashboard/GRAFANA_API_SSL_VERIFY   false                                                                                      * 
mgr           advanced  mgr/dashboard/GRAFANA_API_URL          https://192.168.56.5:3000                                                                  * 
mgr           advanced  mgr/dashboard/PROMETHEUS_API_HOST      http://node1:9095                                                                          * 
mgr           advanced  mgr/dashboard/ssl_server_port          8443                                                                                       * 
mgr           advanced  mgr/orchestrator/orchestrator          cephadm                                                                                      
osd           advanced  osd_memory_target_autotune             true

Для каждой опции есть описание, а также указано, может ли она быть применена «на лету». Если это невозможно, MON самостоятельно уведомит сервис о необходимости перезапуска.


    root@node1:~# ceph config help osd_memory_target
osd_memory_target - When tcmalloc and cache autotuning is enabled, try to keep this many bytes mapped in memory.
  (size, basic)
  Default: 4294967296
  Minimum: 939524096
  Maximum:
  Can update at runtime: true
  See also: [bluestore_cache_autotune,osd_memory_cache_min,osd_memory_base,osd_memory_target_autotune]
 
The minimum value must be at least equal to osd_memory_base + osd_memory_cache_min.

Также можно управлять конфигурацией через сокет и утилитой ceph tell. Но есть ограничения: в первом случае управление возможно только с ноды, на которой развернут сервис. А изменения, внесенные обоими путями, не будут отражены в базе монитора. Это может привести к печальным результатам, если вы не единственный администратор кластера.


    # Пример использования административного сокета.
root@node1:~# ceph daemon /var/run/ceph/6ba7d13c-642b-11ee-b8b2-c70be95e3c50/ceph-osd.2.asok config show | grep debug_osd
    "debug_osd": "1/5",

root@node1:~# ceph daemon /var/run/ceph/6ba7d13c-642b-11ee-b8b2-c70be95e3c50/ceph-osd.7.asok config set debug_osd 10
{
    "success": ""
}

# Пример использования ceph tell. Применим debug_osd=10 ко всем сервисам.
root@node1:~# ceph tell osd.* injectargs "--debug_osd 10"

Если вы задали какие-то настройки в /etc/ceph/ceph.conf, Ceph не позволит их поменять через базу монитора, так как файл конфигурации имеет больший приоритет.

Обслуживание кластера

Режим обслуживания

С помощью оркестратора мы можем переместить хост в режим обслуживания. В результате все сервисы будут корректно остановлены, а мы сможем выключить узел и провести необходимые работы. Достаточно ввести команду:


    # Переводим кластер в режим обслуживания.
root@node1:~# ceph orch host maintenance enter node3
Daemons for Ceph cluster 6ba7d13c-642b-11ee-b8b2-c70be95e3c50 stopped on host node3. Host node3 moved to maintenance mode


root@node1:~# ceph orch host ls
HOST   ADDR          LABELS  STATUS       
node1  192.168.56.5  _admin               
node2  192.168.56.6  _admin               
node3  192.168.56.7  _admin  Maintenance  
3 hosts in cluster

root@node1:~# ceph -s
  cluster:
    id:     6ba7d13c-642b-11ee-b8b2-c70be95e3c50
    health: HEALTH_WARN
            1 host is in maintenance mode
            1/3 mons down, quorum node1,node2
            2 osds down
            1 OSDs or CRUSH {nodes, device-classes} have {NOUP,NODOWN,NOIN,NOOUT} flags set
            1 host (2 osds) down
            Degraded data redundancy: 124/372 objects degraded (33.333%), 32 pgs degraded
 
  services:
    mon: 3 daemons, quorum node1,node2 (age 17s), out of quorum: node3
    mgr: node2.ecffgz(active, since 7h), standbys: node1.cauksk
    osd: 6 osds: 4 up (since 16s), 6 in (since 5h)
 
  data:
    pools:   2 pools, 33 pgs
    objects: 124 objects, 397 MiB
    usage:   2.2 GiB used, 33 GiB / 35 GiB avail
    pgs:     124/372 objects degraded (33.333%)
             32 active+undersized+degraded
             1  active+undersized
 
  io:
    client:   4.0 KiB/s wr, 0 op/s rd, 0 op/s wr

В выводе команды видим, что кластер в статусе WARN, а чуть ниже причины.

  • Недоступен один сервис монитора MON и нарушен кворум (в идеале сервисов MON должно быть пять, но мало кто делает больше трех. Кстати, их все-таки лучше держать на отдельных узлах, если у вас большая инсталляция).
  • Два сервиса OSD находятся в состоянии down.
  • Один узел в состоянии down.
  • 33% данных в деградированном состоянии (на данный момент в кластере отсутствует часть данных).

Обратите внимание, что клиентский ввод/вывод не остановился. Заглянув в веб-панель Nomad и Prometheus, вы в этом легко убедитесь.

Вернем как было и посмотрим, что произойдет:


    # Выводим узел из режима обслуживания.
root@node1:~# ceph orch host maintenance exit node3
Ceph cluster 6ba7d13c-642b-11ee-b8b2-c70be95e3c50 on node3 has exited maintenance mode

# После запуска всех сервисов на узле в кластере запускается процесс восстановления данных
root@node1:~# ceph -s
  cluster:
    id:     6ba7d13c-642b-11ee-b8b2-c70be95e3c50
    health: HEALTH_WARN
            Reduced data availability: 10 pgs peering
 
  services:
    mon: 3 daemons, quorum node1,node2,node3 (age 8s)
    mgr: node2.ecffgz(active, since 7h), standbys: node1.cauksk
    osd: 6 osds: 6 up (since 4s), 6 in (since 6h)
 
  data:
    pools:   2 pools, 33 pgs
    objects: 124 objects, 397 MiB
    usage:   2.5 GiB used, 33 GiB / 35 GiB avail
    pgs:     69.697% pgs not active
             23 peering
             10 active+clean
 
  io:
    client:   1.7 MiB/s rd, 22 op/s rd, 0 op/s wr
    recovery: 685 KiB/s, 0 objects/s

# Через какое-то время node3 догоняет изменения, если они были, и кластер вновь работает.
root@node1:~# ceph -s
  cluster:
    id:     6ba7d13c-642b-11ee-b8b2-c70be95e3c50
    health: HEALTH_OK
 
  services:
    mon: 3 daemons, quorum node1,node2,node3 (age 20s)
    mgr: node2.ecffgz(active, since 7h), standbys: node1.cauksk
    osd: 6 osds: 6 up (since 16s), 6 in (since 6h)
 
  data:
    pools:   2 pools, 33 pgs
    objects: 124 objects, 397 MiB
    usage:   2.2 GiB used, 33 GiB / 35 GiB avail
    pgs:     33 active+clean
 
  io:
    client:   24 KiB/s wr, 0 op/s rd, 3 op/s wr
    recovery: 196 KiB/s, 0 objects/s

Замена диска

А что, если нам надо заменить диск? В первую очередь, отмотаем немного назад и вспомним, каким образом мы развернули сервисы OSD. Мы указали, что используем все незанятые диски кластера. Для того, чтобы новые диски не добавлялись в кластер автоматически, необходимо повесить флаг —unmanaged.


    ceph orch apply osd --all-available-devices --unmanaged=true

Теперь удаляем OSD с пометкой, что будет проведена замена, и смотрим статус:


    root@node1:~# ceph orch osd rm 0 --replace
Scheduled OSD(s) for removal.
VG/LV for the OSDs won't be zapped (--zap wasn't passed).
Run the `ceph-volume lvm zap` command with `--destroy` against the VG/LV if you want them to be destroyed.

root@node1:~# ceph orch osd rm status
OSD  HOST   STATE     PGS  REPLACE  FORCE  ZAP    DRAIN STARTED AT            
0    node3  draining   32  True     False  False  2024-04-12 15:02:05.987153

Мы ожидали, что все PG на удаляемом OSD будут эвакуированы и диск будет удален, но этого не произошло, так как путей для эвакуации нет. В настройках пула (по умолчанию) Nomad указано, что его размер равен трем. Когда все в порядке, в кластере должно быть минимум три копии данных, а минимальный размер— две копии.


    root@node1:~# ceph osd pool ls detail
...
pool 2 'nomad' replicated size 3 min_size 2 crush_rule 1 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode on last_change 131 flags hashpspool,selfmanaged_snaps stripe_width 0 application rbd read_balance_score 1.78

Мы можем обойти это двумя путями. Первый — сменить класс устройства osd.3 на SSD, размещенный на той же ноде. Второй — уменьшить размер пула до двух. Попробуем именно этот вариант, но лишь потому, что классы менять мы уже научились (хотя в проде так, конечно, лучше не делать).


    root@node1:~# ceph osd pool set nomad size 2
set pool 2 size to 2

Все PG были удалены. В кластере прошел процесс remap, то есть перераспределение PG:


    root@node1:/home/vagrant# ceph -s
  cluster:
    id:     6ba7d13c-642b-11ee-b8b2-c70be95e3c50
    health: HEALTH_OK
...
    pgs:     122/372 objects misplaced (32.796%)
             32 active+clean+remapped
             1  active+clean

Удалим разметку, чтобы эмулировать замену диска, на котором был размещен osd.0. Кстати, а какой это диск? Сейчас выясним. Это легко делать с помощью утилиты ceph-volume. Зайдем на node3 и удалим разметку:


    root@node3:~# apt install ceph-volume -y
root@node3:~# ceph-volume lvm list
====== osd.0 =======
  [block]       /dev/ceph-28366058-ad51-452c-af65-3a0114b4a2f0/osd-block-d6b1004d-bdfe-4d01-b010-31940432d912
      block device              /dev/ceph-28366058-ad51-452c-af65-3a0114b4a2f0/osd-block-d6b1004d-bdfe-4d01-b010-31940432d912
      block uuid                mkuCJu-wyBv-YiFn-hTlp-tzy5-p503-73Y328
      cephx lockbox secret      
      cluster fsid              6ba7d13c-642b-11ee-b8b2-c70be95e3c50
      cluster name              ceph
      crush device class        
      encrypted                 0
      osd fsid                  d6b1004d-bdfe-4d01-b010-31940432d912
      osd id                    0
      osdspec affinity          all-available-devices
      type                      block
      vdo                       0
      devices                   /dev/sdb

root@node3:~# ceph-volume lvm zap /dev/sdb
--> Zapping: /dev/sdb
--> Zapping lvm member /dev/sdb.

Затем — обновим список доступных устройств:


    root@node1:~# ceph orch device ls node3 --refresh
HOST   PATH      TYPE  DEVICE ID                           SIZE  AVAILABLE  REFRESHED  REJECT REASONS                                                           
node3  /dev/sdb  hdd   VBOX_HARDDISK_VBef988c66-7de380c8  6000M  Yes        0s ago                                                                              
node3  /dev/sdc  hdd   VBOX_HARDDISK_VBb42afeb2-1643e145  6000M  No         0s ago     Has a FileSystem, Insufficient space (<10 extents) on vgs, LVM detected

Снимем флаг unmaneged и увеличим размер пула до трех. Видно, что PG в кластере снова «поехали»: в этот раз запустился процесс ребалансировки. Кроме того, пул nomad разъехался равномерно по трем дискам.


    root@node1:~# ceph osd df tree class ssd
ID  CLASS  WEIGHT   REWEIGHT  SIZE     RAW USE  DATA     OMAP     META     AVAIL    %USE   VAR   PGS  STATUS  TYPE NAME     
-1         0.03415         -   18 GiB  1.4 GiB  763 MiB    4 KiB  625 MiB   16 GiB   7.71  1.00    -          root default  
-7         0.01138         -  5.9 GiB  379 MiB  259 MiB    4 KiB  120 MiB  5.5 GiB   6.32  0.82    -              host node1
 2    ssd  0.00569   1.00000  5.9 GiB  379 MiB  259 MiB    4 KiB  120 MiB  5.5 GiB   6.32  0.82   19      up          osd.2 
-3         0.01138         -  5.9 GiB  714 MiB  252 MiB      0 B  461 MiB  5.2 GiB  11.90  1.54    -              host node2
 1    ssd  0.00569   1.00000  5.9 GiB  714 MiB  252 MiB      0 B  461 MiB  5.2 GiB  11.90  1.54   24      up          osd.1 
-5         0.01138         -  5.9 GiB  295 MiB  251 MiB      0 B   44 MiB  5.6 GiB   4.92  0.64    -              host node3
 0    ssd  0.00569   1.00000  5.9 GiB  295 MiB  251 MiB      0 B   44 MiB  5.6 GiB   4.92  0.64   21      up          osd.0 
                       TOTAL   18 GiB  1.4 GiB  763 MiB  4.2 KiB  625 MiB   16 GiB   7.71

После восстановления размера пула ожидаем вновь равномерного распределения, по 32 PG на OSD.


    root@node1:~# ceph osd pool set nomad size 3
set pool 2 size to 3

Опять произошел процесс recovery, все PG восстановились в трех экземплярах:


    root@node1:~# ceph osd df tree class ssd
ID  CLASS  WEIGHT   REWEIGHT  SIZE     RAW USE  DATA     OMAP     META     AVAIL    %USE   VAR   PGS  STATUS  TYPE NAME     
-1         0.03415         -   18 GiB  1.7 GiB  1.1 GiB    4 KiB  630 MiB   16 GiB   9.85  1.00    -          root default  
-7         0.01138         -  5.9 GiB  484 MiB  380 MiB    4 KiB  104 MiB  5.4 GiB   8.08  0.82    -              host node1
 2    ssd  0.00569   1.00000  5.9 GiB  484 MiB  380 MiB    4 KiB  104 MiB  5.4 GiB   8.08  0.82   32      up          osd.2 
-3         0.01138         -  5.9 GiB  842 MiB  380 MiB      0 B  461 MiB  5.0 GiB  14.04  1.43    -              host node2
 1    ssd  0.00569   1.00000  5.9 GiB  842 MiB  380 MiB      0 B  461 MiB  5.0 GiB  14.04  1.43   32      up          osd.1 
-5         0.01138         -  5.9 GiB  446 MiB  380 MiB      0 B   65 MiB  5.4 GiB   7.43  0.75    -              host node3
 0    ssd  0.00569   1.00000  5.9 GiB  446 MiB  380 MiB      0 B   65 MiB  5.4 GiB   7.43  0.75   32      up          osd.0 
                       TOTAL   18 GiB  1.7 GiB  1.1 GiB  4.2 KiB  630 MiB   16 GiB   9.85                                   
MIN/MAX VAR: 0.75/1.43  STDDEV: 2.97

Кластер перешел в состояние OK, клиентский ввод/вывод не прекращался, задание в NOMAD не падало, хранилище Prometheus не отключалось. Последнее видно на графике метрики и в uptime задания Prometheus:


    root@node4:~# nomad alloc exec -it -task prometheus-server 0d02495c /bin/sh
/prometheus $ uptime
 15:51:33 up 3 days,  4:47,  0 users,  load average: 0.33, 0.41, 0.42

Заключение

Хотя статья получилась объемной, уложить в нее получилось лишь малую часть даже базовых операций в Ceph. Здесь не упомянуты другие типы доступа к данным, специализированные глобальные флаги, квоты, управление процессом восстановления и многое другое. Впрочем, это хранилище довольно легко изучить самостоятельно, поэтому все в ваших руках.