从手动到自动化:一文搞懂NFS共享存储的Ansible部署
NFS共享存储自动化部署指南 本文介绍了如何通过Ansible实现NFS共享存储的自动化部署。主要内容包括: NFS核心概念解析:依赖rpcbind服务,共享目录配置格式(/etc/exports),权限映射问题解决方案 手动部署步骤演示:服务端创建共享目录、配置exports文件、启动服务;客户端安装工具、挂载目录 Ansible自动化实现:详细拆解服务端和客户端的Playbook编写过程,包括
前言
作为运维工程师,你一定遇到过这样的场景:Web服务器需要上传文件,但有多台后端节点,文件放在哪台机器上都不合适。这时候,共享存储就是最好的解决方案,而NFS(网络文件系统)则是其中最简单、最经典的选择。
但是,手动部署NFS虽然步骤不多,却暗藏不少“坑”:权限怎么配?用户ID要不要统一?客户端挂载怎么写才能永久生效?
今天,我不只教你手动怎么配,更要带你一步步推导出——如何用Ansible将这个过程自动化,最终形成一个可复用、可扩展的部署剧本。
一、先搞懂NFS的核心概念
在动手之前,有几个关键概念必须理清:
1.1 NFS依赖什么服务?
很多人以为NFS只是一个服务,实际上它依赖两个东西:
-
rpcbind:负责RPC(远程过程调用)的端口映射。NFS服务启动后会在随机端口注册到rpcbind,客户端通过rpcbind找到NFS的正确端口。
-
nfs-utils:提供NFS服务端和客户端的所有工具(
showmount、exportfs、mount.nfs等)。
小知识:服务端需要同时安装并启动
nfs-server和rpcbind;客户端只需要rpcbind和nfs-utils中的挂载工具。
1.2 共享目录怎么配置?
NFS的核心配置文件是/etc/exports,每一行的格式如下:
共享目录 允许访问的客户端(参数1,参数2,...)
/data/ 172.16.1.0/24(rw,sync,all_squash,anonuid=666,anongid=666)
参数解释:
| 参数 | 含义 |
|---|---|
rw |
读写权限(ro是只读) |
sync |
同步写入,数据安全但性能稍差 |
all_squash |
将所有客户端访问压缩为匿名用户 |
anonuid/anongid |
匿名用户映射为哪个UID/GID |
1.3 最难理解的权限问题
很多初学者在这里栽跟头:为什么客户端写进去的文件在服务端显示是nobody?为什么权限总是对不上?
核心原因:NFS默认将客户端的root用户压缩为nobody,普通用户则保留原有UID。
解决方案:
-
使用
all_squash强制所有用户都走匿名映射 -
配合
anonuid=666,anongid=666统一映射到一个专用账号 -
在服务端创建相同UID/GID的用户
这样,无论哪个客户端、用什么账号写入,文件最终都属于www用户(UID 666),完美解决权限混乱问题。
二、手动部署一遍,理清所有步骤
假设我们有这样的环境:
| 角色 | IP地址 | 共享目录 | 挂载点 |
|---|---|---|---|
| 服务端 | 10.0.0.71 | /data |
- |
| 客户端 | 10.0.0.41 | - | /WebData |
2.1 服务端手动步骤
# 1. 安装软件
yum install -y nfs-utils rpcbind
# 2. 创建共享目录和专用用户
groupadd -g 666 www
useradd -u 666 -g www -s /sbin/nologin -M www
mkdir /data
chown www:www /data
# 3. 配置exports文件
echo "/data/ 172.16.1.0/24(rw,sync,all_squash,anonuid=666,anongid=666)" > /etc/exports
# 4. 启动服务
systemctl start nfs
systemctl enable nfs
2.2 客户端手动步骤
# 1. 安装软件(注意:客户端不需要启动nfs服务)
yum install -y nfs-utils rpcbind
# 2. 启动rpcbind
systemctl start rpcbind
systemctl enable rpcbind
# 3. 创建挂载点
mkdir /WebData
# 4. 手动挂载(临时)
mount -t nfs 172.16.1.71:/data /WebData
# 5. 写入fstab(永久生效)
echo "172.16.1.71:/data /WebData nfs defaults 0 0" >> /etc/fstab
到这里,手动部署就完成了。但是,如果我有10台客户端呢?如果环境要重建呢?手动重复这些步骤显然不可取。
三、思考:如何用Ansible自动化?
Ansible的核心思想是声明式——你告诉它“最终状态是什么”,它帮你达到这个状态。
3.1 从手动命令到Ansible模块的映射
| 手动操作 | Ansible模块 | 关键参数 |
|---|---|---|
yum install |
yum |
name, state=present |
groupadd |
group |
name, gid |
useradd |
user |
name, uid, group, shell, create_home |
mkdir + chown |
file |
path, state=directory, owner, group |
写入/etc/exports |
copy 或 lineinfile |
content, dest |
systemctl start/enable |
systemd |
name, state, enabled |
mount + 写/etc/fstab |
mount |
src, path, fstype, state=mounted |
3.2 服务端Playbook的推导过程
第一步:安装软件
- name: install nfs server and rpcbind
yum:
name: nfs-utils,rpcbind
state: present
第二步:准备共享目录和用户(注意顺序:先group再user再目录)
- name: create group with gid 666
group:
name: www
gid: 666
state: present
- name: create user with uid 666
user:
name: www
uid: 666
group: www
shell: /sbin/nologin
create_home: false
- name: create data directory
file:
path: /data
state: directory
owner: www
group: www
第三步:写入配置文件
- name: configure nfs exports
copy:
content: "/data/ 172.16.1.0/24(rw,sync,all_squash,anonuid=666,anongid=666)"
dest: /etc/exports
这里为什么用copy而不是lineinfile?因为/etc/exports通常只有一行配置,用content直接写最简单。如果是复杂配置,可以准备模板文件用template模块。
第四步:启动服务
- name: start and enable nfs server
systemd:
name: nfs
state: started
enabled: yes
3.3 客户端Playbook的推导过程
第一步:安装软件(和服务端一样)
- name: install nfs utils on client
yum:
name: nfs-utils,rpcbind
state: present
第二步:启动rpcbind(客户端不需要启动nfs服务,但需要rpcbind)
- name: start and enable rpcbind
systemd:
name: rpcbind
state: started
enabled: yes
第三步:创建挂载点
- name: create mount directory
file:
path: /WebData
state: directory
第四步:挂载共享目录(这个模块最强大:一次操作完成mount和写fstab)
- name: mount nfs share persistently
mount:
src: 172.16.1.71:/data
path: /WebData
fstype: nfs
state: mounted
state=mounted的含义:
-
如果未挂载,立即执行
mount命令 -
同时写入
/etc/fstab,保证重启后自动挂载 -
如果已挂载且参数正确,不做任何操作(幂等性)
四、完整的Ansible剧本
将上面的片段组合起来,就得到了完整的部署剧本:
服务端剧本(保存为 nfs-server.yml)
- hosts: 10.0.0.71
tasks:
- name: install nfs server,rpcbind
yum:
name: nfs-utils,rpcbind
state: present
- name: configue nfs-utils
copy:
content: "/data/ 172.16.1.0/24(rw,sync,all_squash,anonuid=666,anongid=666)"
dest: /etc/exports
- name: create group
group:
name: www
gid: 666
state: present
- name: create user
user:
name: www
uid: 666
group: www
shell: /sbin/nologin
create_home: false
- name: create data
file:
path: /data
state: directory
owner: www
group: www
- name: start nfs server
systemd:
name: nfs
state: started
enabled: yes
客户端剧本(保存为 nfs-client.yml)
- hosts: 10.0.0.41
tasks:
- name: nfs server,rpcbind of client
yum:
name: nfs-utils,rpcbind
state: present
- name: start rpcbind
systemd:
name: rpcbind
state: started
enabled: yes
- name: create mount of directory
file:
path: /WebData
state: directory
- name: mount the shareDirectory on 10.0.0.41
mount:
src: 172.16.1.71:/data
path: /WebData
fstype: nfs
state: mounted
一键执行
ansible-playbook -i "10.0.0.71,10.0.0.41" nfs-server.yml nfs-client.yml
五、你可能想问的几个问题
Q1:为什么服务端IP是10.0.0.71,但exports里写的是172.16.1.0/24?
这是生产环境的常见设计:管理网络(Ansible用的)和业务网络(NFS流量走的)分开。172.16.1.0/24是内网存储网络,性能更好、更安全。
Q2:如果有多台客户端怎么办?
很简单,把客户端的IP列表写进inventory文件:
[nfs_clients]
10.0.0.41
10.0.0.42
10.0.0.43
然后Playbook开头写成:
- hosts: nfs_clients
Q3:怎么验证部署成功了?
执行完Playbook后,在客户端运行:
df -h /WebData # 查看是否挂载成功
touch /WebData/test.txt # 测试写入
在服务端运行:
ls -l /data # 查看文件属主应为www
showmount -e localhost # 查看共享目录是否正确导出
六、总结:从手动到自动化的思维转变
回顾整个过程,我们经历了三个阶段:
-
理解原理:NFS依赖关系、exports参数含义、权限映射逻辑
-
手动实践:在命令行逐条执行,验证每一步的结果
-
自动化抽象:将命令转化为Ansible模块,关注“状态”而非“步骤”
这份剧本现在可以直接用于生产环境,更重要的是,要掌握方法论——任何重复的运维工作,都可以用同样的思路去自动化。
更多推荐
所有评论(0)