一、背景与结论
在一个四节点的Docker Swarm集群上,尝试使用Ceph作为Docker集群的共享存储,解决有状态服务在分布式环境下的数据存储问题。
经过尝试,成功使用CephFS实现了多个Docker节点之间的存储共享。但同时注意到,对于小规模Docker集群并且运维成本有限的场景,Ceph这样的分布式对象存储系统仍然显得有点重了,本文的4节点docker swarm集群上,在Ceph集群与Portainer-Agent(docker运维工具)部署之后,容器数量达到了30个。因此最终决定采用其他方案实现小规模docker集群的共享存储,比如NFS。
但Ceph作为一个高可用高性能的分布式对象/块/文件存储系统,在其他场景还是有使用价值的。
本文主要记述Ceph的搭建过程以及如何用cephfs实现docker swarm集群的共享存储。其他诸如原理机制,运维资料等请参考社区文档。
Ceph对外提供了三种存储接口,分别是对象存储 RGW(rados gateway)、块存储 RBD(rados block device) 和文件存储 CephFS。RGW是RestAPI,docker的数据卷无法直接使用。从性能角度考虑,应该是RBD最快,但本文使用的Ceph版本与使用RBD做共享存储所需要的中间件RexRay貌似存在版本不兼容问题,最终没能成功。。。
最终本文使用了CephFS来实现docker swarm集群的共享存储。
二、版本与相关资料
本文搭建Ceph使用了目前社区文档推荐的安装工具cephadm
,安装的版本为octopus
。四个节点的操作系统均为CentOS7
。
- 社区文档入口:
https://docs.ceph.com/docs/master/
- 中文社区文档入口:
http://docs.ceph.org.cn/
注意,编写本文时,中文社区文档并非最新版本,比如社区文档中目前建议使用的安装工具
cephadm
在中文社区文档中就没有相关资料。
三、Ceph角色规划
No | ip | hostname | OSD盘 | Ceph角色 |
---|---|---|---|---|
1 | 172.17.13.1 | manager01.xxx.com | /dev/sdb | mon,osd,ceph-mds,mgr |
2 | 172.17.13.2 | manager02.xxx.com | /dev/sdb | mon,osd,ceph-mds |
3 | 172.17.13.3 | worker01.xxx.com | /dev/sdb | mon,osd,ceph-mds |
4 | 172.17.13.4 | worker02.xxx.com | /dev/sdb | mon,osd,ceph-mds,mgr,cephadm,NTP服务器 |
Ceph用于存储数据的服务OSD需要使用干净的磁盘,要求如下:
- 设备没有分区
- 设备不得具有任何LVM状态
- 设备没有挂载
- 设备不包含任何文件系统
- 设备不包含ceph bluestore osd
- 设备必须大于5G
也就是给节点增加一块新磁盘之后,只要linux能识别到即可,不要做分区/格式化/mount等操作。
四、各节点环境准备工作
4.1 防火墙与Selinux
提前将Ceph相关防火墙规则设置好。或直接关闭防火墙。
firewall-cmd --permanent --zone=public --add-service=http
firewall-cmd --permanent --zone=public --add-service=https
firewall-cmd --permanent --zone=public --add-service=ceph
firewall-cmd --permanent --zone=public --add-service=ceph-mon
firewall-cmd --reload
firewall-cmd --zone=public --list-services
firewall-cmd --zone=public --add-port=3300/tcp --permanent
firewall-cmd --zone=public --add-port=3300/udp --permanent
firewall-cmd --zone=public --add-port=6789/tcp --permanent
firewall-cmd --zone=public --add-port=6800-7300/tcp --permanent
firewall-cmd --zone=public --add-port=8443/tcp --permanent
firewall-cmd --reload
firewall-cmd --zone=public --list-ports
Ceph集群在使用中最好禁用Selinux。在各个节点上以root用户vi /etc/selinux/config
,修改:
#SELINUX=enforcing
SELINUX=disabled
然后执行setenforce 0
4.2 各节点添加epel-release资源包
从阿里云镜像获取/etc/yum.repos.d/epel.repo
,如下:
wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
4.3 各节点安装依赖库
填坑的过程中尝试过不同的搭建方案,这里有些依赖库可能不是必须的。。。
yum -y install python3 yum-utils
yum install yum-plugin-priorities -y
yum install gcc python-setuptools python-devel -y
easy_install pip
4.4 安装Docker CE
本文的环境已经提前安装了docker ce,docker compose,并创建了docker swarm集群。
每个节点都需要先安装好Docker,具体方法参考官方文档:https://docs.docker.com/engine/install/centos/
。
注意最好使用国内的dokcer安装yum镜像。
yum-config-manager \
--add-repo \
http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
安装完成之后,添加docker镜像仓库地址,vi /etc/docker/daemon.json
,添加:
"registry-mirrors": [
"https://docker.mirrors.ustc.edu.cn",
"https://dockerhub.azk8s.cn",
"https://reg-mirror.qiniu.com",
"https://hub-mirror.c.163.com",
"https://mirror.ccs.tencentyun.com",
"https://registry.docker-cn.com"
],
然后重启docker服务:
systemctl daemon-reload
systemctl restart docker
然后提前为每个节点拉取Ceph相关镜像:
docker pull ceph/ceph:v15
docker pull ceph/ceph-grafana
docker pull prom/prometheus:v2.18.1
docker pull prom/alertmanager:v0.20.0
docker pull prom/node-exporter:v0.18.1
4.5 安装NTP并同步各节点时间
各节点安装ntp服务
yum install ntp ntpdate ntp-doc -y
在管理节点worker02.xxx.com
上安装ntp服务,vi /etc/ntp.conf
:
...
restrict 127.0.0.1
restrict ::1
restrict 172.17.13.0 mask 255.255.255.0
# Hosts on local network are less restricted.
#restrict 192.168.1.0 mask 255.255.255.0 nomodify notrap
# Use public servers from the pool.ntp.org project.
# Please consider joining the pool (http://www.pool.ntp.org/join.html).
#server 0.centos.pool.ntp.org iburst
#server 1.centos.pool.ntp.org iburst
#server 2.centos.pool.ntp.org iburst
#server 3.centos.pool.ntp.org iburst
server 127.127.1.0
...
配置了NTP服务的管理节点需要防火墙配置端口:
firewall-cmd --zone=public --add-port=123/udp --permanent
firewall-cmd --reload
firewall-cmd --zone=public --list-ports
在其他节点设置ntp服务器为刚刚设定的ntp服务器,vi /etc/ntp.conf
:
…
# Use public servers from the pool.ntp.org project.
# Please consider joining the pool (http://www.pool.ntp.org/join.html).
server worker02.xxx.com
#server 0.centos.pool.ntp.org iburst
#server 1.centos.pool.ntp.org iburst
#server 2.centos.pool.ntp.org iburst
#server 3.centos.pool.ntp.org iburst
…
重启各个节点的ntp服务,并设置开机启动:
systemctl enable ntpd
systemctl restart ntpd
systemctl status ntpd
# Centos7默认安装了chronyd并且默认enable,这里需要关闭,否则重启以后会导致ntpd不能启动
systemctl disable chronyd
管理节点从外网同步时间,其他节点从管理节点同步时间:
# 管理节点
ntpdate -u ntp1.aliyun.com
# 其他节点
ntpdate -u worker02.xxx.com
4.6 更新SSH服务
各节点默认已安装,可以更新最新版本,并确认服务状态
yum install openssh-server -y
service sshd status
4.7 确保短主机名可以ping通
在每个节点以root身份vi /etc/hosts
,添加:
172.17.13.1 manager01
172.17.13.2 manager02
172.17.13.3 worker01
172.17.13.4 worker02
Ceph默认使用短域名,社区文档在环境检查中要求能以短域名ping通,但本文环境都是用的FQDN,这里即使设置短域名到hosts文件,后续依然有些许小问题。
五、Ceph集群搭建
5.1 cephadm节点安装cephadm
以下操作均在cephadm节点上执行。(本文规划将worker02.xxx.com
作为cephadm节点)
cd ~
mkdir cephadmin
cd cephadmin
curl --silent --remote-name --location https://hub.fastgit.org/ceph/ceph/raw/octopus/src/cephadm/cephadm
chmod +x cephadm
ll -h
官方地址
https://github.com/ceph/ceph/raw/octopus/src/cephadm/cephadm
总是下载失败,因此使用了国内某镜像地址。
5.2 初始化Ceph集群
以下操作均在cephadm节点上执行。
生成ceph的yum源文件并将其替换为使用阿里云yum源:
./cephadm add-repo --release octopus
cat /etc/yum.repos.d/ceph.repo
sed -i 's#download.ceph.com#mirrors.aliyun.com/ceph#' /etc/yum.repos.d/ceph.repo
cat /etc/yum.repos.d/ceph.repo
yum list | grep ceph
注意版本是
octopus
安装cephadm:
./cephadm install
which cephadm
引导ceph集群:
mkdir -p /etc/ceph
cephadm bootstrap --mon-ip 172.17.13.4 --allow-fqdn-hostname
成功后会出现如下信息:
...
INFO:cephadm:Ceph Dashboard is now available at:
URL: https://worker02.xxx.com:8443/
User: admin
Password: 3y44vf60ms
INFO:cephadm:You can access the Ceph CLI with:
sudo /usr/sbin/cephadm shell --fsid fbd10774-c8cf-11ea-8bcc-00505683571d -c /etc/ceph/ceph.conf -k /etc/ceph/ceph.client.admin.keyring
INFO:cephadm:Please consider enabling telemetry to help improve Ceph:
ceph telemetry on
For more information see:
https://docs.ceph.com/docs/master/mgr/telemetry/
INFO:cephadm:Bootstrap complete.
尝试登录Ceph CLI:
[root@worker02 ~]# cephadm shell --fsid fbd10774-c8cf-11ea-8bcc-00505683571d -c /etc/ceph/ceph.conf -k /etc/ceph/ceph.client.admin.keyring
INFO:cephadm:Using recent ceph image ceph/ceph:v15
[ceph: root@worker02 /]# exit
exit
在浏览器中访问https://worker02.xxx.com:8443/
,打开 ceph ui, 第一次登陆要求更改默认密码
域名访问前先配置浏览器所在节点的hosts文件
5.3 安装ceph-common并验证集群
以下操作均在cephadm节点上执行。
安装 ceph 工具包, 其中包括 ceph, rbd, mount.ceph 等命令:
cephadm install ceph-common
验证集群状态:
# 查看 ceph 集群所有组件运行状态
ceph orch ps
# 查看指定组件运行状态
ceph orch ps --daemon-type mon
# 查看集群当前状态
ceph status
ceph -s
5.4 向集群添加主机
将之前cephadm bootstrap初始化集群命令所生成的ceph密钥拷贝到其他节点root用户的"~/.ssh"目录。注意要输入其他节点root用户密码。
ssh-copy-id -f -i /etc/ceph/ceph.pub [email protected]
ssh-copy-id -f -i /etc/ceph/ceph.pub [email protected]
ssh-copy-id -f -i /etc/ceph/ceph.pub [email protected]
将其他节点加入集群
ceph orch host add manager01.xxx.com
ceph orch host add manager02.xxx.com
ceph orch host add worker01.xxx.com
ceph orch host ls
查看集群当前服务分布(此时应该有4个crash,4个mon,两个mgr)
ceph orch ps
5.5 部署OSD
检查每个节点是否有一块尚未分区的新磁盘,例如这里的sdb
:
[root@worker01 ~]# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
fd0 2:0 1 4K 0 disk
sda 8:0 0 300G 0 disk
├─sda1 8:1 0 500M 0 part /boot
└─sda2 8:2 0 299.5G 0 part
├─centos-root 253:0 0 295.5G 0 lvm /
└─centos-swap 253:1 0 4G 0 lvm [SWAP]
sdb 8:16 0 300G 0 disk
sr0 11:0 1 1024M 0 rom
对于虚拟机,在虚拟机控制台直接给运行中的虚拟机添加新磁盘之后,每个节点执行以下命令就可以刷出磁盘信息,不用重启:
echo "- - -" > /sys/class/scsi_host/host0/scan
echo "- - -" > /sys/class/scsi_host/host1/scan
echo "- - -" > /sys/class/scsi_host/host2/scan
将新磁盘设备加入集群
ceph orch daemon add osd manager01.xxx.com:/dev/sdb
ceph orch daemon add osd manager02.xxx.com:/dev/sdb
ceph orch daemon add osd worker01.xxx.com:/dev/sdb
ceph orch daemon add osd worker02.xxx.com:/dev/sdb
# 查看设备信息
ceph orch device ls
# 查看挂载好的osd信息
ceph osd df
5.6 其他节点安装ceph-common
为了在其他节点也能够直接访问Ceph集群,我们需要在其他节点上也安装ceph-common。
cephadm以外的其他节点执行:
mkdir ~/cephadmin
mkdir /etc/ceph
从cephadm节点以拷贝ceph.repo,cephadm,ceph集群配置文件,ceph客户端管理员密钥到其他节点:
scp /etc/yum.repos.d/ceph.repo [email protected]:/etc/yum.repos.d
scp /etc/yum.repos.d/ceph.repo [email protected]:/etc/yum.repos.d
scp /etc/yum.repos.d/ceph.repo [email protected]:/etc/yum.repos.d
scp ~/cephadmin/cephadm [email protected]:~/cephadmin/
scp ~/cephadmin/cephadm [email protected]:~/cephadmin/
scp ~/cephadmin/cephadm [email protected]:~/cephadmin/
scp /etc/ceph/ceph.conf [email protected]:/etc/ceph/
scp /etc/ceph/ceph.conf [email protected]:/etc/ceph/
scp /etc/ceph/ceph.conf [email protected]:/etc/ceph/
scp /etc/ceph/ceph.client.admin.keyring [email protected]:/etc/ceph/
scp /etc/ceph/ceph.client.admin.keyring [email protected]:/etc/ceph/
scp /etc/ceph/ceph.client.admin.keyring [email protected]:/etc/ceph/
其他节点执行:
cd ~/cephadmin
./cephadm install ceph-common
ceph -s
5.7 健康检查的错误
在执行ceph -s
或者ceph health
时,可能会发现如下的错误:
Module 'cephadm' has failed: auth get failed: failed to find client.crash.worker02 in keyring retval: -2
推测是Ceph对长域名支持不足的原因。通过ceph auth ls
命令可以查看ceph集群所有的用户的密钥,能查到对应的长域名client.crash.worker02.xxx.com
用户但没有短域名用户。通过以下命令创建对应的短域名用户:
# 手动添加用户client.crash.xxx,任意节点执行
ceph auth add client.crash.worker02 mgr 'profile crash' mon 'profile crash'
ceph auth add client.crash.manager01 mgr 'profile crash' mon 'profile crash'
ceph auth add client.crash.manager02 mgr 'profile crash' mon 'profile crash'
ceph auth add client.crash.worker01 mgr 'profile crash' mon 'profile crash'
# 查看新增用户是否成功
ceph auth ls
# 重启ceph集群,各个节点上都需要执行
systemctl restart ceph.target
# 也可以用下面的命令停止再重启ceph集群,各个节点上都需要执行
systemctl stop ceph.target
systemctl stop ceph\*.service ceph\*.target
ps -ef | grep ceph
docker ps -a
systemctl restart ceph.target
# 重启后重新检查状态
ceph -s
六、部署cephfs服务
6.1 创建cephfs
任意节点上执行:
# 创建一个用于cephfs数据存储的池,相关参数自行参阅社区文档,一言难尽。。。
ceph osd pool create cephfs_data 64 64
# 创建一个用于cephfs元数据存储的池
ceph osd pool create cephfs_metadata 32 32
# 创建一个新的fs服务,名为cephfs
ceph fs new cephfs cephfs_metadata cephfs_data
# 查看集群当前的fs服务
ceph fs ls
# 设置cephfs最大mds服务数量
ceph fs set cephfs max_mds 4
# 部署4个mds服务
ceph orch apply mds cephfs --placement="4 manager01.xxx.com manager02.xxx.com worker01.xxx.com worker02.xxx.com"
# 查看mds服务是否部署成功
ceph orch ps --daemon-type mds
本文在这里遇到一个问题,mds服务一直不能启动,查看ceph health
发现一个1 filesystem is online with fewer MDS than max_mds
的警告,应该是ceph fs set cephfs max_mds 4
没有生效。后来重启了整个集群就好了。
# 在所有节点上执行
systemctl restart ceph.target
# 重启之后检查相关服务
ceph orch ps --daemon-type mds
ceph osd lspools
ceph fs ls
6.2 创建cephfs访问用户
创建用户,用于客户端访问CephFs
ceph auth get-or-create client.cephfs mon 'allow r' mds 'allow r, allow rw path=/' osd 'allow rw pool=cephfs_data' -o ceph.client.cephfs.keyring
查看输出的ceph.client.cephfs.keyring
密钥文件,或使用下面的命令查看密钥:
ceph auth get-key client.cephfs
6.3 挂载cephfs到各节点本地目录
在各个节点执行:
mkdir /mnt/cephfs/
mount -t ceph manager01.xxx.com:6789,manager02.xxx.com:6789,worker01.xxx.com:6789,worker02.xxx.com:6789:/ /mnt/cephfs/ -o name=cephfs,secret=
manager01.xxx.com:6789,manager02.xxx.com:6789,worker01.xxx.com:6789,worker02.xxx.com:6789 是所有mon服务
编辑各个节点的/etc/fstab
文件,实现开机自动挂载,添加以下内容:
manager01.xxx.com:6789,manager02.xxx.com:6789,worker01.xxx.com:6789,worker02.xxx.com:6789:/ /mnt/cephfs ceph name=cephfs,secretfile=,noatime,_netdev 0 2
相关参数请自行查阅linux下fstab的配置资料。
6.4 使用cephfs实现docker共享存储
将挂载到本地的cephfs作为本地磁盘使用即可。例如本文中,可以在docker run命令中,或者docker compose编排文件中,使用volume本地挂载到/mnt/cephfs
下。
示例,注意volumes:
...
portainer:
image: portainer/portainer
...
volumes:
- /mnt/cephfs/docker/portainer:/data
...
deploy:
mode: replicated
replicas: 1
placement:
constraints: [node.role == manager]
...
至此,使用cephfs实现docker共享存储的尝试已经OK。
七、部署RBD
Ceph的RBD对外提供的是块存储,但块存储直接作为磁盘挂载到各节点的话,并不能实现不同节点之间的数据共享。因此需要配合中间件Rexray
,以及docker插件rexray/rbd
来实现共享存储。
但本文并未成功,原因后叙。
7.1 初始化rbd pool并创建RBD的image
在任意节点上执行:
ceph osd pool create rbd01 32
rbd pool init rbd01
# 在rbd01上创建一个300G的image
rbd create img01 --size 307200 --pool rbd01
rbd ls rbd01
rbd info --image img01 -p rbd01
此时可以在各个节点上挂载RBD的img01,但是并不能实现存储共享。
# 向linux系统内核载入rbd模块
modprobe rbd
# 将img01映射到系统内核
rbd map img01 --pool rbd01 --id admin
# 失败,需要禁用当前系统内核不支持的feature
rbd feature disable img01 --pool rbd01 exclusive-lock, object-map, fast-diff, deep-flatten
# 重新映射
rbd map img01 --pool rbd01 --id admin
# 映射成功后,会返回映射目录"/dev/rbd0",对该目录进行格式化:
[root@worker01 ~]# mkfs.xfs /dev/rbd0
meta-data=/dev/rbd0 isize=512 agcount=17, agsize=4914176 blks
= sectsz=512 attr=2, projid32bit=1
= crc=1 finobt=0, sparse=0
data = bsize=4096 blocks=78643200, imaxpct=25
= sunit=1024 swidth=1024 blks
naming =version 2 bsize=4096 ascii-ci=0 ftype=1
log =internal log bsize=4096 blocks=38400, version=2
= sectsz=512 sunit=8 blks, lazy-count=1
realtime =none extsz=4096 blocks=0, rtextents=0
# mount到本地
mkdir /mnt/data01
mount /dev/rbd0 /mnt/data01
# 查看本地磁盘信息
df -hT
# 卸除挂载并删除image
umount /mnt/data01
rbd unmap img01 --pool rbd01 --id admin
rbd rm --image img01 -p rbd01
7.2 安装rexray与rexray/rbd
任意某个节点下载rexray:
curl -sSL https://rexray.io/install | sh
编辑配置文件vi /etc/rexray/config.yml
,内容如下:
rexray:
logLevel: debug
libstorage:
logging:
level: debug
httpRequests: true
httpResponses: true
libstorage:
service: rbd
rbd:
defaultPool: rbd01
尝试启动Rexray服务,这里一直失败:
[root@manager01 rexray]# rexray start
...
error: service startup failed: agent: mod init failed: error initializing instance ID cache
日志中除了最后的错误,并无其他有用的信息。在github对应项目的issue中有类似问题,解决方法是ceph配置文件/etc/ceph/ceph.conf
中添加mon_host
配置。但本文使用的ceph版本octopus
的配置文件中已经明确配置了mon_host
,且格式与issue所述不同。最终也没有找到原因,怀疑是Ceph版本太新,与rexray不兼容所致。所以这里的尝试到此为止,后续安装docker插件与创建rbd数据卷并未进行。
如果Rexray服务能成功启动,那么后续还需要在每个节点安装docker插件rexray/rbd
:
docker plugin install rexray/rbd RBD_DEFAULTPOOL=rbd01 LINUX_VOLUME_FILEMODE=0777
最后在docker swarm上创建rbd驱动的数据卷:
docker volume create -d :5011/rexray/rbd <数据卷名称>
如果成功,docker run或编排文件中的volume使用事先创建好的数据卷即可实现存储共享。