Привет, Хабр! На связи Head of DevOps Владимир Яковлев из Дирекции Качества РТЛабс. Сегодня я хочу рассказать историю о том, как мы столкнулись с необходимостью миграции данных из одного кластера Ceph в другой и сделали это с минимальными психологическими затратами.

Введение

Имеем кластер Ceph версии Octopus, в качестве ОС использовали CentOS 7, а сам кластер был развёрнут при помощи CephAdm. Раньше кластер состоял из 5 нод, на которых были развёрнуты сразу все компоненты: MDS, MON, MGR, OSD. В качестве хранилища данных использовался CephFS. В процессе эксплуатации потеряли безвозвратно две ноды и остались без инженера, который администрировал это решение. И вот после очередного падения и потери нескольких десятков тысяч нервных клеток было принято решение дать новую жизнь Ceph и развернуть новый кластер, в который в дальнейшем переключим все микросервисы, использующие Ceph.

Но встал вопрос: как перенести данные из одного Ceph в другой и мигрировать сервисы на новый Ceph?

Делимся нашим алгоритмом решения этой проблемы.

Начало

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

Для нового кластера подготовили следующую архитектуру:

[osds]
infra-ceph-osd01
infra-ceph-osd02
infra-ceph-osd03
infra-ceph-osd04
[mons]
infra-ceph-mon01
infra-ceph-mon02
infra-ceph-mon03
[monitoring]
infra-ceph-mon01
infra-ceph-mon02
infra-ceph-mon03
[mdss]
infra-ceph-mds01
infra-ceph-mds02
[mgrs]
infra-ceph-mgr01
infra-ceph-mgr02

В качестве ОС использовали Ubuntu 20.04 и версию Ceph — Reef. Сам Ceph решено было развернуть при помощи Ansible roleОписание настроек Ceph не относится к теме этой статьи и заслуживает отдельного обсуждения.

Подключение файловой системы Ceph

Итак, мы имеем рабочий кластер. В нём есть хранилище cephfs со стандартным пулом — cephfs_data. Как нам перенести данные так, чтобы не было огромного ДТ (Down Time)?

Для решения этой проблемы воспользуемся утилитой ceph-fuse. На Ubuntu утилита устанавливается следующей командой:

apt-get install ceph-fuse

Устанавливаем утилиту на отдельном виртуальном сервере (не в кластере Ceph), чтобы не создавать лишнюю нагрузку.

Что такое ceph-fuse? Обратимся к официальной документации: ceph-fuse is a FUSE (“Filesystem in USErspace”) client for Ceph distributed file system. It will mount a ceph file system specified via the -m option or described by ceph.conf (see below) at the specific mount point.

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

Чтобы выполнить монтирование fs, нам нужен конфигурационный файл ceph.conf и файл с ключом авторизации. Где их взять? Вы можете зайти на вашу ноду, где установлены компоненты MON, и найти эти файлы по пути /etc/ceph/:

ls -la /etc/ceph
total 40
drwxr-xr-x 2 ceph ceph 4096 Dec 23 13:32 .
drwxr-xr-x 106 root root 4096 Dec 23 13:31 ..
-r-------- 1 ceph ceph 151 Dec 23 13:27 ceph.client.admin.keyring
-rw------- 1 ceph ceph 131 Dec 23 13:32 ceph.client.crash.keyring
-rw-r--r-- 1 ceph ceph 539 Dec 23 13:27 ceph.conf
-rw-r--r-- 1 root root 92 Nov 12 00:43 rbdmap

В данном каталоге (если вы, конечно, устанавливали Ceph в каталог по умолчанию) хранятся конфигурационные файлы. Нас интересуют файлы, которые имеют названия ceph.conf и ceph.client.admin.keyring. Первый — это конфиг Ceph, второй — ключ. Открыв его, вы увидите токен подключения, который, скорее всего, используете в k8s. Также там можно увидеть разрешения для этого токена.

Токен есть, конфиг-файл есть — можем монтировать файловую систему.

На сервере, который мы выбрали в качестве независимого, выполняем монтирование файловой системы Ceph. Для удобства создаём каталоги, куда примонтируем файловую систему:

mkdir /mnt/new_cephfs - кластер в который мы будем переносить данные
mkdir /mnt/old_cephfs - кластер из которого мы будем переносить данные

Далее выполняем команду:

ceph-fuse -c /путь/до/ceph.conf --keyring /путь/до/ceph.client.admin.keyring /mnt/new_cephfs - где 
 
-с флаг для указания конфиг файла кластера 
 
--keyring флаг для указания ключа для подключения к этому кластеру
 
в конце указываете папку куда вы хотите монтировать файловую систему

В итоге у нас есть две файловые системы, и уже можно стандартными командами Linux выполнить копирование/синхронизацию данных.

K8S

Файловые системы двух кластеров мы монтировали, но, зайдя в них, можем увидеть интересную картину:

ls -la /mnt/old_infra_cephfs/volumes/csi
total 191
drwxr-xr-x 381 root root 290028232249 Dec 23 14:05 .
drwxr-xr-x 6 root root 290028232407 Dec 23 14:05 ..
drwxrwxrwx 3 root root 25852 May 11 2023 csi-vol-0004badd-efd4-11ed-b280-9e559261c936
drwxrwxrwx 3 root root 32518 May 11 2023 csi-vol-001e56f2-efd4-11ed-b280-9e559261c936
drwxr-xr-x 3 root root 1454504310 Dec 16 06:11 csi-vol-02b782ec-3fed-4bef-8f85-356372b809ef
drwxrwxrwx 3 root root 1568 Oct 10 2022 csi-vol-0474c140-4884-11ed-ba52-c69a66c45312
drwxrwxrwx 3 root root 32370 Nov 12 12:45 csi-vol-04e1ad07-a0f4-11ef-9e71-66877a12684d
drwxrwxrwx 3 root root 39849 Nov 12 12:45 csi-vol-04e1fcee-a0f4-11ef-9e71-66877a12684d
drwxrwxrwx 3 root root 204474118 Sep 8 2022 csi-vol-0b28968c-2fb5-11ed-b12f-8af21f51cb6d
drwxrwxrwx 3 root root 15832 Dec 23 11:14 csi-vol-0c3f2579-c11f-11ef-9fc4-9a28065be354
drwxrwxrwx 3 root root 32370 Dec 3 07:13 csi-vol-0c912108-b146-11ef-9e71-66877a12684d
drwxrwxrwx 3 root root 39849 Dec 3 07:13 csi-vol-0c9123ad-b146-11ef-9e71-66877a12684d
drwxr-xr-x 3 root root 158 Dec 9 11:30 csi-vol-0e373578-516f-43f7-8430-40d7958fbe20
drwxrwxrwx 3 root root 39849 Nov 15 10:04 csi-vol-0f634e09-a339-11ef-9e71-66877a12684d
drwxrwxrwx 3 root root 32370 Nov 15 10:04 csi-vol-0f640984-a339-11ef-9e71-66877a12684d
drwxrwxrwx 3 root root 32370 Oct 24 14:55 csi-vol-12666a07-9218-11ef-9e71-66877a12684d
drwxrwxrwx 3 root root 35772 Oct 24 14:55 csi-vol-1266832c-9218-11ef-9e71-66877a12684d
drwxrwxrwx 3 root root 35772 Oct 24 14:55 csi-vol-14ddedc5-9218-11ef-9e71-66877a12684d
drwxrwxrwx 3 root root 32376 Oct 24 14:56 csi-vol-14dea200-9218-11ef-9e71-66877a12684d
drwxrwxrwx 3 root root 31767 Sep 8 2022 csi-vol-16ef7842-2f9c-11ed-b12f-8af21f51cb6d
drwxrwxrwx 3 root root 1218179599 Oct 29 11:44 csi-vol-18418c4a-95eb-11ef-9e43-ca882da5a549
drwxrwxrwx 3 root root 26572 Sep 8 2022 csi-vol-185ac814-2fd0-11ed-b12f-8af21f51cb6d
drwxrwxrwx 3 root root 32370 Sep 8 2022 csi-vol-18612028-2fd0-11ed-b12f-8af21f51cb6d
drwxrwxrwx 3 root root 158 Sep 8 2022 csi-vol-190021c4-2fb4-11ed-b12f-8af21f51cb6d
drwxrwxrwx 3 root root 158 Sep 8 2022 csi-vol-1915a27d-2fb4-11ed-b12f-8af21f51cb6d
drwxr-xr-x 3 root root 158 Dec 18 15:54 csi-vol-19aa5521-10ce-49c8-950c-92d928beaadf
drwxrwxrwx 3 root root 15832 May 16 2023 csi-vol-19f60227-f3c1-11ed-b7fb-da6452cd87b3
drwxrwxrwx 3 root root 14420443 May 16 2023 csi-vol-1a0c44e1-f3c1-11ed-b7fb-da6452cd87b3
drwxr-xr-x 3 root root 1276 Dec 9 21:45 csi-vol-1aea43ce-5e95-43c6-b565-ea25a5671bab
drwxrwxrwx 3 root root 28315 Sep 8 2022 csi-vol-1bc4791e-2fc3-11ed-b12f-8af21f51cb6d
drwxrwxrwx 3 root root 32370 Sep 8 2022 csi-vol-1bccb4f0-2fc3-11ed-b12f-8af21f51cb6d
drwxr-xr-x 3 root root 13129262 Nov 23 2023 csi-vol-1d197417-597d-49db-af70-741d9fbf0fbd
drwxrwxrwx 3 root root 1630 Jun 14 2023 csi-vol-1e4aabf7-0aa3-11ee-9119-6691476ab1bd
drwxrwxrwx 3 root root 32370 Nov 21 12:21 csi-vol-1f921100-a803-11ef-9e71-66877a12684d
drwxrwxrwx 3 root root 39849 Nov 21 12:21 csi-vol-1f921b2d-a803-11ef-9e71-66877a12684d
drwxrwxrwx 3 root root 35772 Oct 24 14:49 csi-vol-23662241-9217-11ef-9e71-66877a12684d
drwxrwxrwx 3 root root 32370 Oct 24 14:49 csi-vol-23663fc8-9217-11ef-9e71-66877a12684d
drwxrwxrwx 3 root root 32370 Dec 9 14:30 csi-vol-29cd0667-b63a-11ef-9fc4-9a28065be354
drwxrwxrwx 3 root root 39849 Dec 9 14:30 csi-vol-29cdd0e4-b63a-11ef-9fc4-9a28065be354
drwxr-xr-x 3 root root 163011224 Dec 9 21:45 csi-vol-2ac596a7-d3bb-4bca-8a0c-0b81d118a738

Как нам понять, что из этого списка является PV сервиса, данные которого нам нужно перенести? В кластере k8s, где находится нужный сервис, выполняем команду:

kubectl get pv

NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-13c0c040-b662-4827-9115-58dd3dce7a61 50Gi RWO Delete Bound monitoring
/prometheus-monitoring-kube-prometheus-prometheus-db-prometheus-monitoring-kube-prometheus-prometheus-0 csicephfs-sc 3h36m
pvc-44c2e523-1bb9-4c89-b0a8-4f0d20525a6f 100Gi RWO Delete Bound jenkins-old
/jenkins-old csicephfs-sc-old 13d
pvc-f842a26e-d57c-4c83-acdd-ff65629753ef 100Gi RWO Delete Bound jenkins
/jenkins csi
-cephfs-sc 3h35m

Выбираем volume нужного сервиса (допустим, это будет jenkins) и выполняем команду:

kubectl describe pv pvc-f842a26e-d57c-4c83-acdd-ff65629753ef

Name: pvc-f842a26e-d57c-4c83-acdd-ff65629753ef
Labels: <none>
Annotations: pv.kubernetes.io/provisioned-by: new-cluster
 volume.kubernetes.io/provisioner-deletion-secret-name: csi-cephfs-secret
 volume.kubernetes.io/provisioner-deletion-secret-namespace: cephfs-csi
Finalizers: [kubernetes.io/pv-protection]
StorageClass: csi-cephfs-sc
Status: Bound
Claim: jenkins/jenkins
Reclaim Policy: Delete
Access Modes: RWO
VolumeMode: Filesystem
Capacity: 100Gi
Node Affinity: <none>
Message:
Source:
 Type: CSI (a Container Storage Interface (CSI) volume source)
 Driver: new-cluster
 FSType:
 VolumeHandle: 0001-0024-d0df8f02-9cf1-4843-a157-87c05b49be00-0000000000000001-8d087598-ce95-45ce-b82abb227c720a53
 ReadOnly: false
 VolumeAttributes: clusterID=d0df8f02-9cf1-4843-a157-87c05b49be00
 fsName=cephfs
 kernelMountOptions=readdir_max_bytes=1048576
 mounter=kernel
 pool=cephfs_data
 storage.kubernetes.io/csiProvisionerIdentity=1733953811609-8081-new-cluster
 subvolumeName=csi-vol-8d087598-ce95-45ce-b82a-bb227c720a53
 subvolumePath=/volumes/csi/csi-vol-8d087598-ce95-45ce-b82a-bb227c720a53/3cac1a19-
3588-49a5-853e-b09923648899
Events: <none>

Строка subvolumePath будет соответствовать полному пути на файловой системе Ceph.

Разобрались с тем, откуда нам нужно копировать данные, теперь перейдем к шагу, где нам нужно подключить все наши сервисы в новый Ceph.

Для начала нужно задеплоить в наш кластер ещё один ceph-fs provisioner. Здесь важно не забыть поменять название storageClass и имя используемого драйвера. В противном случае у вас появятся задвоенные ID PV и kubelet не поймёт, что вы от него хотите, когда начнёте деплоить в кластер ваши сервисы. Ну и, конечно же, деплоим его в отдельный namespace. После этого мы будем готовы к переключению в новый Ceph.

Так как у вас новый кластер, то storageClass у вас тоже новый. А если у вас новый storageClass, то необходимо передеплоить ваш сервис, чтобы он создал новый PV уже в новом кластере Ceph. Если вы это сделаете, kubelet сразу же удалит PV и Ceph также удалит данные. Это приведёт к потере данных, которые без бэкапов вы не восстановите (привет, Velero).

Конечно, вы можете заранее при помощи rclone и rsync перенести данные. Но в этом случае в момент переключения у вас будет новый PV, куда вы будете ещё раз переносить данные, так как PV чистый. В результате ДТ разрастётся, а мы в начале статьи говорили, что наша задача — минимизировать затраты. Поэтому берём сервис, который хотим мигрировать на новый Ceph, и деплоим его в наш кластер, но в отдельный namespace. Обязательно делаем так, чтобы на этот сервис не шёл никакой «боевой» трафик. Надеюсь, что если вы читаете этот текст, вы знаете, как это сделать в Kubernetes. Если нет, то это повод встретиться в новых статьях ?.

Теперь у нас есть два сервиса. Остаётся просто скопировать данные и переключить трафик на уже мигрировавший сервис. Через команду kubectl describe pv, ранее уже упоминаемую, находим subvolumePath для мигрировавшего сервиса и возвращаемся с этими данными на наш сервер, где мы монтировали при помощи утилиты ceph-fuse кластера Ceph. Далее нам нужно просто перенести данные — для этого можно воспользоваться утилитой rsync.

Например, так:

rsync -avh --progress /mnt/old_cephfs/volumes/csi/csi-vol-8d087598-ce95-45ce-b82a-bb227c720a53/3cac1a19-3588-49a5-853e-b09923648899/ /mnt/new_cephfs/volumes/csi/csi-vol-ccd5d759-20f6-4df3-8647-199276f539c5/51734485-ea4c-481b-b678-6bf0abb14eae/
 
где /mnt/old_cephfs и /mnt/new_cephfs это ваши точки монтирования файловой системы ceph

После миграции данных нужно убедиться, что сервис, который мигрировал на новый Ceph, видит всю необходимую информацию, и переключить «боевой» трафик на него.

Важно!

Не забываем отмонтировать Ceph после того, как вы закончили с ним работать. Для этого на сервере необходимо выполнить команду:

fusermount -u /ваша/точка_монтирования

Вывод

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

Берегите себя и почаще делайте бэкапы. =)

Комментарии (1)