Rook o non Rook: questo è il dilemma

Rook o non Rook: questo è il dilemma

All'inizio di questo mese, il 3 maggio, è stata annunciata una grande release del "sistema di gestione per i dati distribuiti in Kubernetes" — Rook 1.0.0. Più di un anno fa avevamo già pubblicato una panoramica generale su Rook. Allora ci era stato chiesto di raccontare l'esperienza del suo utilizzo pratico — e ora, proprio in occasione di questo importante traguardo nella storia del progetto, siamo lieti di condividere le impressioni accumulate.

In breve, Rook rappresenta un insieme di operatori per Kubernetes, che si occupano completamente del deployment, della gestione e del ripristino automatico di soluzioni di archiviazione come Ceph, EdgeFS, Minio, Cassandra, CockroachDB.

Attualmente, la soluzione più avanzata (e l'unica in in fase stabile) è rook-ceph-operator : tra le modifiche significative nella release Rook 1.0.0 relative a Ceph, possiamo menzionare il supporto per Ceph Nautilus e la possibilità di utilizzare NFS per i bucket CephFS o RGW. Tra l'altro, è stata raggiunta la fase beta per il supporto di EdgeFS..

Nota: среди значимых изменений в релизе Rook 1.0.0, связанных с Ceph, можно отметить поддержку Сeph Nautilus и возможность использовать NFS для CephFS- или RGW-бакетов. Из прочих выделяется «созревание» поддержки EdgeFS до уровня беты.

Quindi, in questo articolo:

  • risponderemo alla domanda su quali vantaggi vediamo nell'utilizzo di Rook per il deployment di Ceph in un cluster Kubernetes;
  • condivideremo l'esperienza e le impressioni derivate dall'uso di Rook in produzione;
  • Scopriremo perché diciamo «Sì!» a Rook e quali sono i nostri piani per lui.

Iniziamo con concetti e teorie generali.

«Ho un vantaggio di una Torre!» (un giocatore di scacchi ignoto)

Rook o non Rook: questo è il dilemma

Uno dei principali vantaggi di Rook è che l'interazione con i data storage avviene tramite meccanismi Kubernetes. Questo significa che non è più necessario copiare i comandi per configurare Ceph da un foglietto alla console.

— Vuoi distribuire in un cluster CephFS? Basta scrivere un file YAML!
— Cosa? Vuoi distribuire anche un object store con S3 API? Basta scrivere un secondo file YAML!

Rook è creato secondo tutte le regole di un tipico operatore. L'interazione con esso avviene tramite CRD (Custom Resource Definitions), in cui descriviamo le caratteristiche necessarie delle entità Ceph (dato che è l'unica implementazione stabile, per default in questo articolo si parlerà di Ceph, salvo esplicita indicazione contraria). In base ai parametri impostati, l'operatore eseguirà automaticamente i comandi necessari alla configurazione.

Vediamo i dettagli con l'esempio di creazione di un Object Store, e più precisamente — 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 }}

I parametri elencati nell'elenco sono abbastanza standard e non necessitano di commenti particolari, tuttavia è importante prestare particolare attenzione a quelli evidenziati come variabili nel template.

Il funzionamento generale si basa sul fatto che attraverso il file YAML richiediamo delle risorse, per cui l'operatore esegue i comandi necessari e ci restituisce un "segreto" che non è del tutto reale, con il quale possiamo poi lavorare. (vedi sotto). Dalle variabili sopra indicate sarà formulato il comando e il nome del segreto.

Qual è quindi questo comando? Quando si crea un utente per lo storage oggetti, l'operatore Rook all'interno del pod eseguirà quanto segue:

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

Il risultato dell'esecuzione di questo comando sarà una struttura JSON:

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

Chiavi — ciò che sarà necessario in futuro alle applicazioni per accedere allo storage object tramite l'API S3. L'operatore Rook si occupa di selezionarli e conservarli nel proprio namespace come segreto chiamato rook-ceph-object-user-{{ $.Values.s3.crdName }}-{{ $.Values.s3.username }}.

Per utilizzare i dati di questo segreto, è sufficiente aggiungerli al contenitore come variabili d'ambiente. Per esempio, ecco un modello per un Job in cui creiamo automaticamente i bucket per ogni ambiente utente:

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

Tutte le azioni elencate in questo lavoro sono state effettuate senza uscire dall'ambito di Kubernetes. Le strutture descritte nei file YAML sono state consolidate in un repository Git e riutilizzate più volte. Questo rappresenta un grande vantaggio per gli ingegneri DevOps e per il processo CI/CD nel suo complesso.

Con Rook e Rados è un piacere.

L'uso della combinazione Ceph + RBD impone determinate limitazioni nel montaggio dei volumi ai pod.

In particolare, nel namespace deve necessariamente trovarsi un segreto per accedere a Ceph, affinché le applicazioni stateful possano funzionare. È normale avere 2-3 ambienti nei propri spazi dei nomi: si può andare a copiare manualmente il segreto. Ma cosa fare se per ogni feature viene creato un ambiente separato con il proprio namespace?

Noi abbiamo risolto questo problema tramite shell-operator, che copiava automaticamente i segreti nei nuovi namespace (un esempio di questo hook è descritto in questo articolo).

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

Tuttavia, nell'uso di Rook, questo problema non esiste. Il processo di montaggio avviene tramite i propri driver basati su Flexvolume o CSI (attualmente in fase beta) e quindi non richiede segreti.

Rook risolve automaticamente molti problemi, il che ci spinge a utilizzarlo in nuovi progetti.

L'assedio di Rook

Concludiamo la parte pratica implementando Rook e Ceph per poter effettuare esperimenti. Per rendere più facile l'assalto a questa torre inespugnabile, gli sviluppatori hanno preparato un pacchetto Helm. Scarichiamolo:

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

Nel file rook-ceph/values.yaml puoi trovare molte impostazioni diverse. La cosa più importante è specificare le tolerations per gli agenti e la ricerca. Di cosa possiamo utilizzare il meccanismo taints/tolerations, ne abbiamo parlato dettagliatamente in questo articolo.

In breve, non vogliamo che i pod con l'applicazione client si trovino sugli stessi nodi dove sono situati i dischi per l'archiviazione dei dati. La ragione è semplice: in questo modo il lavoro degli agenti Rook non influenzerà l'applicazione stessa.

Quindi, apriamo il file rook-ceph/values.yaml con il nostro editor preferito e aggiungiamo in fondo il seguente blocco:

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

A ogni nodo riservato per l'archiviazione dei dati, aggiungiamo il corrispondente taint:

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

Dopo di che installiamo il chart Helm con il comando:

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

Ora è necessario creare un cluster e specificare la posizione 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"

Controlliamo lo stato di Ceph — ci aspettiamo di vedere 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

Controlliamo inoltre che i pod dell'applicazione client non vengano eseguiti sui nodi riservati di Ceph:

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

Successivamente, se lo si desidera, si possono configurare i componenti aggiuntivi. Maggiori dettagli sono forniti in documentazione. Per l'amministrazione, consigliamo vivamente di installare dashboard e toolbox.

Rook e i suoi limiti: Rook è in grado di soddisfare tutte le esigenze?

Come si può vedere, lo sviluppo di Rook avanza a tutta velocità. Tuttavia, ci sono ancora problemi che ci impediscono di rinunciare completamente alla configurazione manuale di Ceph:

  • Nessun driver Rook è in grado di esportare metriche sull'uso dei volumi montati, il che ci priva del monitoraggio.
  • Flexvolume e CSI non sono in grado di ridimensionare i volumi (a differenza dell'RBD), quindi Rook manca di uno strumento utile (e talvolta critico!).
  • Rook non è ancora flessibile come un Ceph tradizionale. Se volessimo configurare il pool per i metadati CephFS per essere memorizzato su SSD e i dati stessi su HDD, sarà necessario specificare manualmente gruppi separati di dispositivi nelle CRUSH maps.
  • Nonostante il fatto che il rook-ceph-operator sia considerato stabile, ci sono attualmente alcuni problemi nell'aggiornare Ceph dalla versione 13 alla 14.

Conclusioni

«Attualmente la Barca è chiusa al mondo esterno dai pedoni, ma crediamo che un giorno svolgerà un ruolo decisivo nella partita!» (citazione inventata appositamente per questo articolo)

Il progetto Rook ha sicuramente conquistato i nostri cuori — riteniamo che [con tutti i suoi pro e contro] meriti sicuramente anche la vostra attenzione.

I nostri piani futuri si concentrano sul rendere Rook-Ceph un modulo per addon-operator, semplificando ulteriormente il suo utilizzo nei nostri numerosi cluster Kubernetes.

P.S.

Leggete anche nel nostro blog:

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster