资讯 > 行业资讯

Ceph转角遇见k8s:记分布式系统界一对名角的浪漫牵手
2017/3/24 15:06:10

  作者:刘扬宽 BoCloud博云 存储开发工程师。

  1.“佛说前世无数次的痛苦挣扎,换得今生的一次邂逅。 话说分布式系统界的名角ceph,志向远大,他要做分布式存储领域的linux,但接触过ceph的爱好者在初次使用ceph时,都经历过比较痛苦的部署过程。还好后来有了ceph-deploy工具,部署会简单很多。但是由于ceph安装包的依赖关系有点复杂,特别是在没有匹配操作系统版本的ceph安装包时,通过源码编译并安装也是更加头痛的一件事情: 不仅需要依赖包,而且需要开发包;编译过程漫长,一个4核8GB的主机编译需要将近两个多小时;占用磁盘空间大,大约十几个GB。

  虽然ceph比较平易近人,但对于ceph集群的运维也是一个折腾运维工程师的苦差事。Ceph组件中的进程异常掉线,需要及时将其拉起来。服务组件使用的资源如果不加限制,会互相影响。mon是整个集群的关键组件,因此更需要保证其高可用。

  2.当ceph遇上k8s,就有了我们下面要介绍的爱情故事了,快搬来小马扎听我慢慢道来。

  在这里先简单介绍一下ceph及k8s两个的性格特点:

  Ceph号称高可用的分布式存储系统,通过多个MON节点(通常为3个)维护集群的状态及元数据信息,而真正存储数据的OSD节点通过向MON节点汇报状态,并通过CRUSH算法将数据副本布局到相应OSD的所在磁盘上,完成数据的持久化存储。为了保证每个数据副本的高可用,通常采用三副本或EC方式。而提供文件服务的mds组件和提供对象存储的rgw组件都不存储实际数据,只是作为服务态进程存在。

  K8s是Google开源的容器集群管理系统,为容器化的应用提供资源调度、部署运行、服务发现、扩容缩容等整一套功能。系统分为管理节点和容器化节点两种,通过管理节点将服务实例以pod为单位调度到容器化的计算节点上运行。K8s的管理理念很牛:像管理畜生一样管理你的应用,还别说,服务器资源的利用率显著提升。

  此处,默默无闻的幕后工作者docker要出来吼一下了。Docker出身高贵,是核心家族namespace和cgroup的后裔,他通过把应用所依赖的环境及软件库打包在镜像中,让应用在容器内自由运行,通过虚拟网络,和外界互联。

  Ceph想要和k8s牵手,需要有一个磨合的过程,要摒弃一些个性,和容器大家庭做好融合。

  首先ceph的osd组件需要使用到节点上的磁盘,一个osd对应一个磁盘。因此osd的pod需要和响应的主机绑定。Mon只是提供集群状态维护,除了少量的集群系统数据,可以运行在任何节点上,但它必须有一个固定的IP地址提供给众多OSD及客户端连接,而k8s的service恰好解决了这样一个问题。同样mds和rgw也可以采用service对外提供服务地址和负载均衡。

  而这些少量的状态和配置数据可以通过k8s的PV存储,这样,服务组件就可以在任何节点上运行。

  3.牵手细节

  硬件及基础软件环境:多台通过局域网互联的主机,并且作为容器化的主机有相应的磁盘或分区,linux操作系统内核(3.10以上)支持docker。

  首先,需要在基础环境上部署一套完整的k8s集群,然后需要准备一个ceph的docker镜像,本文中使用docker.io/ceph/daemon:tag-build-master-jewel-centos-7。

  1. 准备工作

  先创建用于存储ceph集群状态信息的持久化卷(PV)以及PVC,本文用于PV的分布式存储采用NFS。

  pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: ceph-conf
spec:
  capacity:
    storage: 10Mi
  accessModes:
    - ReadWriteMany
  nfs:
    path: /ceph4k8s/conf
server: 192.168.6.21
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: ceph-data
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteMany
  nfs:
    path: /ceph4k8s/data
    server: 192.168.6.21

  Pvc.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: ceph-conf
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 10Mi
 
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: ceph-data
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 10Gi

  2. 需要通过容器POD将ceph的MON组件部署起来,步骤如下:

  首先创建RC和service,如mon.yaml文件所示:
apiVersion: v1
kind: ReplicationController
metadata:
  app: ceph-mon
spec:
  replicas: 1
  selector:
    app: ceph-mon
  template:
    metadata:
      labels:
        app: ceph-mon
    spec:
      hostname: mon
      containers:
      - name: ceph-mon
        image: docker.io/ceph/daemon:4k8s
        imagePullPolicy: Never
        ports:
        - containerPort: 6789
          protocol: TCP
        env:
        - name: MON_IP
          value: ceph-mon
        - name: CEPH_PUBLIC_NETWORK
          value: 18.18.0.0/16
        - name: CEPH_CLUSTER_NETWORK
          value: 192.168.0.0/16
        args:
        - mon
        volumeMounts:
        - mountPath: /etc/ceph
          name: ceph-conf
        - mountPath: /var/lib/ceph
          name: ceph-data
      volumes:
      - name: ceph-conf
        persistentVolumeClaim:
          claimName: ceph-conf
      - name: ceph-data
        persistentVolumeClaim:
          claimName: ceph-data
 
---
kind: Service
apiVersion: v1
metadata:
  labels:
    app: ceph-mon
  name: ceph-mon
  namespace: default
spec:
  type: NodePort
  clusterIP: 11.11.1.1
  ports:
  - port: 6789
    targetPort: 6789
  selector:
    app: ceph-mon

  运行kubectl create -f mon.yaml

  待POD正常启动后,可以发现nfs中的PV目录被写入了集群的系统数据。

  Kubectl exec ceph-mon-xxxxx -- ceph -s

  显示如下信息:
    cluster fa6fba4c-40f6-4c51-8a5d-fd0be12dc421
     health HEALTH_ERR
            64 pgs are stuck inactive for more than 300 seconds
            64 pgs stuck inactive
            no osds
     monmap e1: 1 mons at {mon=18.18.67.2:6789/0}
            election epoch 3, quorum 0 mon
     osdmap e1: 0 osds: 0 up, 0 in
            flags sortbitwise
      pgmap v2: 64 pgs, 1 pools, 0 bytes data, 0 objects
            0 kB used, 0 kB / 0 kB avail
                  64 creating

  3. 创建OSD的POD,网络采用host方式

  采用这种网络方式,一方面是通信效率高;另一方面是能够利用主机名和设备(OSD)形成所属关系,便于crush map中区分不同host上的osd。由于OSD与MON进行网络连接时,通信组件中会对比验证发送的源IP地址与目标IP地址,如果不一致将出错。而我们通过将MON组件服务化后,对外提供固定的虚拟IP(CLUSTER-IP),而自己内部是采用Pod-IP,因此在此处会因验证不通过而无法建立连接,因此需要将源码中src/msg/async/AsyncConnection.cc:1158和vi src/msg/simple/Pipe.cc:981附近的IP验证代码注释掉,然后重新编译,替换镜像中的可执行文件ceph-osd、ceph-mds、radosgw

  创建osd-0.yaml文件
apiVersion: v1
kind: ReplicationController
metadata:
  name: ceph-osd
spec:
  replicas: 1
  selector:
    name: ceph-osd
  template:
    metadata:
      labels:
        name: ceph-osd
spec:
  nodeName: 192.168.0.21
      containers:
      - name: ceph-osd
        image: docker.io/ceph/daemon:4k8s
        imagePullPolicy: Never
        securityContext:
          privileged: true
        env:
        - name: OSD_DEVICE
          value: /dev/sdb
        - name: OSD_TYPE
        value: disk       
args:
        - osd
        volumeMounts:
        - mountPath: /etc/ceph
          name: ceph-conf
        - mountPath: /var/lib/ceph
          name: ceph-data
        - mountPath: /dev
          name: dev
      hostNetwork: true
      volumes:
      - name: ceph-conf
        persistentVolumeClaim:
          claimName: ceph-conf
      - name: ceph-data
        persistentVolumeClaim:
          claimName: ceph-data
      - name: dev
        hostPath:
          path: "/dev"
  
其中nodeName和环境变量中OSD_DEVICE要根据实际部署的多个OSD来设定。

  运行kubectl create -f osd-*.yaml之后,再到mon容器中运行ceph -s,可以发现osd都加进集群了。

  4. 咱俩真的合适吗?

  真心大考验之一

  删除mon的Pod模拟进程异常退出的故障,看集群是否仍然正常。

  Kubectl delete pod ceph-mon-xxxxx

  发现新的pod又被创建了,同时查看集群状态,仍然正常。

  真心大考验之二

  将k8s集群中运行mon组件Pod的node主机宕机,发现k8s在新的node上创建了新的mon Pod,ceph集群状态依然正常。

  经过以上考验之后,基本可以确定ceph与k8s的结合是合适的。下面接着把mds和rgw组件部署完成,使得ceph集群能够对外提供文件接口、块接口和对象接口。

  Mds.yaml
apiVersion: v1
kind: ReplicationController
metadata:
  name: ceph-mds
spec:
  replicas: 1
  selector:
    name: ceph-mds
  template:
    metadata:
      labels:
        name: ceph-mds
    spec:
      containers:
      - name: ceph-mon
        image: docker.io/ceph/daemon:4k8s
        imagePullPolicy: Never
        env:
        - name: CEPHFS_CREATE
          value: “1”
        args:
        - mds
        volumeMounts:
        - mountPath: /etc/ceph
          name: ceph-conf
        - mountPath: /var/lib/ceph
          name: ceph-data
      volumes:
      - name: ceph-conf
        persistentVolumeClaim:
          claimName: ceph-conf
      - name: ceph-data
        persistentVolumeClaim:
          claimName: ceph-data
 
Rgw.yaml
apiVersion: v1
kind: ReplicationController
metadata:
  name: ceph-rgw
spec:
  replicas: 1
  selector:
    name: ceph-rgw
  template:
    metadata:
      labels:
        name: ceph-rgw
    spec:
      containers:
      - name: ceph-rgw
        image: docker.io/ceph/daemon:4k8s
        imagePullPolicy: Never
        args:
        - rgw
        volumeMounts:
        - mountPath: /etc/ceph
          name: ceph-conf
        - mountPath: /var/lib/ceph
          name: ceph-data
      volumes:
      - name: ceph-conf
        persistentVolumeClaim:
          claimName: ceph-conf
      - name: ceph-data
        persistentVolumeClaim:
          claimName: ceph-data
---
kind: Service
apiVersion: v1
metadata:
  labels:
    app: ceph-rgw
  name: ceph-rgw
  namespace: default
spec:
  type: NodePort
  clusterIP: 11.11.1.2
  ports:
  - port: 80
    targetPort: 80
  selector:
    app: ceph-rgw

  4.小结

  让我们祝福这对新人能够和谐相处,幸福美满!如果出了问题,一定要原厂保修,不要自己修哦!

版权所有:苏州博纳讯动软件有限公司     苏ICP备13004761号