User Tools

Site Tools


implementing_high_availability_and_persistent_storage_with_docker_swarm_and_glusterfs

Implementing High Availability and Persistent Storage with Docker Swarm and GlusterFS

Docker Swarm, while enabling the deployment of stacks, lacks built-in volume management. This can be a challenge when you need to distribute and synchronize assets, such as a website, across multiple nodes to prevent discrepancies between replicas. GlusterFS (GFS) comes to the rescue by providing a solution for maintaining synchronized volumes across a Docker Swarm.

Enabling Docker Swarm

To set up a Docker Swarm, follow these steps:

1. Initialize Swarm on the manager node (e.g., Raspberry Pi):

   docker swarm init

2. Add worker nodes to the swarm using the token obtained from the previous step:

   docker swarm join --token <long token> <manager-ip:port>

3. Check the swarm members:

   docker swarm ls

Setting Up GlusterFS

GlusterFS ensures synchronized volumes across nodes:

1. Install GlusterFS on each node:

   sudo add-apt-repository ppa:gluster/glusterfs-11
   sudo apt update && sudo apt install glusterfs-server -y

2. Start and enable the GlusterFS service:

   sudo systemctl start glusterd && sudo systemctl enable glusterd

3. Check the peer status and pool list:

   sudo gluster peer status
   sudo gluster pool list

4. Create a local directory on each machine for GlusterFS to write data:

   sudo mkdir -p /mnt/nodirectwritedatahere/gfsbrick

5. Link the directories with GlusterFS volumes:

   sudo gluster volume create replicated_volume replica 2 \
   srv00.facundoitest.space:/mnt/nodirectwritedatahere/gfsbrick \
   srv03.facundoitest.space:/mnt/nodirectwritedatahere/gfsbrick force

6. Start the GlusterFS volume:

   sudo gluster volume start replicated_volume

7. Check the volume status:

   sudo gluster volume status

Mounting GlusterFS Volumes

Mount the GlusterFS volume to a local directory on each worker node:

1. Mount the volume:

   sudo mount -t glusterfs srv00.facundoitest.space:/replicated_volume /mnt/swarm/

2. Edit `/etc/fstab` to ensure the volume is mounted at startup:

   srv00.facundoitest.space:/replicated_volume   /mnt/swarm   glusterfs   defaults,_netdev   0   0

Esto viene a resolver que fstab no deja listo el volumen replicado de glusterfs porque systemd procesa a fstab antes de cargar el servicio. Entonces docker se queja de que no existe el directorio y sin embargo mount -a funciona perfecto. Tal vez otra manera viable es con sleep && mount -a en el crontab. No probé.

# systemd mounts glusterFS replicated volume after loading the server service
# The ‘noauto’ option means that autofs won’t touch the mount and systemd will have control over it.
srv04.facundoitest.space:/replicated_volume							/mnt/swarm	glusterfs	defaults,_netdev,noauto,x-systemd.automount	0	0

Deploying Services

Now, you can deploy services using the synchronized volume:

1. Create a `docker-compose.yml` file for the desired service (e.g., homepage):

   version: "3.3"
   services:
     homepage:
       image: ghcr.io/benphelps/homepage:latest
       restart: always
       ports:
         - 3080:3000
       volumes:
         - /mnt/swarm/homepage:/app/config
       deploy:
         replicas: 2
         restart_policy:
           condition: on-failure
         placement:
           constraints: [node.role != manager]

2. Deploy the service:

   docker stack deploy -c docker-compose.yml myservice

Additional Resources

For more in-depth information and guides on implementing Docker Swarm with GlusterFS, refer to these resources:

- [Tutorial: Create a Docker Swarm with Persistent Storage Using GlusterFS](https://thenewstack.io/tutorial-create-a-docker-swarm-with-persistent-storage-using-glusterfs/)

- [Setup 3-Node High Availability Cluster with GlusterFS and Docker Swarm](https://medium.com/running-a-software-factory/setup-3-node-high-availability-cluster-with-glusterfs-and-docker-swarm-b4ff80c6b5c3)

- [Deploying a Docker Stack Across a Docker Swarm Using a Docker Compose File](https://towardsaws.com/deploying-a-docker-stack-across-a-docker-swarm-using-a-docker-compose-file-ddac4c0253da)

- [How to Create a Redundant Storage Pool using GlusterFS on Ubuntu](https://www.cyberciti.biz/faq/howto-glusterfs-replicated-high-availability-storage-volume-on-ubuntu-linux/)

- [GlusterFS Brick Naming Conventions](https://docs.gluster.org/en/main/Administrator-Guide/Brick-Naming-Conventions/#set-up-a-gluster-volume)

- [Creating a Redundant Storage Pool Using GlusterFS on Ubuntu 20.04](https://www.digitalocean.com/community/tutorials/how-to-create-a-redundant-storage-pool-using-glusterfs-on-ubuntu-20-04#step-2-setting-up-software-sources-on-each-machine)

- [Adding New Bricks to an Existing GlusterFS Replicated Volume](https://www.cyberciti.biz/faq/howto-add-new-brick-to-existing-glusterfs-replicated-volume/)

By combining Docker Swarm and GlusterFS, you can achieve high availability and synchronize volumes effectively for your distributed applications.

Adding a New Node (Brick) to an Existing Replicated Volume

To extend your GlusterFS volume with additional storage capacity, you can add a new node (brick) to the existing replicated volume. Follow these steps:

1. Install GlusterFS:

Make sure GlusterFS is installed on the new node and is using the same version as the existing nodes.

2. Create the Working Directory:

Create a directory on the new node where GlusterFS will write data. This directory should be located in a path similar to the existing bricks.

3. Test Connectivity:

Ensure that the new node can communicate with the GlusterFS daemon on the other nodes by testing the peer connection:

   sudo gluster peer probe newNodeName.mydomain.tld

4. Add the New Brick:

Add the new brick to the existing replicated volume using the following command:

sudo gluster volume add-brick replicatedVolume replica n newNodeName.mydomain.tld:/nodirectwritedata/gfs_vol

Replace `replicatedVolume` with the name of your existing volume, `n` with the desired replica count (including the new node), and `newNodeName.mydomain.tld` with the hostname or IP address of the new node.

Resources: https://www.cyberciti.biz/faq/howto-add-new-brick-to-existing-glusterfs-replicated-volume/

Removing an Inactive, Unsynced Brick

Removing an inactive brick that hasn't been synchronized can be useful when a node becomes unavailable. Here's how to do it:

1. Unsynced Brick Removal:

To remove an unsynced brick from the volume, use the following command:

 sudo gluster volume remove-brick replicated_volume replica 3 srv00.facundoitest.space:/mnt/nodirectwritedatahere/gfsbrick force 

In this example, replicated_volume is the name of the volume, replica 3 indicates the new desired replica count, srv00.facundoitest.space is the hostname of the inactive node, and /mnt/nodirectwritedatahere/gfsbrick is the path to the unsynced brick. Use the force flag to proceed.

By following these steps, you can efficiently expand your GlusterFS volume with new nodes or remove inactive bricks as needed.


El original sin formatear:

El orquestador de docker swarm habilita el despliegue de stacks, pero no tiene integrado el manejo de los volúmenes. Entonces si hay que pompartir, por ejemplo los assets de un sitio web y mantenerlo actualizado entre todos los nodos (para que no se hagan cambios en una répica y el resto quede desactualizada), swarm no lo maneja por sí mismo y es necesario usar, por ejemplo NFS o (como en este caso) GlusterFS (GFS).

Una vez instalado el engine en todas las máquinas:

habilitar swarm en el manager (raspberry pi)

docker swarm init

agregar hosts al swarm con el script que devuelve

docker swarm join --token <token largo> <ip.del.swarm.manager:puerto>

ver los miembros del swarm

docker swarm ls

Los 'workers' pueden ser de distintas arquitecturas, en ese caso hay que usar tags y manifestos para hacerle enteneder al manager que no todos llevan la misma imagen. Algunos usarán AMD64, otros ARM64, otros x86, otros armv7, etc. En este caso en particular, el manager es un armhf/armv7 (raspberry pi 2) y los workers son VMs AMD64.

En este punto ya estaría listo el swarm en sí. Ahora queda instalar GlusterFS para mantener sincronizados los volúmenes. De esta manera en cada worker habría una carpeta con exactamente el mismo contenido, uno al declarar el deployment apuntaría el volumen del contenedor/servicio ahí y no habría discrepancias entre cada réplica del servicio.

Instalar glusterfs

sudo add-apt-repository ppa:gluster/glusterfs11 (ver las versiones que mantienen en los ppa acá: https://launchpad.net/~gluster y las versiones en https://docs.gluster.org/en/main/release-notes/)

sudo apt update && sudo apt install glusterfs-server -y

lanzar y habilitar

sudo systemctl start glusterd && sudo systemctl enable glusterd
sudo gluster peer status
sudo gluster pool list

crear el directorio local en todas las máquinas para que glusterfs escriba ahí

sudo mkdir -p /mnt/nodirectwritedatahere/gfsbrick

ahora la magia, una vez que están los directorios en cada worker, hay que vincularlos con el volumen

sudo gluster volume create <volume name> replica <# of replicas> worker01:/path/to/local/dir worker02:/path/to/local/dir force

en el caso real fue

sudo gluster volume create replicated_volume replica 2 srv00.facundoitest.space:/mnt/nodirectwritedatahere/gfsbrick srv03.facundoitest.space:/mnt/nodirectwritedatahere/gfsbrick force

arrancar el volumen

sudo gluster volume start replicated_volume

comprobar el estado

sudo gluster volume status

para modificar el heartbeat

sudo gluster volume set replicated_volume network.ping-timeout "5"

montar el volumen virtual gfs en el directorio local en cada worker

sudo mount -t glusterfs srv00.facundoitest.space:/replicated_volume /mnt/swarm/

editar fstab así se monta solo al inicio

srv00.facundoitest.space:/replicated_volume 			/mnt/swarm 				glusterfs 	defaults,_netdev 	0	0

si se crean archivos en el directorio donde se monta el volumen gFS, deberían aparecer en el resto de los workers. Probar creando 10 archivos sin nada.

sudo touch /mnt/swarm/homepage/test_{0..9}.txt

por último solamente queda desplegar algun servicio usando como volumen la carpeta sincronizada con glusterfs. Por ejemplo, homepage de Ben Phelps (https://github.com/benphelps/homepage)

el docker-compose.yml quedaría así: ´´´ facundo@raspberrypi:~/homepage $ cat docker-compose.yml version: “3.3” services:

homepage:
  image: ghcr.io/benphelps/homepage:latest
  restart: always
  ports:
    - 3080:3000
  volumes:
    - /mnt/swarm/homepage:/app/config # Make sure your local config directory exists. app/config es esa carpeta, no app. O sea todo lo que aparece en config va a crearse ahí en swarm/homepage
  deploy:
    replicas: 2
    restart_policy:
      condition: on-failure
    placement:
      constraints: [node.role != manager] # esta condición es para que no lo haga correr en un swarm manager

´´´

ahora si uno hace workerX:puerto, debería responder el servicio, y si hago manager:puerto también, ya que hace de load balancer el mismo swarm manager.

Recursos: este lo encontré tarde, pero tiene casi todo https://thenewstack.io/tutorial-create-a-docker-swarm-with-persistent-storage-using-glusterfs/

https://medium.com/running-a-software-factory/setup-3-node-high-availability-cluster-with-glusterfs-and-docker-swarm-b4ff80c6b5c3

buen artículo firmado por Brandi nosecuanto, de medium https://towardsaws.com/deploying-a-docker-stack-across-a-docker-swarm-using-a-docker-compose-file-ddac4c0253da

uno de nixCraft https://www.cyberciti.biz/faq/howto-glusterfs-replicated-high-availability-storage-volume-on-ubuntu-linux/

docs.gluster https://docs.gluster.org/en/main/Administrator-Guide/Brick-Naming-Conventions/#set-up-a-gluster-volume

digitalocean sobre gluster https://www.digitalocean.com/community/tutorials/how-to-create-a-redundant-storage-pool-using-glusterfs-on-ubuntu-20-04#step-2-setting-up-software-sources-on-each-machine

agregar nuevos bricks a un gfs existente, por nixCraft https://www.cyberciti.biz/faq/howto-add-new-brick-to-existing-glusterfs-replicated-volume/

implementing_high_availability_and_persistent_storage_with_docker_swarm_and_glusterfs.txt · Last modified: 2024/10/17 21:42 by 127.0.0.1