Zu Rook oder nicht zu Rook – das ist hier die Frage

Zu Rook oder nicht zu Rook – das ist hier die Frage

Anfang dieses Monats, am 3. Mai, wurde eine Hauptveröffentlichung eines „Verwaltungssystems für die verteilte Datenspeicherung in Kubernetes“ angekündigt – Turm 1.0.0. Vor mehr als einem Jahr haben wir bereits veröffentlicht allgemeiner Überblick über Rook. Dann wurden wir gebeten, über seine Erfahrungen zu sprechen in der Praxis nutzen – und jetzt, gerade rechtzeitig zu einem so bedeutenden Meilenstein in der Geschichte des Projekts, teilen wir gerne unsere gesammelten Eindrücke.

Kurz gesagt, Rook ist ein Set Betreiber für Kubernetes, die die volle Kontrolle über die Bereitstellung, Verwaltung und automatische Wiederherstellung von Datenspeicherlösungen wie Ceph, EdgeFS, Minio, Cassandra, CockroachDB übernehmen.

Im Moment ist das am weitesten entwickelte (und der einzige в stabil Stufe) ist die Lösung Rook-Ceph-Operator.

Beachten: Zu den wesentlichen Änderungen in der Rook 1.0.0-Version im Zusammenhang mit Ceph zählen die Unterstützung für Ceph Nautilus und die Möglichkeit, NFS für CephFS- oder RGW-Buckets zu verwenden. Was unter anderem hervorsticht, ist die Reifung der EdgeFS-Unterstützung auf die Beta-Ebene.

In diesem Artikel gehen wir also wie folgt vor:

  • Beantworten wir die Frage, welche Vorteile wir in der Verwendung von Rook für die Bereitstellung von Ceph in einem Kubernetes-Cluster sehen.
  • Wir werden unsere Erfahrungen und Eindrücke vom Einsatz von Rook in der Produktion teilen;
  • Erzählen wir Ihnen, warum wir zu Rook „Ja!“ sagen und welche Pläne wir für ihn haben.

Beginnen wir mit allgemeinen Konzepten und Theorie.

„Ich habe einen Turmvorteil!“ (unbekannter Schachspieler)

Zu Rook oder nicht zu Rook – das ist hier die Frage

Einer der Hauptvorteile von Rook besteht darin, dass die Interaktion mit Datenspeichern über Kubernetes-Mechanismen erfolgt. Das bedeutet, dass Sie die Befehle zur Konfiguration von Ceph nicht mehr vom Blatt in die Konsole kopieren müssen.

— Möchten Sie CephFS in einem Cluster bereitstellen? Schreiben Sie einfach eine YAML-Datei!
- Was? Möchten Sie auch einen Objektspeicher mit S3-API bereitstellen? Schreiben Sie einfach eine zweite YAML-Datei!

Rook wird nach allen Regeln eines typischen Operators erstellt. Die Interaktion mit ihm erfolgt über CRD (Benutzerdefinierte Ressourcendefinitionen), in dem wir die Eigenschaften der von uns benötigten Ceph-Entitäten beschreiben (Da dies die einzige stabile Implementierung ist, wird in diesem Artikel standardmäßig auf Ceph eingegangen, sofern nicht ausdrücklich anders angegeben.). Entsprechend den angegebenen Parametern führt der Bediener automatisch die zur Konfiguration erforderlichen Befehle aus.

Schauen wir uns die Einzelheiten am Beispiel der Erstellung eines Objektspeichers an, oder besser gesagt - 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 }}

Die in der Auflistung angegebenen Parameter sind ziemlich standardisiert und bedürfen kaum eines Kommentars, es lohnt sich jedoch, den Parametern, die den Vorlagenvariablen zugewiesen sind, besondere Aufmerksamkeit zu schenken.

Das allgemeine Arbeitsschema besteht darin, dass wir Ressourcen über eine YAML-Datei „bestellen“, für die der Operator die erforderlichen Befehle ausführt und uns ein „nicht ganz so reales“ Geheimnis zurückgibt, mit dem wir weiterarbeiten können (siehe unten). Und aus den oben aufgeführten Variablen werden der Befehls- und der Geheimname zusammengestellt.

Was ist das für ein Team? Beim Erstellen eines Benutzers für die Objektspeicherung führt der Rook-Operator im Pod Folgendes aus:

radosgw-admin user create --uid="rook-user" --display-name="{{ .Values.s3.username }}"

Das Ergebnis der Ausführung dieses Befehls ist eine JSON-Struktur:

{
    "user_id": "rook-user",
    "display_name": "{{ .Values.s3.username }}",
    "keys": [
        {
           "user": "rook-user",
           "access_key": "NRWGT19TWMYOB1YDBV1Y",
           "secret_key": "gr1VEGIV7rxcP3xvXDFCo4UDwwl2YoNrmtRlIAty"
        }
    ],
    ...
}

Keys - was zukünftige Anwendungen benötigen, um über die S3-API auf Objektspeicher zuzugreifen. Der Rook-Operator wählt sie freundlicherweise aus und fügt sie in Form eines Geheimnisses mit dem Namen in seinen Namensraum ein rook-ceph-object-user-{{ $.Values.s3.crdName }}-{{ $.Values.s3.username }}.

Um die Daten aus diesem Geheimnis zu verwenden, fügen Sie sie einfach als Umgebungsvariablen zum Container hinzu. Als Beispiel gebe ich eine Vorlage für Job an, in der wir automatisch Buckets für jede Benutzerumgebung erstellen:

{{- 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 }}

Alle in diesem Job aufgeführten Aktionen wurden im Rahmen von Kubernetes durchgeführt. Die in YAML-Dateien beschriebenen Strukturen werden in einem Git-Repository gespeichert und viele Male wiederverwendet. Wir sehen darin ein großes Plus für DevOps-Ingenieure und den CI/CD-Prozess insgesamt.

Glücklich mit Rook und Rados

Die Verwendung der Ceph + RBD-Kombination führt zu bestimmten Einschränkungen beim Mounten von Volumes in Pods.

Insbesondere muss der Namespace ein Geheimnis für den Zugriff auf Ceph enthalten, damit zustandsbehaftete Anwendungen funktionieren. Es ist in Ordnung, wenn Sie 2-3 Umgebungen in ihren Namensräumen haben: Sie können das Geheimnis manuell kopieren. Was aber, wenn für jedes Feature eine eigene Umgebung mit eigenem Namensraum für Entwickler erstellt wird?

Wir haben dieses Problem selbst gelöst Shell-Operator, wodurch Geheimnisse automatisch in neue Namespaces kopiert wurden (ein Beispiel für einen solchen Hook wird in beschrieben Dieser Artikel).

#! /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

Bei Verwendung von Rook besteht dieses Problem jedoch einfach nicht. Der Montagevorgang erfolgt mithilfe eigener Treiber basierend auf Flexvolumen oder CSI (noch im Beta-Stadium) und erfordert daher keine Geheimnisse.

Rook löst automatisch viele Probleme, was uns ermutigt, es in neuen Projekten einzusetzen.

Belagerung von Rook

Lassen Sie uns den praktischen Teil abschließen, indem wir Rook und Ceph einsetzen, damit wir unsere eigenen Experimente durchführen können. Um den Sturm auf diesen uneinnehmbaren Turm zu erleichtern, haben die Entwickler ein Helm-Paket vorbereitet. Laden wir es herunter:

$ helm fetch rook-master/rook-ceph --untar --version 1.0.0

Im Ordner rook-ceph/values.yaml Sie können viele verschiedene Einstellungen finden. Das Wichtigste ist, Toleranzen für Agenten und Suche festzulegen. Wir haben ausführlich beschrieben, wofür der Taints/Tolerationsmechanismus verwendet werden kann Dieser Artikel.

Kurz gesagt: Wir möchten nicht, dass sich die Client-Anwendungs-Pods auf denselben Knoten befinden wie die Datenspeicherplatten. Der Grund ist einfach: Auf diese Weise hat die Arbeit der Rook-Agenten keinen Einfluss auf die Anwendung selbst.

Öffnen Sie also die Datei rook-ceph/values.yaml mit Ihrem Lieblingseditor und fügen Sie am Ende den folgenden Block hinzu:

discover:
  toleration: NoExecute
  tolerationKey: node-role/storage
agent:
  toleration: NoExecute
  tolerationKey: node-role/storage
  mountSecurityMode: Any

Fügen Sie für jeden für die Datenspeicherung reservierten Knoten den entsprechenden Taint hinzu:

$ kubectl taint node ${NODE_NAME} node-role/storage="":NoExecute

Anschließend installieren Sie das Helm-Chart mit dem Befehl:

$ helm install --namespace ${ROOK_NAMESPACE} ./rook-ceph

Jetzt müssen Sie einen Cluster erstellen und den Standort angeben 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-Status wird überprüft – wir werden es sehen 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

Überprüfen wir gleichzeitig, ob die Pods mit der Client-Anwendung nicht auf für Ceph reservierten Knoten landen:

$ kubectl -n ${APPLICATION_NAMESPACE} get pods -o custom-columns=NAME:.metadata.name,NODE:.spec.nodeName

Darüber hinaus können weitere Komponenten nach Wunsch konfiguriert werden. Weitere Details dazu finden Sie in Dokumentation. Für die Administration empfehlen wir dringend die Installation des Dashboards und der Toolbox.

Turm und Haken: Reicht Turm für alles?

Wie Sie sehen, ist die Entwicklung von Rook in vollem Gange. Es gibt jedoch immer noch Probleme, die es uns nicht erlauben, vollständig auf die manuelle Konfiguration von Ceph zu verzichten:

  • Kein Turmtreiber kann nicht Exportieren Sie Metriken zur Verwendung gemounteter Blöcke, was uns die Überwachung entzieht.
  • Flexvolume und CSI weiß nicht wie Ändern Sie die Größe von Volumes (im Gegensatz zum gleichen RBD), sodass Rook ein nützliches (und manchmal dringend benötigtes!) Tool vorenthält.
  • Rook ist immer noch nicht so flexibel wie der normale Ceph. Wenn wir den Pool für die Speicherung von CephFS-Metadaten auf SSD und die Daten selbst für die Speicherung auf der Festplatte konfigurieren möchten, müssen wir separate Gerätegruppen manuell in CRUSH-Karten registrieren.
  • Obwohl Rook-Ceph-Operator als stabil gilt, gibt es derzeit einige Probleme beim Upgrade von Ceph von Version 13 auf 14.

Befund

„Im Moment ist Rook durch Bauern von der Außenwelt abgeschottet, aber wir glauben, dass sie eines Tages eine entscheidende Rolle im Spiel spielen wird!“ (Zitat speziell für diesen Artikel erfunden)

Das Rook-Projekt hat zweifellos unsere Herzen erobert – wir glauben, dass es [mit all seinen Vor- und Nachteilen] auf jeden Fall Ihre Aufmerksamkeit verdient.

Unsere Zukunftspläne laufen darauf hinaus, Rook-Ceph zu einem Modul für zu machen Addon-Operator, was den Einsatz in unseren zahlreichen Kubernetes-Clustern noch einfacher und komfortabler machen wird.

PS

Lesen Sie auch auf unserem Blog:

Source: habr.com

Kommentar hinzufügen