乐趣区

“网红架构师”解决你的Ceph 运维难题

欢迎大家前往腾讯云 + 社区,获取更多腾讯海量技术实践干货哦~
本文由 Tstack 发表于云 + 社区专栏本文为长篇连续剧,将分多个篇幅发表,主要介绍了从动手部署环境到后期运营故障处理过程中常见的问题,内容由浅入深,是居家旅行运维 Ceph 的必备良药。

Q1. 环境预准备
绝大多数 MON 创建的失败都是由于防火墙没有关导致的,亦或是 SeLinux 没关闭导致的。一定一定一定要关闭每个每个每个节点的防火墙(执行一次就好,没安装报错就忽视):
CentOS
sed -i ‘s/SELINUX=.*/SELINUX=disabled/’ /etc/selinux/config
setenforce 0
systemctl stop firewalld
systemctl disable firewalld
# iptables -F
service iptables stop
Q2. 清理环境
MON 部署不上的第二大问题就是在旧的节点部署 MON,或者在这个节点部署 MON 失败了,然后重新 new 再 mon create-initial,请查看要部署 MON 的节点上的 /var/lib/ceph/mon/ 目录下是否为空,如果不为空,说明已经在这个目录部署过 MON,再次部署会检测子目录下的 done 文件,由于有了这个文件,就不会再建立新的 MON 数据库,并且不会覆盖之,导致了部署时的各种异常,这里就不赘述了,直接给出万能清理大法:
对于任何需要新部署 MON 的节点,请到这个节点下执行如下指令,确保环境已经清理干净:
ps aux|grep ceph |awk ‘{print $2}’|xargs kill -9
ps -ef|grep ceph
#确保此时所有 ceph 进程都已经关闭!!!如果没有关闭,多执行几次。
rm -rf /var/lib/ceph/mon/*
rm -rf /var/lib/ceph/bootstrap-mds/*
rm -rf /var/lib/ceph/bootstrap-osd/*
rm -rf /var/lib/ceph/bootstrap-rgw/*
rm -rf /etc/ceph/*
rm -rf /var/run/ceph/*
请直接复制粘贴,遇到过好些个自己打错打漏删了目录的。
Q3. 部署前最后的确认
这里介绍的都是个案,不过还是需要提一下:

确保每个节点的 hostname 都设置正确,并且添加至 /etc/hosts 文件中,然后同步到所有节点下。克隆出来的虚拟机或者批量建的虚拟机有可能发生此情形。
确保以下目录在各个节点都存在:
/var/lib/ceph/
/var/lib/ceph/mon/
/var/lib/ceph/osd/
/etc/ceph/
/var/run/ceph/
上面的目录,如果 Ceph 版本大于等于 jewel, 请确认权限均为 ceph:ceph,如果是 root:root,请自行 chown。

Q4. 安装 Ceph
官网指导方法是使用 ceph-deploy install nodeX, 但是因为是国外的源,速度慢得令人发指,所以我们换到阿里的源,并且使用 yum install 的方式安装,没差啦其实,这样反而还快点,毕竟多个节点一起装。
很多安装失败的都是因为没有添加 epel 源请在每个存储节点都执行以下指令,来安装 Ceph:
yum clean all
rm -rf /etc/yum.repos.d/*.repo
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
sed -i ‘/aliyuncs/d’ /etc/yum.repos.d/CentOS-Base.repo
sed -i ‘/aliyuncs/d’ /etc/yum.repos.d/epel.repo
sed -i ‘s/$releasever/7.2.1511/g’ /etc/yum.repos.d/CentOS-Base.repo
echo ”
[ceph]
name=ceph
baseurl=http://mirrors.aliyun.com/ceph/rpm-hammer/el7/x86_64/
gpgcheck=0
[ceph-noarch]
name=cephnoarch
baseurl=http://mirrors.aliyun.com/ceph/rpm-hammer/el7/noarch/
gpgcheck=0
” > /etc/yum.repos.d/ceph.repo
yum install ceph ceph-radosgw -y
这里是安装的 hammer 版本的 Ceph,如果需要安装 jewel 版本的,请执行:
sed -i ‘s/hammer/jewel/’ /etc/yum.repos.d/ceph.repo
yum install ceph ceph-radosgw -y
如果安装了 jewel 版本的 Ceph,想要换回 hammer 版本的 Ceph,可以执行下面的指令:
卸载 Ceph 客户端
rpm -qa |grep `ceph -v |awk ‘{print $3}’` |xargs rpm -e –nodeps
更改 ceph.repo 里面的 Ceph 版本
sed -i ‘s/jewel/hammer/’ /etc/yum.repos.d/ceph.repo
yum install ceph ceph-radosgw -y
Q5. ceph-deploy
这里我要开启话唠模式:
① Ceph-deploy 是什么?
Ceph-deploy 是 Ceph 官方给出的用于部署 Ceph 的一个工具,这个工具几乎全部是 Python 写的脚本,其代码位于 /usr/lib/python2.7/site-packages/ceph_deploy 目录下(1.5.36 版本)。最主要的功能就是用几个简单的指令部署好一个集群,而不是手动部署操碎了心,敲错一个地方就可能失败。所以对于新人来说,或者说以我的经验,接触 Ceph 少于一个月的,又或者说,集群规模不上 PB 的,都没有必要手动部署,Ceph-deploy 完全足够了。
② Ceph-deploy 怎么装?
这个包在 ceph 的源里面:
yum install ceph-deploy -y
③Ceph-deploy 装在哪?
既然 Ceph-deploy 只是个部署 Ceph 的脚本工具而已,那么这个工具随便装在哪个节点都可以,并不需要单独为了装这个工具再搞个节点,我一般习惯放在第一个节点,以后好找部署目录。
④Ceph-deploy 怎么用?
详细的指令暂时不介绍,下面会有,在安装好后,需要在这个节点新建一个目录,用作部署目录,这里是强烈建议建一个单独的目录的,比如我习惯在集群的第一个节点下建一个 /root/cluster 目录,为了以后好找。Ceph-deploy 的所有的指令都需要在这个目录下执行。包括 new,mon,osd 等等一切 ceph-deploy 的指令都需要在这个部署目录下执行!最后一遍,所有的 ceph-deploy 的指令都要在部署目录下执行!否则就会报下面的错:
[ceph_deploy][ERROR] ConfigError: Cannot load config: [Errno 2] No such file or directory: ‘ceph.conf’; has ceph-deploy new been run in this directory?
⑤ Ceph-deploy 怎么部署集群?
我们暂且把部署目录所在的节点叫做部署节点。Ceph-deploy 通过 SSH 到各个节点,然后再在各个节点执行本机的 Ceph 指令来创建 MON 或者 OSD 等。所以在部署之前,你需要从部署节点 ssh-copy-id 到各个集群节点,使其可以免秘钥登陆。
⑥Ceph-deploy 部署的日志在哪里?
就在部署目录下面的 ceph-deploy-ceph.log 文件,部署过程中产生的所有的日志都会保存在里面,比如你大半年前敲的创建 OSD 的指令。在哪个目录下执行 ceph-deploy 指令,就会在这个目录下生成 log,如果你跑到别的目录下执行,就会在执行目录里生成 log 再记下第四点的错。当然,这个 LOG 最有用的地方还是里面记录的部署指令,你可以通过 cat ceph-deploy-ceph.log |grep “Running command” 查看到创建一个集群所需的所有指令,这对你手动建立集群或者创建秘钥等等等等有着很大的帮助!!!
⑦ Ceph-deploy 版本
写这段时的最新的版本号为 1.5.36,下载链接为 ceph-deploy-1.5.36-0.noarch.rpm,之前的 1.5.35 里面有点 bug 在这个版本被修复了,如果使用 1.5.25 部署遇到了问题,可以更新至这个版本,会绕过一些坑。更新到 1.5.36 之后,腰也不酸了, 退了不疼了,Ceph 也能部署上了。
Q6. ceph-deploy new 做了什么
进入部署目录,执行 ceph-deploy new node1 node2 node3,会生成两个文件(第三个是 ceph-deploy-ceph.log,忽视之):
[root@blog cluster]# ls
ceph.conf ceph-deploy-ceph.log ceph.mon.keyring
new 后面跟的是你即将部署 MON 的节点的 hostname,推荐三个就够了,需要是奇数个 MON 节点。不要因为只有两个节点就搞两个 MON,两个节点请用一个 MON,因为两个 MON 挂掉一个,集群也就挂了,和一个 MON 挂掉一个效果是一样的。生成的 ceph.conf 默认情况下长成这样:
[root@blog cluster]# cat ceph.conf
[global]
fsid = 13b5d863-75aa-479d-84ba-9e5edd881ec9
mon_initial_members = blog
mon_host = 1.2.3.4
auth_cluster_required = cephx
auth_service_required = cephx
auth_client_required = cephx
会调用 uuidgen 生成一个 fsid,用作集群的唯一 ID,再将 new 后面的主机加入到 mon_initial_members 和 mon_host 里面,剩下的三行大家都是一样的,默认开启 CephX 认证。下面有一节会专门介绍这个,需要注意的是,部署的时候,千万不要动这三行 下面会有一节介绍之。还有一个文件 ceph.mon.keyring:
[root@blog cluster]# cat ceph.mon.keyring
[mon.]
key = AQB1yWRYAAAAABAAhMoAcadfCdy9VtAaY79+Sw==
caps mon = allow *
除了 key 的内容不一样,剩下的都会是一样的。因为是开启了 CephX 认证了,所以 MON 直接的通讯是需要一个秘钥的,key 的内容就是秘钥。是不是对 Ceph 里面的明文认证感到吃惊,有总比没有强。如果,你再次执行 new,会生成新的 ceph.conf 和新的 ceph.mon.keyring,并将之前的这两个文件给覆盖掉,新旧文件唯一不同的就是 fsid 和 key 的内容,但是对 Ceph 来说,这就是两个集群了。这里说一下我个人非常非常非常反感的一个问题,有的朋友喜欢在 /etc/ceph/ 目录下面执行 ceph-deploy 的命令,这么做和在部署目录下面做一般是没有差别的,因为这两个目录下面都有 ceph.conf 和 ceph.client.admin.keyring,但是我还是强烈推荐创建独立的部署目录,因为 /etc/ceph 目录是 Ceph 节点的运行目录,为了体现各自的功能性,也为了安全性,请不要在 **/etc/ceph** 目录下部署集群!!!
Q7. 为 ceph-deploy 添加参数
Ceph-deploy 的 log 还是很有看头的,查看 ceph-deploy new blog(blog 是我的一台主机)的 log:
[root@blog cluster]# ceph-deploy new blog
[ceph_deploy.conf][DEBUG] found configuration file at: /root/.cephdeploy.conf
[ceph_deploy.cli][INFO] Invoked (1.5.36): /usr/bin/ceph-deploy new blog
[ceph_deploy.cli][INFO] ceph-deploy options:
[ceph_deploy.cli][INFO] username : None
[ceph_deploy.cli][INFO] func : <function new at 0x288e2a8>
[ceph_deploy.cli][INFO] verbose : False
[ceph_deploy.cli][INFO] overwrite_conf : False
[ceph_deploy.cli][INFO] quiet : False
[ceph_deploy.cli][INFO] cd_conf : <ceph_deploy.conf.cephdeploy.Conf instance at 0x28eccf8>
[ceph_deploy.cli][INFO] cluster : ceph
[ceph_deploy.cli][INFO] ssh_copykey : True
[ceph_deploy.cli][INFO] mon : [‘blog’]
[ceph_deploy.cli][INFO] public_network : None
[ceph_deploy.cli][INFO] ceph_conf : None
[ceph_deploy.cli][INFO] cluster_network : None
[ceph_deploy.cli][INFO] default_release : False
[ceph_deploy.cli][INFO] fsid : None
[ceph_deploy.new][DEBUG] Creating new cluster named ceph
可以看到有很多的参数被列出来了,比如:mon : [‘blog’],也有很多参数是 False 或者 None,这些参数能否被设置呢? 因为这里我们可以看到有 fsid : None 这个参数,难道集群的 fsid 可以被指定吗?抱着这些疑惑,我就去看完了 ceph-deploy 的所有代码,答案是:可以设置。所有上面的参数都可以使用参数的形式进行设置,只需要在前面加上两个 –,比如对于 fsid 可以执行:
ceph-deploy new blog –fsid xx-xx-xx-xxxx
如果想要查看每个执行可指定的参数,可以 -h:
[root@blog cluster]# ceph-deploy new -h
usage: ceph-deploy new [-h] [–no-ssh-copykey] [–fsid FSID]
[–cluster-network CLUSTER_NETWORK]
[–public-network PUBLIC_NETWORK]
MON [MON …]

optional arguments:
-h, –help show this help message and exit
–no-ssh-copykey do not attempt to copy SSH keys
–fsid FSID provide an alternate FSID for ceph.conf generation
–cluster-network CLUSTER_NETWORK
specify the (internal) cluster network
–public-network PUBLIC_NETWORK
specify the public network for a cluster
这里就可以看到可以指定 –cluster-network,–public-network,等等,如果 optional arguments 里面没有介绍这个参数,可以直接使用 –xxarg 的方式指定,比如 –overwrite-conf,–verbose 等等,能不能设置这些参数,自己动手试一下就知道了。需要注意的是,参数的位置根据指令而异,比如 –overwrite-conf 参数是跟在 ceph-deploy 后面的,而 –public-network 是跟在 new 后面的:
ceph-deploy –overwrite-conf –verbose new blog –fsid a-a-a-a
[root@blog cluster]# cat ceph.conf |grep fsid
fsid = a-a-a-a
Q8. Public VS Cluster
如果非要在刚刚生成的 ceph.conf 里面添加什么的话,那么可能就要加 public_network 或者 cluster_network 了。那么这两个配置项有什么用呢?这里简单得介绍下 Ceph 的 Public(外网或者叫公网或者前端网)和 Cluster(内网或者叫集群网或者叫后端网)这两个网络,在 Ceph 中,存在以下三种主要的网络通讯关系:

client-> mon =>public : 也就是客户端获取集群状态,或者叫客户端与 MON 通讯走的网络,是走的外网。
client-> osd => public : 也就是客户端向 OSD 直接写入数据走的也是外网。
osd<-> osd => cluster:也就是 OSD 之间的数据克隆,恢复走的是内网,客户端写第一份数据时通过外网写,对于三副本剩下的两个副本 OSD 之间通过内网完成数据复制。当 OSD 挂掉之后产生的 recover, 走的也是内网。

通常,我们会将外网配置为千兆网,而内网配置成万兆网,这是有一定原因的:

客户端可能由成百上千的计算节点组成,外网配成万兆成本太高。
存储节点一般只有几个到几十个节点,配置了万兆内网可以大大加快故障恢复速度,而且剩余的两副本写速度会大大加快,万兆网的性价比极高。举个例子,集群坏掉一个 OSD 千兆需要一小时,那么万兆网只需要五六分钟,一定程度上增加了集群的安全性。

借用官网的这张图来说明集群的网络走势:再假设你的节点有两个网段 172.23.0.1 和 3.3.4.1,还记得我们上一节 ceph-deploy new 的时候是可以指定 public_network 和 cluster_network 的吗!如果不指定这两个参数,那么 ceph-deploy 怎么知道用哪个 IP 作为这个节点的 mon_host 的 IP 呢,其实他是随便选的,如果它选了 172 网段但是你想使用 3.3 网段作为这个节点的 mon_host 的 IP,那么只需要指定 –public-network 172.23.0.0/24 就可以了,其中的 /24 就相当于一个掩码,表示前面的 IP 的前 24 位,也就是 172.23.0.XXX,只要你的主机上有一个处于这个范围内的 IP,那么就会选择这个 IP 作为公网 IP。类似的,/16 表示范围:172.23.XXX.XXX。如果想指定内网 IP,那么只要指定 –cluster-network 3.3.4.1/24 就可以了。
一般情况下,会在 new 生成的 ceph.conf 文件里加入 public_network 配置项以指定公网 IP。当然你的 MON 主机上需要有至少一个 IP 在公网范围内。除了在生成的 ceph.conf 文件中加入公网 IP 的方式,我们还可以使用参数的方式来指定公网 IP:
[root@ceph-1 cluster]# ceph-deploy new ceph-1 –public-network 172.23.0.0/24
[ceph_deploy.cli][INFO] Invoked (1.5.36): /usr/bin/ceph-deploy new ceph-1 –public-network 172.23.0.0/24
[ceph_deploy.cli][INFO] ceph-deploy options:

[ceph_deploy.cli][INFO] public_network : 172.23.0.0/24

[ceph-1][DEBUG] IP addresses found: [u’172.23.0.101′, u’10.0.2.15′]
[ceph_deploy.new][DEBUG] Resolving host ceph-1
[ceph_deploy.new][DEBUG] Monitor ceph-1 at 172.23.0.101
[ceph_deploy.new][DEBUG] Monitor initial members are [‘ceph-1′]
[ceph_deploy.new][DEBUG] Monitor addrs are [u’172.23.0.101’]
[ceph_deploy.new][DEBUG] Writing monitor keyring to ceph.mon.keyring…
[ceph_deploy.new][DEBUG] Writing initial config to ceph.conf…
[root@ceph-1 cluster]# cat ceph.conf
[global]
fsid = d2a2bccc-b215-4f3e-922b-cf6019068e76
public_network = 172.23.0.0/24
mon_initial_members = ceph-1
mon_host = 172.23.0.101
auth_cluster_required = cephx
auth_service_required = cephx
auth_client_required = cephx
查看部署 log 可以发现参数配置已经生效,而这个节点有两个 IP,public_nwtwork 这个参数限定了公网 IP 的搜索范围,生成的 ceph.conf 文件内也包含了 public_network 这个参数。
Q9. 参数是下划线还是空格分隔
这里只是简单的提一下这个小困惑,对于以下的两个参数书写方式,哪种会有问题呢:
public_network = 172.23.0.1/24
public network = 172.23.0.1/24
osd_journal_size = 128
osd journal size = 128
这两种参数的书写方式其实都是正确的,说到底是因为底层调用的是 Python 的 argparse 模块。这两种方式都是等效的,所以不需要担心。
Q10. ceph-deploy mon create-initial 如何一次性通过
这一步坑哭了多少迫切加入 Ceph 世界的新人,看到的最多的就是 5s,10s,10s, 15s,20s。。。然后报了错。再执行,再报错。所以这里给出以下的预检清单,如果被报错失败所烦恼,请认真执行各个子项,尤其是失败后要执行清理环境:

请确保所有节点都安装了 Ceph。
请确保所有节点的防火墙等都关闭了。参考环境预准备一节
请前往各个 MON 节点清理干净,不论你是否相信这个节点是干净的。参考清理环境一节。
请确保各个 MON 节点下存在以下目录,并且对于 Jewel 版本及之后的请确保目录权限为 ceph:ceph。参考部署前最后的确认一节。
请在 ceph-deploy new 生成的 ceph.conf 内添加 public_network 配置项,参考 Public VS Cluster 一节。

这些总结来之不易,我帮过上百个人解决过部署问题和集群故障。我相信在认真确认过之后是肯定可以通过的(反正前三点如果有问题一般是不会建好 MON 的,为什么不认真确认下呢),我遇到过绝大多数都是因为防火墙没关,或者手动删除了一些目录,或者没有修改权限导致的问题。
相对来说,新环境只要关了防火墙就可以一次性通过,旧环境或者失败的环境只要清理环境就可以通过了。
Q11. mon create-initial 做了什么
简单介绍下流程:

ceph-deploy 读取配置文件中的
mon_initial_members
的各个主机,然后依次 SSH 前往各个主机:

将部署目录下的 ceph.conf 推送到新节点的 /etc/ceph/ 目录下。
创建 /var/lib/ceph/mon/$cluster-$hostname/ 目录。
检查 MON 目录下是否有 done 文件,如果有则直接跳到第 6 步。
将 ceph.mon.keyring 拷贝到新节点,并利用该秘钥在 MON 目录下建立 MON 数据库。
在 MON 目录下建立 done 文件,防止重新建立 MON。
启动 MON 进程。
查看 /var/run/ceph/$cluster-mon.$hostname.asokSOCKET 文件,这个是由 MON 进程启动后生成的,输出 MON 状态。

在所有的 MON 都建立好后,再次前往各个主机,查看所有主机是否运行并且到达法定人群(quorum)。如果有没到到的,直接结束报错。如果都到达了,执行下一步。

调用
auth get-or-create
方法创建 (如果不存在) 或者拉取(已经存在)MON 节点上的以下几个 keyring 到
部署目录
中:

ceph.bootstrap-mds.keyring
ceph.bootstrap-osd.keyring
ceph.bootstrap-rgw.keyring
ceph.client.admin.keyring

指令结束。

Q12. mon create-initial 为什么会失败
我不喜欢讲怎么做,我愿意花很大的篇幅介绍为什么会造成各种各样的问题,如果知道了原因,你自然知道该怎么做,所以才会理解 Ceph,而不是机械的去敲指令。
综合上面的所有小节,我来总结下这一步失败的基本上所有可能的原因:

所谓 MON 的 quorum,相当于多个 MON 形成的一个群体,它们之间需要通过网络发送数据包来通讯达成某种协议,如果打开了防火墙,会阻断数据交流。所以不能构成群体,一直等待 (5s->10s->10s->15s->20s) 其他 MON 的数据包,既然被阻断了这样的等待是没有意义的,等了 30s 还没有正常,就可以直接 ctrl+ z 去检查了。
我在配置文件里面添加了 pubilc_network,但是有个主机的所有 IP 都不在公网 IP 段内,那么这个 MON 是建不好的,因为没有 IP 用作 MON 使用,public_network 相当于一个过滤器。
搭好了一台虚拟机后,直接克隆了两台,没有修改主机名,导致 socket 文件路径名识别错误,报了异常,不过这很少发生。
如果在旧的 MON 节点上再次部署新的 MON,再又没有清理环境,之前的 MON 数据库会保留着 done 文件,MON 数据库里面还是记录着之前 fsid,keyring 等等,和新集群是两套完全不同的,所以这个节点的 MON 自然到达不了 MON 群体。
即使你单单删除了 /var/lib/ceph/mon 下的东西,而没有清理那些 keyring,也有可能会因为收集了旧集群的秘钥而发生稀奇古怪的问题。
对于 Jewel,你一不小心删除了 /var/lib/ceph/mon 目录,或者其他的 OSD 目录或者 /var/run/ceph 目录,然后又重建了目录,依然部署不上,是因为 Jewel 的所有 Ceph 指定都是运行在 ceph:ceph 用户下的,自然不能在 root 权限目录下建立任何文件,修改权限即可。
Ceph 生成 MON 数据库是依照主机的 hostname 来命名至目录 /var/lib/ceph/mon/${cluster}-${hostname}的,而检测 SOCKET 文件则是用 ceph.conf 里面的 mon_initial_members 里面的名字来检测的,如果 mon_initial_members 里面的名字和真是的主机名不一致,就会报错。

​ 一旦你运行了 ceph-deploy mon create-initial 指令,并且失败了,有极大的可能性已经在某些节点建立好了 MON 的数据库,再次执行可能会因为旧的环境导致再次失败,所以如果失败了,执行一下第二节中的清理环境即可。清理完毕后,再执行 ceph-deploy mon create-initial。

相关阅读 RMAN 配置、监控与管理 Hadoop 学习 11–Ha 集群配置启动 rsync 服务部署详解【每日课程推荐】机器学习实战!快速入门在线广告业务及 CTR 相应知识

退出移动版