浅析Kubernetes控制器
Kubernetes内拥有许多的控制器类型,用来控制pod的状态、行为、副本数量等等,控制器通过Pod的标签来控制Pod ,从而实现对应用的运维,如伸缩、升级等。
常用的控制器类型如下:
ReplicationController 、ReplicaSet、Deployment:无状态服务,保证在任意时间运行Pod指定的副本数量,能够保证Pod总是可用的,支持滚动更新、回滚。典型用法:web服务。
DaemonSet:确保集群内全部(或部分)node节点上都分配一个pod,如果新加node节点,也会自动再分配对应的pod。典型用法:filebeat日志收集、prometheus资源监控。
StatefulSet:有状态服务,如各种数据存储系统。StatefullSet内的服务有着稳定的持久化存储和网络标识,有序部署,有序伸缩。郑州科大看精神科好吗https://jbk.39.net/yiyuanfengcai/lx_zzjsyy/
Job:只运行一次的作业。
CronJob:周期性运行的作业。典型用法:数据库定时备份。
Horizontal Pod Autoscaling(HPA):按照期望的pod的cpu或内存来自动伸缩pod数量。
为什么需要控制器?
假如我们现在有一个Pod正在提供线上的服务,我们来想想一下我们可能会遇到的一些场景:
某次运营活动非常成功,网站访问量突然暴增
运行当前Pod的节点发生故障了,Pod不能正常提供服务了
针对第一种情况,可能比较好应对,一般活动之前我们会大概计算下会有多大的访问量,提前多启动几个Pod,活动结束后再把多余的Pod杀掉,虽然有点麻烦,但是应该还是能够应对这种情况的。
针对第二种情况,可能某天夜里收到大量报警说服务挂了,然后起来打开电脑在另外的节点上重新启动一个新的Pod,问题也很好的解决了。
如果我们都人工的去解决遇到的这些问题,似乎又回到了以前刀耕火种的时代了,是吧。要是有一种工具能够来帮助我们管理Pod就好了,Pod不够了自动帮我们新增一个,Pod挂了自动帮我们在合适的节点上重新启动一个Pod,如果这样的话,是不是遇到上面的问题,我们都不需要手动去解决了。
Pod分类
Pod分为自主式Pod和控制器管理的Pod这两类。
自主式 Pod:Pod 退出后不会被自动创建,如图中的Pod A。
控制器管理的 Pod:在控制器的生命周期里,始终要维持 Pod 的副本数目,如图中的Pod B。
ReplicationController、ReplicaSet、Deployment
ReplicationController(RC)
简单来说,RC可以保证在任意时间运行Pod的副本数量,能够保证Pod总是可用的。如果实际Pod数量比指定的多,那就结束掉多余的,如果实际数量比指定的少,就新启动一些Pod。当Pod失败、被删除或者挂掉后,RC都会去自动创建新的Pod来保证副本数量,所以即使只有一个Pod,我们也应该使用RC来管理我们的Pod。
简而言之,RC用于确保其管控的Pod对象副本数满足期望的数值,它能实现以下功能:
确保Pod的资源数量精确反应期望值
确保Pod健康运行
弹性伸缩
ReplicationController的示例如下所示:
apiVersion: v1
kind: ReplicationController
metadata:
name: kubia
spec:
replicas: 3
selector:
app: kubia
template:
metadata:
labels:
app: kubia
spec:
containers:
- name: kubia
image: luksa/kubia
ports:
- containerPort: 8080
一个ReplicationController有三个主要部分:
label selector ( 标签选择器):用于确定ReplicationController作用域中有哪些pod
replica count (副本个数): 指定应运行的Pod 数量
pod template (Pod模板): 用于创建新的Pod 副本
RC存在的问题:
大部分情况下,我们可以通过定义一个RC实现的Pod的创建和副本数量的控制 RC中包含一个完整的Pod定义模块(不包含apiversion和kind),RC是通过label selector机制来实现对Pod副本的控制的。通过改变RC里面的Pod副本数量,可以实现Pod的扩缩容功能。通过改变RC里面的Pod模板中镜像版本,可以实现Pod的滚动升级功能(但是不支持一键回滚,需要用相同的方法去修改镜像地址)
ReplicaSet(RS)
随着Kubernetes的高速发展,官方已经推荐我们使用RS和Deployment来代替RC了,实际上RS和RC的功能基本一致, 目前唯一的一个区别就是RC只支持基于等式的selector(如:env=dev或environment!=qa),但RS还支持基于集合的selector(如:version in (v1.0, v2.0)),这对复杂的运维管理就更方便了。
ReplicaSet的示例如下所示:
apiVersion: apps/v1beta2
kind: ReplicaSet
metadata:
name: kubia
spec:
replicas: 3
selector:
matchLabels:
app: kubia
template:
metadata:
labels:
app: kubia
spec:
containers:
- name: kubia
image: luksa/kubia
ReplicationController和ReplicaSet唯一的区别就是在选择器中,不必在selector属性中直接列出pod需要的标签, 而是在selector.matchLabels下指定它们。 这是在ReplicaSet中定义标签选择器的更简单(也更不具表达力)的方式。
除了selector.matchLabels指定之外,还可以使用selector.matchExpressions指定,如下所示:
selector:
matchExpressions:
- key: app
operator: In
values:
- kubia
使用ReplicaSet进行更富表达力的标签选择器有四个有效的运算符:
In : Label的值 必须与其中 一个指定的values 匹配。
NotIn : Label的值与任何指定的values 不匹配。
Exists : pod 必须包含 一个指定名称的标签(值不重要)。使用此运算符时,不应指定 values字段。
DoesNotExist : pod不得包含有指定名称的标签。values属性不得指定 。
如果你指定了多个表达式,则所有这些表达式都必须为true才能使选择器与pod匹配。如果同时指定matchLabels和matchExpressions, 则所有标签都必须匹配,并且所有表达式必须计算为true以使该pod与选择器匹配。
Deployment
不过我们也很少会去单独使用RS,它主要被Deployment这个更加高层的资源对象使用,除非用户需要自定义升级功能或根本不需要升级Pod, Deployment 为 Pod 和 ReplicaSet 提供了一个申明式的定义方法。
典型的应用场景:
用来创建Pod和ReplicaSet、滚动更新和回滚、扩容和缩容、暂停与恢复。
在一般情况下,我们推荐使用Deployment而不直接使用Replica Set。
Deployment基于ReplicaSet之上,可为Pod和ReplicaSet资源提供声明式更新,它具有以下特性:
事件和状态查看:可以查看Deployment对象升级的详细进度和状态
回滚:当升级操作完成后发现问题时,支持将应用返回到指定的历史版本中
版本记录:对Deployment 对象的每一次操作都予以保存
暂停和启动:每一次升级,都可以随时暂停和启动
多种自动更新方案:Recreate-重建更新、RollingUpdate-滚动更新
Deployment的更新策略描述如下:
RollingUpdate 策略:旧控制器的Pod数量不断减少,同时新控制器的Pod不断增加,以下两个属性:maxSurge:升级期间存在的总Pod数量最多可超过期望值的个数,可以是数值或百分比。maxUnavailabe:升级期间正常可用的Pod数(新旧版本)最多不能低于期望的个数,可以是数值或百分比。
Recreate 策略:在删除旧的 pod 之后才开始创建新的 pod。 如果你的应用程序不支持多个版本同时对外提供服务, 需要在启动新版本之前完全停用旧版本, 那么需要使用这种策略。 但是使用这种策略的话, 会导致应用程序出现短暂的不可用。
Deployment的示例如下所示:
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: kubia
spec:
replicas: 3
template:
metadata:
name: kubia
labels:
app: kubia
spec:
containers:
- image: luksa/kubia:v1
name: nodejs