7.9 KiB

Mount NFS Shares

Playbook: playbooks/storage/mount_nfs_shares.yml
Purpose: Configure NFS client mounts on Docker Swarm nodes for persistent storage
Target: All Swarm nodes (managers + workers)


Overview

This playbook configures NFS mounts from the TerraMaster NAS to Docker Swarm nodes, providing shared storage for application data and media files. It ensures all nodes have consistent access to centralized storage while maintaining the storage contract principle that NAS is not a dependency for Swarm control-plane operations.


Prerequisites

On TerraMaster NAS (10.0.0.250)

  • NFS service enabled
  • Two NFS exports configured:
    • /Volume1/appdata — Application data, configs, persistent volumes
    • /Volume2/media — Media files (Plex, etc.)
  • NFS permissions allow access from Swarm subnet (10.0.0.0/24)

On Swarm Nodes

  • Ubuntu 24.04 LTS (Noble)
  • SSH access as chester user with sudo privileges
  • Network connectivity to TerraMaster on port 2049 (NFS)

What It Does

  1. Installs NFS clientnfs-common package
  2. Creates mount points/mnt/homelab and /mnt/media
  3. Configures fstab — Persistent mounts survive reboots
  4. Mounts shares immediately — Makes storage available without reboot
  5. Verifies accessibility — Tests that mounts are readable

Usage

Run on all Swarm nodes

cd /home/chester/homelab/ansible
ansible-playbook playbooks/storage/mount_nfs_shares.yml

Run with specific tags

# Only install packages and create directories
ansible-playbook playbooks/storage/mount_nfs_shares.yml --tags setup

# Only update fstab (no mount action)
ansible-playbook playbooks/storage/mount_nfs_shares.yml --tags config

# Mount without fstab changes (testing)
ansible-playbook playbooks/storage/mount_nfs_shares.yml --tags mount

# Verify existing mounts
ansible-playbook playbooks/storage/mount_nfs_shares.yml --tags verify

Limit to specific nodes

# Only managers
ansible-playbook playbooks/storage/mount_nfs_shares.yml --limit swarm_managers

# Only workers
ansible-playbook playbooks/storage/mount_nfs_shares.yml --limit swarm_workers

# Single node
ansible-playbook playbooks/storage/mount_nfs_shares.yml --limit swarm-worker-1

Configuration

Variables

Defined in the playbook (vars section):

Variable Value Description
nfs_server 10.0.0.250 TerraMaster NAS IP address
nfs_mounts[0].src /Volume1/appdata NFS export path for application data
nfs_mounts[0].dest /mnt/homelab Local mount point for app data
nfs_mounts[1].src /Volume2/media NFS export path for media
nfs_mounts[1].dest /mnt/media Local mount point for media
nfs_mounts[*].opts defaults Mount options

Customizing Mount Options

To change mount options (e.g., add noatime for performance):

nfs_mounts:
  - src: "/Volume1/appdata"
    dest: "/mnt/homelab"
    opts: "defaults,noatime,rw"

Common NFS options:

  • noatime — Don't update access times (performance)
  • hard — Retry indefinitely if NFS server unavailable (default)
  • soft — Fail after timeout (risky for data integrity)
  • rsize=8192,wsize=8192 — Adjust read/write buffer sizes
  • nfsvers=4 — Force NFSv4 (recommended)

Using NFS Mounts in Docker

Method 1: Bind Mounts (Current Approach)

Docker Compose:

services:
  app:
    image: myapp:latest
    volumes:
      - /mnt/homelab/appdata/myapp:/data
      - /mnt/media:/media:ro  # Read-only for safety

Pros:

  • Simple and transparent
  • Easy to debug with standard Linux tools
  • One mount serves all containers

Cons:

  • Services coupled to host filesystem paths
  • Must ensure mount exists before container starts

Method 2: Docker NFS Volumes (Alternative)

Docker Compose:

volumes:
  homelab_data:
    driver: local
    driver_opts:
      type: nfs
      o: addr=10.0.0.250,rw,nfsvers=4
      device: ":/Volume1/appdata"
  
  media:
    driver: local
    driver_opts:
      type: nfs
      o: addr=10.0.0.250,ro,nfsvers=4
      device: ":/Volume2/media"

services:
  app:
    image: myapp:latest
    volumes:
      - homelab_data:/data
      - media:/media:ro

Pros:

  • Portable volume names (no hardcoded paths)
  • Docker manages mount lifecycle
  • Per-service isolation possible
  • Automatic retry on NFS failure

Cons:

  • More complex configuration
  • Harder to inspect with standard tools
  • Must define volumes in every compose file

Recommendation

Use bind mounts (Method 1) for now:

  • You already have working fstab configuration
  • Simpler to manage across 6 nodes
  • Better visibility for troubleshooting
  • Can switch to Docker volumes later if needed

Verification

Check mount status

# On any Swarm node
df -h | grep mnt

# Expected output:
# 10.0.0.250:/Volume1/appdata  500G  100G  400G  20% /mnt/homelab
# 10.0.0.250:/Volume2/media    2.0T  500G  1.5T  25% /mnt/media

Test write access

# On a Swarm node
sudo touch /mnt/homelab/test-write
ls -l /mnt/homelab/test-write
sudo rm /mnt/homelab/test-write

Check fstab persistence

cat /etc/fstab | grep mnt
# Should show both NFS entries

Troubleshooting

Mount fails with "Connection refused"

Cause: NFS service not running or firewall blocking port 2049

Solution:

# Test NFS connectivity
showmount -e 10.0.0.250

# If fails, check TerraMaster NFS settings

Mount fails with "Permission denied"

Cause: NFS export permissions don't allow Swarm node IPs

Solution: Update TerraMaster NFS export to allow 10.0.0.0/24 subnet


Mount succeeds but directory is empty

Cause: Mounted wrong export path or path doesn't exist on NAS

Solution:

# List available exports
showmount -e 10.0.0.250

Mount exists but containers can't write

Cause: NFS mounted read-only or wrong permissions

Solution:

# Check mount options
mount | grep "/mnt/homelab"

# Remount with write permissions if needed
sudo mount -o remount,rw /mnt/homelab

Stale NFS file handle errors

Cause: NFS server restarted or export changed

Solution:

# Unmount and remount
sudo umount -f /mnt/homelab
sudo mount -a

Safety Considerations

Storage Contract Compliance

Compliant:

  • Mounting NFS on all nodes for data access
  • Using NAS for application data (not control-plane state)
  • Swarm can operate if NFS is temporarily unavailable

Violations to avoid:

  • Don't store Swarm raft data on NFS
  • Don't run manager services that require NFS to stay healthy
  • Don't use NFS for /var/lib/docker or other system paths

Backup Verification

Per storage contract:

  • Data on /mnt/homelab backed up via TerraMaster → Synology rsync
  • Verify backup jobs are running: Check Synology logs
  • Test restores periodically

Maintenance

Adding new NFS shares

  1. Configure export on TerraMaster
  2. Add entry to nfs_mounts list in playbook
  3. Run playbook with --tags setup,config,mount

Removing NFS shares

  1. Unmount: sudo umount /mnt/someshare
  2. Remove from /etc/fstab
  3. Remove directory: sudo rmdir /mnt/someshare


Tags Reference

Tag Purpose
setup Install packages, create directories
packages Install NFS client only
filesystem Create mount point directories only
config Update fstab only
fstab Alias for config
mount Execute mount operations
verify Test mounts and display status