1. 介绍
NFS 即网络文件系统(Network File-System),可以通过网络让不同机器、不同系统之间可以实现文件共享。通过 NFS,可以访问远程共享目录,就像访问本地磁盘一样。NFS 只是一种文件系统,本身并没有传输功能,是基于 RPC(远程过程调用)协议实现的,采用 C/S 架构。
2. 安装
Ubuntu
$ sudo apt-get install nfs-kernel-server # 安装 NFS服务器端
$ sudo apt-get install nfs-common # 安装 NFS客户端
CentOS
$ rpm -qa nfs-utils rpcbind # 检查是否已经安装(有输出表示已安装对应包)
$ yum install -y nfs-utils rpcbind # 服务端
$ yum install -y nfs-utils # 客户端
3. 配置共享目录
在服务端创建一个共享目录 /share ,作为客户端挂载的远端入口,然后设置权限
$ mkdir -p /share
$ chmod -R 777 /share
添加到配置文件中
$ vim /etc/exports
# 添加下面这句
/share 192.168.0.0/16(rw,sync,no_root_squash)
# /share *(rw,sync,no_root_squash) # 表示所有主机
编辑/etc/exports文件添加需要共享目录,每个目录的设置独占一行,编写格式如下:
NFS共享目录路径 客户机IP或者名称(参数1,参数2,…,参数n)
更多参数如下:
参数 | 说明 |
---|---|
ro | 只读访问 |
rw | 读写访问 |
sync | 所有数据在请求时写入共享 |
async | nfs 在写入数据前可以响应请求 |
secure | nfs 通过 1024 以下的安全 TCP/IP 端口发送 |
insecure | nfs 通过 1024 以上的端口发送 |
wdelay | 如果多个用户要写入 nfs 目录,则归组写入(默认) |
no_wdelay | 如果多个用户要写入 nfs 目录,则立即写入,当使用 async 时,无需此设置 |
hide | 在 nfs 共享目录中不共享其子目录 |
no_hide | 共享 nfs 目录的子目录 |
subtree_check | 如果共享 /usr/bin 之类的子目录时,强制 nfs 检查父目录的权限(默认) |
no_subtree_check | 不检查父目录权限 |
all_squash | 共享文件的 UID 和 GID 映射匿名用户 anonymous,适合公用目录 |
no_all_squash | 保留共享文件的 UID 和 GID(默认) |
root_squash | root 用户的所有请求映射成如 anonymous 用户一样的权限(默认) |
no_root_squash | root 用户具有根目录的完全管理访问权限 |
anonuid=xxx | 指定 nfs 服务器 /etc/passwd 文件中匿名用户的 UID |
anongid=xxx | 指定 nfs 服务器 /etc/passwd 文件中匿名用户的 GID |
注1:尽量指定主机名或IP或IP段最小化授权可以访问NFS 挂载的资源的客户端;注意如果在k8s集群中配合nfs-client-provisioner使用的话,这里需要指定pod的IP段,否则nfs-client-provisioner pod无法启动,报错 mount.nfs: access denied by server while mounting | |
注2:经测试参数insecure必须要加,否则客户端挂载出错mount.nfs: access denied by server while mounting |
4. 开启NFS服务
Ubuntu
$ sudo /etc/init.d/nfs-kernel-server start # 开启
$ sudo systemctl start nfs-kernel-server.service # 开启
$ sudo /etc/init.d/nfs-kernel-server restart # 重启
CentOs
$ service rpcbind start # 开启
$ /bin/systemctl start rpcbind.service # 开启
5. 查看配置信息
查看NFS已开启端口
$ rpcinfo -p localhost
查看NFS已加载共享目录
$ showmount -e 192.168.1.8 # 地址是服务端地址
Export list for 192.168.1.8:
/share 192.168.0.0/16
这些命令都在NFS服务端执行才有效。
6. 本地挂载
客户机本地挂在远端目录
$ mount 192.168.1.8:/share /loc_share
$ df -h | grep 192.168.1.8
Filesystem Size Used Avail Use% Mounted on
192.168.1.8:/share 27G 11G 17G 40% /loc_share
NFS 默认使用 UDP 协议来进行挂载,为了提高 NFS 的稳定性,可以使用 TCP 协议挂载:
$ mount 192.168.1.8:/share /loc_share -o proto=tcp -o nolock
挂在成功后,我们就可以对/share目录进行读写(创建删除修改文件和目录)
客户端卸载
$ umount /share
7. libnfs库
上面我们是在终端中对共享目录/share进行读写,除此之外我们也可以通过编写程序来执行上面的所有操作,包括创建、挂载、卸载、读写等等。这里介绍写libnfs库,里面封装好了很多接口,使用也很简单。
https://github.com/sahlberg/libnfs
(1)libnfs安装
# 下载
$ git clone https://github.com/sahlberg/libnfs.git
# 进入到项目根目录
$ cd libnfs
# 构建项目
$ ./bootstrap
# 根据配置生成makefile文件
$ ./confiure # 默认配置即可
# 编译
$ make
# 安装
$ make install
(2)libnfs 程序示例
场景:向共享目录下指定文件写入一行数据
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "libnfs.h"
#include "libnfs-raw.h"
#include "libnfs-raw-mount.h"
int main(int argc, char *argv[])
{
int ret = 1;
struct nfs_context *nfs = NULL;
struct nfsfh *nfsfh = NULL;
struct nfs_url *url = NULL;
if (argc != 2)
{
fprintf(stderr, "无效URL, 格式[nfs://ip/path/filename].\n");
goto finished;
}
// 初始化nfs上下文
nfs = nfs_init_context();
if (nfs == NULL)
{
printf("failed to init context\n");
goto finished;
}
// 解析传入的nfs url, 格式[nfs://ip/path/filename]
url = nfs_parse_url_full(nfs, argv[1]);
if (url == NULL)
{
fprintf(stderr, "%s\n", nfs_get_error(nfs));
goto finished;
}
// 挂在目录(此处挂在的就是配置文件exports里面配置好的共享目录)
if (nfs_mount(nfs, url->server, url->path) != 0)
{
fprintf(stderr, "Failed to mount nfs share : %s\n", nfs_get_error(nfs));
goto finished;
}
// 打开需要读写的文件
ret = nfs_open(nfs, url->file, 0600, &nfsfh);
if (ret != 0)
{
printf("failed to open %s\n", url->file);
goto finished;
}
// 写点数据
ret = nfs_write(nfs, nfsfh, sizeof("write successfully\n"), "write successfully\n");
if (ret < 0)
{
printf("failed to write %s\n", url->file);
goto finished;
}
printf("successfully\n");
finished:
// 用完记得释放资源
nfs_destroy_url(url);
if (nfs != NULL)
{
if (nfsfh)
{
nfs_close(nfs, nfsfh);
}
nfs_destroy_context(nfs);
}
return ret;
}
编译
# 当前在exapmles目录下面
$ gcc nfs-io.c -static -I ../include/ -I ../include/nfsc/ -I ../mount/ -lnfs -o nfscli
执行
$ ./nfscli nfs://192.168.1.8/share/data
查看结果:
还有更多操作包括读数据,创建文件等等可以参考examples里面的例子和libnfs.h文件里面对接口的描述进行学习。
参考:
https://github.com/gjmzj/kubeasz/blob/master/docs/guide/nfs-server.md