Ansible Playbook - GlusterFS - Apache

4 minute read

Read this first (June 2026): GlusterFS is effectively legacy now. Red Hat ended Gluster Storage and disbanded its engineering team at the end of 2024, upstream commits have slowed to a trickle, and CentOS Stream 10 dropped GlusterFS packages. The community project still exists, but I would not start a new build on it. If you are designing this fresh today, look at CephFS for distributed storage, or for the narrow goal here (keeping /var/www in sync across Apache nodes) a shared NFS mount, object storage with a deploy pipeline, or building artifacts in CI and shipping them to each node. The Ansible patterns below are modernized to FQCN for anyone still maintaining a Gluster deployment, but treat the post as a reference rather than a recommendation.

Background

This is a multi-tier lab build: HAProxy load balancers in front of Apache web servers, MariaDB for data, and a separate GlusterFS cluster. The Apache nodes mount a GlusterFS volume at /var/www so their content stays in sync. The original post collected the playbooks for reference, and this refresh updates the syntax that has drifted since 2015.

Inventory

The site_hosts inventory, with the modern connection variables (ansible_host rather than the deprecated ansible_ssh_host):

ans-test-web01 ansible_host=10.0.110.193 ansible_ssh_private_key_file=.ssh/home
ans-test-web02 ansible_host=10.0.110.222 ansible_ssh_private_key_file=.ssh/home
ans-test-web03 ansible_host=10.0.110.130 ansible_ssh_private_key_file=.ssh/home
ans-test-gs01  ansible_host=10.0.110.132 ansible_ssh_private_key_file=.ssh/home
ans-test-gs02  ansible_host=10.0.110.131 ansible_ssh_private_key_file=.ssh/home
ans-test-gs03  ansible_host=10.0.110.129 ansible_ssh_private_key_file=.ssh/home

[gs-vms]
ans-test-gs[01:03]

[gs-vms:vars]
glusterfs_server=true
glusterfs_client=true
gluster_brick_dir=/mnt/gluster
cluster_hosts=ans-test-gs01,ans-test-gs02,ans-test-gs03

[web-vms]
ans-test-web[01:03]

[web-vms:vars]
glusterfs_client=true
primary_gfs_server=ans-test-gs01
secondary_gfs_server=ans-test-gs02
tertiary_gfs_server=ans-test-gs03
apache_backup_dir=/var/www.backup
apache_home=/var/www

site.yml

The top-level play, with become: true replacing the deprecated sudo: yes:

---
- hosts: all
  become: true
  roles:
    - base
    - zabbix-agent

- hosts: web-vms
  become: true
  roles:
    - glusterfs
    - apache2
    - memcached

- hosts: gs-vms
  become: true
  roles:
    - glusterfs

LVM

The original repeated a full LVM playbook here. That same playbook is covered, modernized, in Ansible Playbook - LVM, so rather than duplicate it, use that version (FQCN, community.general.lvg/lvol, one cross-distro install task) to prepare the /mnt/gluster brick disk.

Installing GlusterFS

The 2015 version added a Launchpad PPA for trusty and imported a key with apt_key. Both are dead: that Ubuntu release and PPA are gone, and apt_key is deprecated in favor of keyrings under /etc/apt/keyrings. On a current distribution, install from the distro packages (or the upstream gluster.org repo for your release). The task itself collapses to a single apt call, since the module takes a list directly instead of a with_items loop:

---
- name: Install GlusterFS prerequisites
  ansible.builtin.apt:
    name:
      - software-properties-common
      - xfsprogs
    state: present
    update_cache: true

- name: Install GlusterFS server
  ansible.builtin.apt:
    name: glusterfs-server
    state: present
  when: glusterfs_server

- name: Install GlusterFS client
  ansible.builtin.apt:
    name: glusterfs-client
    state: present
  when: glusterfs_client

- name: Enable and start glusterd
  ansible.builtin.service:
    name: glusterd
    state: started
    enabled: true
  when: glusterfs_server

Building The Volume And Mounting It

The configuration playbook, modernized to FQCN and loop. Note that the dedicated gluster modules were removed from community.general as the project wound down, so volume creation now drives the gluster CLI directly through ansible.builtin.command:

---
- hosts: gs-vms
  become: true
  tasks:
    - name: Probe the gluster peers
      ansible.builtin.command: "gluster peer probe {{ item }}"
      register: gluster_peer_probe
      changed_when: "'already in peer list' not in gluster_peer_probe.stdout"
      loop: "{{ groups['gs-vms'] }}"

    - name: Create the brick directories
      ansible.builtin.file:
        path: "{{ gluster_brick_dir }}/{{ item.name }}/"
        owner: "{{ item.owner }}"
        group: "{{ item.group }}"
        state: directory
        mode: "0755"
      loop:
        - {name: webs-test, owner: root, group: www-data}
        - {name: loadbalancers-test, owner: root, group: root}

    - name: Create the gluster volumes
      ansible.builtin.command: >
        gluster volume create {{ item }} replica 3
        {% for host in groups['gs-vms'] %}{{ host }}:/mnt/gluster/{{ item }}/brick {% endfor %}
        force
      register: gluster_volume_create
      changed_when: "'success' in gluster_volume_create.stdout"
      failed_when:
        - gluster_volume_create.rc != 0
        - "'already exists' not in gluster_volume_create.stderr"
      loop:
        - webs-test
        - loadbalancers-test
      run_once: true

    - name: Start the gluster volumes
      ansible.builtin.command: "gluster volume start {{ item }}"
      register: gluster_volume_start
      changed_when: "'success' in gluster_volume_start.stdout"
      failed_when:
        - gluster_volume_start.rc != 0
        - "'already started' not in gluster_volume_start.stderr"
      loop:
        - webs-test
        - loadbalancers-test
      run_once: true

- hosts: web-vms
  become: true
  tasks:
    - name: Check whether /var/www has already been moved
      ansible.builtin.stat:
        path: "{{ apache_backup_dir }}"
      register: www_backup

    - name: Move the existing /var/www aside
      ansible.builtin.command: "mv {{ apache_home }} {{ apache_backup_dir }}"
      when: not www_backup.stat.exists

    - name: Mount the gluster volume at /var/www
      ansible.posix.mount:
        path: "{{ apache_home }}"
        src: "{{ primary_gfs_server }}:/webs-test"
        fstype: glusterfs
        opts: "defaults,_netdev,backup-volfile-servers={{ secondary_gfs_server }}:{{ tertiary_gfs_server }}"
        state: mounted

A couple of correctness notes beyond the syntax: the backup-server mount option is backup-volfile-servers (plural, colon-separated list), not a repeated backupvolfile-server key as the original had it. And moving /var/www aside before the first mount is destructive, so guard it on the backup not already existing, which the when above does.

Conclusion

If you already run GlusterFS, the modernized playbooks above will keep working. If you are building this today, spend your time on a storage layer that is still actively developed. The tiered HAProxy and Apache pattern is fine; it is the Gluster layer underneath that has aged out.

Enjoy!

Comments