
В началото на този месец, 3 май, беше анонсиран голям релиз на «системата за управление на разпределени хранилища на данни в Kubernetes» — . Повече от година вече публикуваме използването му на практика — и ето, точно навреме за такава значима веха в историята на проекта, сме щастливи да споделим натрупаните впечатления. Ако накратко, Rook представлява набор
от оператори В момента най-развитото (и
единствено в фаза) решение е rook-ceph-operator .
ЗабележкаИ така, в тази статия ние:
ще отговорим на въпроса какви предимства виждаме в използването на Rook за разгръщане на Ceph в клъстера Kubernetes;
- ще споделим опит и впечатления от използването на Rook в продукция;
- ще разкажем защо казваме на Rook „Да!“, и за нашите планове относно него.
- Нека започнем с общи концепции и теория.
„Имате предимство с една ладия!“ (неизвестен шахматист)
Едно от основните предимства на Rook е, че взаимодействието с хранилищата на данни се извършва чрез механизмите на Kubernetes. Това означава, че вече не е необходимо да копирате команди за настройка на Ceph от бележки в конзолата.

— Искаш ли да разгръщаш CephFS в клъстера? Просто напиши YAML файл!
— Какво? Искаш ли да разгръщаш и обектно хранилище с S3 API? Просто напиши втори YAML файл!
Rook е създаден по всички правила на типичен оператор. Взаимодействието с него се извършва чрез
CRD (Custom Resource Definitions) (тъй като това е единствената стабилна реализация, в статията ще става дума именно за Ceph, освен ако не е посочено друго) . Според зададените параметри операторът автоматично ще изпълни необходимите команди за настройки.Нека разгледаме конкретиката на примера с създаване на Object Store, а конкретно —
CephObjectStoreUser CephObjectStoreUser.
apiVersion: ceph.rook.io/v1
kind: CephObjectStore
metadata:
name: {{ .Values.s3.crdName }}
namespace: kube-rook
spec:
metadataPool:
failureDomain: host
replicated:
size: 3
dataPool:
failureDomain: host
erasureCoded:
dataChunks: 2
codingChunks: 1
gateway:
type: s3
sslCertificateRef:
port: 80
securePort:
instances: 1
allNodes: false
---
apiVersion: ceph.rook.io/v1
kind: CephObjectStoreUser
metadata:
name: {{ .Values.s3.crdName }}
namespace: kube-rook
spec:
store: {{ .Values.s3.crdName }}
displayName: {{ .Values.s3.username }}Посочените параметри в листинга са достатъчно стандартни и едва ли изискват коментари, но е важно да се обърне специално внимание на тези, които са изведени в шаблонни променливи.
Общата схема на работа се свежда до това, че чрез YAML файл ние "поръчваме" ресурси, за което операторът изпълнява нужните команди и ни връща "не напълно истински" секрет, с който можем да работим нататък. (вж. по-долу). А от променливите, които са посочени по-горе, ще бъде съставена команда и име на секрет.
Каква е тази команда? При създаването на потребител за обектното хранилище, Rook операторът в pod-ът ще изпълни следното:
radosgw-admin user create --uid="rook-user" --display-name="{{ .Values.s3.username }}"Резултатът от изпълнението на тази команда ще бъде JSON структура:
{
"user_id": "rook-user",
"display_name": "{{ .Values.s3.username }}",
"keys": [
{
"user": "rook-user",
"access_key": "NRWGT19TWMYOB1YDBV1Y",
"secret_key": "gr1VEGIV7rxcP3xvXDFCo4UDwwl2YoNrmtRlIAty"
}
],
...
} Ключове — това, което ще е необходимо в бъдеще на приложенията за достъп до обектното хранилище чрез S3 API. Rook операторът любезно ги избира и ги съхранява в своя namespace под формата на секрет с името rook-ceph-object-user-{{ $.Values.s3.crdName }}-{{ $.Values.s3.username }}.
За да използвате данните от този секрет, е достатъчно да ги добавите в контейнера като променливи на средата. Като пример давам шаблон за Job, в който автоматично създаваме bucket-ове за всяка потребителска среда:
{{- range $bucket := $.Values.s3.bucketNames }}
apiVersion: batch/v1
kind: Job
metadata:
name: create-{{ $bucket }}-bucket-job
annotations:
"helm.sh/hook": post-install
"helm.sh/hook-weight": "2"
spec:
template:
metadata:
name: create-{{ $bucket }}-bucket-job
spec:
restartPolicy: Never
initContainers:
- name: waitdns
image: alpine:3.6
command: ["/bin/sh", "-c", "while ! getent ahostsv4 rook-ceph-rgw-{{ $.Values.s3.crdName }}; do sleep 1; done" ]
- name: config
image: rook/ceph:v1.0.0
command: ["/bin/sh", "-c"]
args: ["s3cmd --configure --access_key=$(ACCESS-KEY) --secret_key=$(SECRET-KEY) -s --no-ssl --dump-config | tee /config/.s3cfg"]
volumeMounts:
- name: config
mountPath: /config
env:
- name: ACCESS-KEY
valueFrom:
secretKeyRef:
name: rook-ceph-object-user-{{ $.Values.s3.crdName }}-{{ $.Values.s3.username }}
key: AccessKey
- name: SECRET-KEY
valueFrom:
secretKeyRef:
name: rook-ceph-object-user-{{ $.Values.s3.crdName }}-{{ $.Values.s3.username }}
key: SecretKey
containers:
- name: create-bucket
image: rook/ceph:v1.0.0
command:
- "s3cmd"
- "mb"
- "--host=rook-ceph-rgw-{{ $.Values.s3.crdName }}"
- "--host-bucket= "
- "s3://{{ $bucket }}"
ports:
- name: s3-no-sll
containerPort: 80
volumeMounts:
- name: config
mountPath: /root
volumes:
- name: config
emptyDir: {}
---
{{- end }}Всички действия, изброени в този Job, бяха извършени, без да се излиза извън Kubernetes. Определените в YAML файловете структури са съхранени в Git репозиторий и многократно използвани. В това виждаме огромно предимство за DevOps инженерите и процеса CI/CD като цяло.
С Rook и Rados е удоволствие
Използването на комбинация от Ceph + RBD налага определени ограничения върху монтиране на томове към pod.
По-специално, в namespace задължително трябва да има секрет за достъп до Ceph, за да функционират stateful приложенията. Нормално е, ако имате 2-3 среди в собствените си пространства от имена: можете да отидете и ръчно да копирате секрета. Но какво да правите, ако за всяка функция за разработчиците се създава отделна среда с свой namespace?
При нас решихме този проблем с помощта на , който автоматично копираше секрети в нови namespace (пример за подобен хук е описан в ).
#! /bin/bash
if [[ $1 == “--config” ]]; then
cat <<EOF
{"onKubernetesEvent":[
{"name": "OnNewNamespace",
"kind": "namespace",
"event": ["add"]
}
]}
EOF
else
NAMESPACE=$(kubectl get namespace -o json | jq '.items | max_by( .metadata.creationTimestamp ) | .metadata.name')
kubectl -n ${CEPH_SECRET_NAMESPACE} get secret ${CEPH_SECRET_NAME} -o json | jq ".metadata.namespace="${NAMESPACE}"" | kubectl apply -f -
fiОбаче, при използването на Rook, този проблем просто не съществува. Процесът на монтиране се извършва чрез собствени драйвери на базата на или (все още в бета стадий) и следователно не изисква секрети.
Rook автоматично решава много проблеми, което ни насърчава да го използваме в нови проекти.
Обсадата на Rook
Нека завършим практическата част с разгръщането на Rook и Ceph, за да можем да провеждаме собствени експерименти. За да улесним атаката на тази непристъпна кула, разработчиците подготвиха Helm пакет. Нека го изтеглим:
$ helm fetch rook-master/rook-ceph --untar --version 1.0.0 В файла rook-ceph/values.yaml можем да намерим множество различни настройки. Най-важното е да укажем tolerations за агентите и търсенето. За какво може да се използва механизмът taints/tolerations, подробно разгледахме в .
Ако накратко, не искаме pod-ове с клиентското приложение да се разполагат на същите възли, където са дисковете за съхранение на данни. Причината е проста: така работата на агентите Rook няма да влияе на самото приложение.
И така, отваряме файла rook-ceph/values.yaml с любимия редактор и добавяме следния блок в края:
discover:
toleration: NoExecute
tolerationKey: node-role/storage
agent:
toleration: NoExecute
tolerationKey: node-role/storage
mountSecurityMode: AnyНа всеки възел, резервиран за съхранение на данни, добавяме съответния taint:
$ kubectl taint node ${NODE_NAME} node-role/storage="":NoExecuteСлед това инсталираме Helm графика с командата:
$ helm install --namespace ${ROOK_NAMESPACE} ./rook-cephСега е необходимо да създадем клъстер и да укажем местоположението на :
apiVersion: ceph.rook.io/v1
kind: CephCluster
metadata:
clusterName: "ceph"
finalizers:
- cephcluster.ceph.rook.io
generation: 1
name: rook-ceph
spec:
cephVersion:
image: ceph/ceph:v13
dashboard:
enabled: true
dataDirHostPath: /var/lib/rook/osd
mon:
allowMultiplePerNode: false
count: 3
network:
hostNetwork: true
rbdMirroring:
workers: 1
placement:
all:
tolerations:
- key: node-role/storage
operator: Exists
storage:
useAllNodes: false
useAllDevices: false
config:
osdsPerDevice: "1"
storeType: filestore
resources:
limits:
memory: "1024Mi"
requests:
memory: "1024Mi"
nodes:
- name: host-1
directories:
- path: "/mnt/osd"
- name: host-2
directories:
- path: "/mnt/osd"
- name: host-3
directories:
- path: "/mnt/osd" Проверяваме статуса на Ceph — очакваме да видим HEALTH_OK:
$ kubectl -n ${ROOK_NAMESPACE} exec $(kubectl -n ${ROOK_NAMESPACE} get pod -l app=rook-ceph-operator -o name -o jsonpath='{.items[0].metadata.name}') -- ceph -sСъщевременно проверяваме, че pod-овете с клиентското приложение не попада на резервираните за Ceph възли:
$ kubectl -n ${APPLICATION_NAMESPACE} get pods -o custom-columns=NAME:.metadata.name,NODE:.spec.nodeNameСлед това по желание се настройват допълнителни компоненти. Подробности за тях са посочени в . Настоятелно препоръчваме да инсталирате dashboard и toolbox за администриране.
Rook-of-hooks: достатъчно ли е за всичко Rook?
Както изглежда, разработката на Rook напредва. Но все още остават проблеми, които не ни позволяват да се откажем напълно от ръчната настройка на Ceph:
- Нито един драйвер на Rook да експортира метрики за използването на монтирани блокове, което ни лишава от мониторинг.
- Flexvolume и CSI не могат да променят размера на тайловете (в противоречие с RBD), затова Rook губи полезен (а понякога и критично необходим!) инструмент.
- Rook все още не е толкова гъвкав, колкото обикновеният Ceph. Ако искаме да настроим, за да се съхранява пула за метаданни CephFS на SSD, а самите данни — на HDD, ще трябва ръчно да запишем отделни групи устройства в CRUSH картите.
- Въпреки че rook-ceph-operator се счита за стабилен, в момента съществуват определени проблеми при обновление на Ceph от версия 13 до 14.
Изводи
„В момента Ладята е затворена от външния свят с пешки, но ние вярваме, че един ден тя ще изиграе решаваща роля в партията!“ (цитат, измислен специално за тази статия)
Проектът Rook без съмнение завладя нашите сърца — считаме, че [с всички свои плюсове и минуси] той определено заслужава и вашето внимание.
Нашите бъдещи планове са да направим rook-ceph модул за , което ще направи използването му в нашите многобройни Kubernetes клъстери още по-просто и удобно.
P.S.
Прочетете също в нашия блог:
- «»;
- «»;
- «»;
- «»;
- «».
Източник: habr.com
