Skip to content

NFS 高可用存储部署指南

方案概述

  • 架构:GlusterFS 3 副本复制卷 + NFS-Ganesha + Keepalived VIP
  • 节点数:3 台(推荐奇数,便于仲裁)
  • 后端存储:各节点本地磁盘,无需 SAN/iSCSI
  • 客户端:普通 Linux 服务器 + Kubernetes 集群
  • 部署方式:手动步骤
  • 不加密:按默认配置部署

架构图

                    ┌─────────────────┐
                    │   Keepalived    │
                    │   VIP: 10.0.0.100│
                    └────────┬────────┘

           ┌─────────────────┼─────────────────┐
           │                 │                 │
    ┌──────▼──────┐   ┌──────▼──────┐   ┌──────▼──────┐
    │  node1      │   │  node2      │   │  node3      │
    │  NFS-Ganesha│   │  NFS-Ganesha│   │  NFS-Ganesha│
    │  GlusterFS  │◄─►│  GlusterFS  │◄─►│  GlusterFS  │
    │  /dev/sdb   │   │  /dev/sdb   │   │  /dev/sdb   │
    └─────────────┘   └─────────────┘   └─────────────┘
           ▲                 ▲                 ▲
           │                 │                 │
           └─────────────────┴─────────────────┘
                    3 副本复制卷

              ┌──────────────┴──────────────┐
              ▼                             ▼
      Linux 客户端 mount            K8s NFS Provisioner

环境规划

节点IP角色数据盘
node110.0.0.11GlusterFS + Ganesha + Keepalived/dev/sdb
node210.0.0.12GlusterFS + Ganesha + Keepalived/dev/sdb
node310.0.0.13GlusterFS + Ganesha + Keepalived/dev/sdb
VIP10.0.0.100浮动 IP,客户端统一入口-

请根据实际网络替换 IP 和网卡名称。

前置准备(所有节点执行)

1. 设置主机名

bash
# node1
hostnamectl set-hostname node1

# node2
hostnamectl set-hostname node2

# node3
hostnamectl set-hostname node3

2. 配置 /etc/hosts

bash
cat <<EOF >> /etc/hosts
10.0.0.11 node1
10.0.0.12 node2
10.0.0.13 node3
EOF

3. 关闭防火墙或放行端口

bash
# Ubuntu
ufw disable

# RHEL/CentOS/Rocky
systemctl stop firewalld
systemctl disable firewalld

如需放行,GlusterFS 主要端口:

  • 24007-24008(GlusterFS 守护进程)
  • 49152+(brick 端口,每个卷一个)
  • 2049(NFS,Ganesha 使用)
  • 111(rpcbind,可选)

4. 时间同步

bash
# Ubuntu
apt install -y chrony
systemctl enable --now chronyd

# RHEL/CentOS/Rocky
dnf install -y chrony
systemctl enable --now chronyd

5. 格式化并挂载数据盘

bash
# 确认磁盘路径,以下以 /dev/sdb 为例
mkfs.xfs -f -i size=512 /dev/sdb

mkdir -p /data/brick1
mount /dev/sdb /data/brick1

echo '/dev/sdb /data/brick1 xfs defaults 0 0' >> /etc/fstab

安装 GlusterFS(所有节点执行)

Ubuntu 22.04

bash
apt update
apt install -y software-properties-common
add-apt-repository ppa:gluster/glusterfs-11 -y
apt update
apt install -y glusterfs-server
systemctl enable --now glusterd

RHEL/CentOS/Rocky 9

bash
dnf install -y centos-release-gluster11
dnf install -y glusterfs-server
systemctl enable --now glusterd

验证服务

bash
systemctl status glusterd

组建 GlusterFS 集群(在 node1 执行)

bash
gluster peer probe node2
gluster peer probe node3

# 查看集群状态
gluster peer status

应看到 2 个 peers in cluster。

创建 3 副本复制卷(在 node1 执行)

bash
gluster volume create gv0 replica 3 \
    node1:/data/brick1/gv0 \
    node2:/data/brick1/gv0 \
    node3:/data/brick1/gv0 force

gluster volume start gv0

# 查看卷状态
gluster volume info gv0
gluster volume status gv0

启用常用优化

bash
gluster volume set gv0 storage.fips-mode-rchecksum on
gluster volume set gv0 performance.cache-size 256MB
gluster volume set gv0 performance.io-thread-count 16
gluster volume set gv0 network.ping-timeout 5

安装 NFS-Ganesha(所有节点执行)

Ubuntu 22.04

bash
apt install -y nfs-ganesha nfs-ganesha-gluster

RHEL/CentOS/Rocky 9

bash
dnf install -y nfs-ganesha nfs-ganesha-gluster

配置 NFS-Ganesha(所有节点执行)

编辑 /etc/ganesha/ganesha.conf

bash
cat > /etc/ganesha/ganesha.conf <<'EOF'
EXPORT {
    Export_Id = 1;
    Path = "/gv0";
    Pseudo = "/gv0";
    Protocols = 3, 4;
    Access_Type = RW;
    Squash = No_Root_Squash;
    FSAL {
        Name = GLUSTER;
        Hostname = localhost;
        Volume = "gv0";
    }
}

LOG {
    Default_Log_Level = INFO;
}
EOF

Hostname = localhost 表示 Ganesha 通过本地 GlusterFS 客户端访问卷,每个节点独立工作。

启动服务:

bash
systemctl enable --now nfs-ganesha
systemctl status nfs-ganesha

验证导出:

bash
showmount -e localhost

应输出:

Export list for localhost:
/gv0 *

安装并配置 Keepalived(所有节点执行)

安装

bash
# Ubuntu
apt install -y keepalived

# RHEL/CentOS/Rocky
dnf install -y keepalived

node1 配置

创建 /etc/keepalived/keepalived.conf

bash
cat > /etc/keepalived/keepalived.conf <<'EOF'
vrrp_script check_ganesha {
    script "/usr/bin/systemctl is-active nfs-ganesha"
    interval 2
    weight -50
    fall 2
    rise 2
}

vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1234
    }
    virtual_ipaddress {
        10.0.0.100/24
    }
    track_script {
        check_ganesha
    }
}
EOF

eth0 替换为实际网卡名。

node2 配置

bash
cat > /etc/keepalived/keepalived.conf <<'EOF'
vrrp_script check_ganesha {
    script "/usr/bin/systemctl is-active nfs-ganesha"
    interval 2
    weight -50
    fall 2
    rise 2
}

vrrp_instance VI_1 {
    state BACKUP
    interface eth0
    virtual_router_id 51
    priority 90
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1234
    }
    virtual_ipaddress {
        10.0.0.100/24
    }
    track_script {
        check_ganesha
    }
}
EOF

node3 配置

bash
cat > /etc/keepalived/keepalived.conf <<'EOF'
vrrp_script check_ganesha {
    script "/usr/bin/systemctl is-active nfs-ganesha"
    interval 2
    weight -50
    fall 2
    rise 2
}

vrrp_instance VI_1 {
    state BACKUP
    interface eth0
    virtual_router_id 51
    priority 80
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1234
    }
    virtual_ipaddress {
        10.0.0.100/24
    }
    track_script {
        check_ganesha
    }
}
EOF

启动 Keepalived

bash
systemctl enable --now keepalived
systemctl status keepalived

查看 VIP 当前所在节点:

bash
ip addr show eth0

客户端挂载

Linux 客户端

bash
# 安装 NFS 客户端
# Ubuntu
apt install -y nfs-common

# RHEL/CentOS/Rocky
dnf install -y nfs-utils

# 创建挂载点
mkdir -p /mnt/nfs-ha

# 临时挂载
mount -t nfs -o vers=4.1,hard,intr,timeo=600,retrans=3 10.0.0.100:/gv0 /mnt/nfs-ha

# 永久挂载(写入 /etc/fstab)
echo '10.0.0.100:/gv0 /mnt/nfs-ha nfs4 defaults,_netdev,hard,intr,timeo=600,retrans=3 0 0' >> /etc/fstab

Kubernetes 客户端

使用 nfs-subdir-external-provisioner 动态供给 PVC。

1. 添加 Helm 仓库

bash
helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
helm repo update

2. 安装 Provisioner

bash
helm install nfs-provisioner nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \
  --set nfs.server=10.0.0.100 \
  --set nfs.path=/gv0 \
  --set storageClass.defaultClass=true

3. 创建测试 PVC

yaml
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: test-pvc
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
EOF

验证与故障测试

1. 检查 NFS 导出

在任意客户端:

bash
showmount -e 10.0.0.100

2. 写数据测试

bash
dd if=/dev/zero of=/mnt/nfs-ha/testfile bs=1M count=100
ls -lh /mnt/nfs-ha/testfile

3. 单节点故障测试

bash
# 1. 找到当前持有 VIP 的节点
ip addr show eth0 | grep 10.0.0.100

# 2. 在该节点停止 Ganesha
systemctl stop nfs-ganesha

# 3. 观察 VIP 是否漂移到其他节点
ip addr show eth0 | grep 10.0.0.100

# 4. 在客户端验证挂载仍然可用
touch /mnt/nfs-ha/failover-test
ls -l /mnt/nfs-ha/failover-test

预期:VIP 在数秒内漂移到健康节点,客户端 IO 短暂停顿后恢复。

4. GlusterFS 自愈验证

当某个节点离线后又恢复,GlusterFS 会自动同步期间变更的数据:

bash
gluster volume heal gv0 info

如看到 Number of entries: 0,说明无需修复。

日常运维命令

bash
# 查看 GlusterFS 集群节点
gluster peer status

# 查看卷信息
gluster volume info gv0

# 查看卷状态
gluster volume status gv0

# 查看 Ganesha 导出
cat /var/run/ganesha/export-1

# 查看 Keepalived 日志
journalctl -u keepalived -f

# 查看 Ganesha 日志
journalctl -u nfs-ganesha -f

# 触发 GlusterFS 修复
gluster volume heal gv0

# 查看存储使用情况
df -h /data/brick1

注意事项

  1. 网络稳定性:GlusterFS 对网络延迟敏感,节点间建议千兆及以上,延迟越低越好。
  2. 脑裂防护:3 副本复制卷天然有仲裁能力,单节点故障不会脑裂;请勿在生产环境中使用 2 副本。
  3. 备份策略:高可用不等于备份,建议定期将关键数据异地备份。
  4. 性能调优:如遇到性能瓶颈,可调整 performance.* 参数或增加 brick 数量。
  5. 防火墙:如果必须开启防火墙,请放行 GlusterFS、NFS-Ganesha、Keepalived(VRRP 协议 112)所需端口。

附录:卸载与清理

如需彻底清理环境:

bash
# 停止并删除卷(在 node1 执行)
gluster volume stop gv0
gluster volume delete gv0

# 断开 peer 关系(在 node1 执行)
gluster peer detach node2
gluster peer detach node3

# 停止服务(所有节点)
systemctl stop nfs-ganesha keepalived glusterd
systemctl disable nfs-ganesha keepalived glusterd

# 卸载数据盘
umount /data/brick1
rm -rf /data/brick1

文档版本:v1.0
适用系统:Ubuntu 22.04 / RHEL 9 / Rocky Linux 9