在Docker里运行Ceph

jopen 9年前

Ceph是开源社区深受欢迎的存储方案,具有稳定性高、性能好、可扩展性强等特点。原作者的这篇文章展示并探讨了如何将Ceph运行在Docker上,无疑为Docker生态系统的完善迈出了重要一步。存储问题是将Docker应用于生产环境中的备受关注的话题之一,这篇文章抛砖引玉,必将激发广大开源和 Docker技术爱好者探究现有存储方案与Docker相整合的热情。

Ceph是一个完全开源的分布式存储方案、网络块设备以及文件系统,具有高稳定性、高性能、高扩展性等特点,可应对terabyte到exabyte级别的数据量。通过使用创新性的调度算法(CRUSH)、主动存储节点、以及peer-to-peer的gossip协议,Ceph规避了传统集中控制和lookup table中的扩展性和可靠性问题。Ceph目前在整个开源社区中极受推崇,已被广泛应用与虚拟化平台(Proxmox)、云计算平台(OpenStack、 CloudStack、OpenNebula)、容器技术(Docker)、以及大数据分析系统(Hadoop、作为HDFS的meted服务器)中。

我尝试将Ceph运行在Docker中已经快两年了。直到今天我依然在做这些工作。最近我更是在Docker中部署Ceph方面投入了不小的精力。

(在展开技术细节前,我要特别感谢Sean C McCord对此工作的大力支持,当年的开源ceph-docker项目也的确是基于Sean的早期工作)

现在让我们具体看看如何将Ceph运行在Docker里!

原理

将Ceph运行在Docker中是一个比较有争议的话题,不少人质疑这样操作的意义。虽然将检测模块、metadata服务器、以及RADOS gateway容器化都没有太大问题,但对于OSD(object storage daemon),事情会变得很棘手。Ceph的OSD专门针对物理机器进行优化,与底层硬件有很多关联。如果物理硬盘失效,OSD也无法运作,这给容器化的场景带来了问题。

坦白地讲,在过去某个时刻我也在想:

“我不知道自己为什么做这个,我只知道有人需要这个功能(当然,他们可能也不知道为什么想要)。我只是觉得想进行技术尝试,那就试试看!”
当然上述想法听起来并不乐观,但这确实是我当时真实的想法。我的观点随后有了一些变化,我来解释下为什么是值得的。希望这个解释也能改变你的看法(我的解释不仅仅是“Docker很酷,所以我们要把所有东西都跑在Docker里!”)。

不少开发者已经花了很多时间将他们的软件容器化。在这个过程中,他们也用过多种不同的工具来构建和管理他们的环境。如果我看到有人用 Kubernetes来作为管理工具也一点都不会吃惊。有的人就喜欢将最新潮的技术应用到生产当中,否则他们会觉得工作很无聊。所以当他们看到自己最喜欢的开源存储方案也正在被容器化时,他们会因为这个顺应了“一切容器化”的方式而感到高兴。

与传统的yum或apt-get不同,容器使得软件的升级和回卷变得容易:我们可以通过docker stop或者docker run来发布新的daemons版本。我们甚至可以在一台物理机器上运行多个相互隔离的集群。这些都为开发过程提供了极大的便利。

项目

如上所述,所有的工作都基于Sean C McCord的早期贡献,我们后来都在围绕他的工作做完善。现在如果你用ceph-docker,你可以将每个单一的Ceph daemon运行在Ubuntu或CentOS上。我们在Docker Hub里有很多的镜像,我们使用Ceph的命名空间,因此我们的镜像前缀都是ceph/<daemon>。我们使用了自动构建,因此每次我们整合一个新的补丁就会触发新的构建,从而生成一个新的容器镜像。由于我们现在在从事代码重构,你会看到有很多的镜像版本。一直以来我们对每一个daemon构建一个单独的镜像(我们整合这些补丁的时候都会这样做)。所以监测、OSD、mds和radosgw各自都有独立的镜像。这个并不是最理想的方案,因此我们在尝试将所有组件都整合到一个叫做daemon的镜像中。这个镜像包含了所有的模块,你可以在运行docker run的时候通过命令行选择性地激活不同模块。如果你想试用我们的镜像,我们推荐使用ceph/daemon镜像。下面我就举例说明如何运行。

容器化Ceph

监测

由于监测模块不能在NAT过的网络中进行通信,我们必须使用--net=host来将主机的网络层开放给容器:
$ sudo docker run -d --net=host \  -v /etc/ceph:/etc/ceph \  -v /var/lib/ceph/:/var/lib/ceph \  -e MON_IP=192.168.0.20 \  -e CEPH_PUBLIC_NETWORK=192.168.0.0/24 \  ceph/daemon mon

你可以配置如下选项:
  • MON_IP是运行Docker的主机IP
  • MON_NAME是你监测模块的名称(默认为$(hostname))
  • CEPH_PUBLIC_NETWORK是运行Docker的主机的CIDR。它和MON_IP必须是同一个网络。
  • CEPH_CLUSTER_NETWORK是运行Docker的主机的备用网口的CIDR,为OSD的备份流量使用。

Object Storage Daemon

我们现在能实现允许每一个OSD进程运行在一个独立的容器里。按照微服务的理念,一个容器里不应该运行超过一个服务。而在我们这里,在同一个容器里运行多个OSD进程,打破了这一理念,当然这也会给系统的配置和维护带来额外的复杂度。

在这样的配置下,我们必须使用--privileged=true来使得容器中的进程可以访问/dev等其他内核功能。然后,我们在开放OSD的目录的基础上也支持其他配置,开放OSD的目录可以让operators来对设备做合适的准备工作。这样我们就可以简单地开放OSD目录,配置OSD(ceph-osd mkfs)的工作就会通过Entry Point来完成。我下面介绍的配置方法是最简单的,因为它只需要你指定一个block device,剩下的事情都会由Entry Point完成。

如果不想用--privileged=true可以采用我的第二个例子。
$ sudo docker run -d --net=host \  --privileged=true \  -v /etc/ceph:/etc/ceph \  -v /var/lib/ceph/:/var/lib/ceph \  -v /dev/:/dev/ \  -e OSD_DEVICE=/dev/vdd \  ceph-daemon osd_ceph_disk

如果你不想使用--privileged=true,你也可以使用你喜欢的配置管理工具来手动配置OSD。

下面这个例子我假定你已经实现分区并配置好文件系统。运行下面的命令来生成你的OSD:
$ sudo docker exec <mon-container-id> ceph osd create.
然后运行你的容器:
docker run -v /osds/1:/var/lib/ceph/osd/ceph-1 -v /osds/2:/var/lib/ceph/osd/ceph-2  $ sudo docker run -d --net=host \  -v /etc/ceph:/etc/ceph \  -v /var/lib/ceph/:/var/lib/ceph \  -v /osds/1:/var/lib/ceph/osd/ceph-1 \  ceph-daemon osd_disk_directory

可配置的选项如下:
  • OSD_DEVICE i是OSD设备,例如:/dev/sdb
  • OSD_JOURNAL使用来储存OSD journal的设备,例如:/dev/sdz
  • HOSTNAME是运行OSD的主机(默认为$(hostname)
  • OSD_FORCE_ZAP会强制将制定的设备内容zapping(默认为 0,设为1去开启)
  • OSD_JOURNAL_SIZE是OSD journal的大小(默认为 100)

Metadata 服务器

这个组件的设置较为直观。唯一需要注意的地方是在Docker中我们可以访问Ceph管理员密钥。这个密钥会用来生成CephFS pools和文件系统。

如果你运行0.87以前的Ceph版本,你就不需要做此配置,然而我们最好运行最新的版本!
$ sudo docker run -d --net=host \  -v /var/lib/ceph/:/var/lib/ceph \  -v /etc/ceph:/etc/ceph \  -e CEPHFS_CREATE=1 \  ceph-daemon mds

可配置的选项如下:
  • MDS_NAME是Metadata服务器的名字(默认为mds-$(hostname))。
  • CEPHFS_CREATE会为Metadata服务器生成文件系统(默认为0,设为1 去开启)。
  • CEPHFS_NAME是Metadata文件系统的名字(默认为cephfs)。
  • CEPHFS_DATA_POOL是Metadata服务器data pool的名字(默认为cephfs_data)。
  • CEPHFS_DATA_POOL_PG是data pool的placement groups的数量 (默认为8)。
  • CEPHFS_DATA_POOL是Metadata服务器metadata pool的名字(默认为cephfs_metadata)。
  • CEPHFS_METADATA_POOL_PG是metadata pool的placement groups的数量(默认为 8)。

RADOS gateway

我们部署RADOS gateway时默认开启civetweb。当然,我们也可以通过指定地址和端口来使用不同的CGI前端:
$ sudo docker run -d --net=host \  -v /var/lib/ceph/:/var/lib/ceph \  -v /etc/ceph:/etc/ceph \  ceph-daemon rgw

可配置的选项如下:
  • RGW_REMOTE_CGI指定是否使用嵌入的web服务器(默认为0,设为1去关闭)。
  • RGW_REMOTE_CGI_HOST指定运行CGI进程的远程主机。
  • RGW_REMOTE_CGI_PORT是运行CGI进行的远程主机端口。
  • RGW_CIVETWEB_PORT是civetweb的监听端口(默认为80)。
  • RGW_NAME是RADOS gateway实例的名字(默认为$(hostname))。

后续工作

后端配置存储

在默认配置下,ceph.conf和所有的Ceph密钥都会在监测模块启动阶段生成。这个过程假定了你必须在将集群扩展到多节点的时候去把这些配置传送到所有节点上。这个操作并不灵活,我们希望去改善它。我马上要提出的一个方案就是利用Ansible来生成这些配置文件和密码,并将他们安装到所有机器上。

另一种方法是将所有的配置信息存储到不同的后端服务器上,例如etcdconsul

部署管理

最直观的方案是使用现成的ceph-ansible,虽然我还需要做一些变动,但主体工作已经完成。另一种方案是使用Kubernetes,他们的预览版本已经发布。

支持Rocket等其他容器技术

也不需要做什么,因为你可以直接将你的Docker镜像运送到Rocket里,然后运行。

想要知道更多?可以看看视频

原文链接:Running Ceph inside Docker(翻译:Julia Han 审校:魏小红)

========================================
译者介绍:
Julia Han:School of Information Sciences, University of Pittsburgh, USA,硕士,Docker爱好者。

来自:http://dockone.io/article/558