Kubernetes中的workload(工作负载)
Deployment
简介
Deployment负责管理无状态应用的部署,管理模式为:
(1)Deployment只负责管理不同版本的ReplicaSet,每个名为${deployment-name}-${template-hash}的ReplicaSet都对应了Deployment template的一个版本
(2)由RepliaSet管理Pod副本数,一个RepliaSet下的Pod都是一模一样的副本,名为${deployment-name}-${template-hash}-${random-suffix}
DeploymentSpec数据结构
-
Replicas
Pod的副本数
所谓扩缩容,就是修改Replicas,Deployment controller会把Replicas同步到当前版本的RS中,由RS执行扩缩容
扩缩容命令实际也是修改了Replicas:
$ kubectl scale deployment nginx-deployment --replicas 10
- Selector
Pod选择器,圈定Deployment管理的Pod范围。所有扩容出来的Pod的Labels必须匹配该标签。
- Template
Pod相关的模板(k8s包含了podtemplates这种资源对象,但不能创建,只能包含在workload资源对象中),包含了:
期望Pod的metadata,其中包含了labels(和selector.matchLabels相匹配的标签)
最终创建出的Pod的spec
例如修改template中一个容器的image,Deployment controller会基于新template创建一个新ReplicaSet,然后逐渐修改两个ReplicaSet中Pod的期望数量,最终完成一次发布。
- Strategy
为Recreate时,会先停掉所有旧的再起新的;
为RollingUpdate(默认)时,会滚动更新,此时有两个可配置项:
MaxUnavailable:滚动过程中最多有多少个Pod不可用;
MaxSurge:滚动过程中最多存在多少个Pod超过预期replicas数量。
如果用户的资源足够,且更注重发布过程中的可用性,可设置MaxUnavailable较小、MaxSurge较大。
如果用户的资源比较紧张,可以设置MaxSurge较小,甚至设置为0
注意:MaxSurge和MaxUnavailable不能同时为0!
- MinReadySeconds
默认情况下Deployment会根据Pod是否ready判断其是否可用。设置了MinReadySeconds后,Deployment会等若干秒之后才认为Pod是available的;
- RevisionHistoryLimit
除了当前版本外,还保留的历史版本数量,默认值为10个。
- Paused
标识Deployment只做数量维持,不做新的发布。所有对spec.template.spec的修改都不会触发新的rollout,只会把replicas同步到对应的ReplicaSet中,更新一下Deployment的status。在Debug场景下才会设置为true。
- RollbackTo
回滚的配置,里面只有一个int64的Revision(版本号),决定了回退到哪个版本
所谓回滚,其实就把template回滚为旧版本的template。
Deployment会重新修改旧ReplicaSet中Pod的期望数量,逐渐减少新版本ReplicaSet中的replica,最终把Pod从旧版本重新创建出来。
回滚命令其实也是修改了RollbackTo:
$ kubectl rollout undo deployment/nginx-deployment $ kubectl rollout undo deployment.v1.apps/nginx-deployment —-to-revision=2
--to-revision指定可以回滚到某一个具体的版本,必须先查一下版本号:
$ kubectl rollout history deployment.v1.apps/nginx-deployment
- ProgressDeadlineSeconds
设置Deployment处于Processing状态的超时时间。超时后Deployment认为这个Pod进入failed状态。
DeploymentStatus数据结构
- ObservedGeneration
表示最近一次观察到的可用的Generation
与metadata中的Generation对应,只有在版本更新的时候会有所不同
查看rollout的状态,其实就是查看ObservedGeneration是否大于Generation:
$ kubectl rollout status deployment/nginx-deployment
- Replicas、UpdateReplicas、ReadyReplicas、AvailableReplicas、UnavailableReplicas
- Conditions
k8s将Deployment的状态分为Processing(扩容/发布中)、Complete(运行中)以及Failed:
- CollisonCount
Deployment的哈希碰撞值,创建RepliaSet时用以避免重复
Deployment Controller实现原理
Deployment Controller关注Deployment和ReplicaSet相关的event,收到事件后会加入到队列中。
从队列中把事件取出来后,会检查paused(Deployment是否需要新的发布)
ReplicaSet Controller也通过Informer机制监听ReplicaSet资源来维持应用希望的状态数量,但是只管理副本数。如果发现replicas比Pod数量大的话扩容,比实际数量小就缩容。
假如rsA的replicas从2被改到3。
首先,Reflector会watch到ReplicaSet和Pod两种资源的变化,在DeltaFIFO中塞入了对象是rsA、类型是Updated的记录。
Informer把新的ReplicaSet更新到Index中并调用Update的回调函数。
ReplicaSet Controller的Update回调函数发现ReplicaSet变化后会把nsA/rsA作为key值加入到工作队列中,
ReplicaSet Controller会并发启动多个worker,以处理不同的对象实例。
worker池中一个worker从工作队列中取到了key(nsA/rsA),并从Index中取到了ReplicaSet rsA的最新数据。
worker通过比较rsA的spec和status里的数值,发现需要对它进行扩容,因此创建了一个Pod。这个Pod的Ownereference指向向了ReplicaSet rsA。
worker如果处理失败,一般会把key重新加入到工作队列中,从而方便之后进行重试。
然后Reflector watch到的Pod新增事件,在DeltaFIFO中塞入了对象是Pod、类型是Add的记录。
Informer把新的Pod更新到Index中并调用ReplicaSet Controller的Add的回调函数。
ReplicaSet Controller的Add回调函数通过检查Pod的ownerReferences找到了对应的ReplicaSet,并把nsA/rsA字符串塞入到了工作队列中。
woker在得到新的工作项后,从缓存中取到了新的ReplicaSet记录,并得到了其所有创建的Pod。因为ReplicaSet 的status不是最新的(创建的Pod总数还未更新)。因此在此时ReplicaSet更新status使得spec和status达成一致。
StatefulSet
简介
Statefulset负责管理有状态应用的部署,管理模式为:
(1)StatefulSet只负责管理不同版本的ControllerRevision,每个名为${statefulset-name}-${template-hash}的ControllerRevision对应了StatefulSet template的一个版本
(2)一个ControllerRevision下的Pod都是不同的副本:
每个Pod会有Order序号,会按照序号来创建、删除、更新Pod。例如创建时,依序创建${statefulset-name}-0、${statefulset-name}-1……前一个Pod都Ready之后,才会创建下一个Pod
每个Pod会有一个标签controller-revision-hash: hbase-master-${template-hash},StatefulSet通过该标签标识Pod所属的版本 。
StatefulsetSpec数据结构
- Replicas
- Selector
- Template
- VolumeClaimTemplates
可以定义一个或多个PVC模板。通过这样的方式使每个Pod都有独立的PVC,并且挂载到容器中对应目录。
例如,定义一个名为www的PVC模板:
volumeClaimTemplates:
- metadata:
name: ${pvc-name}
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "my-storage-class"
resources:
requests:
storage: 1Gi
每个Pod创建前,会顺序创建的名为${pvc-name}-0、${pvc-name}-1……的PVC
PVC创建完成后,Pending状态的Pod和PV进行绑定,然后才会开始调度和ContainerCreating。
注意:当前版本的StatefulSet不会在PVC中添加OwnerReference,删除StatefulSet之后,StatefulSet创建的ControllerRevision和Pod都会被删除,但是PVC不会被级联删除。
- ServiceName
通过配置一个headless Service,可以使Statefulset中的每个Pod有一个唯一的网络标识(hostname)
首先需要创建一个headless Service:
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx
ServiceName需要对应Headless Service的名字
PS:也可以随便取一个错误的名字(不会做校验)。此时不会为Pod分配唯一的hostname
- PodManagementPolicy
默认是OrderedReady(按序扩缩容),也有Paralel(并行扩缩容)
- UpdateStrategy
type为OnDelete时,Statefulset controller不会自动更新Pod,必须手动删除旧的
type为RollingUpdate时,按照2->1->0的顺序升级(删除重建),controller-revision-hash会随之升级,PVC则会自动复用。
RollingUpdate是更新的配置,里面只有一个partition字段,用于指定部分更新(即只进行一定数量的灰度发布)
PS:假设当前有个replicas为10的StatefulSet,Pod 序号为0~9。partition是8。更新时,会保留0~7这8个Pod为旧版本,只更新2个新版本作为灰度。
PS:若partition≥replicas,更新无法成功
- RevisionHistoryLimit
要清除的版本,必须没有Pod。否则该ControllerRevision不能被删除的。
- MinReadySeconds
StatefulsetStatus数据结构体
- ObservedGeneration
- Replicas、UpdatedReplicas、ReadyReplicas、AvailableReplicas、CurrentReplicas
所有值都是一样时,表示所有Pod已经升级到了所需要的版本。
- Conditions
k8s目前未对Statefulset的状态作划分
- CurrentRevision和UpdateRevision
当前和拟更新到的${statefulset-name}-${template-hash}
- CollisionCount
StatefulSet Controller实现原理
StatefulSet Controller从工作队列将工作项取出来后,先Update Revision,即查看当前拿到的StatefulSet中的template,有没有对应的ControllerRevision。如果没有,说明template已经更新过,Controller就会创建一个新版本的Revision,也就有了一个新的ControllerRevision hash版本号。
Update in order:Controller把所有版本号拿出来,并且按照序号整理一遍。这个整理的过程中,如果发现有缺少的 Pod,就按照序号去创建;如果发现有多余的 Pod,就按照序号去删除。即查看所有Pod是否满足序号。
Update status:当保证了Pod数量和序号满足Replica数量之后,Controller会去查看是否需要更新Pod。即查看Pod期望的版本是否符合要求,并且通过序号来更新。
Update in order中删除 Pod后,其实是在下一次触发事件,Controller才会发现缺少Pod,然后在Update in order中把新的Pod创建出来。在这之后Controller才会Update status(通过命令行看到的status 信息)。
Job
简介
Job的管理模式为:
(1)Job直接管理名为${job-name}−{random-suffix}的Pod,会跟踪Job的状态,根据配置重试或者继续创建
(2)根据并行配置,保证上一批Pod完成之后再运行下一批Pod
直接看Job的yaml文件无法看出Job创建了哪些Pod
只能通过kubectl describe job xxx看相应的Event,也可以从Pod的Ownerferences看出它归由哪个Job管理:
JobSpec数据结构
- Parallelism
若要并行运行Job时使用,代表并行执行的Pod个数
- Completions和CompletionMode
当有Completions个Pod执行成功时认为此Job成功,但CompletionMode分为两种:
NonIndexed模式下,只要有任意Completions个Pod执行成功即可
Indexed模式下会给Pod加index,必须是第0~Completions-1个Pod执行成功才行
- ActiveDeadlineSeconds和BackoffLimit
ActiveDeadlineSeconds为job安排一个最大运行时间,BackoffLimit则表示一个Job到底能重试多少次。
ActiveDeadlineSeconds的优先级高于BackoffLimit
- Selector和ManualSelector
Selector无需手动指定。生成的Job中,会自动加上此Pod选择器:
selector:
matchLabels:
controller-uid: df858f2d-82cf-4726-85e9-8e7899d13d74
创建的Pod会自动加上controller-uid:xxx的标签
ManualSelector设置为true时,表示希望手动进行设置
- Template
通过设置Pod的重启策略来设置Job的重启策略
- TTLSecondsAfterFinished
Job执行结束后多久自动删除此Pod
- Suspend
如果为true,不会创建新的Pod,且会删除已创建的Pod
JobStatus数据结构
- Conditions
k8s将Job的状态分为Suspended、Complete以及Failed
如果job运行失败,会显示Failed的reson和message:
status:
conditions:
- lastProbeTime: "2020-10-20T12:09:53Z"
lastTransitionTime: "2020-10-20T12:09:53Z"
message: Job has reached the specified backoff limit
reason: BackoffLimitExceeded
status: "True"
type: Failed
failed: 2
startTime: "2020-10-20T12:09:07Z"
- StartTime和CompletionTime
- Active、Succeed、Failed
- CompletedIndexes
CompletionMode为Indexed模式时,会保存执行成功的Pod的index
例如,CompletedIndexes为"1,3-5,7"时,表示第1、3、4、5、7个Pod执行成功
Job Controller实现原理
CronJob
简介
CronJob主要是用来运作一些定时任务(如Jenkins构建等)
CronSpec数据结构
- Schedule
Cron格式的字符串,形如"*/1 * * * *"
- StartingDeadlineSeconds
每次运行Job的时候最长可以等多长时间,超过时间CronJob就会停止这个 Job
- ConcurrencyPolicy
表示是否允许并行运行。分为Allow、Forbid、Replace三种
PS:并行运行指的是,如果Job运行的时间特别长,第二个Job需要运行的时候上一个Job还没完成,会同时运行两个Job。
- Suspend
- JobTemplate
-
SuccessfulJobsHistoryLimit和FailedJobsHistoryLimit
定时Job的执行历史的存留数。
CronStatus数据结构
- Active
目前哪些Job是跑着的
- LastScheduleTime和lastSuccessfulTime
DaemonSet
简介
DaemonSet也是Kubernetes提供的一个default controller,它是一个守护进程的控制器,能帮我们做到以下几件事情:
(1)保证集群内的每一个节点都运行一个名为{$DaemonsetName}−{random-suffix}的Pod
(2)根据节点的状态,保证新加入的节点自动创建对应的Pod,移除的节点能自动删除对应的Pod
常用于以下场景:
存储:需要每台节点上都运行一个类似于Agent的东西
日志收集:如logstash或者fluentd,需要每台节点都运行一个Agent
监控:如Promethues
DaemonsetSpec数据结构
- Selector
- Template
- UpdateStrategy
RollingUpdate(默认):先更新第一个Pod,然后老的Pod被移除,通过健康检查之后再建第二个Pod
OnDelete:模板更新后,Pod不会有任何变化。除非手动删除某一个节点上的Pod
- MinReadySeconds
- TemplateGeneration
- RevisionHistoryLimit
DaemonsetStatus数据结构
- CurrentNumberScheduled、NumberMisscheduled、DesiredNumberScheduled、NumberReady、UpdatedNumberScheduled、NumberAvailable、NumberUnavailable
- ObservedGeneration
- CollisionCount
- Conditions
k8s目前未对Daemonset的状态作划分
DaemonSet Controller实现原理
大体上与Job Controller类似,不过它还会监控Node的状态,根据配置的affinity或者label去选择对应的节点后,进行Pod的创建、Pod的版本比较和升级等。
更新完了之后,它会更新整个DaemonSet的状态