В кластере Ceph есть основные 3 роли которые может иметь узел:
Так же есть 2 дополнительные роли:
Нужны ли RGW и MDS для Kubernetes?
На текущий момент существует 3 подхода (+ RGW для организации S3 хранилища) к их связи:
Способ | Простота | Подходит для | Нужные компоненты Ceph |
---|---|---|---|
RBD (вручную) | Средняя | Блочные диски (аналог EBS) | MON, OSD, MGR |
Ceph CSI (RBD) | Средняя | Автоматическое управление томами | MON, OSD, MGR |
CephFS | Сложнее | Файловое хранилище (аналог NFS) | MON, OSD, MGR, MDS |
RGW (S3) | Отдельная тема | Объектное хранилище (аналог MinIO) | MON, OSD, MGR, RGW |
Самый походящий способом связывания сегодня это использование CSI (Container Storage Interface) драйвера, который позволяет динамически управлять хранилищем. Это обеспечивает гибкость и масштабируемость, что делает его лучшей практикой для продакшн-сред.
НО! Есть нюанс (куда же без них)
CSI RBD поддерживает только режим RWO (ReadWriteOnce) для volume, соответственно поддержка RWX отсутствует.
Если требуется RWX (ReadWriteMany), то самым предпочтительным вариантом будет использовать внутри одного кластера Ceph два типа хранилищ и RBD и CephFS, и подключить их к K8s.
Если RWX в кластере не требуется, то лучше ограничиться только RBD, так как у него выше производительность.
В этой статье в одном кластере Ceph, будут реализованы сразу 2 типа хранилища.
Для production среды между кластером Kubernetes и кластером Ceph должна быть выделенная сеть с пропускной способностью не менее 10 Гбит/с (Public Network), где будет идти общение между подами в K8s и их volume в Ceph.
Так же должна быть сеть Cluster Network, предназначенная только для репликации данных между узлами Ceph.
Но для тестовой среды (которая и описывается в этой статье) подойдет и одна общая сеть.
На каждой машине нашего кластера будут работать все три демона. Соответственно, демоны монитора и менеджера как служебные, и демоны OSD для дисков нашей виртуальной машины. Используемый дистрибутив - Red Hat Enterprise Linux 10.0.
Развертывание будет осуществляться с помощью официального инструмента Cephadm. Документация расположена тут.
Перед началом на каждом сервере должно быть корректное время. Желательно использование одного и того же NTP сервера.
На каждом узле рекомендуется иметь по 3 диска. 1 - Система, 2 - Хранилище, 3 - Хранилище + Журнал. А лучше вообще иметь под журнал выделенный диск.
Если OSD (дисков) в кластере будет меньше 4, то будет использоваться репликация, за место эффективного Erasure Coding.
Актуальную версию Ceph можно узнать на официальном сайте.
Узлы которые будут использоваться с ролью OSD, нужно подготовить к добавлению в кластер Ceph.
Диски которые будут использоваться в качестве хранилища должны быть подключены к машинам, но не иметь на них данных (ни ФС, ни таблицы разделов). Если на них что-то есть, то данные будут автоматически стерты (я не проверял, но должно быть именно так).
На всех узлах (ceph-1, ceph-2, ceph-3) выполните:
# Установка зависимостей
sudo dnf install -y podman lvm2 chrony openssh-server python3 python3-pyyaml
# Настройка времени (если не настроено заранее)
sudo systemctl enable --now chronyd
# Отключение SELinux (или настройка в permissive mode)
sudo setenforce 0
sudo sed -i 's/^SELINUX=.*/SELINUX=permissive/' /etc/selinux/config
# Настройка firewalld (или отключение)
sudo firewall-cmd --zone=public --add-service=ceph --permanent
sudo firewall-cmd --zone=public --add-service=ceph-mon --permanent
sudo firewall-cmd --zone=public --add-service=ceph-mgr --permanent
sudo firewall-cmd --reload
Установка cephadm на bootstrap-узле (ceph-1):
CEPH_RELEASE=19.2.2 # Замените на желаемый релиз
curl --silent --remote-name --location https://download.ceph.com/rpm-${CEPH_RELEASE}/el9/noarch/cephadm
chmod +x cephadm
sudo mv ./cephadm /usr/bin/
На ceph-1 выполните:
sudo cephadm bootstrap \
--mon-ip 172.16.1.121 \
--initial-dashboard-user admin \
--initial-dashboard-password P@ssw0rd \
--allow-fqdn-hostname # Если используется fqdn, а не короткое имя
Пример команды для Production среды с несколькими сетями:
sudo cephadm bootstrap \ --mon-ip 172.16.1.100 \ --initial-dashboard-user admin \ --initial-dashboard-password P@ssw0rd \ --allow-fqdn-hostname \ --public-network 172.16.0.0/23 \ --cluster-network 10.10.0.0/24 \ # Если вам не нужен встроенный мониторинг и выключен firewalld --skip-monitoring-stack \ --skip-firewalld
После этого вы сможете перейти в Web GUI по адресу https://ceph-1.k8s.rhel:8443/
Для большого количества действий придется использовать утилиту ceph, но я не нашел ее в пакетах RHEL 10.0 (для этого нужен пакет ceph-common). Но как оказалось для исполнений команд ceph можно использовать cephadm:
# Хороший вариант это зайти в оболочку ceph и выполнять команды в ней
sudo cephadm shell
# Ну или исполнять каждую команду с этой припиской
sudo cephadm shell -- ceph <команда>
# Либо попробуйте установить ceph-common через репозиторий, если получится
sudo cephadm add-repo --release squid
sudo cephadm install ceph-common
Подробности по работе с оболочкой можно найти в документации.
Сначала получите ключ:
sudo ceph cephadm get-pub-key > ~/ceph.pub
Затем на каждом узле (ceph-1, ceph-2, ceph-3) добавьте ключ:
sudo ssh-copy-id -f -i ~/ceph.pub root@ceph-1.k8s.rhel
sudo ssh-copy-id -f -i ~/ceph.pub root@ceph-2.k8s.rhel
sudo ssh-copy-id -f -i ~/ceph.pub root@ceph-3.k8s.rhel
Или скриптом:
for host in ceph-1.k8s.rhel ceph-2.k8s.rhel ceph-3.k8s.rhel; do
sudo ssh-copy-id -f -i ~/.ssh/ceph.pub root@$host
done
Ключи нужно добавлять именно для пользователя root, так как Ceph будет принудительно использовать именно его.
Добавьте хосты в кластер:
sudo ceph orch host add ceph-2.k8s.rhel
sudo ceph orch host add ceph-3.k8s.rhel
Здесь ничего сложного, если уже знать что требуется от кластера:
# Развертывание мониторов (Обязательно минимум на 3-х узлах, число должно быть нечетное)
sudo ceph orch apply mon --placement="ceph-1.k8s.rhel,ceph-2.k8s.rhel,ceph-3.k8s.rhel"
# Развертывание менеджеров (Для HA минимум 2)
sudo ceph orch apply mgr --placement="ceph-1.k8s.rhel,ceph-2.k8s.rhel,ceph-3.k8s.rhel"
# Развертывание MDS на нескольких узлах (для отказоустойчивости) (Если CephFS не нужен, не пишите это):
ceph orch apply mds cephfs --placement="3" # По 1 MDS на каждом узле
# Проверка состояния сервисов
sudo ceph orch ps
При проверке состояния все сервисы должны иметь состояние running.
Перейдем к настройке OSD. Создайте файл osd_spec.yaml:
service_type: osd
service_id: default_drive_group
placement:
hosts:
- ceph-1.k8s.rhel
- ceph-2.k8s.rhel
- ceph-3.k8s.rhel
data_devices:
paths:
- /dev/sdb
- /dev/sdc
Или если у вас диски на нодах называются по разному:
service_type: osd
service_id: osd_ceph1
placement:
hosts:
- ceph-1.k8s.rhel
data_devices:
paths:
- /dev/sdb
- /dev/sdc
---
service_type: osd
service_id: osd_ceph2
placement:
hosts:
- ceph-2.k8s.rhel
data_devices:
paths:
- /dev/nvme0n1
---
service_type: osd
service_id: osd_ceph3
placement:
hosts:
- ceph-3.k8s.rhel
data_devices:
paths:
- /dev/vdb
Примените конфигурацию:
sudo ceph orch apply osd -i osd_spec.yaml
Если у вас та же проблема что и у меня с ceph-common, то передать файл в утилиту ceph напрямую не получится, поэтому придется использовать команду с Heredoc:
sudo ceph orch apply osd -i - <<EOF
service_type: osd
service_id: default_drive_group
placement:
hosts:
- ceph-1.k8s.rhel
- ceph-2.k8s.rhel
- ceph-3.k8s.rhel
data_devices:
paths:
- /dev/sdb
- /dev/sdc
EOF
После этого перейдите в Web GUI и проверьте что все ноды имеют статус Available и в кластере нет ошибок.
Grafana доступна по URL - https://ceph-1.k8s.rhel:3000/
Порты остальных сервисов можно узнать командой sudo ceph orch ps
На управляющем узле Ceph выполните:
# Пулы для RBD (тут значения стоят для небольшого кластера)
sudo ceph osd pool create kube_rbd 128 128
sudo ceph osd pool application enable kube_rbd rbd
# Пулы для CephFS (Если он вам не нужен, то писать это не нужно)
sudo ceph osd pool create cephfs_data 128 128
sudo ceph osd pool create cephfs_metadata 32 32
sudo ceph fs new cephfs cephfs_metadata cephfs_data
sudo ceph fs subvolumegroup create cephfs csi # В созданой файловой системе CephFS создаем subvolumegroup
Создайте пользователей для подключения K8s:
# Пользователь для RBD
sudo ceph auth get-or-create client.kube mon 'profile rbd' osd 'profile rbd pool=kube_rbd' mgr 'profile rbd pool=kube_rbd'
# Пользователь для CephFS (Если он вам не нужен, то писать это не нужно)
sudo ceph auth get-or-create client.kube_cephfs mon 'allow r' mgr 'allow rw' mds 'allow rws' osd 'allow rw pool=cephfs_data, allow rw pool=cephfs_metadata'
Ключ (или ключи) который будет выведен сохраните для дальнейшего подключения K8s по ним.
Если вы их потеряете их можно запросить заново:
ceph auth get-key client.kube
ceph auth get-key client.kube_cephfs
Установите Helm (если еще не установлен).
Добавьте репозиторий Ceph CSI RBD:
helm repo add ceph-csi https://ceph.github.io/csi-charts
helm repo update
# Получаем набор переменных чарта ceph-csi-rbd
# Переменные можно изменять в файле или применить в терминале к helm через --set
helm inspect values ceph-csi/ceph-csi-rbd > cephrbd.yml
Теперь нужно заполнить файл cephrbd.yml. Для этого узнаем ID кластера и IP-адреса мониторов в Ceph:
ceph fsid # так мы узнаем clusterID
ceph mon dump # а так увидим IP-адреса мониторов
Полученные значения заносим в файл cephrbd.yml. Попутно включаем создание политик PSP (Pod Security Policies):
csiConfig:
- clusterID: "130ad1f8-60ed-11f0-81e5-bc24118e2b70"
monitors:
- "v2:172.16.1.121:3300/0,v1:172.16.1.121:6789/0"
- "v2:172.16.1.122:3300/0,v1:172.16.1.122:6789/0"
- "v2:172.16.1.123:3300/0,v1:172.16.1.123:6789/0"
nodeplugin:
podSecurityPolicy:
enabled: true
provisioner:
podSecurityPolicy:
enabled: true
Далее всё что нам остаётся — установить чарт в кластер Kubernetes:
helm upgrade -i ceph-csi-rbd ceph-csi/ceph-csi-rbd \
-f cephrbd.yml \
--create-namespace \
--namespace ceph-csi-rbd \
--set provisioner.replicaCount=1 # Используйте эту опцию только если хотите выбрать колиство
# подов для Provisioner (должно быть нечетным) (по умолчанию 3)
# Оно так же должно быть меньше количества Worker нод
Занесём значения в Secret, нам нужны username и ключ из Ceph:
kubectl create secret generic csi-rbd-secret \
--namespace ceph-csi-rbd \
--from-literal=userID=kube \
--from-literal=userKey=<user-key>
Далее нам нужен примерно такой манифест StorageClass:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: csi-rbd-sc
provisioner: rbd.csi.ceph.com
parameters:
clusterID: <cluster-id>
pool: kube_rbd
imageFeatures: layering
# Эти секреты должны содержать данные для авторизации
# в ваш пул.
csi.storage.k8s.io/provisioner-secret-name: csi-rbd-secret
csi.storage.k8s.io/provisioner-secret-namespace: ceph-csi-rbd
csi.storage.k8s.io/controller-expand-secret-name: csi-rbd-secret
csi.storage.k8s.io/controller-expand-secret-namespace: ceph-csi-rbd
csi.storage.k8s.io/node-stage-secret-name: csi-rbd-secret
csi.storage.k8s.io/node-stage-secret-namespace: ceph-csi-rbd
csi.storage.k8s.io/fstype: xfs # Тут по желанию
reclaimPolicy: Delete
allowVolumeExpansion: true
mountOptions:
- discard
Нужно заполнить clusterID, который мы уже узнали командой ceph fsid, и применить этот манифест в кластере Kubernetes:
kubectl apply -f storageclass-rbd.yaml
Теперь проверим правильно ли все настроено. Для этого создадим тестовый PVC:
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: rbd-test-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: csi-rbd-sc
EOF
И теперь проверим его статус:
kubectl get pvc rbd-test-pvc
Получим значения из нужного нам нового Helm-чарта:
helm inspect values ceph-csi/ceph-csi-cephfs > cephfs.yml
Снова нужно заполнить файл cephfs.yml. Как и ранее, помогут команды Ceph:
ceph fsid
ceph mon dump
Заполняем файл со значениями примерно так:
csiConfig:
- clusterID: "130ad1f8-60ed-11f0-81e5-bc24118e2b70"
monitors:
- "172.16.1.121:6789"
- "172.16.1.122:6789"
- "172.16.1.123:6789"
nodeplugin:
httpMetrics:
enabled: true
containerPort: 8091
podSecurityPolicy:
enabled: true
provisioner:
replicaCount: 1
podSecurityPolicy:
enabled: true
Обратите внимание, что адреса мониторов указываются в простой форме address:port. Для монтирования cephfs на узле эти адреса передаются в модуль ядра, который ещё не умеет работать с протоколом мониторов v2.
Порт для httpMetrics (туда будет ходить Prometheus за метриками для мониторинга) мы меняем для того, чтобы он не конфликтовал с nginx-proxy, который устанавливается Kubespray’ем.
Устанавливаем Helm-чарт в кластер Kubernetes:
helm upgrade -i ceph-csi-cephfs ceph-csi/ceph-csi-cephfs \
-f cephfs.yml \
--create-namespace \
--namespace ceph-csi-cephfs
Создадим отдельные Secret и StorageClass (не забудьте ввести верный userKey).
Ничего нового, мы это уже видели на примере RBD::
kubectl create secret generic csi-cephfs-secret \
--namespace ceph-csi-cephfs \
--from-literal=userID=kube_cephfs \
--from-literal=<user-key>
А теперь – отдельный StorageClass:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: csi-cephfs-sc
provisioner: cephfs.csi.ceph.com
parameters:
clusterID: <cluster-id>
# Имя файловой системы CephFS, в которой будет создан том
fsName: cephfs
# Пул Ceph, в котором будут храниться данные тома
pool: cephfs_data
# (необязательно) Разделенные запятыми опции монтирования для Ceph-fuse
# например:
# fuseMountOptions: debug
# (необязательно) Разделенные запятыми опции монтирования CephFS для ядра
# См. man mount.ceph чтобы узнать список этих опций. Например:
# kernelMountOptions: readdir_max_bytes=1048576,norbytes
# Секреты должны содержать доступы для админа и/или юзера Ceph.
csi.storage.k8s.io/provisioner-secret-name: csi-cephfs-secret
csi.storage.k8s.io/provisioner-secret-namespace: ceph-csi-cephfs
csi.storage.k8s.io/controller-expand-secret-name: csi-cephfs-secret
csi.storage.k8s.io/controller-expand-secret-namespace: ceph-csi-cephfs
csi.storage.k8s.io/node-stage-secret-name: csi-cephfs-secret
csi.storage.k8s.io/node-stage-secret-namespace: ceph-csi-cephfs
# (необязательно) Драйвер может использовать либо ceph-fuse (fuse),
# либо ceph kernelclient (kernel).
# Если не указано, будет использоваться монтирование томов по умолчанию,
# это определяется поиском ceph-fuse и mount.ceph
# mounter: kernel
reclaimPolicy: Delete
allowVolumeExpansion: true
mountOptions:
- debug
Заполним тут clusterID и применим в Kubernetes:
kubectl apply -f storageclass-cephfs.yaml
Для проверки, как и в прошлом примере, создадим PVC:
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: cephfs-test-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 5Gi
storageClassName: csi-cephfs-sc
EOF
И проверим результат:
kubectl get pvc cephfs-test-pvc
Если вдруг потребуется удаление всех установленных компонентов, то начинайте удаление с Helm-чарта, а потом удалите Namespace:
helm uninstall ceph-csi-rbd -n ceph-csi-rbd
helm uninstall ceph-csi-cephfs -n ceph-csi-cephfs
kubectl delete ns ceph-csi-rbd
kubectl delete ns ceph-csi-cephfs
После такого удаления никаких компонентов не останется.
Если удалять вручную, то не забудьте про Service Accounts, Cluster Roles, Roles, Cluster Role Bindings, Role Bindings, StorageClass и csidriver.
В кластере желательно указать какой из StorageClass будет использоваться по умолчанию:
kubectl patch storageclass <storage-class-name> -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
При выборе исходите из того какие приложения будут находится в кластере.
Для диагностики проблем и дальнейшей поддержки кластера могут пригодиться команды:
# Проверка состояния кластера
sudo ceph -s
# Проверка OSD
sudo ceph osd tree
# Проверка мониторов
sudo ceph mon stat
# Проверка использования
sudo ceph df
# Для обновления Ceph до новых версий (обновление возможно так же через Web GUI):
sudo ceph orch upgrade start --ceph-version <target-version>