GlusterFS como almacenamiento externo para Kubernetes

imagen
Encontrar el almacenamiento óptimo es un proceso bastante complicado, todo tiene sus ventajas y desventajas. Por supuesto, el líder en esta categoría es CEPH, pero es un sistema bastante complejo, aunque con una funcionalidad muy rica. Para nosotros, dicho sistema es redundante, dado que necesitábamos un almacenamiento replicado simple en modo maestro-maestro para un par de terabytes. Habiendo estudiado mucho material, se decidió probar el producto más moderno del mercado para el circuito que nos interesa. Debido al hecho de que no se encontró una solución preparada de dicho plan, me gustaría compartir mis mejores prácticas sobre este tema y describir los problemas que encontramos en el proceso de implementación.

Metas


¿Qué esperábamos del nuevo repositorio:

  • Capacidad para trabajar con un número par de nodos para la replicación.
  • Fácil instalación, configuración, soporte
  • El sistema debe ser adulto, probado y usuarios.
  • Capacidad para ampliar el espacio de almacenamiento sin tiempo de inactividad
  • El almacenamiento debe ser compatible con Kubernetes
  • Debería haber una conmutación por error automática cuando uno de los nodos falla

Sobre el último punto tenemos muchas preguntas.

Despliegue


Para la implementación, se crearon dos máquinas virtuales en CentOs 8. Cada una de ellas está conectada a través de un disco adicional con almacenamiento.

Preparación preliminar


Para GlusterFS, debe asignar un disco separado con XFS para que no afecte al sistema de ninguna manera.

Seleccione la partición:

$ fdisk /dev/sdb
Command (m for help): n
Partition type
   p   primary (0 primary, 0 extended, 4 free)
   e   extended (container for logical partitions)
Select (default p): p
Partition number (1-4, default 1):  1
First sector (2048-16777215, default 2048): 
Last sector, +sectors or +size{K,M,G,T,P} (2048-16777215, default 16777215): 
 
Created a new partition 1 of type ‘Linux’ and of size 8 GiB.
Command (m for help): w 

The partition table has been altered.
Calling ioctl() to re-read partition table. Syncing disks.

Formatear en XFS y montar:

$ mkfs.xfs /dev/sdb1
$ mkdir /gluster
$ mount /dev/sdb1 /gluster

Y para colmo, suelte la entrada en / etc / fstab para montar automáticamente el directorio al inicio del sistema:

/dev/sdb1       /gluster        xfs     defaults        0       0

Instalación


Con respecto a la instalación, se han escrito muchos artículos, en este sentido no profundizaremos en el proceso, solo consideraremos a qué vale la pena prestarle atención.

En ambos nodos, instale y ejecute la última versión de glusterfs:

$ wget -P /etc/yum.repos.d  https://download.gluster.org/pub/gluster/glusterfs/LATEST/CentOS/glusterfs-rhel8.repo
$ yum -y install yum-utils
$ yum-config-manager --enable PowerTools
$ yum install -y glusterfs-server
$ systemctl start glusterd

A continuación, debe decirle al glaster dónde está su nodo vecino. Se realiza con un solo nodo. Un punto importante: si tiene una red de dominio, debe especificar el nombre del servidor con el dominio, de lo contrario en el futuro tendrá que rehacer todo.

$ gluster peer probe gluster-02.example.com

Si fue exitoso, entonces verificamos la conexión con el comando desde ambos servidores:

$ gluster peer status
Number of Peers: 1

Hostname: gluster-02.example.com
Uuid: a6de3b23-ee31-4394-8bff-0bd97bd54f46
State: Peer in Cluster (Connected)
Other names:
10.10.6.72

Ahora puede crear un Volumen en el que escribiremos.

gluster volume create main replica 2 gluster-01.example.com:/gluster/main gluster-02.example.com:/gluster/main force

Dónde:

  • main - nombre Volumen
  • réplica - escriba Volumen (se pueden encontrar más detalles en la documentación oficial )
  • 2 - número de réplicas

Ejecute Volume y verifique su rendimiento:

gluster volume start main
gluster volume status main

Para el volumen replicado, se recomienda establecer los siguientes parámetros:

$ gluster volume set main network.ping-timeout 5
$ gluster volume set main cluster.quorum-type fixed
$ gluster volume set main cluster.quorum-count 1
$ gluster volume set main performance.quick-read on

Con estos simples pasos, hemos creado un clúster GlusterFS. Queda por conectarse y verificar el rendimiento. Ubuntu está instalado en la máquina del cliente, para el montaje necesita instalar el cliente:

$ add-apt-repository ppa:gluster/glusterfs-7
$ apt install glusterfs-client
$ mkdir /gluster
$ mount.glusterfs gluster-01.example.com:/main /gluster

Gluster, cuando está conectado a uno de los nodos, proporciona las direcciones de todos los nodos y se conecta automáticamente a todos. Si el cliente ya se ha conectado, la falla de uno de los nodos no llevará a un alto. Pero si el primer nodo no está disponible, no será posible conectarse en caso de interrupción de la sesión. Para hacer esto, al montar, puede pasar el parámetro backupvolfile que indica el segundo nodo.
mount.glusterfs gluster-01.example.com:/main /gluster -o backupvolfile-server=gluster-02.example.com

Un punto importante: gluster sincroniza archivos entre nodos solo si su cambio fue a través del volumen montado. Si realiza cambios directamente en los nodos, el archivo no estará sincronizado.

Conectar a Kubernetes


En esta etapa, comenzaron las preguntas: "¿Cómo conectarlo?". Y hay varias opciones. Considerarlos.

Heketi


Lo más popular y recomendado es utilizar un servicio externo: heketi. heketi es una capa entre kubernetes y gluster, que le permite administrar y trabajar con el almacenamiento a través de http. Pero heketi será ese único punto de falla, porque El servicio no está agrupado. La segunda instancia de este servicio no podrá funcionar de forma independiente, porque cualquier cambio se almacena en la base de datos local. Ejecutar este servicio en kubernetes tampoco es adecuado, porque necesita un disco estático en el que se almacenará su base de datos. En este sentido, esta opción resultó ser la más inapropiada.

Punto final en Kubernetes


Si tiene Kubernetes en sistemas con gestores de paquetes, esta es una opción muy conveniente. El punto es que para todos los servidores GlusteFS en Kubernetes, se crea un punto final común. Se cuelga un servicio en este Endpoint y ya estaremos montados en este servicio. Para que esta opción funcione, es necesario instalar glusterfs-client en cada nodo de Kubernetes y asegurarse de que se pueda montar. En Kubernetes, implemente la siguiente configuración:

apiVersion: v1
kind: Endpoints
metadata: 
  name: glusterfs-cluster
subsets:
  - addresses:
      #  ip  
      - ip: 10.10.6.71
    ports:
      #    1,    
      - port: 1
  - addresses:
      - ip: 10.10.6.72
    ports:
      - port: 1

---
apiVersion: v1
kind: Service
metadata:
  name: glusterfs-cluster
spec:
  ports:
  - port: 1

Ahora podemos crear una implementación de prueba simple y verificar cómo funciona el montaje. A continuación se muestra un ejemplo de una implementación de prueba simple:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: gluster-test
spec:
  replicas: 1
  selector:
    matchLabels:
      app: gluster-test
  template:
    metadata:
      labels:
        app: gluster-test
    spec:
      volumes:
      - name: gluster
        glusterfs:
          endpoints: glusterfs-cluster
          path: main
      containers:
      - name: gluster-test
        image: nginx
        volumeMounts:
        - name: gluster
          mountPath: /gluster

Esta opción no nos convenía, porque tenemos container-linux en todos los nodos de Kubernetes. El administrador de paquetes no está allí, por lo que no fue posible instalar gluster-client para el montaje. En este sentido, se encontró la tercera opción, que se decidió utilizar.

GlusterFS + NFS + keepalived


Hasta hace poco, GlusterFS ofrecía su propio servidor NFS, pero ahora el servicio externo nfs-ganesha se usa para NFS. Se ha escrito bastante sobre esto, en relación con esto, descubriremos cómo configurarlo.

El repositorio debe registrarse manualmente. Para hacer esto, en el archivo /etc/yum.repos.d/nfs-ganesha.repo agregamos:

[nfs-ganesha]
name=nfs-ganesha
baseurl=https://download.nfs-ganesha.org/2.8/2.8.0/RHEL/el-8/$basearch/
enabled=1
gpgcheck=1
[nfs-ganesha-noarch]
name=nfs-ganesha-noarch
baseurl=https://download.nfs-ganesha.org/2.8/2.8.0/RHEL/el-8/noarch/
enabled=1
gpgcheck=1

E instalar:

yum -y install nfs-ganesha-gluster --nogpgcheck

Después de la instalación, llevamos a cabo la configuración básica en el archivo /etc/ganesha/ganesha.conf.

# create new
NFS_CORE_PARAM {
    # possible to mount with NFSv3 to NFSv4 Pseudo path
    mount_path_pseudo = true;
    # NFS protocol
    Protocols = 3,4;
}
EXPORT_DEFAULTS {
    # default access mode
    Access_Type = RW;
}
EXPORT {
    # uniq ID
    Export_Id = 101;
    # mount path of Gluster Volume
    Path = "/gluster/main";
    FSAL {
        # any name
        name = GLUSTER;
        # hostname or IP address of this Node
        hostname="gluster-01.example.com";
        # Gluster volume name
        volume="main";
    }
    # config for root Squash
    Squash="No_root_squash";
    # NFSv4 Pseudo path
    Pseudo="/main";
    # allowed security options
    SecType = "sys";
}
LOG {
    # default log level
    Default_Log_Level = WARN;
}

Necesitamos iniciar el servicio, habilitar nfs para nuestro volumen y verificar que esté activado.

$ systemctl start nfs-ganesha
$ systemctl enable nfs-ganesha
$ gluster volume set main nfs.disable off
$ gluster volume status main

Como resultado, el estado debe indicar que el servidor nfs se ha iniciado para nuestro volumen. Necesitas montar y verificar.

mkdir /gluster-nfs
mount.nfs gluster-01.example.com:/main /gluster-nfs

Pero esta opción no es tolerante a fallas, por lo que debe crear una dirección VIP que viajará entre nuestros dos nodos y ayudará a cambiar el tráfico si uno de los nodos cae.

La instalación de keepalived en CentOs se realiza inmediatamente a través del administrador de paquetes.

$ yum install -y keepalived

Configuramos el servicio en el archivo /etc/keepalived/keepalived.conf:

global_defs {
    notification_email {
        admin@example.com
    }
    notification_email_from alarm@example.com
    smtp_server mail.example.com
    smtp_connect_timeout 30

    vrrp_garp_interval 10
    vrrp_garp_master_refresh 30
}

#C   ,   .    , VIP .
vrrp_script chk_gluster {
    script "pgrep glusterd"
    interval 2
}

vrrp_instance gluster {
    interface ens192
    state MASTER #     BACKUP
    priority 200 #      ,  100
    virtual_router_id 1
    virtual_ipaddress {
        10.10.6.70/24
    }

    unicast_peer {
        10.10.6.72 #        
    }

    track_script {
        chk_gluster
    }
}

Ahora podemos iniciar el servicio y verificar que aparezca el VIP en el nodo:

$ systemctl start keepalived
$ systemctl enable keepalived
$ ip addr
1: ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:50:56:97:55:eb brd ff:ff:ff:ff:ff:ff
    inet 10.10.6.72/24 brd 10.10.6.255 scope global noprefixroute ens192
       valid_lft forever preferred_lft forever
    inet 10.10.6.70/24 scope global secondary ens192
       valid_lft forever preferred_lft forever

Si todo funcionó para nosotros, entonces queda agregar PersistentVolume a Kubernetes y crear un servicio de prueba para verificar la operación.

---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: gluster-nfs
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  nfs:
    server: 10.10.6.70
    path: /main

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
 name: gluster-nfs
spec:
 accessModes:
 - ReadWriteMany
 resources:
   requests:
     storage: 10Gi
 volumeName: "gluster-nfs"

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: gluster-test
  labels:
    app: gluster-test
spec:
  replicas: 1
  selector:
    matchLabels:
      app: gluster-test
  template:
    metadata:
      labels:
        app: gluster-test
    spec:
      volumes:
      - name: gluster
        persistentVolumeClaim:
          claimName: gluster-nfs
      containers:
      - name: gluster-test
        image: nginx
        volumeMounts:
        - name: gluster
          mountPath: /gluster

Con esta configuración, en caso de una caída del nodo principal, estará inactivo durante aproximadamente un minuto hasta que el montaje se caiga en el tiempo de espera y cambie. Simple por un minuto para este almacenamiento, digamos que esta no es una situación normal y rara vez nos encontraremos con ella, pero en este caso el sistema cambiará automáticamente y continuará funcionando, y podremos resolver el problema y llevar a cabo la recuperación sin preocuparnos por lo simple.

Resumen


En este artículo, examinamos 3 posibles opciones para conectar GlusterFS a Kubernetes, en nuestra versión es posible agregar un aprovisionador a Kubernetes, pero aún no lo necesitamos. Queda por agregar los resultados de las pruebas de rendimiento entre NFS y Gluster en los mismos nodos.

Archivos en 1Mb:

sync; dd if=/dev/zero of=tempfile bs=1M count=1024; sync
Gluster: 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 2.63496 s, 407 MB/s
NFS: 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 5.4527 s, 197 MB/s

Archivos en 1Kb:

sync; dd if=/dev/zero of=tempfile bs=1K count=1048576; sync
Gluster: 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 70.0508 s, 15.3 MB/s
NFS: 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 6.95208 s, 154 MB/s

NFS funciona igual para cualquier tamaño de archivo, la diferencia de velocidad no es particularmente notable, a diferencia de GlusterFS, que está muy degradada con archivos pequeños. Pero al mismo tiempo, con archivos de gran tamaño, NFS muestra un rendimiento 2-3 veces menor que Gluster.

All Articles