feat(docker): switch NFS mounts to HA cluster storage VIP
Check NixOS configurations / eval-hosts (push) Failing after 16m43s

Updates mount-data.nix to mount all docker shares from
nfs.storage.home (Pacemaker vip-storage, 192.168.20.229) over docker's
eth1/vmbr2 interface instead of server.sweet.home over the LAN.
Adds haStorageNfsFqdn variable to variables.nix for the storage.home
zone FQDN so mounts survive a future VIP renumber without a rebuild.
Storage root changes from /tank (server ZFS pool) to /srv/ha-data
(HA cluster XFS-over-DRBD). Share subpaths are unchanged.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J8djTWdXVzXZc99iujU6T2
This commit is contained in:
2026-07-29 20:27:15 +10:00
co-authored by Claude Sonnet 4.6
parent 944af9597d
commit 4ed2db906a
2 changed files with 14 additions and 18 deletions
+13 -18
View File
@@ -10,24 +10,19 @@ let
# non-blocking behavior, so they don't need `nofail` too). # non-blocking behavior, so they don't need `nofail` too).
automountOpts = if config.boot.isContainer then [ "nofail" ] else [ "x-systemd.automount" ]; automountOpts = if config.boot.isContainer then [ "nofail" ] else [ "x-systemd.automount" ];
# A bare hostname here never resolves reliably: systemd-resolved only # FQDN in the storage.home zone — resolves to the Pacemaker vip-storage
# ever tries LLMNR for single-label names (never DNS, regardless of any # (192.168.20.229) on docker's eth1/vmbr2 interface. Using the DNS name
# configured search domain), and a *global* search domain (the first fix # rather than the raw IP means a future VIP renumber only requires a DNS
# attempted here) backfires worse -- confirmed live on lxc-docker, adding # update, not a NixOS rebuild. The storage.home zone is served by the same
# `networking.search` made systemd-resolved prioritize its domain-matched # FreeIPA nameserver (domainControllerIp) that docker already uses, so
# but server-less global scope over eth0's correctly-configured one for # resolution reaches it over eth0 without any extra routing.
# every "*.sweet.home" query, silently sending them to public fallback nfsServer = vars.haStorageNfsFqdn;
# DNS instead. `resolvectl query --interface=eth0 server.sweet.home` storageRoot = vars.haStorageRoot;
# resolved fine throughout, proving the LAN DNS server was never the
# problem -- only the ambient, unqualified device string was. Using the
# FQDN directly sidesteps all of that, matching the pattern
# ../raspi/mount-data.nix already uses for the same reason.
nfsServer = "${vars.nfsServerHost}.${vars.homeDomain}";
in in
{ {
fileSystems = { fileSystems = {
${vars.nfsShares.dockerConfig.mountpoint} = { ${vars.nfsShares.dockerConfig.mountpoint} = {
device = "${nfsServer}:${vars.storageRoot}/${vars.nfsShares.dockerConfig.subpath}"; device = "${nfsServer}:${storageRoot}/${vars.nfsShares.dockerConfig.subpath}";
fsType = "nfs"; fsType = "nfs";
options = [ options = [
@@ -38,7 +33,7 @@ in
}; };
${vars.nfsShares.dockerDatabases.mountpoint} = { ${vars.nfsShares.dockerDatabases.mountpoint} = {
device = "${nfsServer}:${vars.storageRoot}/${vars.nfsShares.dockerDatabases.subpath}"; device = "${nfsServer}:${storageRoot}/${vars.nfsShares.dockerDatabases.subpath}";
fsType = "nfs"; fsType = "nfs";
options = [ options = [
@@ -49,7 +44,7 @@ in
}; };
${vars.nfsShares.dockerVolumes.mountpoint} = { ${vars.nfsShares.dockerVolumes.mountpoint} = {
device = "${nfsServer}:${vars.storageRoot}/${vars.nfsShares.dockerVolumes.subpath}"; device = "${nfsServer}:${storageRoot}/${vars.nfsShares.dockerVolumes.subpath}";
fsType = "nfs"; fsType = "nfs";
options = [ options = [
@@ -60,7 +55,7 @@ in
}; };
${vars.nfsShares.nextcloudData.mountpoint} = { ${vars.nfsShares.nextcloudData.mountpoint} = {
device = "${nfsServer}:${vars.storageRoot}/${vars.nfsShares.nextcloudData.subpath}"; device = "${nfsServer}:${storageRoot}/${vars.nfsShares.nextcloudData.subpath}";
fsType = "nfs"; fsType = "nfs";
options = [ options = [
@@ -71,7 +66,7 @@ in
}; };
${vars.nfsShares.raspiVolumes.mountpoint} = { ${vars.nfsShares.raspiVolumes.mountpoint} = {
device = "${nfsServer}:${vars.storageRoot}/${vars.nfsShares.raspiVolumes.subpath}"; device = "${nfsServer}:${storageRoot}/${vars.nfsShares.raspiVolumes.subpath}";
fsType = "nfs"; fsType = "nfs";
options = [ options = [
+1
View File
@@ -128,6 +128,7 @@
haClientCidr = "192.168.20.0/24"; # storage-client subnet — VLAN 20, internal to pve1 only haClientCidr = "192.168.20.0/24"; # storage-client subnet — VLAN 20, internal to pve1 only
haClientPrefixLength = 24; # storage-client subnet prefix length (/24) haClientPrefixLength = 24; # storage-client subnet prefix length (/24)
haStorageRoot = "/srv/ha-data"; # XFS-over-DRBD mount point on the Active node haStorageRoot = "/srv/ha-data"; # XFS-over-DRBD mount point on the Active node
haStorageNfsFqdn = "nfs.storage.home"; # NFS VIP FQDN (storage.home zone) — resolves to haServerVip; use this in fileSystems device strings
haIscsiIqn = "iqn.2026-01.home.sweet:ha-storage"; haIscsiIqn = "iqn.2026-01.home.sweet:ha-storage";
# DRBD backing disk — identified by SCSI controller path so it resolves to the # DRBD backing disk — identified by SCSI controller path so it resolves to the
# correct block device regardless of OS-level naming (sda vs sdb can differ # correct block device regardless of OS-level naming (sda vs sdb can differ