Помимо блочного и файлового типов доступа к данным, Ceph так же поддерживает объектный доступ с помощью привычных API S3, либо Swift.
В данном случае мы посмотрим, какие настройки необходимо выполнить со стороны Ceph, чтобы предоставить клиентам возможность управления данными с помощью S3 API.
Напомню, что ранее процедура установки Ceph 17 с нуля мной уже была описана в этой статье. В данном случае я использую эту же площадку, а также клиента на базе Rocky Linux 8.6.
Про подключение блочных устройств с помощью RBD я ранее писал здесь.
Объектное хранение в Ceph осуществляется с помощью компонента под названием Object Gateway, который ранее назывался RADOS Gateway или RGW. Данный компонент принимает от клиентов HTTP/HTTPS запросы и выполняет соответствующие действия со стороны Ceph.
Процедура предоставления доступа клиентам по S3 достаточно простая:
- Необходимо создать Object Gateway;
- Создать пользователя S3 и передать клиенту Access Key и Secret Key;
- Клиент, используя привычный S3 API размещает данные в Ceph.
Начнем с того, что проверим текущее количество узлов в кластере:
[root@ceph-mon-01 ~]# ceph orch host ls
HOST ADDR LABELS STATUS
ceph-mon-01 10.10.10.13 _admin
ceph-mon-02 10.10.10.14
ceph-mon-03 10.10.10.15
ceph-osd-01 10.10.10.16
ceph-osd-02 10.10.10.17
ceph-osd-03 10.10.10.18
6 hosts in cluster
В моем кластере 6 узлов, 3 из которых используются для системных служб, на 3 оставшихся хранятся данные и используются они только под OSD.
Для организации Object Gateway, я добавляю к текущему кластеру дополнительно два новых узла. Нетрудно догадаться, что делается это для отказоустойчивости. В случае выхода из строя одного узла, нагрузка будет перенесена на второй.
Кстати, в документации рекомендуется использование хотя бы трех узлов, но в лабораторном случае, думаю, это можно опустить.
Новые хосты называются ceph-rgw-01 и ceph-rgw-02. Предварительно их необходимо подготовить и задать короткий Hostname (указывать FQDN не нужно), а также установить Python 3 и Podman (либо Docker):
[root@ceph-rgw-01 ~]# dnf -y install python39 podman
[root@ceph-rgw-02 ~]# dnf -y install python39 podman
Далее все действия выполняются с управляющего узла. В моем случае это ceph-mon-01. Скопируем сертификат для беспарольного SSH-доступа с mon01 на rgw01/02:
[root@ceph-mon-01 ~]# ssh-copy-id -f -i /etc/ceph/ceph.pub root@ceph-rgw-01
[root@ceph-mon-01 ~]# ssh-copy-id -f -i /etc/ceph/ceph.pub root@ceph-rgw-02
Передадим узлы в управление Ceph:
[root@ceph-mon-01 ~]# ceph orch host add ceph-rgw-01
Added host 'ceph-rgw-01' with addr '10.10.10.20'
[root@ceph-mon-01 ~]# ceph orch host add ceph-rgw-02
Added host 'ceph-rgw-02' with addr '10.10.10.21'
Список хостов в кластере теперь выглядит следующим образом:
[root@ceph-mon-01 ~]# ceph orch host ls
HOST ADDR LABELS STATUS
ceph-mon-01 10.10.10.13 _admin
ceph-mon-02 10.10.10.14
ceph-mon-03 10.10.10.15
ceph-osd-01 10.10.10.16
ceph-osd-02 10.10.10.17
ceph-osd-03 10.10.10.18
ceph-rgw-01 10.10.10.20
ceph-rgw-02 10.10.10.21
8 hosts in cluster
Можно заметить новые узлы ceph-rgw-01 и ceph-rgw-02.
Установим для данных узлов метку rgw:
[root@ceph-mon-01 ~]# ceph orch host label add ceph-rgw-01 rgw
Added label rgw to host ceph-rgw-01
[root@ceph-mon-01 ~]# ceph orch host label add ceph-rgw-02 rgw
Added label rgw to host ceph-rgw-02
Теперь запустим службу RGW (Ceph Object Gateway) на всех узлах, где ранее была установлена метка rgw и используем порт 8080. На каждом узле будет запущено по одной службе RGW, но можно и больше:
[root@ceph-mon-01 ~]# ceph orch apply rgw s3.vmik.lab '--placement=label:rgw count-per-host:1' --port=8080
Scheduled rgw.s3.vmik.lab update...
Если перейти на любой из узлов rgw, можно увидеть новый контейнер, а также открытый порт 8080:
[root@ceph-rgw-01 ~]# podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6e83e4590364 quay.io/ceph/ceph@sha256:b4e95ad6b1a4fb02b3d5c3fc8cbdb91431d03fdf5c6d904f8a5cf1efb4053f27 -n client.rgw.s3.... 48 seconds ago Up 48 seconds ago ceph-2178c624-0901-11ed-ba0a-005056a97edd-rgw-s3-vmik-lab-ceph-rgw-01-lwxrag
[root@ceph-rgw-01 ~]# firewall-cmd --list-ports
8080/tcp 9100/tcp
Статус кластера будет также отображать наличие служб rgw:
[root@ceph-mon-01 ~]# ceph -s
cluster:
id: 2178c624-0901-11ed-ba0a-005056a97edd
health: HEALTH_OK
services:
mon: 3 daemons, quorum ceph-mon-01,ceph-mon-02,ceph-mon-03 (age 5w)
mgr: ceph-mon-01.khfosw(active, since 5w), standbys: ceph-mon-02.cfeaei
osd: 9 osds: 9 up (since 5w), 9 in (since 2M); 1 remapped pgs
rgw: 2 daemons active (2 hosts, 1 zones)
Если посмотреть список пулов, можно заметить три новых:
[root@ceph-mon-01 ~]# ceph osd lspools
1 .mgr
3 rbd_images_pool
4 .rgw.root
5 default.rgw.log
6 default.rgw.control
7 default.rgw.meta
Предыдущей командой мы запустили Ceph RGW на двух узлах и, в принципе, к каждому из них можно подключаться и выполнять S3 запросы, если обратиться на порт 8080:
[root@ceph-mon-01 ~]# curl ceph-rgw-01.vmik.lab:8080
<?xml version="1.0" encoding="UTF-8"?><ListAllMyBucketsResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Owner><ID>anonymous</ID><DisplayName></DisplayName></Owner><Buckets></Buckets></ListAllMyBucketsResult>
[root@ceph-mon-01 ~]# curl ceph-rgw-02.vmik.lab:8080
<?xml version="1.0" encoding="UTF-8"?><ListAllMyBucketsResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Owner><ID>anonymous</ID><DisplayName></DisplayName></Owner><Buckets></Buckets></ListAllMyBucketsResult>
Однако, в случае выхода из строя любого из шлюзов, клиенту придется менять адрес подключения и это плохо.
Данная проблема решается с помощью развертывания служб Ingress на базе HAProxy, а также общего IP-адреса с помощью Keepalived.
Для развертывания Ingress нужно создать соответствующий yaml манифест:
[root@ceph-mon-01 ~]# vi ./rgw_ingress.yaml
service_type: ingress
service_id: rgw.s3.vmik.lab
placement:
hosts:
- ceph-rgw-01
- ceph-rgw-02
spec:
backend_service: rgw.s3.vmik.lab
virtual_ip: 10.10.10.22/24
frontend_port: 80
monitor_port: 1967
virtual_interface_networks: 10.10.10.0/24
Где:
service_id – рекомендуется называть по аналогии с сервисом RGW;
hosts – список узлов, на которых будут развернуты службы Ingress. Это не обязательно должны быть те же самые узлы, где работают службы RGW, но в моем случае это так;
backend_service – название сервиса RGW, для которого применяется данный Ingress;
virtual_ip – адрес, который будет использоваться как точка входа для клиентов. В случае выхода из строя одного из узлов, данный адрес перемещается на другой узел;
frontend_port – порт, используемый клиентами для подключения. Важный момент – если используются одни и те же хосты под RGW и Ingress, порты RGW и Ingress должны различаться. В моем случае RGW использует порт 8080, а Ingress 80.
Применим данный манифест:
[root@ceph-mon-01 ~]# ceph orch apply -i rgw_ingress.yaml
Scheduled ingress.rgw.s3.vmik.lab update...
Если перейти на любой из узлов RGW, можно увидеть два новых контейнера:
[root@ceph-rgw-01 ~]# podman ps
cea8c4bca503 docker.io/arcts/keepalived:latest ./init.sh 22 seconds ago Up 22 seconds ago ceph-2178c624-0901-11ed-ba0a-005056a97edd-keepalived-rgw-s3-vmik-lab-ceph-rgw-01-lkhddg
79b360010d09 docker.io/library/haproxy:2.3 haproxy -f /var/l... 16 seconds ago Up 17 seconds ago ceph-2178c624-0901-11ed-ba0a-005056a97edd-haproxy-rgw-s3-vmik-lab-ceph-rgw-01-ksjmla
HAProxy отвечает за прием запросов от клиентов и перенаправление их в RGW, а Keepalived за доступность общего IP-адреса.
В списке служб Ceph у нас так же пополнение. Служба Ingress:
[root@ceph-mon-01 ~]# ceph orch ls
NAME PORTS RUNNING REFRESHED AGE PLACEMENT
alertmanager ?:9093,9094 1/1 39s ago 2M count:1
crash 8/8 9m ago 2M *
grafana ?:3000 1/1 39s ago 2M count:1
ingress.rgw.s3.vmik.lab 10.10.10.22:80,1967 4/4 40s ago 81s ceph-rgw-01;ceph-rgw-02
mgr 2/2 9m ago 2M count:2
mon 3/3 9m ago 2M ceph-mon-01;ceph-mon-02;ceph-mon-03;count:3
node-exporter ?:9100 8/8 9m ago 2M *
osd 9 9m ago - <unmanaged>
prometheus ?:9095 1/1 39s ago 2M count:1
rgw.s3.vmik.lab ?:8080 2/2 40s ago 51m count-per-host:1;label:rgw
Теперь можно обратиться к общему адресу по порту 80:
[root@ceph-mon-01 ~]# curl ceph-rgw.vmik.lab
<?xml version="1.0" encoding="UTF-8"?><ListAllMyBucketsResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Owner><ID>anonymous</ID><DisplayName></DisplayName></Owner><Buckets></Buckets></ListAllMyBucketsResult>
В моем случае это DNS имя ceph-rgw.vmik.lab, ссылающееся на адрес 10.10.10.22 (общий адрес Ingress).
Таким образом мы настроили службы RGW и добавили немного отказоустойчивости за счет Ingress. Теперь при подключении клиентов к общему Ingress адресу, потеря любого из узлов не потребует изменение настроек подключения, а перемещение адреса с узла на узел не превышает секунды.
Следующий этап. Мы обеспечили точку входа и теперь необходимо создать учетные записи и передать данные для доступа клиентам.
Все управление производится с помощью radosgw-admin.
Создадим учетную запись:
[root@ceph-mon-01 ~]# radosgw-admin user create --uid=vmik --display-name="VMIK Test" --email=vmik@vmik.lab
{
"user_id": "vmik",
"display_name": "VMIK Test",
"email": "vmik@vmik.lab",
"suspended": 0,
"max_buckets": 1000,
"subusers": [],
"keys": [
{
"user": "vmik",
"access_key": "O2TY3UOYYF2CBQasda",
"secret_key": "d08o34L2hrhjsqCoo8vycasdasd"
}
],
"swift_keys": [],
"caps": [],
"op_mask": "read, write, delete",
"default_placement": "",
"default_storage_class": "",
"placement_tags": [],
"bucket_quota": {
"enabled": false,
"check_on_raw": false,
"max_size": -1,
"max_size_kb": 0,
"max_objects": -1
},
"user_quota": {
"enabled": false,
"check_on_raw": false,
"max_size": -1,
"max_size_kb": 0,
"max_objects": -1
},
"temp_url_keys": [],
"type": "rgw",
"mfa_ids": []
}
Важные поля здесь access_key и secret_key, которые необходимо передать клиенту.
Можно обратить внимание, что изначально никаких квот и ограничений для пользователя нет, что, скорее всего, неправильно.
Установить квоты мы можем как на размер bucket, так и целиком на пользователя. Подробнее про тонкости можно почитать в документации.
Выставим квоту в 3GB пользователю:
[root@ceph-mon-01 ~]# radosgw-admin quota set --quota-scope=user --uid=vmik --max-size=3G
[root@ceph-mon-01 ~]# radosgw-admin quota enable --quota-scope=user --uid=vmik
Теперь, если просмотреть информацию о пользователе, можно увидеть наличие квот:
[root@ceph-mon-01 ~]# radosgw-admin user info --uid vmik
"bucket_quota": {
"enabled": false,
"check_on_raw": false,
"max_size": -1,
"max_size_kb": 0,
"max_objects": -1
},
"user_quota": {
"enabled": true,
"check_on_raw": false,
"max_size": 3221225472,
"max_size_kb": 3145728,
"max_objects": -1
}
Кстати, квоты отрабатывают не моментально и рекомендуется почитать внимательно секцию Quota Cache в документации.
Когда пользователь создан, а квоты установлены, можно попробовать подключиться к хранилищу. Здесь кому как удобнее и привычнее работать с S3.
Для себя и тестов я написал небольшую программу на python с использованием библиотеки boto, которая выполняет базовое взаимодействие по S3 API.
Для начала я пробую создать несколько bucket:
What do you want to do? (Print help if you don't know what to do): bucket_create
Enter bucket name: vmik
--------------------------------------------------
What do you want to do? (Print help if you don't know what to do): bucket_create
Enter bucket name: vmik2
--------------------------------------------------
What do you want to do? (Print help if you don't know what to do): bucket_create
Enter bucket name: vmik3
--------------------------------------------------
What do you want to do? (Print help if you don't know what to do): bucket_list
My buckets:
vmik
vmik2
vmik3
В то же время в Ceph:
[root@ceph-mon-01 ~]# radosgw-admin bucket list
[
"vmik2",
"vmik3",
"vmik"
]
Теперь загружу файл в bucket vmik:
What do you want to do? (Print help if you don't know what to do): file_upload
Enter file path: /mnt/d/CentOS-7-x86_64-Minimal-2009.iso
Enter bucket name: vmik
--------------------------------------------------
What do you want to do? (Print help if you don't know what to do): bucket_files
Enter bucket name: vmik
CentOS-7-x86_64-Minimal-2009.iso 2022-10-17T02:58:28.416Z
--------------------------------------------------
Проверим статистику пользователя:
[root@ceph-mon-01 ~]# radosgw-admin user stats --uid vmik --sync-stats
{
"stats": {
"size": 1020264448,
"size_actual": 1020264448,
"size_kb": 996352,
"size_kb_actual": 996352,
"num_objects": 1
},
"last_stats_sync": "2022-10-17T03:01:16.739986Z",
"last_stats_update": "2022-10-17T03:01:16.737704Z"
}
Видно, что некоторый объем пользователем уже занят.
Удалю ранее загруженный файл:
What do you want to do? (Print help if you don't know what to do): file_delete
Enter bucket name: vmik
Enter file name to delete: CentOS-7-x86_64-Minimal-2009.iso
Ceph сообщает о высвобождении пространства:
[root@ceph-mon-01 ~]# radosgw-admin user stats --uid vmik --sync-stats
{
"stats": {
"size": 0,
"size_actual": 0,
"size_kb": 0,
"size_kb_actual": 0,
"num_objects": 0
},
"last_stats_sync": "2022-10-17T03:02:29.482104Z",
"last_stats_update": "2022-10-17T03:02:29.479980Z"
}
Кстати, после создания bucket и загрузки данных, в Ceph появятся новые пулы:
[root@ceph-mon-01 ~]# ceph osd lspools
1 .mgr
3 rbd_images_pool
4 .rgw.root
5 default.rgw.log
6 default.rgw.control
7 default.rgw.meta
8 default.rgw.buckets.index
9 default.rgw.buckets.data
Таким образом мы создали отказоустойчивый вариант RGW, предоставили доступ клиенту, установили квоты, загрузили и удалили файлы.
На этом, про объектный доступ в Ceph у меня все. В качестве факультатива можете подумать на вопрос подключения сертификатов и использования HTTPS, что будет наиболее правильно с точки зрения безопасности.