Rook o no Rook - esa es la pregunta



A principios de este mes, 3 de mayo, se anunció un lanzamiento importante del "sistema de gestión para almacenes de datos distribuidos en Kubernetes": Rook 1.0.0 . Hace más de un año, ya publicamos una descripción general de Rook. Luego se nos pidió hablar sobre la experiencia de su uso en la práctica , y ahora, a tiempo para un hito tan importante en la historia del proyecto, nos complace compartir nuestras impresiones acumuladas.

En resumen, Rook es un conjunto de operadores para Kubernetes que toman el control completo de la implementación, administración y recuperación automática de soluciones de almacenamiento como Ceph, EdgeFS, Minio, Cassandra, CockroachDB.

Por el momento, la solución más desarrollada (y solo en una etapa estable ) es el operador rook-ceph .

Nota : Entre los cambios significativos en el lanzamiento de Rook 1.0.0 relacionados con Ceph, se puede observar el soporte de Ceph Nautilus y la capacidad de utilizar NFS para CephFS o RGW. Entre otros, se destaca la "maduración" del soporte de EdgeFS para el nivel beta.

Entonces, en este artículo nosotros:

  • responda la pregunta de qué ventajas vemos al usar Rook para implementar Ceph en el clúster de Kubernetes;
  • compartir experiencias e impresiones sobre el uso de Rook en la producción;
  • Le diremos por qué decimos "¡Sí!" A Rook y nuestros planes para él.

Comencemos con los conceptos generales y la teoría.

"¡Tengo una ventaja en una Torre!" (jugador de ajedrez desconocido)




Una de las principales ventajas de Rook es que la interacción con los almacenes de datos se lleva a cabo a través de mecanismos de Kubernetes. Esto significa que ya no necesita copiar los comandos para configurar Ceph desde el folleto a la consola.

- ¿Desea implementar en un clúster CephFS? ¡Solo escribe un archivo yaml!
- que? ¿Desea implementar un almacén de objetos con la API S3? ¡Solo escribe un segundo archivo yaml!

Rook es creado por todas las reglas de un operador típico. La interacción con él ocurre con la ayuda de CRD (Definiciones de recursos personalizadas) , en la que describimos las características de las entidades Ceph que necesitamos (dado que esta es la única implementación estable, por defecto el artículo hablará de Ceph, a menos que se indique explícitamente lo contrario) . De acuerdo con los parámetros especificados, el operador ejecutará automáticamente los comandos necesarios para la configuración.

Veamos los detalles utilizando el ejemplo de crear un Almacén de objetos, o más bien 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 }} 

Los parámetros indicados en la lista son bastante estándar y es poco probable que necesiten comentarios, pero debe prestar especial atención a los que están resaltados en las variables de la plantilla.

El esquema general de trabajo se reduce al hecho de que a través del archivo YAML "ordenamos" recursos, para lo cual el operador ejecuta los comandos necesarios y nos devuelve el secreto "no real", con el que podemos continuar trabajando (ver más abajo) . Y a partir de las variables que se indican arriba, se compondrá el comando y el nombre del secreto.

¿Qué tipo de equipo es este? Al crear un usuario para el almacenamiento de objetos, la instrucción Rook dentro del pod hará lo siguiente:

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

El resultado de este comando será una estructura JSON:

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

Keys es lo que necesitarán las aplicaciones futuras para acceder al almacenamiento de objetos a través de la API S3. El operador de rook-ceph-object-user-{{ $.Values.s3.crdName }}-{{ $.Values.s3.username }} selecciona amablemente y los coloca en su espacio de nombres en forma de secreto con el nombre rook-ceph-object-user-{{ $.Values.s3.crdName }}-{{ $.Values.s3.username }} .

Para usar datos de este secreto, simplemente agréguelos al contenedor como variables de entorno. Como ejemplo, daré una plantilla para Job, en la que creamos automáticamente cubos para cada entorno de usuario:

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

Todas las actividades enumeradas en este trabajo se realizaron sin ir más allá de Kubernetes. Las estructuras descritas en los archivos YAML se pliegan en el repositorio de Git y se reutilizan repetidamente. En esto vemos una gran ventaja para los ingenieros de DevOps y el proceso de CI / CD en su conjunto.

Con Rook y Rados a Joy


El uso de un montón de Ceph + RBD impone ciertas restricciones en el montaje de volúmenes en pods.

En particular, el espacio de nombres debe tener un secreto para acceder a Ceph para que las aplicaciones con estado puedan funcionar. Está bien si tiene 2-3 entornos en sus espacios de nombres: puede ir y copiar el secreto manualmente. Pero, ¿qué sucede si cada característica del desarrollador crea un entorno separado con su propio espacio de nombres?

Resolvimos este problema con la ayuda de un operador de shell , que copiaba automáticamente los secretos en el nuevo espacio de nombres (en este artículo se describe un ejemplo de dicho enlace).

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

Sin embargo, cuando se usa Rook, este problema simplemente no existe. El proceso de montaje se lleva a cabo utilizando sus propios controladores basados ​​en Flexvolume o CSI (todavía en beta) y, por lo tanto, no requiere secretos.

Rook resuelve automáticamente muchos problemas, lo que nos anima a usarlo en nuevos proyectos.

Asedio de la torre


Completamos la parte práctica con el despliegue de Rook y Ceph para la posibilidad de realizar nuestros propios experimentos. Para asaltar esta torre inexpugnable, fue más fácil, los desarrolladores han preparado un paquete Helm. Vamos a descargarlo:

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

rook-ceph/values.yaml encontrar muchas configuraciones diferentes en el archivo rook-ceph/values.yaml . Lo más importante, especifique tolerancias para agentes y búsqueda. Por qué puede utilizar el mecanismo de tolerancias / contaminaciones, lo describimos en detalle en este artículo .

En resumen, no queremos que los pods con la aplicación cliente se ubiquen en los mismos nodos donde se encuentran los discos para el almacenamiento de datos. La razón es simple: de esta manera, el trabajo de los agentes de Rook no afectará a la aplicación en sí.

Entonces, abra el archivo rook-ceph/values.yaml editor favorito y agregue el siguiente bloque al final:

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

Para cada nodo reservado para el almacenamiento de datos, agregue la mancha correspondiente:

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

Luego instale el Helm-chart con el comando:

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

Ahora necesita crear un clúster e indicar la ubicación del 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" 

Verifique el estado de Ceph: espere ver 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 

Al mismo tiempo, verifique que los pods con la aplicación cliente no lleguen a los nodos reservados para Ceph:

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

Otros componentes opcionales están configurados. Más información sobre ellos se indica en la documentación . Para la administración, recomendamos instalar el tablero y la caja de herramientas.

Grajos y ganchos: ¿es suficiente Grajo para todo?


Como puede ver, el desarrollo de Rook está en pleno apogeo. Pero todavía hay problemas que no nos permiten abandonar por completo la configuración manual de Ceph:

  • Ningún controlador de Rook puede exportar métricas sobre el uso de bloques montados, lo que nos priva de la supervisión.
  • Flexvolume y CSI no saben cómo cambiar el tamaño de los volúmenes (a diferencia del mismo RBD), por lo que Rook pierde una herramienta útil (¡y a veces críticamente necesaria!).
  • Rook todavía no es tan flexible como Ceph normal. Si queremos configurar el grupo para que los metadatos CephFS se almacenen en el SSD, y los datos en sí mismos en el HDD, necesitaremos registrar manualmente grupos de dispositivos individuales en los mapas CRUSH.
  • A pesar de que rook-ceph-operator se considera estable, por el momento existen ciertos problemas al actualizar Ceph de la versión 13 a la 14.

Conclusiones


"Ahora Rook está cerrada del mundo exterior por peones, ¡pero creemos que algún día ella jugará un papel decisivo en la fiesta!" (una cita fue inventada específicamente para este artículo)

El proyecto Rook, sin duda, se ha ganado nuestros corazones: creemos que [con todas sus ventajas y desventajas] definitivamente merece su atención.

Nuestros planes adicionales se reducen a hacer de rook-ceph un módulo para el operador de complementos , lo que hará que su uso en nuestros muchos grupos de Kubernetes sea aún más simple y conveniente.

PS


Lea también en nuestro blog:

Source: https://habr.com/ru/post/451818/


All Articles