通过ganesha-nfs将 Ceph 导出为 NFS

前言

本文介绍了两种方式将 Ceph 导出为 NFS,一种通过 RGW,一种通过 CephFS,通过 FSAL 模块 连接到 RGW 或者 CephFS, 其中,FSAL_RGW 调用 librgw2 将 NFS 协议转义为 S3 协议再通过 RGW 存入到 Ceph 中,FSAL_CEPH 调用 libcephfs1 将 NFS 转义为 Cephfs 协议再存入到 Ceph 中。所以需要额外安装这两个包。

经过测试发现,FSAL_RGW 模块在压测是很不稳定,对大文件的写入经常报 io error (5)FSAL_CEPH 模块比较稳定。

声明
本文只是介绍 ganesha-nfs 的部署方式,不代表其能否在生产环境使用。

另外,本文部署环境为,Ceph -> Jewel, ganesha-nfs -> V2.4-stable, OS -> CentOS 7。

Git下载编译

对于 Jewel 版本的 Ceph,前往 nfs-ganesha 的Git,下载 V2.4-stable,安装一些依赖后,通过源码部署,操作系统是CentOS-7.2.1511, Ceph 版本是 Jewel:

下载

1
git clone -b V2.4-stable https://github.com/nfs-ganesha/nfs-ganesha.git --recursive

安装依赖

1
2
3
4
5
6
7
yum install gcc git cmake autoconf libtool bison flex doxygen openssl-devel gcc-c++ libuuid-devel nfs-utils -y
# 如果要生成 FSAL_RGW 模块,需要安装 librgw2-devel
yum install librgw2-devel -y
# 如果要生成 FSAL_CEPH 模块,需要安装 libcephfs1-devel
yum install libcephfs1-devel -y

编译 nfs-ganesha, 注意打开对应的模块:

  • 如果需要生成 FSAL_RGW 模块,则在编译选项中添加: -DUSE_FSAL_RGW=ON
  • 如果需要生成 FSAL_CEPH 模块,则在编译选项中添加: -DUSE_FSAL_CEPH=ON
1
2
3
mkdir /tmp/build/
cd /tmp/build/
cmake -DUSE_FSAL_RGW=ON -DUSE_FSAL_CEPH=ON /tmp/nfs-ganesha/src/

注意,在 cmake 的输出中,会有如下输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
-- Looking for ceph_ll_lookup_root in cephfs - found
-- Found cephfs libraries: /usr/lib64/libcephfs.so
-- Found CEPHFS: /usr/include
-- Looking for rgw_mount in rgw
-- Looking for rgw_mount in rgw - found
-- Found rgw libraries: /usr/lib64/librgw.so
-- Found RGW: /usr (found suitable version "1.1", minimum required is "1.1")
...
-- USE_FSAL_CEPH = ON
-- USE_FSAL_CEPH_MKNOD = OFF
-- USE_FSAL_CEPH_SETLK = OFF
-- USE_FSAL_CEPH_LL_LOOKUP_ROOT = ON
-- USE_FSAL_RGW = ON

确保,确保,确保: -- USE_FSAL_CEPHON,以及 -- USE_FSAL_RGWON

如果是 OFF,请检查下librgw2-devel或者libcephfs1-devel是否有安装,如果这两个包都已经安装了,还显示为 OFF, 可以尝试下清空编译目录:rm -rf /tmp/build/*,再进行编译,如果依旧为 OFF,可以尝试下删除所有的 Ceph 包,再重新 yum install ceph librgw2-devel libcephfs1-devel -y

这两项编译输出为 OFF 的输出可能如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
-- Looking for ceph_ll_lookup in cephfs
-- Looking for ceph_ll_lookup in cephfs - not found
-- Found cephfs libraries: CEPHFS_LIBRARY-NOTFOUND
-- Could NOT find CEPHFS (missing: CEPHFS_INCLUDE_DIR CEPHFS_LIBRARY_DIR)
CMake Warning at CMakeLists.txt:564 (message):
Cannot find CEPH runtime. Disabling CEPH fsal build
-- Looking for rgw_mount in rgw
-- Looking for rgw_mount in rgw - not found
-- Found rgw libraries: RGW_LIBRARY-NOTFOUND
-- Could NOT find RGW: Found unsuitable version "0.0", but required is at least "1.1" (found )
CMake Warning at CMakeLists.txt:577 (message):
Cannot find supported RGW runtime. Disabling RGW fsal build
...
-- USE_FSAL_CEPH = OFF
...
-- USE_FSAL_RGW = OFF

编译,安装

1
2
3
cd /tmp/build/
make
make install

TIP
make install 生成的输出中,可以看到:

1
2
3
4
> -- Up-to-date: /usr/share/doc/ganesha/config_samples/rgw.conf
> ...
> -- Up-to-date: /usr/share/doc/ganesha/config_samples/ceph.conf
>

这两个文件就是配置将 RGW 和 CephFS 配置为 ganesha-nfs 的配置模板。

编辑配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
cat /etc/ganesha/ganesha.conf
EXPORT
{
Export_ID=1;
Path = /;
Pseudo = /cephfs;
Access_Type = RW;
NFS_Protocols = 4;
Transport_Protocols = TCP;
FSAL {
Name = CEPH;
}
}
EXPORT
{
Export_ID=2;
Path = /;
Pseudo = /rgw;
Access_Type = RW;
Squash = No_root_squash;
NFS_Protocols = 4;
Transport_Protocols = TCP;
FSAL {
Name = RGW;
User_Id = "admin";
Access_Key_Id ="M54WD1J33ZRZA7D6YX8E";
Secret_Access_Key = "lXu1DgwO1YLoV8IPlbH9FpaCIZyHcOBIrMLQ2xUi";
}
}
RGW {
ceph_conf = "/etc/ceph/ceph.conf";
}

上面配置的为 CephFS 的配置,下面的配置为 RGW 的配置。

其中,User_Id , Access_Key_Id, Secret_Access_Key 根据自己的环境进行修改。

librgw init failed (-5) 解决方法

经过多次尝试,包括在ganesha.conf内添加init_args 指定秘钥和Ceph的用户,ganesha-nfs 均无法启动,报的错如标题,解决方法就是关闭CephX,将/etc/ceph/ceph.conf内的三个 cephx改为none,然后重启 ceph-mon,ceph-osd,ceph-radosgw, ceph-mds 进程,再启动ganesha-nfs,即可正常运行。

完整报错信息如下:

1
2
RGW-1 : nfs-ganesha-2232083[main] create_export :FSAL :CRIT :RGW module: librgw init failed (-5)
RGW-1 : nfs-ganesha-2232083[main] mdcache_fsal_create_export :FSAL :MAJ :Failed to call create_export on underlying FSAL

启动 ganesha-nfs

1
ganesha.nfsd -L /var/log/ganesha.log

如果一切顺利,你应该可以看到 ganesha.nfsd 进程在那,如果进程不在,那么查看Log,记得在启动进程前,关闭所有 CephX 配置。

挂载 nfs

1
mount -t nfs4 {$ganesha-server-ip}:/ /mnt

此时,ll /mnt/ 如果顺利的话,会看到:

1
2
3
4
ll /mnt/
总用量 1
drwxr-xr-x 1 root root 5295308800 3月 30 23:30 ceph
drwxrwxrwx 3 root root 0 1月 1 1970 rgw

说明 CephFS 和 RGW 都已经正常对接。不过,我在操作过程中,看到了一个报错信息:

1
2
ls /mnt/
ls: 正在读取目录/mnt/: 远程 I/O 错误

这个现象是可以复现的,复现指令如下:

1
2
3
4
5
6
7
8
[root@node ~]# ps -ef|grep ganesha
root 51719 1 0 23:28 ? 00:00:01 ganesha.nfsd -L /var/log/ac
root 52838 50284 0 23:39 pts/4 00:00:00 grep --color=auto ganesha
[root@node ~]# kill -9 51719
[root@node ~]# ganesha.nfsd -L /var/log/ganesha.log
[root@node ~]# mount -t nfs4 10.4.0.104:/ /mnt/
[root@node ~]# ls /mnt/
ls: 正在读取目录/mnt/: 远程 I/O 错误

目前找到的一个比较笨的解决方法是,具体原因还不太清楚,但是目录显示正确后,不会再发生远程I/O 错误:

1
2
3
4
5
6
7
# mkdir /root/a
# ceph-fuse -m 10.4.0.101:6789,10.4.0.102:6789,10.4.0.103:6789 /root/a
# umount /root/a
# ll /mnt/
总用量 1
drwxr-xr-x 1 root root 5295308800 3月 30 23:43 ceph
drwxrwxrwx 3 root root 0 1月 1 1970 rgw

如果,你所使用的admin用户名下有很多的桶,那么这些桶都会以/mnt/rgw/xxbucket的结构显示出来,如果你在/mnt/rgw/下建立的一个目录,那么就相当于通过 RGW 建立了一个桶,所以,你执行touch /mnt/rgw/123 是会报错的,因为不符合S3的对象必须位于桶内的规定,简单点说,就是把/mnt/rgw/和S3的根目录一一对应即可。

同样, CephFS 内的内容都会显示在/mnt/cephfs/目录下。可以开始愉快的玩耍了!!!

RGW 模块测试时遇到的一些问题

我将 ganesha-nfs 部署到一个较大的集群中去,然后挂载NFS,对挂载目录进行压力测试,测试指令如下:

1
for i in {0..1000} ;do dd if=/dev/zero of=./$i bs=4k count=$i; done;

目的是,快速写入4KB~4MB不同大小的对象,现象是:

  • 对于200KB以下的文件,写入正常,万次测试没有出现ioerror
  • 对于400KB~1MB的文件,有5%的可能性,文件写入时报 ioerror(5)。
  • 对于2MB以上的文件,有40%的可能性,文件写入报 ioerror(5)。

也就是说,对于几十KB的小文件写入,没有见到过ioerror,对于1MB以上的大文件写入,有很大(70% for 100MB+)概率报 ioerror(5)。 原因不明。希望知道原因的朋友可以指导下!

将 RBD 导出为 NFS。

指令很简单,这里就不细说,具体可以参考一篇keepalived+ceph rbd配置nfs的高可用文章:

1
2
3
4
5
6
7
8
rbd -p rbd create bar --size 10G --image-format 1
rbd map -p rbd bar
mkfs.xfs /dev/rbd0
mount /dev/rbd0 /mnt
yum install nfs-utils -y
echo "/mnt *(rw,async,no_subtree_check,no_root_squash)" > /etc/exports
systemctl start nfs-server.service
exportfs -r

RBD 和 CephFS 导出的 NFS 速度测试

测试机选择了一台非 NFS 提供节点作为 客户端,使用 FIO 进行测试:

1
fio -direct=1 -iodepth 32 -thread -ioengine=libaio -bs=4K/4M -size=10G -runtime=60 -group_reporting -name=mytest -filename=/mnt/xxx -rw=randwrite

结果如下,另外测了一次ceph-fuse挂载的写速度,还有使用kernel挂载cephfs的速度:

BS iops bw
CephFS 4K 5765 23 MB/s
4M 169 695 MB/s
RBD 4K 70765 283 MB/s
4M 203 832 MB/s
ceph-fuse 4K 500 2 MB/s
4M 10 43 MB/s
mount -t ceph 4K 8261 33 MB/s
4M 293 1173.9 MB/s

参考文档: