OPPO基于Kubernetes的云平台存储容器化实践

本文根据OPPO云平台高级后端工程师蔡逸煌在DBAplus的线上分享整理而成,主要讲述OPPO云平台存储容器化的实践。

关于做者:蔡逸煌,OPPO云平台高级后端工程师,主要从事云平台开发工做,擅长K8S、容器网络、存储等领域。node

今天分享的主题是OPPO云存储的上云之路。docker

1. 分布式存储介绍

存储相比于其余组件,更底层,因此有必要作一个简单的科普。后端

1.1 对象存储

主要是对整个文件进行操做,提供了对整个文件进行增删查改的能力。不支持对对象内容进行增量修改,如七牛的对象存储,AWS S3,阿里OSS,呈现给咱们调用方式是http api。api

1.2 分布式文件系统

文件存储实现了文件的POSIX接口,因为整个文件系统不依赖操做系统,经常使用于实现共享文件系统,常见的好比说ceph fs,gluster fs呈现给咱们的使用方式是文件系统。网络

1.3 分布式块存储

提供裸块的能力交由物理机使用,协议是SCSI,iSCSI,文件系统层由操做系统提供。呈现给咱们的使用方式是裸盘,不带任何文件系统,须要格式化后使用,或者使用块API。架构

2. 云平台存储基本架构

目前块存储主要是三个组件,gateway、storage、 cluster manager。app

  • gateway主要是解析iscsi协议,把块请求解析发送到storage进行处理;运维

    • storage则是对块的读写操做进行处理,管理磁盘数据
  • cluster manager为元数据中心,保存节点的状态,对整个集群的健康状态作仲裁

3. 云原生存储

如今Kubernetes 的趋势愈演愈烈,Kubernetes 逐渐成为云原生时代的基础设施,为了给上云的程序提供服务,云原生也随之出现,目前世面上已经有OpenEBS Portworx 和Rook等产品。分布式

云原生存储不只要为上云的服务提供服务,自身也利用云的特性加强自身的功能,依赖Kubernetes的特性,咱们能够轻运维,轻部署,利用容器隔离的能力,减小异常进程以前的相互影响,提升总体资源的利用率。ide

4. Kubernetes与CSI

Kubernetes做为将来云上的操做系统,把存储整个生命周期和管理抽象成三种资源。

4.1 StorageClass

抽象了管理存储相关的配置,主要是provisioner、parameters、reclaimPolicy这三个配置。

  • provisioner: 表示某一种存储资源
  • parameters: 至关于自定义配置,自定义一些存储属性
  • reclaimPolicy:设置volume释放后,pv的动做,Delete or Retain

经过声明不一样stroageclass能够管理多种类型的存储好比说ceph,glusterfs等等。

4.2 PersistentVolume

表示一段已分配的存储,能够是文件系统,也能够是裸块,云存储的云盘或者文件系统映射到Kubernetes 就是一个PersistentVolume。

4.3 PersistentVolumeClaim

用户存储的请求,能够请求特定的容量大小和访问模式(例如,能够以读/写一次或指向屡次模式挂载)。

抽象出PersistentVolumeClaim把存储和管理分离,经过PersistentVolumeClaim咱们能够控制访问存储的权限,存储的容量和类型。

下图是Kubernetes使用存储的一个方式:

这里衍生下Kubernetes 的一些设计理念,Kubernetes 使用声明式的API,经过YAML声明请求,并保存到etcd,这样作的好处是把整个请求记录下来,对于问题的回溯也比较方便,不用本身去记录日志提炼请求。

另外Kubernetes 还提供了对于各类资源的watch Api,各类资源的crud均可以经过watch api实时的拿到对应的YAML,这样的设计的好处是让Kubernetes 拥有很是好的扩展性,经过实现controller 去watch各类资源的变化状况,定义该资源的crud行为。

4.4 Container Storage Interface

提供一个将任意块或者文件存储系统对接到给容器编排系统(COs)上的接口标准,如Kubernetes。

把存储从建立到销毁整个生命周期抽象成一组标准接口,Kubernetes经过对接CSI,实现对存储整个生命周期的管理。

下图就是CSI定义的存储卷的生命周期:

4.5 Kubernetes中对接CSI

上文说道Kubernetes 对存储的抽象是StorageClass,PersistentVolume ,PersistentVolumeClaim等资源CSI 则是提供一组标准接口。因此须要引入一层把Kubernetes 中的资源行为转为CSI接口的程序,Kubernetes 提供了多个sidecar屏蔽这个过程。

这里简单科普下sidecar,通常来讲,引入sdk实现某些功能,在编译的时候把sdk代码编译进去,更新sdk要从新发布,和工程耦合的比较紧密,sidecar则是把sdk实现的功能经过在pod运行一个独立的容器实现,经过sidecar们提供rpc接口进行交互,能够做为被调用方,也能够是把服务包装起来加强服务功能,增长这样子的好处是解耦,让更新sidecar容器的版本更简单。

经过引入如下sidecar,咱们能够只专一于实现CSI定义的接口。

  • external-attacher:辅助触发ControllerPublishVolume
  • external-provisioner:辅助触发Controller相关接口
  • node-driver-registar:辅助注册csi插件到kubelet
  • external-resizer:辅助实现volume扩容
  • external-snappshotter:辅助实现volume快照
  • livenessprobe:转换csi prob到k8s的liveness

4.6 Kubernetes和CSI的架构

从官网给的图咱们就能够直白的看到粉红色框的sidecar们至关于一层胶水,把Kubernetes和csi连接起来。

1)PV与调度

至此咱们已经讲完了Kubernetes和CSI与K8S怎么交互的,接下来说下PV与调度的关系。

在调度阶段,PV的affinity 会影响Pod的调度,因此有调度需求的能够经过PV的affinity控制。

2)NodeStatgeVolume与NodePublishVolume

以前查阅资料的时候发现这两个接口的说明讲的比较少。

NodeStatgeVolume的接口是把远端的云盘挂到物理机上面。NodePublishVolume的接口是把NodeStatgeVolume以后的盘挂进容器里面。Kubernetes 在NodeStatgeVolume阶段会给每一个PV生成一个全局挂载点,以下图:

经过判断这个挂载点是否挂载能够方式PV重复挂载致使出错。接下来NodePublishVolume把NodeStatgeVolume的的挂载点挂载的本身Pod文件夹下,最终这个Pod的挂载点会被挂载进容器里面。

5. 存储容器化

存储做为基础组件,直接和本地盘打交道,因此咱们一个要解决的事情就是若是Kubernetes 管理本地盘。

kubernetes管理本地盘

经过官方提供的local-static-provisioner自动生成LocalPersistentVolume管理磁盘。

LocalPersistentVolume是Kubernetes提供的一种管理本地盘的资源。

5.1 使用Statefulset管理存储容器

经过statefulset 管理有状态的存储服务, 为每一个pod分配一个单独的磁盘可使用volumeClaimTemplates给每一个pod生成惟一的pvc,具体规则${claimNmae}-${podName},事先准备好PVC 和 PV,经过Statefulset 咱们就能够把咱们的存储托管到云上了。另外借助daemonset,能够把咱们gateway模块部署到每个node上面。处理云存储的请求。

5.2 存储容器化的收益

1)下降运维成本

基于Kubernetes和statfulset得到了滚动更新,灰度更新,健康检查,快速扩容等功能,只须要一组yaml文件就能够快速搭建一个集群,相比于传统写ansible脚本部署的方式复杂度大大下降。

2)下降开发运维成本

因为Kubernetes把存储抽象成StorageClass PersistentVolume PersistentVolumeClaim。咱们能够经过他们管理咱们的存储资源,基于Kubernetes lable的过滤功能,能够实现简单的关系查询,经过PVC与PV管理存储资源,减小管理端的开发。定位问题也能经过POD信息快速定位到问题机器和问题云盘。并且接入Kubernetes生态上的prometheus后,监控告警也能快速开发。

3)隔离性加强

docker限制cpu memory使用,减小进程之间资源互相干扰,进一步提高资源利用率。

线上问答

Q1:基于K8S的在线集群实现离线任务的混合部署,有什么心得吗?

目前咱们线上的转码job就是部署在在线集群,因为离线任务用到的cpu比较多,部署的时候须要经过affinity策略设置pod强制分散在各个物理机,不过最重要仍是要看整个集群的监控大盘,根据负载设置离线任务的资源。

Q2:OPPO这边用的是什么监控?作了什么改进吗?

咱们这边是自研的监控,监控核心是tsdb,咱们这边自研了一个分布式的tsdb,性能很是强大,每秒支撑上千万的metrics入库,因此咱们如今是每秒采集一次监控指标,相比于广泛的30秒采集一次,咱们在分析性能峰刺的问题有更多数据能够参考。

Q3:自研监控和Prometheus相比,对于监控是怎么取舍的?

咱们这边的tsdb是监控Prometueus的接口,可以充分利用Prometheus的开源生态,至关因而分布式版本的Prometheus。

Q4:存储的伸缩性是怎么处理的?

这里不知道是指哪一个伸缩性哈,我理解的有两个:

存储集群的伸缩性:有存储集群自己的扩缩容机制保证;

存储卷的伸缩性,csi提供了expand接口,能够经过此次接口实现对卷的扩缩容。

Q5:K8S每次更新pod版本判断服务ready有什么好的方法吗?

咱们这边是写了个controller watch了K8S pod的事件,经过事件判断pod是否ready。

Q6:除了经过storageclass、pv/pvc对接存储外,有尝试过把ceph、hdfs等存储集群自身也部署到容器集群内吗?

有的,咱们目前有部分存量数据用了ceph,storageclass、pv、pvc这三个是K8S对于整个分布式存储的抽象,想要灵活高效的使用存储都避不开这三个,此外K8S还提供了flexvolume,这个是以二进制的形式扩展到K8S里面的,比较简单,没有controller作中控,对动态扩容、快照之类的功能支持的比较弱。

相关文章
相关标签/搜索