一、NFS环境部署与共享配置
1.1 默认共享配置实践
首先,在NFS服务端创建测试目录并准备示例文件。
root@ubuntu24:~# mkdir /data/dir{a,b}
root@ubuntu24:~# cp /etc/fstab /data/dira/
接下来,编辑NFS的主配置文件 /etc/exports,设置共享目录与访问规则。
root@ubuntu24:~# cat /etc/exports
/data/dira * # 所有主机都可以挂载,权限是默认的权限
1.2 使配置生效
配置完成后,需要重新加载或重启NFS服务使共享设置生效。
root@ubuntu24:~# exportfs -r
# 或使用systemctl重启服务
root@ubuntu24:~# systemctl restart nfs-server.service
1.3 测试与默认权限解读
使用 exportfs -v 命令可以详细查看当前的共享列表及其对应的默认选项。
root@ubuntu24:~# exportfs -v
/data/dira <world>
(sync,wdelay,hide,no_subtree_check,sec=sys,ro,secure,root_squash,no_all_squash)
下面对关键默认权限进行解读:
- sync:数据同步写入,请求会等待数据写入磁盘后才返回。
- wdelay:延迟写入,将多个客户端的写操作归组以提高性能。
- hide:不自动共享共享目录的子目录。
- no_subtree_check:不检查父目录权限,提升访问速度,但可能带来安全风险。
- sec=sys:使用基于主机名和用户ID的传统UNIX安全机制进行身份验证。
- ro:只读权限,客户端无法写入。
- secure:NFS服务仅通过小于1024的公认安全端口进行通信。
- root_squash:将客户端root用户的请求映射为服务端的匿名用户(如nobody),这是重要的安全设置。
- no_all_squash:非root用户保持其原有的UID和GID。

我们也可以在客户端使用 showmount 命令查看服务器提供的共享列表。
root@ubuntu24:~# showmount -e 10.0.0.13
Export list for 10.0.0.13:
/data/dira *
二、客户端挂载测试
2.1 挂载操作
在客户端创建本地挂载点,并将远程NFS共享目录挂载上来。
root@ubuntu24:~# mkdir -pv /data/dir{1,2}
mkdir: created directory '/data'
mkdir: created directory '/data/dir1'
mkdir: created directory '/data/dir2'
# 执行挂载
root@ubuntu24:~# mount 10.0.0.13:/data/dira /data/dir1
使用 mount 和 df 命令验证挂载状态并查看文件。
root@ubuntu24:~# mount | grep nfs
10.0.0.13:/data/dira on /data/dir1 type nfs4 (ro,relatime,vers=4.2,rsize=262144,wsize=262144,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=10.0.0.16,local_lock=none,addr=10.0.0.13)
root@ubuntu24:~# df -h /data/dir1/
Filesystem Size Used Avail Use% Mounted on
10.0.0.13:/data/dira 97G 7.4G 85G 9% /data/dir1
root@ubuntu24:~# ls -l /data/dir1
total 4
-rw-r--r-- 1 root root 657 Jul 9 09:58 fstab
2.2 验证只读权限
由于服务端配置为ro(只读),客户端尝试写入文件将会失败。
root@ubuntu24:~# cat /data/dir1/fstab
# /etc/fstab: static file system information.
...
root@ubuntu24:~# echo "123" >> /data/dir1/fstab
-bash: /data/dir1/fstab: Read-only file system
root@ubuntu24:~# touch /data/dir1/test
touch: cannot touch '/data/dir1/test': Read-only file system
三、精细化权限控制实践
3.1 基于客户端的读写授权
我们可以修改 /etc/exports 文件,针对不同IP地址指定不同的访问权限。
root@ubuntu24:~# cat /etc/exports
# 10.0.0.16 可读写, 10.0.0.12 保持默认只读选项
/data/dira 10.0.0.16(rw) 10.0.0.12
重新导出共享并查看详情,可见不同主机已应用不同权限。
root@ubuntu24:~# exportfs -r
root@ubuntu24:~# exportfs -v
/data/dira
10.0.0.16(sync,wdelay,hide,no_subtree_check,sec=sys,rw,secure,root_squash,no_all_squash)
/data/dira
10.0.0.12(sync,wdelay,hide,no_subtree_check,sec=sys,ro,secure,root_squash,no_all_squash)

3.2 解决“可配置不可写”问题
即使服务端为特定主机(如10.0.0.16)配置了rw权限,客户端挂载后仍可能无法写入。这通常是因为共享目录本身对“其他用户(others)”没有写权限。
# 在10.0.0.16客户端测试,仍报错
root@ubuntu24-16:~# touch /data/dir1/test-16
touch: cannot touch '/data/dir1/test-16': Permission denied
# 在服务端检查共享目录权限
root@ubuntu24:~# ll /data/dira -d
drwxr-xr-x 2 root root 4096 10月 18 20:23 /data/dira/
# 可见,权限为755,其他用户(o)无写(w)权限
需要在NFS服务端为共享目录添加其他用户的写权限。
root@ubuntu24:~# chmod o+w /data/dira
root@ubuntu24:~# ll /data/dira -d
drwxr-xrwx 2 root root 4096 10月 18 20:23 /data/dira/
此时,客户端10.0.0.16即可成功创建文件。注意,由于root_squash生效,创建的文件属主为nobody。
root@ubuntu24-16:~# touch /data/dir1/test-16
root@ubuntu24-16:~# ls /data/dir1/ -l
总计 4
-rw-r--r-- 1 root root 473 11月 26 23:12 fstab # 原文件属主
-rw-r--r-- 1 nobody nogroup 0 11月 26 23:30 test-16 # 新文件属主被映射
而另一台仅具有ro权限的主机(10.0.0.12)则无法写入。
[root@rocky9 ~]# mount 10.0.0.13:/data/dira /data/dir1
[root@rocky9 ~]# ls /data/dir1
fstab test-16
[root@rocky9 ~]# touch /data/dir1/test-12
touch: 无法创建 '/data/dir1/test-12': 只读文件系统
3.3 授权范围验证
未被明确授权的主机将无法挂载共享目录。
root@ubuntu24:~# showmount -e 10.0.0.13
Export list for 10.0.0.13:
/data/dira 10.0.0.12,10.0.0.16
# 使用一个未授权IP尝试挂载
root@ubuntu24:~# mount 10.0.0.13:/data/dira /data/0.13
mount.nfs: access denied by server while mounting 10.0.0.13:/data/dira
四、Rsync实时同步环境搭建
为实现文件的实时同步,我们常使用rsync。在云原生/IaaS环境中,跨主机的高效文件同步是基础运维需求。
| IP |
角色 |
系统 |
| 10.0.0.13 |
rsync-server |
ubuntu24 |
| 10.0.0.12 |
rsync-client |
rocky9 |
4.1 启动Rsync守护进程
在Ubuntu系统上,默认的rsync服务并未启动,需要手动启用。
root@ubuntu24-13:~# systemctl status rsync
○ rsync.service - fast remote file copy program daemon
Loaded: loaded (/usr/lib/systemd/system/rsync.service; disabled; preset:enabled)
Active: inactive (dead)
# 启用并启动服务
root@ubuntu24-13:~# systemctl enable --now rsync.service
启动可能会失败,提示缺少配置文件 /etc/rsyncd.conf。
root@ubuntu24-13:~# systemctl status rsync
...
Condition: start condition unmet ...
└─ ConditionPathExists=/etc/rsyncd.conf was not met
创建该文件后再次启动即可成功。
root@ubuntu24-13:~# touch /etc/rsyncd.conf
root@ubuntu24-13:~# systemctl start rsync.service
root@ubuntu24-13:~# ss -tunlp | grep rsync
tcp LISTEN 0 5 0.0.0.0:873 0.0.0.0:*
tcp LISTEN 0 5 [::]:873 [::]:*
4.2 定制服务端Rsync配置
编辑 /etc/rsyncd.conf,配置模块、认证等信息。
root@ubuntu24-13:~# cat /etc/rsyncd.conf
uid=root
gid=root
max connections=0
log file=/var/log/rsyncd.log
pid file=/var/run/rsyncd.pid
lock file=/var/run/rsyncd.lock
[dir1] # 模块名
path=/data/dir1/ # 服务端实际目录路径
comment=rsync dir1
read only=no # 允许写入
auth users=rsyncer # 授权用户(非系统用户)
secrets file=/etc/rsyncd.pwd # 密码文件路径
创建密码文件并设置严格权限。
# 格式:用户名:密码
root@ubuntu24-13:~# echo 'rsyncer:123456' > /etc/rsyncd.pwd
# 密码文件权限必须为600
root@ubuntu24-13:~# chmod 600 /etc/rsyncd.pwd
root@ubuntu24-13:~# systemctl restart rsync.service

4.3 客户端连接测试
从客户端测试连接,需使用配置中指定的认证用户名。
# 错误示范:匿名连接(未指定用户)
[root@rocky9-12 ~]# rsync 10.0.0.13::dir1
Password:
@ERROR: auth failed on module dir1
# 正确连接:指定认证用户
[root@rocky9-12 ~]# rsync rsyncer@10.0.0.13::dir1
Password: # 手动输入密码 123456
drwxrwxr-x 4,096 2024/11/26 17:32:53 .
-rw-r--r-- 661 2024/11/26 17:31:43 fstab
-rw-r--r-- 23 2024/11/26 17:32:53 issue
# 推送文件测试
[root@rocky9-12 ~]# rsync /etc/hosts rsyncer@10.0.0.13::dir1
Password:
# 在服务端查看,文件同步成功
root@ubuntu24-13:~# ll /data/dir1
-rw-r--r-- 1 root root 158 11月 26 17:43 hosts # 新文件
4.4 使用密码文件实现非交互同步
为便于脚本调用,可以将密码保存在客户端的文件中,实现免交互同步。
在客户端准备测试目录和文件。
[root@rocky9-12 ~]# mkdir -p /data/www/dira
[root@rocky9-12 ~]# cp /etc/os-release /data/www/dira/
[root@rocky9-12 ~]# touch /data/www/{f1,f2}
[root@rocky9-12 ~]# cp /etc/fstab /etc/issue /data/www/
[root@rocky9-12 ~]# tree /data/www/
/data/www/
├── dira
│ └── os-release
├── f1
├── f2
├── fstab
└── issue
创建仅包含密码的客户端密码文件。
[root@rocky9-12 ~]# echo "123456" > /etc/rsyncd.pwd
[root@rocky9-12 ~]# chmod 600 /etc/rsyncd.pwd
执行同步命令,--delete 选项会使目标目录与源目录严格一致。
[root@rocky9-12 ~]# rsync -avz --delete --password-file=/etc/rsyncd.pwd /data/www/ rsyncer@10.0.0.13::dir1
sending incremental file list
deleting hosts # 删除了服务端原有的hosts文件
./
f1
f2
fstab
issue
dira/
dira/os-release
sent 685 bytes received 147 bytes 1,664.00 bytes/sec
total size is 1,191 speedup is 1.43
五、Inotify + Rsync 实现实时同步
仅使用rsync是定时或手动同步。要实现实时同步,需要借助 inotify-tools 监控本地目录变化,然后触发rsync。
5.1 编写实时同步脚本
以下是一个功能较完善的实时同步脚本示例,它包含了系统判断和自动安装依赖。
[root@rocky9-12 ~]# cat /data/scrips/rsync.sh
#!/bin/bash
# 定制环境变量
USER="rsyncer"
PASS_FILE="/data/scrips/www_rsync.pwd"
REMOTE_HOST="10.0.0.13"
SRC="/data/www/"
REMOTE_DIR="dir1"
DEST="${USER}@${REMOTE_HOST}::${REMOTE_DIR}"
LOG_FILE="/data/scrips/www_rsync.log"
# 安装依赖函数 (inotify-tools 和 rsync)
ubuntu_install_inotify() {
if [ ! -f /usr/bin/inotifywait ]; then
apt update && apt install inotify-tools rsync -y
fi
}
centos_install_inotify() {
if [ ! -f /usr/bin/inotifywait ]; then
yum install epel-release -y
yum install inotify-tools rsync -y
fi
}
install_inotify() {
if grep -iq ubuntu /etc/os-release; then
ubuntu_install_inotify
else
centos_install_inotify
fi
}
# 核心监控与同步函数
rsync_file() {
inotifywait -mr --exclude=".*\.swp" --timefmt "%Y-%m-%d %H:%M:%S" --format '%T %w %f' \
-e create,delete,moved_to,close_write,attrib ${SRC} | while read DATE TIME DIR FILE; do
FILEPATH=${DIR}${FILE}
# 执行同步并记录日志
rsync -az --delete --password-file=${PASS_FILE} ${SRC} ${DEST} && \
echo "At ${TIME} on ${DATE}, file ${FILEPATH} was backup via rsync" >> ${LOG_FILE}
done
}
# 主函数
main(){
install_inotify
# 首次全量同步
rsync -az --delete --password-file=${PASS_FILE} ${SRC} ${DEST}
echo "Initial sync completed at $(date)" >> ${LOG_FILE}
# 开始实时监控
rsync_file
}
# 执行
main

5.2 执行脚本
在客户端准备好密码文件并运行脚本。
[root@rocky9-12 ~]# mkdir -p /data/scrips
[root@rocky9-12 ~]# echo 123456 > /data/scrips/www_rsync.pwd
[root@rocky9-12 ~]# chmod 600 /data/scrips/www_rsync.pwd
[root@rocky9-12 ~]# /bin/bash /data/scrips/rsync.sh &
脚本将常驻后台,监控/data/www/目录的变化并实时同步到服务端。
六、使用Sersync实现实时同步
Sersync是基于Inotify和Rsync的国产解决方案,它使用多线程,在同步大量小文件时性能通常优于单纯脚本。
6.1 Rocky9客户端部署Sersync
下载并解压Sersync二进制包。
[root@rocky9-12 ~]# mkdir /data/softs -p ; cd /data/softs
[root@rocky9-12 softs]# wget https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/sersync/sersync2.5.4_64bit_binary_stable_final.tar.gz
[root@rocky9-12 softs]# tar xf sersync2.5.4_64bit_binary_stable_final.tar.gz
[root@rocky9-12 softs]# mv GNU-Linux-x86/ /usr/local/sersync
[root@rocky9-12 softs]# cd /usr/local/sersync/
[root@rocky9-12 sersync]# ls
confxml.xml sersync2
6.2 修改配置文件
配置文件confxml.xml是关键,需要根据我们的环境进行调整。
<?xml version="1.0" encoding="ISO-8859-1"?>
<head version="2.5">
<host hostip="localhost" port="8008"></host>
<debug start="false"/>
<fileSystem xfs="false"/>
<!-- 过滤器,根据需求开启 -->
<filter start="false">
<exclude expression="(.*)\.svn"></exclude>
<exclude expression="(.*)\.gz"></exclude>
</filter>
<!-- 定义要监控的事件 -->
<inotify>
<delete start="true"/>
<createFolder start="true"/>
<createFile start="true"/> <!-- 改为 true,监控文件创建 -->
<closeWrite start="true"/>
<moveFrom start="true"/>
<moveTo start="true"/>
<attrib start="true"/> <!-- 改为 true,监控属性变化 -->
<modify start="true"/> <!-- 改为 true,监控文件修改 -->
</inotify>
<!-- Rsync同步配置 -->
<sersync>
<!-- 本地要同步的目录 -->
<localpath watch="/data/www">
<!-- 远程Rsync服务器模块 -->
<remote ip="10.0.0.13" name="dir1"/>
</localpath>
<rsync>
<commonParams params="-artuz"/>
<!-- 启用认证,指定用户名和密码文件 -->
<auth start="true" users="rsyncer" passwordfile="/etc/rsyncd.pwd"/>
<userDefinedPort start="false" port="874"/>
<timeout start="false" time="100"/>
<ssh start="false"/>
</rsync>
<!-- 失败重传日志 -->
<failLog path="/tmp/rsync_fail_log.sh" timeToExecute="60"/>
<crontab start="false" schedule="600">
<crontabfilter start="false">
<exclude expression="*.php"></exclude>
</crontabfilter>
</crontab>
<plugin start="false" name="command"/>
</sersync>
</head>
6.3 启动Sersync
查看帮助信息并以后台守护进程模式启动。
[root@rocky9-12 sersync]# ./sersync2 -h
...
参数-d:启用守护进程模式
参数-r:在监控前,将监控目录与远程主机用rsync命令推送一遍
参数-o:指定配置文件,默认使用confxml.xml文件
...
# 清理客户端源目录,并确保密码文件存在
[root@rocky9-12 ~]# rm -rf /data/www/*
[root@rocky9-12 ~]# echo 123456 > /etc/rsyncd.pwd
[root@rocky9-12 ~]# chmod 600 /etc/rsyncd.pwd
[root@rocky9-12 ~]# mkdir -p /data/www/dira/dirb/dirc
# 以守护进程模式启动,-r表示先进行全量同步
[root@rocky9-12 sersync]# ./sersync2 -dro ./confxml.xml
set the system param
execute:echo 50000000 > /proc/sys/fs/inotify/max_user_watches
execute:echo 327679 > /proc/sys/fs/inotify/max_queued_events
parse the command param
option: -d run as a daemon
option: -r rsync all the local files to the remote servers before the sersync work
...
watch path is: /data/www
# 检查进程
[root@rocky9-12 sersync]# ps aux | grep confxml
root 2689 0.0 0.0 182464 1536 ? Ssl 19:33 0:00 ./sersync2 -dro ./confxml.xml

6.4 验证实时同步效果
在服务端查看,初始目录结构已同步完成。
root@ubuntu24-13:~# tree /data/dir1/
/data/dir1/
└── dira
└── dirb
└── dirc
在客户端源目录进行增删改操作,观察服务端是否实时同步。
# 客户端操作
[root@rocky9-12 ~]# mkdir -pv /data/www/dirb/dirb/dirc
[root@rocky9-12 ~]# cp /etc/fstab /data/www/
[root@rocky9-12 ~]# dd if=/dev/zero of=/data/www/test.img bs=1M count=10
# 服务端实时查看结果
root@ubuntu24-13:~# tree /data/dir1/
/data/dir1/
├── dira
│ └── dirb
│ └── dirc
├── dirb
│ └── dirb
│ └── dirc
├── fstab
└── test.img
至此,通过NFS实现静态共享,以及通过Rsync结合Inotify或Sersync实现动态实时同步的完整流程已实践完毕。根据实际业务对实时性、性能和复杂度的要求,可以选择合适的同步方案。在运维/DevOps工作中,这些是保障多节点间数据一致性的重要手段。