# Setup Highly Available applications with Docker Swarm and Gluster

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

<div id="bkmrk-" style="text-align: justify;"><div><div class="speechify-ignore ab co"><div class="speechify-ignore bg l"><div class="gq gr gs gt gu ab"><div><div class="ab gv"></div></div></div></div></div></div></div><div id="bkmrk-published-in%C2%A0oct-28%2C" style="text-align: justify;"><div><div class="speechify-ignore ab co"><div class="speechify-ignore bg l"><div class="gq gr gs gt gu ab"><div class="bm bg l"><div class="ab"><div><div class="hh ab q"></div></div></div><div class="l ht"><div class="ab cm hu hv hw"><div class="hx hy ab"><div class="be b bf z dw ab hz"><span class="ia l ht">Published in </span><span data-testid="storyPublishDate">Oct 28, 2018</span></div></div></div></div></div></div></div></div></div></div><figure class="ma mb mc md me mf lx ly paragraph-image" id="bkmrk-docker-swarm-cluster"><div class="mg mh ec mi bg mj" role="button" tabindex="0"><div class="lx ly lz"><picture><source sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 700px" srcset="https://miro.medium.com/v2/resize:fit:640/format:webp/1*Bg_s3i30ScFLcsLMLmChvw.png 640w, https://miro.medium.com/v2/resize:fit:720/format:webp/1*Bg_s3i30ScFLcsLMLmChvw.png 720w, https://miro.medium.com/v2/resize:fit:750/format:webp/1*Bg_s3i30ScFLcsLMLmChvw.png 750w, https://miro.medium.com/v2/resize:fit:786/format:webp/1*Bg_s3i30ScFLcsLMLmChvw.png 786w, https://miro.medium.com/v2/resize:fit:828/format:webp/1*Bg_s3i30ScFLcsLMLmChvw.png 828w, https://miro.medium.com/v2/resize:fit:1100/format:webp/1*Bg_s3i30ScFLcsLMLmChvw.png 1100w, https://miro.medium.com/v2/resize:fit:1400/format:webp/1*Bg_s3i30ScFLcsLMLmChvw.png 1400w" type="image/webp"><source data-testid="og" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 700px" srcset="https://miro.medium.com/v2/resize:fit:640/1*Bg_s3i30ScFLcsLMLmChvw.png 640w, https://miro.medium.com/v2/resize:fit:720/1*Bg_s3i30ScFLcsLMLmChvw.png 720w, https://miro.medium.com/v2/resize:fit:750/1*Bg_s3i30ScFLcsLMLmChvw.png 750w, https://miro.medium.com/v2/resize:fit:786/1*Bg_s3i30ScFLcsLMLmChvw.png 786w, https://miro.medium.com/v2/resize:fit:828/1*Bg_s3i30ScFLcsLMLmChvw.png 828w, https://miro.medium.com/v2/resize:fit:1100/1*Bg_s3i30ScFLcsLMLmChvw.png 1100w, https://miro.medium.com/v2/resize:fit:1400/1*Bg_s3i30ScFLcsLMLmChvw.png 1400w">![](https://miro.medium.com/v2/resize:fit:945/1*Bg_s3i30ScFLcsLMLmChvw.png)</source></source></picture></div></div><figcaption class="ml mm mn lx ly mo mp be b bf z dw" data-selectable-paragraph="">Docker Swarm cluster with shared glusterFS replicated volume for HA</figcaption></figure>A good design pattern for highly available applications is to deploy the application as a container on a Docker Swarm cluster with persistent storage provided by GlusterFS. GlusterFS is a fast shared filesystem that can keep the container volume in sync between multiple VMs running the Docker Swarm cluster. This pattern ensures high availability for your containerised application. In the event a VM dies, Docker Swarm will spin up the container on another VM. GlusterFS will ensure the container has access to the same data when it comes up.

In this tutorial, we’ll look at setting up GlusterFS on 3 VMs and create a replicated volume with a replication factor of 3. Later we’ll install Docker Swarm over these three VMs. Goal is to use GlusterFS to provide persistent storage to your application container, and docker swarm for high availability.

# 1. Plan and setup the infrastructure

For the setup, first we’ll need three Ubuntu Gluster VMs, each with 2 disks attached. We’ll use the first disk to run the OS, and the second as the GlusterFS replicated volume. Create three VMs with two disks. In my case, my VMs had the root volume on `/dev/vda` and the second disk on `/dev/vdc`. Create three VMs and let’s assume the private IPs of these VMs are `192.168.2.100, 192.168.2.101, 192.168.2.102`, and their hostnames are `gluster1, gluster2, gluster3`.

Note: All commands are being executed as `root` user (hence the # at the beginning)

```
# lsblk<br></br>NAME   MAJ:MIN RM SIZE RO TYPE MOUNTPOINT<br></br>vda    253:0    0  30G  0 disk<br></br>└─vda1 253:1    0  30G  0 part /<br></br>vdb    253:16   0  64M  0 disk <br></br>vdc    253:32   0  10G  0 disk
```

Update the /etc/hosts files on each VM to reflect the private IPs of each VM. This is important for GlusterFS, and you may encounter bugs or issues if you give private IPs directly to Gluster volumes. After editing the files should look like:

```
(gluster1)# cat /etc/hosts<br></br>127.0.0.1       localhost<br></br>192.168.2.100   gluster1<br></br>192.168.2.101   gluster2<br></br>192.168.2.102   gluster3(gluster2)# cat /etc/hosts<br></br>127.0.0.1       localhost<br></br>192.168.2.100   gluster1<br></br>192.168.2.101   gluster2<br></br>192.168.2.102   gluster3(gluster3)# cat /etc/hosts<br></br>127.0.0.1       localhost<br></br>192.168.2.100   gluster1<br></br>192.168.2.101   gluster2<br></br>192.168.2.102   gluster3
```

Format the disks with xfs filesystem on each VM in case you haven’t already. You can also use ext4 if you prefer.

```
# mkfs.xfs /dev/vdc
```

# 2. Create directories for GlusterFS storage

Setup the glusterFS directories where the gluster “bricks” will reside. Better to name them differently so it’s easy to identify on which node the replicated volumes reside. Also add an entry to your /etc/fstab file on each VM so that our brick gets mounted when the operating system boots or restarts.

```
(gluster1)# mkdir -p /gluster/bricks/1<br></br>(gluster1)# echo '/dev/vdc /gluster/bricks/1 xfs defaults 0 0' >> /etc/fstab<br></br>(gluster1)# mount -a<br></br>(gluster1)# mkdir /gluster/bricks/1/brick(gluster2)# mkdir -p /gluster/bricks/2<br></br>(gluster2)# echo '/dev/vdc /gluster/bricks/2 xfs defaults 0 0' >> /etc/fstab<br></br>(gluster2)# mount -a<br></br>(gluster2)# mkdir /gluster/bricks/2/brick(gluster3)# mkdir -p /gluster/bricks/3<br></br>(gluster3)# echo '/dev/vdc /gluster/bricks/3 xfs defaults 0 0' >> /etc/fstab<br></br>(gluster3)# mount -a<br></br>(gluster3)# mkdir /gluster/bricks/3/brick
```

# 3. Install GlusterFS

Install GlusterFS on all VMs by executing following commands on each VM:

```
# apt-get -y update && apt-get -y upgrade<br></br># apt-get install -y software-properties-common<br></br># add-apt-repository ppa:gluster/glusterfs-6 && apt-get update # Use the latest glusterFS version instead of 6, which was the latest at the time of writing this tutorial<br></br># apt-get install -y glusterfs-server<br></br># systemctl enable glusterd # automatically start glusterfs on boot<br></br># systemctl start glusterd # start glusterfs right now<br></br># systemctl status glusterd # Should show status active
```

# 4. Peer with other Gluster VMs

Now peer with other nodes from gluster1:

```
(gluster1)# gluster peer probe gluster2<br></br>peer probe: success.<br></br>(gluster1)# gluster peer probe gluster3<br></br>peer probe: success.<br></br>(gluster1)# gluster peer status<br></br>Number of Peers: 2Hostname: gluster2<br></br>Uuid: 60861905-6adc-4841-8f82-216c661f9fe2<br></br>State: Peer in Cluster (Connected)Hostname: gluster3<br></br>Uuid: 572fed90-61de-40dd-97a6-4255ed8744ce<br></br>State: Peer in Cluster (Connected)
```

# 5. Setup the Gluster “replicated volume”

GlusterFS has multiple [volume types](https://docs.gluster.org/en/v3/Administrator%20Guide/Setting%20Up%20Volumes/). For our HA architecture, we want to setup a “replicated” volume that stores the files created on each of the 3 VMs and hence the file is available to any app or container running on these VMs. Create the replicated volume named “gfs” with 3 replicas:

```
(gluster1)# gluster volume create gfs \<br></br>replica 3 \<br></br>gluster1:/gluster/bricks/1/brick \<br></br>gluster2:/gluster/bricks/2/brick \<br></br>gluster3:/gluster/bricks/3/brickvolume create: gfs: success: please start the volume to access data(gluster1)# gluster volume start gfs<br></br>(gluster1)# gluster volume status gfsStatus of volume: gfs<br></br>Gluster process                             TCP Port  RDMA Port  Online  Pid<br></br>------------------------------------------------------------------------------<br></br>Brick gluster1:/gluster/bricks/1/brick      49152     0          Y       4619<br></br>Brick gluster2:/gluster/bricks/2/brick      49152     0          Y       4504<br></br>Brick gluster3:/gluster/bricks/3/brick      49152     0          Y       4306<br></br>Self-heal Daemon on localhost               N/A       N/A        Y       4641<br></br>Self-heal Daemon on gluster2                N/A       N/A        Y       4526<br></br>Self-heal Daemon on gluster3                N/A       N/A        Y       4328Task Status of Volume gfs<br></br>------------------------------------------------------------------------------<br></br>There are no active volume tasks(gluster1)# gluster volume info gfsVolume Name: gfs<br></br>Type: Replicate<br></br>Volume ID: 703e46cb-a637-4620-adfa-6b292a15e0d5<br></br>Status: Started<br></br>Snapshot Count: 0<br></br>Number of Bricks: 1 x 3 = 3<br></br>Transport-type: tcp<br></br>Bricks:<br></br>Brick1: gluster1:/gluster/bricks/1/brick<br></br>Brick2: gluster2:/gluster/bricks/2/brick<br></br>Brick3: gluster3:/gluster/bricks/3/brick<br></br>Options Reconfigured:<br></br>transport.address-family: inet<br></br>nfs.disable: on<br></br>performance.client-io-threads: off
```

# 6. Setup security and authentication for this volume

GlusterFS will allow any clients to connect to volumes by default. However, you will need to authorize the three infra VMs running GlusterFS to connect to the GlusterFS Volumes on each node. You can do it by authorizing the private IPs of each VM to connect to the volume. This will allow replication to happen. Execute:

```
(gluster1)# gluster volume set gfs auth.allow 192.168.2.100,192.168.2.101,192.168.2.102
```

# 7. Mount the glusterFS volume where applications can access the files

We’ll mount the volume onto `/mnt` on each VM, and also append it to our /etc/fstab file so that it mounts on boot:

```
(gluster1)# echo 'localhost:/gfs /mnt glusterfs defaults,_netdev,backupvolfile-server=localhost 0 0' >> /etc/fstab<br></br>(gluster1)# mount.glusterfs localhost:/gfs /mnt(gluster2)# echo 'localhost:/gfs /mnt glusterfs defaults,_netdev,backupvolfile-server=localhost 0 0' >> /etc/fstab<br></br>(gluster2)# mount.glusterfs localhost:/gfs /mnt(gluster3)# echo 'localhost:/gfs /mnt glusterfs defaults,_netdev,backupvolfile-server=localhost 0 0' >> /etc/fstab<br></br>(gluster3)# mount.glusterfs localhost:/gfs /mnt
```

# 8. Verify

Verify mounted glusterfs volume:

```
# df -Th<br></br>Filesystem     Type            Size  Used Avail Use% Mounted on<br></br>udev           devtmpfs        7.9G     0  7.9G   0% /dev<br></br>tmpfs          tmpfs           1.6G   17M  1.6G   2% /run<br></br>/dev/vda1      ext4             30G  2.1G   27G   8% /<br></br>tmpfs          tmpfs           7.9G   12K  7.9G   1% /dev/shm<br></br>tmpfs          tmpfs           5.0M     0  5.0M   0% /run/lock<br></br>tmpfs          tmpfs           7.9G     0  7.9G   0% /sys/fs/cgroup<br></br>tmpfs          tmpfs           1.6G     0  1.6G   0% /run/user/1001<br></br>/dev/vdb       xfs              10G   33M   10G   1% /gluster/bricks/1<br></br>localhost:/gfs fuse.glusterfs   10G  135M   10G   2% /mnt
```

The total space available on the volume comes up as 10G even though we have 3 disks of 10G each connected to GlusterFS. This is due to our replication factor of 3. Total volume size is 30G, but with a replication factor or 3 for each file only 10G is available to us.

Test GlusterFS replication:

```
(gluster1)# echo "Hello World!" | sudo tee /mnt/test.txt(gluster2)# cat /mnt/test.txt<br></br>Hello World!(gluster3)# cat /mnt/test.txt<br></br>Hello World!
```

# Part 2: Setup Docker Swarm

Now let’s setup the Docker Swarm cluster with the gluster VMs (gluster1/2/3) as the workers, and a new VM (swarm-manger) as the Swarm manager. We’ll use our gluster replicated volume to achieve High Availability for our stateful containerized application. We’ll test with Wordpress.

All commands executed as root.

# 1. Setup Docker community edition on all VMs

Install docker-ce on all four VMs (swarm-manager, gluster1/2/3) using the instructions given here: [https://docs.docker.com/install/linux/docker-ce/ubuntu/](https://docs.docker.com/install/linux/docker-ce/ubuntu/) (I feel it’s redundant to repeat the standard instructions).

However, after the installation, please do verify if Docker is installed properly by running following command on all VMs:

```
# docker run hello-world<br></br>Unable to find image 'hello-world:latest' locally<br></br>latest: Pulling from library/hello-world<br></br>1b930d010525: Pull complete<br></br>Digest: sha256:92695bc579f31df7a63da6922075d0666e565ceccad16b59c3374d2cf4e8e50e<br></br>Status: Downloaded newer image for hello-world:latestHello from Docker!<br></br>This message shows that your installation appears to be working correctly.
```

# 2. Initialize Docker swarm from the swarm-manager

We’ll use the swarm-manager’s private IP as the “advertised address”.

```
swarm-manager:~# docker swarm init --advertise-addr 192.168.2.99<br></br>Swarm initialized: current node (sz42o1yjz08t3x98aj82z33pe) is now a manager.To add a worker to this swarm, run the following command:docker swarm join --token SWMTKN-1-3gi2wi4o22nyiqij3io055na7wt0201oamaegykllea0t5vi5k-2qjld08v7ouzax6gzw15dw2ab 192.168.2.99:2377To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
```

# 3. Add the three gluster VMs as swarm workers

```
gluster1:~# docker swarm join --token SWMTKN-1-3gi2wi4o22nyiqij3io055na7wt0201oamaegykllea0t5vi5k-2qjld08v7ouzax6gzw15dw2ab 192.168.2.99:2377<br></br>This node joined a swarm as a worker.gluster2:~# docker swarm join --token SWMTKN-1-3gi2wi4o22nyiqij3io055na7wt0201oamaegykllea0t5vi5k-2qjld08v7ouzax6gzw15dw2ab 192.168.2.99:2377<br></br>This node joined a swarm as a worker.gluster3:~# docker swarm join --token SWMTKN-1-3gi2wi4o22nyiqij3io055na7wt0201oamaegykllea0t5vi5k-2qjld08v7ouzax6gzw15dw2ab 192.168.2.99:2377<br></br>This node joined a swarm as a worker.swarm-manager:~# docker node ls<br></br>ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION<br></br>qjmuz0n8n770ryougk2tsb37x     gluster1            Ready               Active                                  18.09.5<br></br>kcwsavrtzhvy038357p51lwl2     gluster2            Ready               Active                                  18.09.5<br></br>ifnzgpk25p27y19vslee4v74x     gluster3            Ready               Active                                  18.09.5<br></br>sz42o1yjz08t3x98aj82z33pe *   swarm-manager       Ready               Active              Leader              18.09.5
```

# Part 3: Test the High Availability Setup

We’ll use docker stack to setup a single container Wordpress backed by a single container of MySQL, and then test if this setup is resilient to VM failure.

# 1. Create replicated directories for wordpress and mysql in glusterFS

```
gluster1:~# mkdir /mnt/wp-content<br></br>gluster1:~# mkdir /mnt/mysql
```

# 2. Create the wordpress-stack.yml file

This stack file exposes wordpress on port 8080 on all swarm nodes, even the swarm-manager node. It mounts the directories created for wp-content and mysql as volumes on the containers.

```
swarm-manager:~# cat wordpress-stack.yml<br></br># wordpress-stack.yml<br></br>version: '3.1'services:  wordpress:<br></br>    image: wordpress<br></br>    restart: always<br></br>    ports:<br></br>      - 8080:80<br></br>    environment:<br></br>      WORDPRESS_DB_HOST: db<br></br>      WORDPRESS_DB_USER: exampleuser<br></br>      WORDPRESS_DB_PASSWORD: examplepass<br></br>      WORDPRESS_DB_NAME: exampledb<br></br>    volumes:<br></br>      - "/mnt/wp-content:/var/www/html/wp-content"<br></br>    deploy:<br></br>      placement:<br></br>        constraints: [node.role == worker]  db:<br></br>    image: mysql:5.7<br></br>    restart: always<br></br>    environment:<br></br>      MYSQL_DATABASE: exampledb<br></br>      MYSQL_USER: exampleuser<br></br>      MYSQL_PASSWORD: examplepass<br></br>      MYSQL_RANDOM_ROOT_PASSWORD: '1'<br></br>    volumes:<br></br>      - "/mnt/mysql:/var/lib/mysql"<br></br>    deploy:<br></br>      placement:<br></br>        constraints: [node.role == worker]
```

# 3. Use docker stack to deploy Wordpress and MySQL

```
swarm-manager:~# docker stack deploy -c wordpress-stack.yml wordpress<br></br>Ignoring unsupported options: restartCreating network wordpress_default<br></br>Creating service wordpress_db<br></br>Creating service wordpress_wordpressswarm-manager:~# docker stack ps wordpress<br></br>ID                  NAME                    IMAGE               NODE                DESIRED STATE       CURRENT STATE           ERROR               PORTS<br></br>x5vvrt6ohko2        wordpress_db.1          mysql:5.7           gluster2            Running             Running 5 minutes ago<br></br>idree9r7qlxb        wordpress_wordpress.1   wordpress:latest    gluster1            Running             Running 5 minutes ago
```

Check if Wordpress is up by entering http://&lt;any-worker-external-ip&gt;:8080/ in the browser.

<figure class="ov ow ox oy oz mf lx ly paragraph-image" id="bkmrk-note%3A-10.147.106.32-"><div class="mg mh ec mi bg mj" role="button" tabindex="0"><div class="lx ly pk"><picture><source sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 700px" srcset="https://miro.medium.com/v2/resize:fit:640/format:webp/1*zfyk6djhy2k-msLkOa6-tg.png 640w, https://miro.medium.com/v2/resize:fit:720/format:webp/1*zfyk6djhy2k-msLkOa6-tg.png 720w, https://miro.medium.com/v2/resize:fit:750/format:webp/1*zfyk6djhy2k-msLkOa6-tg.png 750w, https://miro.medium.com/v2/resize:fit:786/format:webp/1*zfyk6djhy2k-msLkOa6-tg.png 786w, https://miro.medium.com/v2/resize:fit:828/format:webp/1*zfyk6djhy2k-msLkOa6-tg.png 828w, https://miro.medium.com/v2/resize:fit:1100/format:webp/1*zfyk6djhy2k-msLkOa6-tg.png 1100w, https://miro.medium.com/v2/resize:fit:1400/format:webp/1*zfyk6djhy2k-msLkOa6-tg.png 1400w" type="image/webp"><source data-testid="og" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 700px" srcset="https://miro.medium.com/v2/resize:fit:640/1*zfyk6djhy2k-msLkOa6-tg.png 640w, https://miro.medium.com/v2/resize:fit:720/1*zfyk6djhy2k-msLkOa6-tg.png 720w, https://miro.medium.com/v2/resize:fit:750/1*zfyk6djhy2k-msLkOa6-tg.png 750w, https://miro.medium.com/v2/resize:fit:786/1*zfyk6djhy2k-msLkOa6-tg.png 786w, https://miro.medium.com/v2/resize:fit:828/1*zfyk6djhy2k-msLkOa6-tg.png 828w, https://miro.medium.com/v2/resize:fit:1100/1*zfyk6djhy2k-msLkOa6-tg.png 1100w, https://miro.medium.com/v2/resize:fit:1400/1*zfyk6djhy2k-msLkOa6-tg.png 1400w">![](https://miro.medium.com/v2/resize:fit:945/1*zfyk6djhy2k-msLkOa6-tg.png)</source></source></picture></div></div><figcaption class="ml mm mn lx ly mo mp be b bf z dw" data-selectable-paragraph="">Note: 10.147.106.32 was one of my gluster worker VM’s (gluster3) external IP</figcaption></figure>Go through the install process, choose an admin username and password, and create your first post.

# 4. Test High Availability by shutting down a VM

Check on which VM the Wordpress and MySQL containers are running. We’ll shutdown each VM to understand whether HA is working properly. In my case, the Wordpress container was running on gluster1 and MySQL was running on gluster2.

```
swarm-manager:~# docker stack ps wordpress<br></br>ID                  NAME                    IMAGE               NODE                DESIRED STATE       CURRENT STATE            ERROR               PORTS<br></br>x5vvrt6ohko2        wordpress_db.1          mysql:5.7           gluster2            Running             Running 24 minutes ago<br></br>idree9r7qlxb        wordpress_wordpress.1   wordpress:latest    gluster1            Running             Running 24 minutes ago
```

Shutdown gluster1 and check what happens. You’ll find that docker swarm starts a new container on a new worker VM. The website will continue to work, your data will still be stored, but you’ll have to login again as the session data is lost with the previous container.

```
swarm-manager:~# docker stack ps wordpress<br></br>ID                  NAME                    IMAGE               NODE                DESIRED STATE       CURRENT STATE                ERROR               PORTS<br></br>u8s93kowj2mx        wordpress_wordpress.1   wordpress:latest    gluster3            Running             Running 3 seconds ago<br></br>x5vvrt6ohko2        wordpress_db.1          mysql:5.7           gluster2            Running             Running 28 minutes ago<br></br>idree9r7qlxb        wordpress_wordpress.1   wordpress:latest    gluster1            Shutdown            Running about a minute ago
```

Start the gluster1 VM again and let’s repeat the HA test with MySQL host gluster2. Shutdown gluster2 which was running the MySQL container. After shutdown, you’ll find docker swarm has scheduled MySQL on another worker VM.

```
swarm-manager:~# docker stack ps wordpress<br></br>ID                  NAME                    IMAGE               NODE                DESIRED STATE       CURRENT STATE              ERROR               PORTS<br></br>px90rs5q22ei        wordpress_db.1          mysql:5.7           gluster1            Running             Preparing 41 seconds ago<br></br>u8s93kowj2mx        wordpress_wordpress.1   wordpress:latest    gluster3            Running             Running 6 minutes ago<br></br>x5vvrt6ohko2        wordpress_db.1          mysql:5.7           gluster2            Shutdown            Running 50 seconds ago<br></br>idree9r7qlxb        wordpress_wordpress.1   wordpress:latest    gluster1            Shutdown            Shutdown 3 minutes ago
```

The website will continue to work without any data loss as the MySQL container would have found the replicated volume under the same path (/mnt/mysql).

Add the three worker VM IPs with port behind a Load Balancer (like AWS ELB) and *voilà*, A Highly Available stateful deployment on Docker Swarm using GlusterFS.