什么是控制器?
Kubernetes内领有许多的控制器类型,用来管制pod的状态、行为、正本数量等等,控制器通过Pod的标签来管制Pod ,从而实现对利用的运维,如伸缩、降级等。
罕用的控制器类型如下:
ReplicationController 、ReplicaSet、Deployment
:无状态服务,保障在任意工夫运行Pod指定的正本数量,可能保障Pod总是可用的,反对滚动更新、回滚。典型用法:web服务。DaemonSet
:确保集群内全副(或局部)node节点上都调配一个pod,如果新加node节点,也会主动再调配对应的pod。典型用法:filebeat日志收集、prometheus资源监控。StatefulSet
:有状态服务,如各种数据存储系统。StatefullSet内的服务有着稳固的长久化存储和网络标识,有序部署,有序伸缩。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: v1kind: ReplicationControllermetadata: name: kubiaspec: 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/v1beta2kind: ReplicaSetmetadata: name: kubiaspec: 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/v1beta1kind: Deploymentmetadata: name: kubiaspec: replicas: 3 template: metadata: name: kubia labels: app: kubia spec: containers: - image: luksa/kubia:v1 name: nodejs
ReplicationController、ReplicaSet、Deployment的协调流程
ReplicationController、ReplicaSet、Deployment的区别
ReplicaSet是新一代的ReplicationController, 并举荐应用它代替ReplicationController来复制和治理 Pod。
同时,在应用 Deployment 时,理论的 Pod是由Deployment的Replicaset创立和治理的,而不是由Deployment间接创立和治理的。
StatefulSet
背景
Deployment不足以笼罩所有的利用编排问题,因为在它看来,一个利用的所有Pod,是齐全一样的,所以它们之间就没有程序,也无所谓运行在哪台宿主机上。须要时,Deployment就通过Pod模板创立新的Pod。不须要时,就“杀掉”任意一个Pod。然而在理论场景中,并不是所有利用都满足这样的要求。比方:主从关系,主备关系,还有就是数据存储类利用,多个实例通常会在本地磁盘上保留一份数据,而这些实例一旦被杀掉,即便重建进去,实例与数据之间的对应关系也曾经失落,从而导致利用失败。这种实例之间有不对等关系,或者有依赖关系的利用,被称为“有状态利用”。
StatefulSet简述
StatefulSet实质上是Deployment的一种变体,它为了解决有状态服务的问题,它所治理的Pod领有固定的Pod名称,启停程序,在StatefulSet中,Pod名字称为网络标识(hostname),还必须要用到共享存储。
在Deployment中,与之对应的服务是Service,而在StatefulSet中与之对应的Headless Service,Headless Service,即无头服务,与service的区别就是它没有Cluster IP,解析它的名称时将返回该Headless Service对应的全副Pod的Endpoint列表。
除此之外,StatefulSet在Headless Service的根底上又为StatefulSet管制的每个Pod正本创立了一个DNS域名,这个域名的格局为:$(podname).(headless server name)
,
FQDN(全限定域名)格局为:$(podname).(headless server name).namespace.svc.cluster.local
StatefulSet将真实世界里的利用状态,形象为了两种状况:
- 拓扑状态:这种状况是说,利用的多个实例之间不是齐全对等的关系。这些利用实例,必须依照某些程序启动,比方某个利用的主节点A要先于B启动,那么当我把A和B两个节点删除之后,从新创立进去时,也要是这个程序才行。并且,新创建进去的A和B,必须和原来的A和B网络标识一样,这样原先的访问者能力应用同样的办法,拜访到这个新Pod。
- 存储状态:这种状况是说,利用的多个实例别离绑定了不同的存储数据。对于这些利用实例来说,Pod A第一次读取到的数据,和隔了十分钟之后再次读取到的数据,应该是同一份,哪怕在此期间Pod A被从新创立过。
所以,StatefulSet的外围性能就是通过某种形式,记录这些状态,而后在Pod被从新创立时,可能为新Pod复原这些状态。
Headless Service
在深刻理解StatefulSet之前,咱们先来讲讲Headless Service。
咱们晓得,Service是Kubernetes我的项目中用来将一组Pod裸露给外界拜访的一种机制。比方,一个Deployment有3个Pod,那么我就能够定义一个Service,而后用户只有能拜访到这个Service,就能拜访到某个具体的Pod。然而,这个Service是怎么被拜访到的呢?
- 第一种形式,以Service的VIP(Virtual IP,即:虚构IP)形式。比方:当我拜访
192.168.0.1
这个Service的IP地址时,它就是一个VIP。在理论中,它会把申请转发到Service代理的具体Pod上。 - 第二种形式,就是以Service的DNS形式。在这里又分为两种解决办法:第一种是
Normal Service
。这种状况下,当拜访DNS记录时,解析到的是Service的VIP。第二种是Headless Service
。这种状况下,拜访DNS记录时,解析到的就是某一个Pod的IP地址。
能够看到,Headless Service不须要调配一个VIP,而是能够间接以DNS记录的形式解析出被代理Pod的IP地址。(Headless Service 是将Service的公布文件中的spec.clusterIP
示意为None ,不让其获取clusterIP,DNS解析的时候间接走pod。) 这样设计有什么益处呢?
这样设计能够使Kubernetes为Pod调配惟一“可解析身份”。而有了这个身份之后,只有晓得了一个Pod的名字以及它对应的Service的名字,就能够十分确定地通过这条DNS记录拜访到Pod的IP地址。
创立StatefulSet
与ReplicaSet不同, 由StatefulSet创立的Pod领有规定的名称(和主机名)。
StatefulSet的失败重启机制
StatefulSet应用标识完全一致的新的Pod替换, ReplicaSet则是应用一个不相干的新的Pod替换。
StatefulSet的示例如下所示:
apiVersion: apps/v1beta1kind: StatefulSetmetadata: name: kubiaspec: serviceName: kubia replicas: 2 template: metadata: labels: app: kubia spec: containers: - name: kubia image: luksa/kubia-pet ports: - name: http containerPort: 8080 volumeMounts: - name: data mountPath: /var/data volumeClaimTemplates: - metadata: name: data spec: resources: requests: storage: 1Mi accessModes: - ReadWriteOnce
在这个YAML文件中,多了一个serviceName=kubia
字段。这个字段的作用,就是通知StatefulSet控制器,在执行管制循环时,要应用kubia这个Headless Service来保障Pod的“可解析身份”。这样,在创立Pod过程中,StatefulSet给它所治理的所有Pod名字,进行编号,使得每个Pod实例不反复。而更重要的是,这些Pod的创立,也是严格依照编号程序来进行的。
StatefulSet和Deployment的区别
- Deployment利用于无状态利用;StatefulSet利用于有状态利用。
- Deployment的Pod之间没有程序;StatefulSet的Pod部署、扩大、更新、删除都要有程序。
- Deployment的所有pod共享存储;StatefulSet的每个pod都有本人存储,所以都用volumeClaimTemplates,为每个pod都生成一个本人的存储,保留本人的状态。
- Deployment的pod名字蕴含随机数字;StatefulSet的pod名字始终是固定的。
- Deployment的Service都有ClusterIP,能够负载平衡;StatefulSet的Service没有ClusterIP,是Headless Service,所以无奈负载平衡,返回的都是pod名,所以pod名字都必须固定,StatefulSet在Headless Service的根底上又为StatefulSet管制的每个Pod正本创立了一个DNS域名:
$(podname).(headless server name).namespace.svc.cluster.local
。
DaemonSet
DaemonSet控制器确保集群中的每一个Node只运行一个特定的Pod正本,实现零碎级的后台任务,也具备标签选择器。
也能够指定局部满足条件的Node运行一个Pod正本,比方监控具备ssd存储的Node节点。
罕用来部署一些集群的日志、监控或者其余系统管理利用。典型的利用包含:
- 日志收集,比方fluentd、logstash等。
- 系统监控,比方Prometheus Node Exporter、collectd、New Relic agent、Ganglia gmond等。
- 零碎程序,比方kube-proxy、kube-dns、Glusterd、Ceph等。
DaemonSet的示例如下所示:
前提:
# 列出所用的节点kubectl get node# 给节点名为minikube的节点增加 disk=ssd 标签kubectl label node minikube disk=ssd
上面创立一个模仿运行ssd-monitor 监控器过程的 DaemonSet, 该过程每5 秒会将 “SSD OK” 打印到规范输入。它将运行 一个基于 luksa/ssd-monitor 容器镜像的单容器 pod。 该 pod 的实例将在每个具备disk=ssd 标签的节点上创立。
apiVersion: apps/v1beta2kind: DaemonSetmetadata: name: ssd-monitorspec: selector: matchLabels: app: ssd-monitor template: metadata: labels: app: ssd-monitor spec: nodeSelector: disk: ssd containers: - name: main image: luksa/ssd-monitor
Job
到目前为止, 咱们只议论了须要继续运行的 pod
。 你会遇到只想运行实现工作后就终止工作的清况。 ReplicationController 、 ReplicaSet和 DaemonSet 会继续运行工作, 永远达不到实现态。 这些 pod 中的过程在退出时会重新启动。 然而在一个可实现的工作中, 其过程终止后, 不应该再重新启动。
Job控制器用于配置Pod对象运行一次性工作,容器中的过程在失常运行完结后不会进行重启,而是将Pod对象置于“Completed”状态。若容器中的过程因为谬误而终止,则须要配置确定是否要重启。
Job控制器对象次要有两种:
- 单工作队列地串行式Job:多个一次性的作业形式串行执行屡次作业,直到满足冀望的次数
- 多工作队列的并行式Job:多个工作队列并行运行多个一次性作业
配置项:
- completions:总的执行的作业数
- parallelism:作业执行的并行度
- activeDeadlineSeconds:最大流动工夫长度,超出此时长的作业将被终止
- backoffLimit:将作业标记为失败状态之前的重试次数,默认为6
- ttlSecondsAfterFinished:Completed的job默认不会清理。此配置项设置当job实现后的保留xx秒就主动清理这个job。当ttl controller清理job的时候是级联删除的,会把这个job下的pod一并删除。如果设置为0,job会被立刻删除。如果不指定,job则不会被删除。
Job的示例如下所示:
定义了一个Job类型的资源,它将运行luksa/batch-job镜像,该镜像调用 一个运行120秒的过程,而后退出。
apiVersion: batch/v1kind: Jobmetadata: name: batch-jobspec: completions: 5 parallelism: 2 activeDeadlineSeconds: 100 backoffLimit: 5 ttlSecondsAfterFinished: 100 template: metadata: labels: app: batch-job spec: restartPolicy: OnFailure containers: - name: main image: luksa/batch-job
下面没有指定pod选择器,它将依据pod模板中的标签进行创立。
阐明:
在一个pod的定义中,能够指定在容器中运行的过程完结时,Kubernetes应该做什么?
这是通过pod配置的属性restartPolicy实现的,默认为Always。Job类型的资源pod不能应用默认策略,因为它们不是要无限期地运行。因而,须要明确地将重启策略设置为OnFailure或Never。此设置避免容器在实现工作时重新启动。
CronJob
CronJob控制器执行周期性工作作业,管制其运行的工夫点及反复运行的形式,相似于Linux操作系统的周期性工作作业打算的形式管制其运行的工夫点和反复运行的形式。
配置项:
- jobTemplate:Job控制器模板。
- schedule:Cron格局的作业调度运行的工夫点。
- concurrencyPolicy:并发执行策略,用于定义前一次作业尚未实现时如何执行下一此工作。默认是Allow,即容许前后Job,甚至是属于同一个CrontJob的更多Job同时运行。如果设置为Forbid则禁止前后两个Job同时运行,如果前一个尚未完结,后一个不会启动(跳过),如果设置为Replace,则后一个Job会代替前一个Job,即终止前一个,启动后一个。
- failedJobHistoryLimit:为失败的工作执行保留的历史记录数,默认是1。
- successfulJobsHistoryLimit:为胜利的工作执行保留的历史记录数,默认是3。
- startingDeadlineSeconds:因各种起因不足执行作业的工夫点所导致的启动作业谬误的超时时长,会被记入谬误历史记录
- suspend:是否挂起后续的工作执行,默认是false。
CronJob的示例如下所示:
定义了一个CronJob类型的资源每15分钟运行一次批处理工作。
apiVersion: batch/v1beta1kind: CronJobmetadata: name: batch-job-every-fifteen-minutesspec: schedule: "0,15,30,45 * * * *" jobTemplate: spec: template: metadata: labels: app: periodic-batch-job spec: restartPolicy: OnFailure containers: - name: main image: luksa/batch-job
配置时间表如下图所示:
时间表从左到右蕴含以下五个条目:
- 分钟
- 小时
- 每月中的第几天
- 月
- 星期几
理解调度Job如何运行
你可能产生 Job或Pod创立并运行得绝对较晚的状况。你可能对这项作业有很高的要求,工作开始不能落后于预约的工夫过多。
在这种状况下,能够通过指定CronJob标准中的startingDeadlineSeconds
字段来指定截止日期。
apiVersion: batch/v1beta1kind: CronJobspec: schedule: "0,15,30,45 * * * *" startingDeadlineSeconds: 15
Pod 最迟必须在预约工夫15秒后开始运行, 如果作业运行的工夫应该是10:30:00
。如果因为任何起因10:30:15
不启动,工作将不会运行,并将显示为Failed。
在失常状况下,CronJob总是为schedule中配置的每个执行创立一个 Job, 但可能会同时创立两个Job, 或者基本没有建。
为了解决第一个问题,你的工作应该是幕等的(屡次(而不是一次)运行不会失去不心愿的后果)。
对于第二个问题,请确保下一个工作运行实现本应该由上一次(错过的) 运行实现的任何工作。
HorizontalPodAutoscaler(HPA)
利用的资源使用率通常都有顶峰和低谷的时候,如何削峰填谷,进步集群的整体资源利用率,让Service中的Pod 个数主动调整呢?这就有赖于Horizontal Pod Autoscaling了,顾名思义,使Pod程度主动缩放(依照冀望的pod的cpu或内存来主动伸缩pod数量)。
apiVersion: autoscaling/v1# 资源类型是HPAkind: HorizontalPodAutoscalermetadata: name: hpa-test namespace: testspec: # 最大正本数 maxReplicas: 10 # 最小正本数 minReplicas: 3 scaleTargetRef: apiVersion: apps/v1beta1 kind: Deployment # 监控名为deploy-test的Deployment name: deploy-test # cpu 阈值 CPU大于80会主动创立pod来分担服务压力,小于80则缩小pod数量 targetCPUUtilizationPercentage: 80
基于多个Pod度量的主动伸缩(例如: CPU使用率和每秒查问率[QPS])的计算也并不简单。 Autoscaler独自计算每个度量的正本数, 而后取最大值(例如:如果须要4个pod达到目标CPU使用率, 以及须要3个pod来达到目标QPS, 那么Autoscaler 将扩大到4个pod) 。
总结
咱们通常将利用分为无状态利用、有状态利用、守护型利用、批处理利用这四种。Kubernetes针对各种类型的利用设计了相应的控制器。本文简略介绍了这几种控制器的不同用处。
控制器 | 用处 |
---|---|
Deployment | 无状态利用 |
StatefulSet | 有状态利用 |
DaemonSet | 守护过程利用 |
Job & CronJob | 批处理作业 |
本文由博客一文多发平台 OpenWrite 公布!