Rook или не Rook — вот в чём въпрос

Rook или не Rook — вот в чём въпрос

В началото на този месец, 3 май, беше анонсиран голям релиз на «системата за управление на разпределени хранилища на данни в Kubernetes» — Rook 1.0.0. Повече от година вече публикуваме общ преглед на Rook. Тогава ни молеха да разкажем за опита си с използването му на практика — и ето, точно навреме за такава значима веха в историята на проекта, сме щастливи да споделим натрупаните впечатления. Ако накратко, Rook представлява набор

от оператори за Kubernetes, които напълно поемат контрол над разгръщането, управлението и автоматичното възстановяване на решения за съхранение на данни, като Ceph, EdgeFS, Minio, Cassandra, CockroachDB. В момента най-развитото (и

единствено стабилна в фаза) решение е rook-ceph-operator : сред значимите промени в релиза Rook 1.0.0, свързани с Ceph, мога да отбележа поддръжка на Ceph Nautilus и възможността да се използва NFS за CephFS или RGW контейнери. От останалите се откроява "узряването" на поддръжката на EdgeFS до бета ниво..

ЗабележкаИ така, в тази статия ние:

ще отговорим на въпроса какви предимства виждаме в използването на Rook за разгръщане на Ceph в клъстера Kubernetes;

  • ще споделим опит и впечатления от използването на Rook в продукция;
  • ще разкажем защо казваме на Rook „Да!“, и за нашите планове относно него.
  • Нека започнем с общи концепции и теория.

„Имате предимство с една ладия!“ (неизвестен шахматист)

Едно от основните предимства на Rook е, че взаимодействието с хранилищата на данни се извършва чрез механизмите на Kubernetes. Това означава, че вече не е необходимо да копирате команди за настройка на Ceph от бележки в конзолата.

Rook или не Rook — вот в чём въпрос

— Искаш ли да разгръщаш CephFS в клъстера? Просто напиши YAML файл!

­— Какво? Искаш ли да разгръщаш и обектно хранилище с S3 API? Просто напиши втори YAML файл!
Rook е създаден по всички правила на типичен оператор. Взаимодействието с него се извършва чрез

CRD (Custom Resource Definitions) , в които описваме необходимите характеристики на обектите Ceph(тъй като това е единствената стабилна реализация, в статията ще става дума именно за 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?

При нас решихме този проблем с помощта на shell-operator, който автоматично копираше секрети в нови 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, този проблем просто не съществува. Процесът на монтиране се извършва чрез собствени драйвери на базата на Flexvolume или CSI (все още в бета стадий) и следователно не изисква секрети.

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

Сега е необходимо да създадем клъстер и да укажем местоположението на OSD:

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 модул за addon-operator, което ще направи използването му в нашите многобройни Kubernetes клъстери още по-просто и удобно.

P.S.

Прочетете също в нашия блог:

Източник: habr.com

Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри 🔥 Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри | ProHoster