Будет рассмотрена работа с блочными устройствами (RBD) и распредененной файловой системой (CephFS).

Конфиг кластера:

Ноды кластера
2 штуки с CentOS 7
HDD
1 для os + 2 для кластера
Сеть
172.22.12.0/24

Устанавливаем на все ноды кластера ntp и импортируем ssh ключи для беспарольного доступа пользователю root:

[root@ceph1 ~]# ssh-keygen
[root@ceph1 ~]# ssh-copy-id ceph2
Добавляем необходимые репы на ноду с которой будем запускать ceph-deploy:
[root@ceph1 ~]# yum install -y yum-utils && sudo yum-config-manager --add-repo https://dl.fedoraproject.org/pub/epel/7/x86_64/ && sudo yum install --nogpgcheck -y epel-release && sudo rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7 && sudo rm /etc/yum.repos.d/dl.fedoraproject.org*
Создаем репу Ceph релиз jewel для CentOS 7
[root@ceph1 ~]# vim /etc/yum.repos.d/ceph.repo

[ceph-noarch]
name=Ceph noarch packages
baseurl=http://download.ceph.com/rpm-jewel/el7/noarch
enabled=1
gpgcheck=1
type=rpm-md
gpgkey=https://download.ceph.com/keys/release.asc
Устанавливаем ceph-deploy
[root@ceph1 ~]# yum update && sudo yum install ceph-deploy
Создаем директорию для размещегия конфигов кластера при деплое
[root@ceph1 ~]# mkdir mycluster
[root@ceph1 ~]# cd mycluster
Создаем непосредственно кластер ceph
[root@ceph1 mycluster]# ceph-deploy new ceph1
Добавляем в файл ceph.conf в директории mycluster следующие строки:
public network = 172.22.12.0/24
osd pool default size = 2
osd_crush_update_on_start = false<
У вас должно получится что-то вроде этого:
[root@ceph1 mycluster]# cat ceph.conf 
[global]
fsid = 11d81bd3-fd49-4169-b38c-bfaa475ab1b5
mon_initial_members = ceph1
mon_host = 172.22.12.31
auth_cluster_required = cephx
auth_service_required = cephx
auth_client_required = cephx

public network = 172.22.12.0/24
osd pool default size = 2
osd_crush_update_on_start = false
Остановимся на том бепределе, что мы внесли в конфиг. Строка public network = 172.22.12.0/24 указывает кластеру менеджмент сеть. По ней так же будет осуществляться и репликация данных между нодами. В боевых системах стоит разделять эти вещи в разные сети и вешать на разные сетевые интерфейсы. Строка osd pool default size = 2 говорит о том, что мы будем использовать репликацию с коэфициентом 2, по умолчанию ceph использует реплику 3, но так как у нас всего две ноды и реплика будет идти между ними, то выбор очевиден. Последняя запись osd_crush_update_on_start = false запрещает ceph управлять CRUSH картой кластера. Ее мы будем править руками и импортировать в кластер.
Так как я запускаю ceph-deploy с ноды кластера, то нужно закоментить репу ceph, чтобы при установке основных пакетов скрипт правильно отработал. Если вы запускаете деплой со своего ноута или PC, тогда этот шаг можно пропустить.
[root@ceph1 mycluster]# mv /etc/yum.repos.d/ceph.repo /etc/yum.repos.d/ceph.repo.old
Инсталим ceph на ноды ceph1 и ceph2 явно указывая серсию кластера --release jewel
[root@ceph1 mycluster]# ceph-deploy install --release jewel ceph{1,2}
Если все прошло успешно - инсталим монитор mon и создаем ключи для ceph. Монитор в нашем случае один, так как для создания кворума нужно нечетное число мониторов, а нод у нас всего две. Но для тестов пойдет. Главное, когда будете ломать кластер не убивайте ноду с монитором или не останавливайте сервис ceph.mon. Или добавте еще одну ноду без дисков и разместите на ней монитор и на второй ноде с дисками. Итого у вас будет их три, тогда и ломайте.
[root@ceph1 mycluster]# ceph-deploy mon create-initial
Создаем osd, т.е. включаем наши диски, выделенные для данных на нодах в кластер. В моем случае я использую диски vdb и vdc на обеих нодах. Журналы osd у меня будут хранится на тех же дисках, ceph автоматом создаст под них партиции. Можно конечно скормить и директории в системе в роли дисков, но для удобства, я рекомендую под osd отдавать непосредственно сам диск или на крайний случай lvm.
[root@ceph1 mycluster]# ceph-deploy osd create --zap-disk ceph{1,2}:vd{b,c}
Данная команда сотрет все данные с дисков и отформатирует их в xfs.
Копируем конфиг ceph который мы заполняли в самом начале в файлике ceph.conf на все наши ноды кластера командой:
[root@ceph1 mycluster]# ceph-deploy admin ceph{1,2}
Тепрь займемся созданием CRUSH карты. Вытягиваем текущую карту кластера командой:
[root@ceph1 mycluster]# ceph osd getcrushmap -o map.current
Декомпилируем ее в человеческий формат:
[root@ceph1 mycluster]# crushtool -d map.current -o map.decompile
И приводим ее к такому виду:
[root@ceph1 mycluster]# cat map.decompile
# begin crush map
tunable choose_local_tries 0
tunable choose_local_fallback_tries 0
tunable choose_total_tries 50
tunable chooseleaf_descend_once 1
tunable chooseleaf_vary_r 1
tunable straw_calc_version 1

# devices
device 0 osd.0
device 1 osd.1
device 2 osd.2
device 3 osd.3

# types
type 0 osd
type 1 host
type 2 chassis
type 3 rack
type 4 row
type 5 pdu
type 6 pod
type 7 room
type 8 datacenter
type 9 region
type 10 root

# buckets
host ceph1 {
	id -1
	alg straw
	hash 0  # rjenkins1
	item osd.0 weight 0.010
	item osd.1 weight 0.010
}

host ceph2 {
        id -2
        alg straw
        hash 0  # rjenkins1
        item osd.2 weight 0.010
        item osd.3 weight 0.010
}

root default {
	id -3		# do not change unnecessarily
	# weight 0.000
	alg straw
	hash 0	# rjenkins1
	item ceph1 weight 0.020
	item ceph2 weight 0.020
}

# rules
rule replicated_ruleset {
	ruleset 0
	type replicated
	min_size 1
	max_size 10
	step take default
	step chooseleaf firstn 0 type host
	step emit
}

# end crush map
Компилируем ее обратно и скармливаем ceph:
[root@ceph1 mycluster]# crushtool -c map.decompile -o map.new
[root@ceph1 mycluster]# ceph osd setcrushmap -i map.new
Проверяем состояние кластера командой ceph -s. Через какоето время он перестроит pg и вывод будет примерно таким:
[root@ceph1 mycluster]# ceph -s
    cluster 11d81bd3-fd49-4169-b38c-bfaa475ab1b5
     health HEALTH_OK
     monmap e1: 1 mons at {ceph1=172.22.12.31:6789/0}
            election epoch 3, quorum 0 ceph1
     osdmap e11: 4 osds: 4 up, 4 in
            flags sortbitwise
      pgmap v42: 64 pgs, 1 pools, 0 bytes data, 0 objects
            131 MB used, 20304 MB / 20435 MB avail
                  64 active+clean
Чтобы проверить карту osd сделаем так:
[root@ceph1 mycluster]# ceph osd tree
ID WEIGHT  TYPE NAME      UP/DOWN REWEIGHT PRIMARY-AFFINITY 
-3 0.03998 root default                                     
-1 0.01999     host ceph1                                   
 0 0.00999         osd.0       up  1.00000          1.00000 
 1 0.00999         osd.1       up  1.00000          1.00000 
-2 0.01999     host ceph2                                   
 2 0.00999         osd.2       up  1.00000          1.00000 
 3 0.00999         osd.3       up  1.00000          1.00000 
Здесть мы видим что все osd, они же диски имеют статус UP и относятся нужным нодам, согласно нашей crush карте. На этом создание кластера закончено. Далее будем создавать пулы RBD и CephFS.

Созание CephFS

Для функционирование распределенной файловой системы служат сереры mds. на них хранятся метаданные. В нашем случае мы созданим два сервера метаданных на обеих нодах в режиме standby_replay (главный и запасной). В случае отказа основго mds егороль подхватит второй. Важное замечание: в нашей тестовой схеме только один сервер мониторов mon, поэтому важно обеспечить его доступность. В продакшене у вас должно быть три и более монитора. Еще одно замечание: если у вас вдруг будут недоступны сера mds, то файловые операции просто застопорятся. При восстановлении работы сервра метаданных - система продолжит работу.
Создадим сервра MDS на ceph1 и ceph2:

[root@ceph1 mycluster]# ceph-deploy mds create ceph{1,2}
Создадим пулы для данных и метаданных в кластере для нашей файловой системы:
[root@ceph1 mycluster]# ceph osd pool create cephfs_data 64
pool 'cephfs_data' created
[root@ceph1 mycluster]# ceph osd pool create cephfs_metadata 64
pool 'cephfs_metadata' created
Если посмотреть состояние кластера после создание пулов, то будем иметь следующую картину:
[root@ceph1 mycluster]# ceph -s
    cluster 11d81bd3-fd49-4169-b38c-bfaa475ab1b5
     health HEALTH_ERR
            64 pgs are stuck inactive for more than 300 seconds
            17 pgs peering
            64 pgs stuck inactive
     monmap e1: 1 mons at {ceph1=172.22.12.31:6789/0}
            election epoch 3, quorum 0 ceph1
     osdmap e15: 4 osds: 4 up, 4 in
            flags sortbitwise
      pgmap v119: 192 pgs, 3 pools, 0 bytes data, 0 objects
            133 MB used, 20302 MB / 20435 MB avail
                 128 active+clean
                  47 creating+activating
                  17 creating+peering
В данный момент кластер занят ребалансировкой и созданием pg. Через несколько секунд снова проверяем статус и видим что все ок:
[root@ceph1 mycluster]# ceph -s
    cluster 11d81bd3-fd49-4169-b38c-bfaa475ab1b5
     health HEALTH_OK
Установим пулам cephfs_data и cephfs_metadata режим реплики size 2, обеспечим работу кластера в режиме деградации пока доступна хотябы одна копия данных в пуле min_size 1 и укажем правило репликации pg crush_ruleset 0 согласно нашей crush карте, что занчит реплицировать пул между хостами кластера.
[root@ceph1 mycluster]# ceph osd pool set cephfs_data size 2
set pool 1 size to 2
[root@ceph1 mycluster]# ceph osd pool set cephfs_data min_size 1
set pool 1 min_size to 1
[root@ceph1 mycluster]# ceph osd pool set cephfs_data crush_ruleset 0
set pool 1 crush_ruleset to 0
[root@ceph1 mycluster]# ceph osd pool set cephfs_metadata size 2
set pool 2 size to 2
[root@ceph1 mycluster]# ceph osd pool set cephfs_metadata min_size 1
set pool 2 min_size to 1
[root@ceph1 mycluster]# ceph osd pool set cephfs_metadata crush_ruleset 0
set pool 2 crush_ruleset to 0
Создаем нашу фаловую систему:
root@ceph1 mycluster]# ceph fs new cephfs cephfs_metadata cephfs_data
Посмотрим на состояние кластера и увидим, что файловая система создалась
[root@ceph1 mycluster]# ceph -s
    cluster 11d81bd3-fd49-4169-b38c-bfaa475ab1b5
     health HEALTH_OK
     monmap e1: 1 mons at {ceph1=172.22.12.31:6789/0}
            election epoch 3, quorum 0 ceph1
      fsmap e6: 1/1/1 up {0=ceph2=up:active}, 1 up:standby
     osdmap e22: 4 osds: 4 up, 4 in
            flags sortbitwise
      pgmap v179: 192 pgs, 3 pools, 2068 bytes data, 20 objects
            135 MB used, 20300 MB / 20435 MB avail
                 192 active+clean
Проверим статус наших серверов метаданных:
[root@ceph1 mycluster]# ceph mds stat
e6: 1/1/1 up {0=ceph2=up:active}, 1 up:standby
Нам сообщают, что в данный момент активен mds на ноде ceph2 и второй (ceph1) в режиме standby. Если погасить сервис mds на ноде ceph2, то активным станет mds на ceph1.
[root@ceph1 mycluster]# ceph mds stat
e11: 1/1/1 up {0=ceph1=up:active}
Перейдем к созданию пользователя для аунтификации при монтировании файловой системы на клиентах, так как делать это от админа не очень хорошо в целях безопасности. Дадим пользователю cephfs права на чтение из mon и mds и полные права на пулы cephfs_data и cephfs_metadata
[root@ceph1 mycluster]# ceph auth get-or-create client.cephfs mon 'allow r' mds 'allow r' osd 'allow rwx pool=cephfs_metadata,allow rwx pool=cephfs_data' -o /etc/ceph/client.cephfs.keyring
У вас должен был создаться новый пользователь в кластере:
[root@ceph1 mycluster]# ceph auth list

client.cephfs
	key: AQBdX0NXobyACBAArLIkcDRrAHYEDc3izToMnA==
	caps: [mds] allow r
	caps: [mon] allow r
	caps: [osd] allow rwx pool=cephfs_metadata,allow rwx pool=cephfs_data

Монтирование файловой системы на клиенте

Монтировать будем через модуль ядра. Для этого нам нужно установить недостающие пакеты на клиенте:

root@client ~ # yum update&&yum install ceph-fs-common
Создадим файл ключа пользователя cephfs для монтирования FS на клиенте и директорию для монтирования /mnt/cephfs:
root@client ~ # mkdir -p /etc/ceph
root@client ~ # echo "AQBdX0NXobyACBAArLIkcDRrAHYEDc3izToMnA==" > /etc/ceph/cephfskey
root@client ~ # sudo mkdir /mnt/cephfs
В отличии от glusterfs в cephfs можно монтировать сразу директории из корневой fs. В нашем случае у нас их пока нет, поэтому понтируем корень. Команда имеет следующий формат mount -t ceph [mon_ip_or_fqdn]:[mon_port]:/ /mnt/cephfs/ -o name=cephfs,secretfile=[path_secretfile]. Порт монитора можно опустить, так как он стандартный:
mount -t ceph 172.22.12.31:/ /mnt/cephfs/ -o name=cephfs,secretfile=/etc/ceph/cephfskey
Смотрим вывод dh -h и видим, что cephfs примонтирована и ее текущий размер 20GB. Это полезный обьем данных, сырой обьем в кластере 20GB (4 osd по 10GB реплика 2):
Filesystem               Size  Used Avail Use% Mounted on
/dev/mapper/centos-root  6.7G  1.4G  5.4G  21% /
devtmpfs                 235M     0  235M   0% /dev
tmpfs                    245M     0  245M   0% /dev/shm
tmpfs                    245M  4.4M  241M   2% /run
tmpfs                    245M     0  245M   0% /sys/fs/cgroup
/dev/vda1                497M  165M  332M  34% /boot
tmpfs                     49M     0   49M   0% /run/user/0
172.22.12.31:/            20G  132M   20G   1% /mnt/cephfs
Собственно можно пользоваться и проводить тесты.

Работа с блочными устройствами RBD и взаимодействие с libvirt

При создании кластера ceph по умолчанию создается пул rbd. С ним мы и будеи работать. Вы можете создать отдельный пул или несколько для работы с libvirt, все зависит от ваших нужд. К примеру пул для gold image и пул для vm image. В пулах мы будем размещать блочные устройства и отдавать виртуалкам в виде дисков и получить кучу плюсов. Помимо надёжности и производительности RBD также предоставляет функциональность корпоративного уровня подобную полным и инкрементальным снимкам, динамичному выделению (thin provisioning), клонированию копированием при записи (copy on write), динамическое изменение размеров и тому подобное. RBD также поддерживает кэширование в памяти.
Вернемся на любую из нод кластера и посмотрим статистику занятого места по пулам:

[root@ceph1 mycluster]# ceph df
GLOBAL:
    SIZE       AVAIL      RAW USED     %RAW USED 
    20435M     20300M         135M          0.66 
POOLS:
    NAME                ID     USED     %USED     MAX AVAIL     OBJECTS 
    rbd                 0         0         0        10150M           0 
    cephfs_data         1         0         0        10150M           0 
    cephfs_metadata     2      2378         0        10150M          20
Мы видим три пула: rbd, cephfs_data, cephfs_metadata которые имеют одинаковую емкость. Это обусловлено тем, что каждому пулу изначально доступно все место в кластере. Расширяя объем кластера - вы автоматически расширяете все пулы. Хорошо это или плохо - решать вам.
Теперь перейдем к созданию пользователя libvirt в ceph. Тут все аналогично как и с cephfs, только мы не указываем права на mds, так как для работы блочных устройст сервер метаданных не нужен. Даем права на чтение из mon и полные права на пул rbd. прошу обратить внимание, что пулы которые мы создали для cephfs не будут доступны пользователю libvirt. Это хорошо и правильно.
root@ceph1 mycluster]# ceph auth get-or-create client.libvirt mon 'allow r' osd 'allow class-read object_prefix rbd_children, allow rwx pool=rbd'
[client.libvirt]
	key = AQCsY0NXYEbzFhAAS/JicyexWrrcnVm0XUFEeA==
Создадим блочное устройство в пуле rbd размером 10G:
[root@ceph1 mycluster]# rbd create rbd/vm-test.img --size 10G
[root@ceph1 mycluster]# rbd ls -p rbd
vm-test.img
Если посмотреть информацию по vm-test.img то увидим, что оно не занимает место на диске. Это дополнительная плюшка ceph, которая и реализует thin provisioning
[root@ceph1 mycluster]# rbd info vm-test.img -p rbd
rbd image 'vm-test.img':
	size 10240 MB in 2560 objects
	order 22 (4096 kB objects)
	block_name_prefix: rbd_data.10502ae8944a
	format: 2
	features: layering, exclusive-lock, object-map, fast-diff, deep-flatten
	flags: 

[root@ceph1 mycluster]# rbd du vm-test.img -p rbd
NAME        PROVISIONED USED 
vm-test.img      10240M    0 
Идем на гипервизор и создаем файл секрета для доступа libvirt к ceph rbd:
cat > secret.xml <<EOF
<secret ephemeral='no' private='no'>
        <usage type='ceph'>
                <name>client.libvirt secret</name>
        </usage>
</secret>
EOF
Ипортируем файл через virsh:
[root@ceph1 mycluster]# virsh secret-define --file secret.xml
Secret 36607386-41fe-4730-9c13-624081e5d21a created
Устанавливаем ключ пользователя libvirt из ceph который мы получили выше:
[root@ceph1 mycluster]# sudo virsh secret-set-value --secret 36607386-41fe-4730-9c13-624081e5d21a --base64 AQCsY0NXYEbzFhAAS/JicyexWrrcnVm0XUFEeA==
Secret value set

[root@ceph1 mycluster]# sudo virsh secret-list
 UUID                                  Usage
--------------------------------------------------------------------------------
 36607386-41fe-4730-9c13-624081e5d21a  ceph client.libvirt secret
Правим конфиг виртуалки через virsh edit vm-test, которой хотим отдать блочное устройство из ceph
<disk type='network' device='disk'>
        <source protocol='rbd' name='rbd/vm-test.img'>
                <host name='172.22.12.31' port='6789'/>
        </source>
        <auth username='libvirt'>
        	<secret type='ceph' uuid='36607386-41fe-4730-9c13-624081e5d21a'/≶
		</auth>
        <target dev='vda' bus='virtio'/>
</disk>
Небольшое пояснение: <source protocol='rbd' name='rbd/vm-test.img'> сообщает, что мы будем использовать блочное устройство с именем vm-test.img которое находится в пуле rbd. Пул и rbd диск должен существовать (и то и другое было создано выше). Указываем наш монитор <host name='172.22.12.31' port='6789'/>. Их должно быть столько же, сколько у нас мониторов. Реализуется просто добавлением аналогичных строк в секции <source></source>. Тут мы передаем указатель на секрет, созданный выше <secret type='ceph' uuid='36607386-41fe-4730-9c13-624081e5d21a'/>.
Если у вас гипервизор находится на ноде, которая не входит в кластер ceph, то прийдется установить пакеты ceph для обеспечения работы. Нормальной практикой считается совмещение ролей compute и storage на одной ноде с целью уплотнения потребления ресурсов, энергии и места в стойке.

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