一、Operator是什么,解决了什么问题

1.1、为什么需要Operator

1.1.1、无状态和有状态

K8s作为容器编框架,可以减轻配置、部署、管理和监控大规模容器应用的负担,早期的k8s非常善于管理无状态的应用程序,比如k8s提供的Deployment控制器,他认为所有的Pod都是完全一样的,Pod间没有顺序和依赖,扩容的时候,就根据模板创建一个一模一样的新的应用,也可以任意删除Pod。
但对于向DB这样的有状态的应用程序,添加删除实例可能需要不同的节点做不同的配置,与已有的集群进行通信写上等,这些操作通常需要我们人工来干预,这就会增加运维的负担,并增加出错的可能性,最重要的是他消除了k8s的一个主要的卖点:自动化。

这是一个大问题,那么如果在k8s中管理有状态的应用程序呢?

1.1.2、StatefulSet的价值和不足

k8s 1.5版本开始,出现了StatefulSet, StatefulSet提供了一系列资源来处理有状态的容器,比如: volume, 稳定的网络标识,从0到N的顺序索引等。通过为Pod编号,再使用k8s里面的两个标准功能:headless service和PV/PVC,实现了对Pod的拓扑状态和存储状态的维护,从而让用户可以在k8s上运行有状态的应用。

然后StatefulSet只能提供受限的管理,通过StatefulSet我们还是需要编写复杂的脚步,通过判断节点编号来区别节点的关系和拓扑,需要关心具体的部署工作,并且一旦你的应用没法通过上述方式进行状态的管理,那就代表了StatefuleSet已经不能解决他的部署问题了。

既然StatefulSet不能完美的圣人管理有状态应用的工作,那么还有什么优雅的解决方案呢?答案是Operator。
Operator在2016年由CoreOS提出,用来扩充K8s管理有状态应用的能力。

二、Operator的核心原理

解释operator不得不提k8s中两个最具价值的理念:“声明式API”和“控制器模式”。

“声明式API”的核心原理,就是当用户向k8s提交了一个API对象描述之后,k8s会负责为你保证整个集群里各项资源的状态,都与你的API对象描述的需求相一致。k8s通过启动一种叫做“控制器模式”的无限循环,watch这些API对象的变化,不断检查,然后调谐,最后确保整个集群的状态与这个API对象的描述一致。

比如k8s自带的控制器:Deployment,如果我们想在k8s中部署双副本的Nginx服务,那么我们就定义一个repicas为2的Deployment对象,Deployment控制器watch到我们的对象后,通过控制循环,最终会帮我们在k8s启动两个Pod。

Operator是同样的道理,以我们的Redis Operator为例,为了实现Operator,我们首先需要将自定义对象的说明,注册到k8s中,这个对象的说明就叫做CRD(Custom Resource Definition),用于描述我们Operator控制的应用:Redis集群实例,这样当用户告诉K8s我想要一个redis集群实例后,Redis Operator就能通过控制循环执行调谐逻辑达到用户定义状态。

在这里插入图片描述
所以Operator本质上是一个个特殊应用的控制器,其提供了一种在k8s API之上构建应用程序并在k8s上部署程序的方法,他允许开发中扩展k8s API,增加新功能,像管理k8s原生组件一样管理自定义的资源。如果你想运行一个Redis哨兵模式的主从集群,或者TiDB集群,那么你只需要提交一个声明就可以了,而不需要关心部署这些分布式的应用需要的相关领域的知识,Operator本身就可以做到创建应用、监控应用状态、扩缩容、升级、故障恢复、及资源清理等,从而将分布式应用的使用门槛降到最低。

2.1、Operator核心价值

  • Operator扩展了k8s的能力
  • Operator将人工的运维知识系统化为代码
  • Operator以可扩展、可重复、标准化的方式实现目标
  • Operator减轻了开发人员的负担

2.2、Operator服务化目标

用户想在k8s中快速的运行一些分布式有状态的应用,但他们本身不关心部署、运维,既然Operator可以灵活和优雅的管理有状态应用,我们可以做个Operator平台,基于Operator将K8s管理有状态应用的能力方便的暴露给用户。

核心的目标主要有两方面:
1、针对Operator平台

  • 提供一个简单易用的控制台供用户使用,用户只需要点点鼠标,就能快速拉起有状态应用,并且能在控制台上实时看到应用部署的进度和事件,查看资源,更新资源等。
  • 通用化,将应用名称等通用配置和应用参数(如:redis的maxclients, timeout等参数)解耦。这样带来的好处就是不同的Operator可以共用创建页面,而不需要为每种Operator定制创建页面,同时Operator暴露出更多的应用配置参数时,前端开发也不需关心,由后端通过API返回给前端参数,前端渲染参数,用户修改参数后,通过API传递到后端,后端将参数与模板渲染成最终的实例声明,提交到k8s中,节省了前端开发时间。
    在这里插入图片描述
  • 可以管理通过公共的Operator和Namespace私有的Operator创建的实例。用户可以用我们提供的公用的Operator,也可以把operator部署到自己的namespace,给自己的项目提供服务,但这两种operator创建的应用实例都可以通过operator控制台管理。
  • 可以无限添加Operator

2、针对Operator控制器

  • 拉起分布式集群,自动运行配置、运维
  • 可以动态更改所控制应用参数
  • 控制器本身需要无状态,不能依赖外部数据库等
  • 实时更新状态,维护状态,推送事件
  • 可以运行在集群范围,也能运行在单namespace, 并且可以共存,不能冲突;

针对上述目标,最终我们实现了operator控制台:
在这里插入图片描述
同时为Operator控制台定义了第一个Operator:Redis Operator,未来可推出更多的operator。

三、Redis Operator

3.1、Redis集群模式选型

我们知道Redis集群模式主要有主从模式、哨兵模式、Redis官方CLuster模式及社区的代理分区模式。

分析以上几种模式,主从模式的Redis集群不具备自动容错和恢复功能,主节点和从节点的宕机,都会导致读写请求失败,需要等待节点恢复才能恢复正常;
而Redis官方cluster模式及社区的代理分区模式,只有在数据量及并发数大的业务中才有使用需求。哨兵模式基于主从模式,但因为增加了哨兵节点,使得redis集群拥有了主从切换,故障转移的能力,系统可用性更好,而客户端也只需要通过哨兵节点拿到master和slave地址就能直接使用。因此我们决定为operator平台提供一个快速创建哨兵模式的redis集群的redis operator。

3.2、开源Operator的不足

目前已有一些开源的Redis Operator,通过对这些Operator分析,我们发现都不能满足我们的需求,这些开源的Operator:

  • 不能设置redis密码
  • 不能动态响应更改参数
  • 没有维护状态,推送事件
  • 不能在开启了istio自动注入的namespace中启动实例
  • 只能运行在集群或但namespace模式

3.3、改进工作

我们定制开发了Redis Operator在Github上开源:https://github.com/ucloud/redis-operator,提供:

  • 动态响应更改Redis配置参数
  • 实时监控集群状态,并且推送事件,更新状态
  • 误删除节点故障恢复
  • 设置密码
  • 打开关闭持久化快捷配置
  • 暴露Prometheus metrics

使用Redis Operator我们可以很方便的起一个哨兵模式的集群,集群只有一个Master节点,多个slave节点,假如指定Redis集群的size为3,那么Redis Operator就会帮我们启动一个master节点,2个slave节点,同时启动是3个sentinel节点来管理Redis集群:
在这里插入图片描述
Redis Operator通过StatefulSet管理Redis节点,通过Deployment来管理Sentinel节点,这比管理裸Pod要容易,节省实现成本。同时创建一个Service指向所有的哨兵节点,通过Service对客户端提供查询Master,slave节点的服务。最终,Redis Operator控制循环会调谐集群的状态,设置集群的拓扑,让所有的Sentinel监控同一个Master节点,监控相同的Slave节点。Redis operator除了会watch实例的创建、更新、删除事件外,还会定时检测已有的集群的监控状态,实时把集群的状态记录到spec.status.conditions中:

status:
  conditions:
  - lastTransitionTime: "2019-09-06T11:10:15Z"
    lastUpdateTime: "2019-09-09T10:50:36Z"
    message: Cluster ok
    reason: Cluster available
    status: "True"
    type: Healthy
  - lastTransitionTime: "2019-09-06T11:12:15Z"
    lastUpdateTime: "2019-09-06T11:12:15Z"
    message: redis server or sentinel server be removed by user, restart
    reason: Creating
    status: "True"
    type: Creating

为了让用户通过kubectl快速查看redis集群的状态,我们在CRD中定义了如下的additionalPrinterConlums:additionalPrinterColumns:

- JSONPath: .spec.size
    description: The number of Redis node in the ensemble
    name: Size
    type: integer
  - JSONPath: .status.conditions[].type
    description: The status of Redis Cluster
    name: Status
    type: string
  - JSONPath: .metadata.creationTimestamp
    name: Age
    type: date

由于CRD的addtionalPrinterColumns对数组类型支持不完善,只能显示数组的第一个元数据,所以需要将spec.status.conditions中的状态按时间倒序,最新的状态显示在上方,方便用户查看最新的状态。通过使用也可以通过kubectl命令直接查看集群的监控状况:
在这里插入图片描述

3.4、快速持久化

我们还了解到,用户使用Redis时,有一些使用场景是直接将Redis当数据库用,需要持久化配置,而有些只是当做缓存,允许数据丢失。

为此,我们特意在Redis集群的CRD中添加了快速持久化配置的开关,默认为启用,这会为用户自动开启和配置RDB和AOF持久化,同时结合PVC(Persistent Volume Claim)可以将用户的数据持久化起来。但节点故障,被误删除时数据也不会丢失,并且PVC默认不会跟随Redis集群的删除而删除,当用户在相同namespace下启动同名的Redis集群时,又可以使用上次的PVC,从而恢复数据。

podAntiAffinity:
   preferredDuringSchedulingIgnoredDuringExecution:
   - podAffinityTerm:
       labelSelector:
         matchLabels:
           app.kubernetes.io/component: redis
           app.kubernetes.io/managed-by: redis-operator
           app.kubernetes.io/name: test
           app.kubernetes.io/part-of: redis-cluster
           redis.kun/v1beta1: prj-shu_test
       topologyKey: kubernetes.io/hostname
     weight: 100

为了让Redis拥有更高的可用性,我们为Redis节点提供了设置node affinity, pod anti affinity的能力(可避免某些Pod部署在同一个Node上),可以灵活的控制redis数据节点泡在不同Node或者不同数据中心,做到跨机房容灾。如上所示,redis operator缺省情况下,会为每个Pod注入podAntiAffinity,让每个redis服务尽量不会运行在同一个Node节点。

3.5、监控

Operator中还内置了Prometheus Exporter,不仅将operator自身的一些metrics暴露出来,还会将operator创建的每一个redis集群实例的状态通过metrics暴露出来。

这还不够,我们还为每个redis节点提供了单独暴露metrics的能力,用户可以在启动redis集群的时候,为每个redis节点注入单独的exporter,这样每个集群的每个redis暑假节点都能被我们单独的监控起来,结合Prometheus和AlterManager可以很方便的将Operator及Operator创建的实例监控起来。

结合Operator的运维、StatefulSet的能力,加上Sentinel的能力,等于说为Redis集群加了三重保险,可以确保集群的高可用。

参考链接:https://www.infoq.cn/article/pPP3LRqf8BApcg3azNL3

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐