容器持久化存储与Ceph

image001

 

 

前言

本文仅介绍容器的 persistent volume,而不介绍容器的 graph driver。还需要你对文件系统和块设备有所了解。

通过persistent volume,可以在容器上运行stateful(有状态应用)。

image001

 

用户角度

应用如何访问存储

对于一般应用,访问存储的接口最常见的是文件系统。比如 web 服务器,图片、视频、CSS等文件都是通过文件系统来存取的。也有一些程序,比如Oracle,可以直接使用块设备来作为存储后端。

持久化存储的接口

 

如果说我们的持久存储本身就是文件系统,比如一个本地的目录。那么我们可以通过 mount namespace 让容器能够访问这个目录就可以了。这是最常见的一种情形。对应的 docker 命令即是 # docker run --volume /host-path:/container-path/ image

 

那如果我们的持久存储是一个块设备呢,比如 /dev/sdb。第一种方法就是在主机上把 /dev/sdb 格式化成一个文件系统,比如ext4,然后把它挂载到一个目录上,然后通过 volume 参数传给 docker。

 

第二种方法就是我们把 /dev/sdb 这个块设备直接给到容器内部。对应 docker 命令是

# docker run --device=/dev/sdb

 

目前来讲,我们都是用第一种方式的,第二种方式仅在应用程序直接使用块设备时才用到。

 

如何给容器提供持久化存储?

 

但是我们每次想挂载一个块设备存储时,都要手动在主机上挂载,那且不是很麻烦?其实 docker和kubernetes 是有Volume Plugin如何把这些操作进行自动化的。

 

如果我们要以docker volume形式使用块设备,步骤如下:

  1. 创建一个Volume。
  2. 将这个Volume映射到主机,作为一个块设备。
  3. 检测块设备上是否有文件系统,假如没有,需要格式化块设备,创建一个文件系统
  4. 在主机上挂载这个块设备。
  5. 将对应的挂载点传给docker的volume参数

我们可以使用volume plugin来自动化这一系列操作,这样通过docker运行应用时,只使用下面一条命令就可以了:

#docker run --volume-driver=rbd --volume foo:/mnt/foo
对于 kubernetes,一些volume plugin已经集成在 kubernetes 内了,所以只需在 yaml 文件指定 volume 的格式就可以了。

 

 

Volume Plugin的类型

Docker Volume Plugin

Docker 1.8 之后支持 volume plugin,可以使用第三方的 volume 插件。Docker 原生支持主机 mount 时原本支持的参数和类型,例如 nfs。通过第三方插件可以使用更多的存储类型,例如通过 flocker 插件使用 Ceph、ScaleIO、NetApp

更多插件,可以查询

https://store.docker.com/search?category=volume&page=1&q=&type=plugin

 

image003

Kubernetes Volume Plugin

Kubernetes 集成了多种 volume 类型,包括各种云服务商的云硬盘,具体可以参考 https://kubernetes.io/docs/concepts/storage/volumes/#types-of-volumes

 

image005

 

 

Ceph RBD-NBD提供持久化存储

 

之前可以通过CephFS和Ceph KRBD像容器提供持久化存储,但是CephFS还不够成熟,不能大规模应用; KRBD使用内核态,性能不佳,而且功能被用户诟病。我们怎么才能给Kubernetes、Docker、Mesos用上用户态的Ceph RBD块设备呢?

image007

由Kylin Cloud给Ceph社区贡献的rbd-nbd工具,可以向宿主机提供nbd块设备,而且调用的是用户态的librbd,这使得容器使用用户态的rbd成为可能。其后,Mirantis还给Kubernetes提交了“Add support for accessing Ceph RBD-based volumes with the rbd-nbd client”的patch,使得Kubernetes可以直接使用用户态的rbd块设备。

https://github.com/kubernetes/kubernetes/pull/38936

UMCloud也给rbd-nbd开发了Docker volume plugin,使得Docker也可以直接使用用户态的rbd块设备。

下面我们来看怎么集成Kubernetes/Docker和Ceph RBD。

 

K8s witch Ceph Runbook

使用 https://github.com/kubernetes/kubernetes/pull/38936 重新编译安装k8s。在宿主机上检查内核是否支持nbd模块,比如目前CentOS还使用的是不支持nbd的内核。部署Ceph集群,并记住MON的地址。

 

我们使用K8s和Ceph创建一个redis应用,这个redis使用Ceph RBD块设备作为持久化存储。

redis.json文件内容如下所示:

 

{

“apiVersion”: “v1”,

“kind”: “Pod”,

“metadata”: {

“name”: “redis”

},

“spec”: {

“containers”: [

{

“name”: “redis-c”,

“image”: “redis”,

“volumeMounts”: [

{

“mountPath”: “/data”,

“name”: “redispd”

}

],

“command”: [“redis-server”],

“args”: [“–appendonly”, “yes”]

}

],

“volumes”: [

{

“name”: “redispd”,

“rbd”: {

“monitors”: [

“192.168.80.165:6789”

],

“pool”: “kube”,

“image”: “redis”,

“user”: “admin”,

“keyring”: “/etc/ceph/ceph.client.admin.keyring”,

“fsType”: “ext4”,

“readOnly”: false,

“backendType”: “nbd”

}

}

]

}

}

 

 

执行以下命令:

#rbd create kube/redis --size 128

#cluster/kubectl.sh create -f ~/redis

 

Docker with Ceph Runbook

需要安装新的插件,插件地址在https://github.com/UMCloudHQ/ceph-moby-plugin

#go get github.com/UMCloudHQ/ceph-moby-plugin

 

测试redis应用

# docker run -d --volume-driver=ceph-docker --volume redis-vol:/data redis:3

 

在Host查看mount状态

#mount

/dev/nbd0 on /var/lib/ceph-docker/rbd-redis-vol

 

 

未来与展望

Ceph通过rbd-nbd的方式向容器提供持久化存储,而且是用户态的,性能更高,功能也更灵活,开发更方便。

目前rbd-nbd也存在一些可以改进的地方,比如:

  1. 没有QoS,不能限制IOPS和吞吐率。
  2. 没有持久化Cache。
  3. 每个persistent volume都会启动一个rbd-nbd server,消耗资源。

UMCloud和Mirantis将会去解决这些问题。

1 Comment

发表评论

电子邮件地址不会被公开。 必填项已用*标注