
Au début de ce mois, le 3 mai, une version majeure d'un « système de gestion du stockage de données distribué dans Kubernetes » a été annoncée - . Il y a plus d'un an, nous aperçu général de Rook. Ensuite, on nous a demandé de parler de son expérience utilisation en pratique — et maintenant, juste à temps pour une étape aussi importante dans l'histoire du projet, nous sommes heureux de partager nos impressions accumulées.
Bref, Rook est un ensemble pour Kubernetes, qui prennent le contrôle total du déploiement, de la gestion, de la récupération automatique des solutions de stockage de données telles que Ceph, EdgeFS, Minio, Cassandra, CockroachDB.
À l'heure actuelle, le plus développé (et в stable étape), la solution est .
Noter: Parmi les changements significatifs de la version Rook 1.0.0 liés à Ceph, on peut noter le support de Ceph Nautilus et la possibilité d'utiliser NFS pour les buckets CephFS ou RGW. Ce qui ressort entre autres, c'est la maturation du support EdgeFS jusqu'au niveau bêta.
Ainsi, dans cet article, nous :
- Répondons à la question des avantages que nous voyons à utiliser Rook pour déployer Ceph dans un cluster Kubernetes ;
- Nous partagerons notre expérience et nos impressions sur l'utilisation de Rook en production ;
- Voyons pourquoi nous disons « Oui ! » à Rook et quels sont nos projets pour lui.
Commençons par les concepts généraux et la théorie.
"J'ai l'avantage d'une Tour !" (joueur d'échecs inconnu)

L'un des principaux avantages de Rook est que l'interaction avec les magasins de données s'effectue via les mécanismes Kubernetes. Cela signifie que vous n'avez plus besoin de copier les commandes pour configurer Ceph depuis la feuille vers la console.
— Voulez-vous déployer CephFS dans un cluster ? Écrivez simplement un fichier YAML !
- Quoi? Souhaitez-vous également déployer un magasin d'objets avec l'API S3 ? Écrivez simplement un deuxième fichier YAML !
Rook est créé selon toutes les règles d'un opérateur typique. L'interaction avec lui se produit en utilisant , dans lequel nous décrivons les caractéristiques des entités Ceph dont nous avons besoin (puisqu'il s'agit de la seule implémentation stable, par défaut cet article parlera de Ceph, sauf indication contraire explicite). Selon les paramètres spécifiés, l'opérateur exécutera automatiquement les commandes nécessaires à la configuration.
Regardons les détails en utilisant l'exemple de création d'un Object Store, ou plutôt - 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 }}Les paramètres indiqués dans le listing sont assez standards et ne nécessitent guère de commentaires, mais il convient de prêter une attention particulière à ceux attribués aux variables du modèle.
Le schéma général de travail se résume au fait que nous « commandons » les ressources via un fichier YAML, pour lequel l'opérateur exécute les commandes nécessaires et nous renvoie un secret « pas si réel » avec lequel nous pouvons continuer à travailler. (voir ci-dessous). Et à partir des variables répertoriées ci-dessus, la commande et le nom du secret seront compilés.
De quel genre d'équipe s'agit-il ? Lors de la création d'un utilisateur pour le stockage d'objets, l'opérateur Rook à l'intérieur du pod effectuera les opérations suivantes :
radosgw-admin user create --uid="rook-user" --display-name="{{ .Values.s3.username }}"Le résultat de l'exécution de cette commande sera une structure JSON :
{
"user_id": "rook-user",
"display_name": "{{ .Values.s3.username }}",
"keys": [
{
"user": "rook-user",
"access_key": "NRWGT19TWMYOB1YDBV1Y",
"secret_key": "gr1VEGIV7rxcP3xvXDFCo4UDwwl2YoNrmtRlIAty"
}
],
...
} Keys - de quelles futures applications auront besoin pour accéder au stockage objet via l'API S3. L'opérateur Rook les sélectionne gentiment et les met dans son espace de noms sous la forme d'un secret avec le nom rook-ceph-object-user-{{ $.Values.s3.crdName }}-{{ $.Values.s3.username }}.
Pour utiliser les données de ce secret, ajoutez-les simplement au conteneur en tant que variables d'environnement. A titre d'exemple, je vais donner un modèle pour Job, dans lequel nous créons automatiquement des buckets pour chaque environnement utilisateur :
{{- 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 }}Toutes les actions répertoriées dans ce Job ont été réalisées dans le cadre de Kubernetes. Les structures décrites dans les fichiers YAML sont stockées dans un référentiel Git et réutilisées de nombreuses fois. Nous considérons cela comme un énorme avantage pour les ingénieurs DevOps et le processus CI/CD dans son ensemble.
Heureux avec Rook et Rados
L'utilisation de la combinaison Ceph + RBD impose certaines restrictions sur le montage de volumes sur les pods.
En particulier, l'espace de noms doit contenir un secret d'accès à Ceph pour que les applications avec état fonctionnent. Ce n'est pas grave si vous avez 2-3 environnements dans leurs espaces de noms : vous pouvez copier le secret manuellement. Mais que se passerait-il si, pour chaque fonctionnalité, un environnement distinct avec son propre espace de noms était créé pour les développeurs ?
Nous avons résolu ce problème nous-mêmes en utilisant , qui copiait automatiquement les secrets dans de nouveaux espaces de noms (un exemple d'un tel hook est décrit dans ).
#! /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 -
fiCependant, lorsque vous utilisez Rook, ce problème n'existe tout simplement pas. Le processus de montage s'effectue à l'aide de ses propres pilotes basés sur ou (encore en phase bêta) et ne nécessite donc pas de secrets.
Rook résout automatiquement de nombreux problèmes, ce qui nous encourage à l'utiliser dans de nouveaux projets.
Siège de Rook
Terminons la partie pratique en déployant Rook et Ceph afin de pouvoir mener nos propres expériences. Pour faciliter la prise d'assaut de cette tour imprenable, les développeurs ont préparé un package Helm. Téléchargeons-le :
$ helm fetch rook-master/rook-ceph --untar --version 1.0.0 En fichier rook-ceph/values.yaml vous pouvez trouver de nombreux paramètres différents. Le plus important est de préciser les tolérances pour les agents et la recherche. Nous avons décrit en détail à quoi peut servir le mécanisme des contaminations/tolérances. .
En bref, nous ne souhaitons pas que les pods des applications clientes soient situés sur les mêmes nœuds que les disques de stockage de données. La raison est simple : de cette façon, le travail des agents Rook n'affectera pas l'application elle-même.
Alors, ouvrez le fichier rook-ceph/values.yaml avec votre éditeur préféré et ajoutez le bloc suivant à la fin :
discover:
toleration: NoExecute
tolerationKey: node-role/storage
agent:
toleration: NoExecute
tolerationKey: node-role/storage
mountSecurityMode: AnyPour chaque nœud réservé au stockage des données, ajoutez la teinte correspondante :
$ kubectl taint node ${NODE_NAME} node-role/storage="":NoExecuteInstallez ensuite la charte Helm avec la commande :
$ helm install --namespace ${ROOK_NAMESPACE} ./rook-cephVous devez maintenant créer un cluster et spécifier l'emplacement :
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" Vérification de l'état de Ceph - attendez-vous à voir 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 -sEn parallèle, vérifions que les pods avec l'application client ne finissent pas sur des nœuds réservés à Ceph :
$ kubectl -n ${APPLICATION_NAMESPACE} get pods -o custom-columns=NAME:.metadata.name,NODE:.spec.nodeNameDe plus, des composants supplémentaires peuvent être configurés à volonté. Plus de détails à leur sujet sont indiqués dans . Pour l'administration, nous vous recommandons fortement d'installer le tableau de bord et la boîte à outils.
Rook and hooks : Rook est-il suffisant pour tout ?
Comme vous pouvez le constater, le développement de Rook bat son plein. Mais il reste encore des problèmes qui ne permettent pas d'abandonner complètement la configuration manuelle de Ceph :
- Pas de pilote de tour exporter des métriques sur l'utilisation des blocs montés, ce qui nous prive de surveillance.
- Flexvolume et CSI modifiez la taille des volumes (par opposition au même RBD), de sorte que Rook est privé d'un outil utile (et parfois indispensable !).
- Rook n'est toujours pas aussi flexible que Ceph ordinaire. Si nous souhaitons configurer le pool pour que les métadonnées CephFS soient stockées sur SSD et que les données elles-mêmes soient stockées sur le disque dur, nous devrons enregistrer manuellement des groupes distincts de périphériques dans les cartes CRUSH.
- Malgré le fait que rook-ceph-operator soit considéré comme stable, il y a actuellement quelques problèmes lors de la mise à niveau de Ceph de la version 13 à la version 14.
résultats
"Pour l'instant, Rook est fermée au monde extérieur par des pions, mais nous pensons qu'un jour, elle jouera un rôle décisif dans le jeu !" (citation inventée spécifiquement pour cet article)
Le projet Rook a sans aucun doute conquis nos cœurs – nous pensons que [avec tous ses avantages et inconvénients] il mérite définitivement votre attention.
Nos projets futurs se résument à faire de rook-ceph un module pour , ce qui rendra son utilisation dans nos nombreux clusters Kubernetes encore plus simple et pratique.
PS
A lire aussi sur notre blog :
- «";
- «";
- «";
- «";
- «».
Source: habr.com
