Kubernetes笔记(5) - Pod控制器

自主式Pod对象由调度器绑定至目标工作节点后即由相应节点上的kubelet负责监控其容器的存活性,容器主进程崩溃后,kubelet能够自动重启相应的容器,基于存活性探测,在容器出现其他问题时也能作出响应,但如果Pod被意外删除、或者工作节点发生故障,kubelet就无能为力了。
Pod控制器可应对这类情况。Pod控制器由master的kube-controller-manager组件提供。kube-controller-manager是一个独立的单体守护进程,它包含了众多功能不同的控制器,除了Pod Controller,还有NodeLifecycle Controller、Namespace Controller、Service Controller等等。这些控制器不间断地监控着由其负责的资源,并在因故障、更新或其他原因导致系统状态发生变化时,尝试让资源的当前状态向期望状态迁移和逼近。

ReplicaSet控制器

ReplicaSet替代了早期的ReplicationController,用于确保由其管控的Pod对象副本数在任一时刻都能精确满足期望的数量

通过控制器创建的Pod与用户手动创建的Pod功能相同,但相比于手动创建来说,ReplicaSet能够实现以下功能:

  • 确保Pod资源对象的数量精确反映期望值
  • 确保Pod健康运行,在探测到由其管控的Pod对象因其所在的工作节点故障而不可用时,自动请求由调度器于其他工作节点创建缺失的Pod副本
  • 弹性伸缩:在资源需求存在较大波动时,可以通过ReplicaSet控制器动态调整相关Pod资源对象的数量。还可以配合HPA(HroizontalPodAutoscaler)实现Pod资源规模的自动伸缩。

创建ReplicaSet

通常一个Pod控制器的资源清单的spec包含如下基本属性:

  • selector:标签选择器,匹配并关联Pod资源对象,并据此完成受其管控的Pod资源计数
  • replicas:期望的副本数,期望在集群中精确运行着的Pod资源的对象数量
  • template:Pod模板,用于新建Pod资源对象的Pod模板资源

例如:

apiVersion: apps/v1
kind: ReplicaSet
metadata:
 name: rs-example
spec:
 replicas: 2
 selector:
   matchLabels:
     app: rs-demo
 template:
   metadata:
     labels:
       app: rs-demo
   spec:
     containers:
     - name: myapp
       image: ikubernetes/myapp:v2 
       imagePullPolicy: Never     
       ports:
       - name: http
         containerPort: 80
         protocol: TCP

将这份配置清单apply后,使用kubectl get pods -l app=rs-demo查看,会看到有两个容器,状态从ContainerCreating转为Running,两个pod名称以控制器的名称rs-example为前缀,rs-example-j98fp、rs-example-wj8zg。
运行kubectl get replicaset rs-example,配合-o json\wide等选项可查看控制器的详细状态。

ReplicaSet管控下的Pod对象

ReplicaSet之所以能对Pod对象数目的异常及时做出响应,是因为它向API Server注册监听了相关资源及其列表的变动信息,于是API Server会在变动发生时立即通知给监听方。

缺少、多出Pod副本

任何原因导致的相关Pod对象丢失,都会由ReplicaSet控制器自动补足。
手动删除一个Pod,ReplicaSet马上会新建一个;之前创建的ReplicaSet依赖标签app: rs-demo来管理Pod,那么强制修改这个标签也会触发副本的新建:
kubectl label pods rs-example-wj8zg app=others --overwrite
之前的Pod rs-example-wj8zg还存在,如果它能被别的控制器通过标签选择器选中,就会隶属于这个控制器,否会成为自助式Pod。
多余的部分则会被控制器自动删除,经测试Age最小的会被首先删除。

kubectl describe replicasets/rs-example命令可打印出ReplicaSet的详细状态以及Events。

更新ReplicaSet

更改template:升级应用

更改template对已经创建完成的活动对象无效,但可以逐个手动关闭其旧版本的Pod资源来实现滚动升级。
相比于ReplicaSet的手动操作方式,Deployment控制器能够自动实现更完善的滚动更新和回滚,并为用户提供自定义更新策略的接口。

更改replicas:扩容和缩容

通过修改replicas属性并apply,可实现应用规模的水平伸缩;kubectl还提供了一个专用的子命令scale用于实现应用规模的伸缩,比如:
kubectl scale replicasets rs-example --replicas=2
使用--current-replicas选项还可实现在副本数量为指定值时才变更replicas,比如下面的命令,如果当前副本数量不等于4就不会执行成功:
kubectl scale replicasets rs-example --current-replicas=4 --replicas=2

如果让ReplicaSet管控有状态应用,例如主从架构的Redis集群,那么上述这些升降级、扩缩容操作都需要精心编排和参与才能进行,针对这类需求,可以使用K8S专门提供的StatefulSet,ReplicaSet通常仅用于管理无状态的应用,如HTTP服务程序等。

删除ReplicaSet资源

删除命令:
kubectl delete -f ...
或者
kubectl delete replicaset ...
删除ReplicaSet对象时默认会一并删除其管控的各Pod对象。但有时考虑到这些Pod资源未必由其创建,或者Pod资源后续可能会再次用到时,可以添加--cascade=false选项取消级联删除。

Deployment控制器

Deployment控制器构建于ReplicaSet控制器之上,可为Pod和ReplicaSet资源提供声明式更新。Pod和ReplicaSet是较低级别的资源,很少被直接使用。
Deployment控制器在ReplicaSet的基础上,添加了多种增强的功能:

  • 事件和状态查看:必要时可以查看Deployment对象升级的详细进度和状态
  • 回滚:在升级发现问题时,可以使用回滚机制将应用返回到前一个或由指定的历史版本
  • 版本记录:保存每一次操作记录,以供后续可能执行的回滚操作使用
  • 暂停和启动:对于每一次升级,都能够随时暂停和启动
  • 多种自动更新方案:
    • Recreate,重建更新机制,全面停止、删除旧有的Pod后用新版本替代
    • RollingUpdate,滚动升级机制,逐步替换旧有的Pod至新的版本。

创建Deployment

Deployment将ReplicaSet对象作为其二级资源,配置清单中除了kind、name,其它字段与ReplicaSet的相同,示例:

kind: Deployment
metadata:
  name: myapp-deploy

创建完成后可用kubectl get deployments myapp-deploy查看其状态:

NAME           READY   UP-TO-DATE   AVAILABLE   AGE
myapp-deploy   2/2     2            2           15s

UP-TO-DATE表示已经达到期望状态的Pod副本数量,AVAILABLE则表示当前处于可用状态的应用程序的数量。
查看相关的ReplicaSet资源:

~ kubectl get replicasets -l app=myapp   
NAME                      DESIRED   CURRENT   READY   AGE
myapp-deploy-7cfbdc886d   2         2         2       2m53s

ReplicaSet资源的命名格式为[DEPLOYMENT-NAME]-[POD-TEMPLATE-HASH-VALUE]
查看相关的Pod资源:

~ kubectl get pods -l app=myapp          
NAME                            READY   STATUS    RESTARTS   AGE
myapp-deploy-7cfbdc886d-8lw6f   1/1     Running   0          4m55s
myapp-deploy-7cfbdc886d-xn7xp   1/1     Running   0          4m55s

Pod资源的名称以ReplicaSet资源的名称为前缀,加5位随机字符。

更新策略

Deployment控制器支持RollingUpdate和Recreate两种更新策略,默认为滚动更新。

Recreate

类似于使用ReplicaSet时一次性删除全部Pod对象,而后由控制器基于新模板重新创建出新版本资源对象。这种方式通常只应该在应用的新旧版本不兼容(如依赖的后端数据库的schema不同且无法兼容)时才使用,因为它会导致应用替换期间暂时不可用,但好处在于它不存在中间状态。

RollingUpdate

滚动升级是在删除一部分旧版本Pod资源的同时,补充创建一部分新版本的Pod对象,使用这种方式时,容器中应用提供的服务不会中断,但要求应用程序能够应对新旧版本同时工作的情形,例如新旧版本兼容同一个数据库方案等。
滚动升级时会同时存在新旧版本的ReplicaSet,旧版ReplicaSet的Pod对象数量不断减少的同时,新版ReplicaSet的Pod对象数量不断增加,直到旧版ReplicaSet不再拥有Pod对象,而新版ReplicaSet的副本数量变得完全符合预期。
升级期间还要确保可用的Pod对象数量不低于某阈值以确保可以持续处理客户端的服务请求,变动的方式和Pod对象的数量范围将通过spec.strategy.rollingUpdate下的maxSurge和maxUnavailable两个属性协同定义:

  • maxSurge:升级期间存在的总Pod对象数量最多可超出期望值的个数,其值可以是0或正整数,也可以是一个期望值的百分比
  • maxUnavailable:升级期间正常可用的Pod副本数(包括新旧版本)最多不能低于期望数值的个数,其值可以是0或正整数,也可以是一个期望值的百分比,默认值为1。

maxSurge和maxUnavailable相当于定义了pod数量的波动范围,所以它们的值不可同时为0,两者作用方式如下图举例:
rollinupdate

此外,还可以设置spec.minReadySeconds属性:

  • ,控制应用升级的速度,滚动升级时默认新的Pod对象只要就绪探测成功就可用,于是开始开始下一轮的替换操作。而minReadySeconds能够定义在新的Pod对象创建后至少要等待多久才会将其视作就绪,在此期间,更新操作会被阻塞。

升级Deployment

修改Pod模板相关的配置参数便能完成Deployment控制器资源的更新,可以通过apply和patch命令来修改;如果只是修改容器镜像,可以直接使用set image命令。
为了使得升级过程更易于观测,先使用“kubectl patch”命令指定minReadySeconds=6s:

kubectl patch deployments myapp-deploy -p '{"spec":{"minReadySeconds":6}}'

修改Deployment控制器的minReadySeconds、replicas和strategy等字段的值并不会触发Pod资源的更新操作,因为它们不会对现存的Pod对象不产生任何影响。
使用set image命令更新镜像版本:

kubectl set image deployments myapp-deploy myapp=ikubernetes/myapp:v2

随后使用如下命令可以观察滚动升级的过程:

kubectl rollout status deployments myapp-deploy --watch

升级完成后,旧版本的ReplicaSet控制器会保留在历史记录中,但其此前的管控Pod对象将会被删除。

金丝雀发布

Deployment控制器支持更新操作的暂停、继续,再结合maxSurge和maxUnavailable,可以实现金丝雀发布(Canary Release),即待第一批新的Pod资源创建完成后立即暂停更新过程,此时,仅存在一小部分新版本的应用,主体部分还是旧的版本。然后将一小部分流量导到新版本的Pod应用,并持续观察其是否能稳定地按期望的方式运行,确定没有问题后再继续完成余下Pod资源的滚动更新,否则立即回滚更新操作。
为了尽可能地降低对现有系统的影响,金丝雀发布过程通常建议采用“先添加、再删除,且可用Pod资源对象总数不低于期望值”的方式进行,首次添加的Pod对象数量取决于其接入的第一批请求的规则及单个Pod的承载能力。
接下来的试验中将maxSurge和maxUnavailable分别设置为1和0,并通过修改升级镜像版本来触发更新,但要在第一批更新启动后就暂停,由于设置了minReadySeconds,可以在这个过程中发出暂停命令,对于kubectl来说,也可以直接以“&&”符号在Shell中连接两个命令:

kubectl set image deployments myapp-deploy myapp=ikubernetes/myapp:v2 --record=true&& kubectl rollout pause deployments myapp-deploy

查看状态可知更新操作已经暂停:

kubectl rollout status deployments myapp-deploy 

此时,通过Service或Ingress资源及相关路由策略等设定,即可将一部分用户的流量引入到这些Pod之上进行发布验证,确认没有问题后即可继续更新:

kubectl rollout resume deployments myapp-deploy
回滚

如果因各种原因导致滚动更新无法正常进行,如镜像文件获取失败、“金丝雀”遇险等,则应该将应用回滚到之前的版本或者指定的历史记录中的版本,直接回滚至上一版本:

kubectl rollout undo deployments myapp-deploy

加上--to-revision选项可以回滚至指定版本,如下命令可以查看保存的历史版本:

kubectl rollout history deployments myapp-deploy

需要注意的是,只有回滚至被保存的历史版本,spec.revisionHistoryLimit定义了保存的版本数量,默认为10个。另外rollout history显示的CHANGE-CAUSE一列的内容默认为空,在执行命令时加上--record=true选项,可以记录触发更新的命令的内容。此外,处于暂停状态的更新无法回滚。

扩容、缩容

直接修改配置清单中的spec.replicas并apply可以改变Pod资源的副本数量,也可以使用专用的命令kubectl scale:

kubectl scale [--resource-version=version] [--current-replicas=count] --replicas=COUNT (-f FILENAME | TYPE NAME)

比如在当前Pod副本数为4个时,调整为2个:

kubectl scale --current-replicas=4 --replicas=2 deployment/myapp-deploy  

DaemonSet控制器

DaemonSet用于在集群中的全部或指定节点上同时运行一份指定的Pod资源副本,后续新加入集群的工作节点也会自动创建一个相关的Pod对象,当从集群移除节点时,此类Pod对象也将被自动回收而无须重建。
DaemonSet是一种特殊的控制器,它有特定的应用场景,通常运行那些执行系统级操作任务的应用,如集群存储的守护进程、日志收集守护进程、监控系统的代理守护进程等。

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: daemonset-demo
spec:
  selector:
    matchLabels:
      app: daemonset-pod
  template:
    metadata:
      labels:
        app: daemonset-pod
    spec:
      nodeSelector:
        kubernetes.io/hostname: docker-desktop
      containers:
      - name: myapp
        image: ikubernetes/myapp:v1
        imagePullPolicy: Never

Job控制器

Job控制器用于调配Pod对象运行一次性任务,容器中的进程在正常运行结束后,Pod对象会被置于Completed状态。Job控制器的配置清单相对简单:

apiVersion: batch/v1
kind: Job
metadata:
  name: job-example
spec:
  completions: 5
  parallelism: 5
  template:
    metadata:
      labels:
        app: job1
    spec:
      restartPolicy: Never
      containers:
      - name: job1
        image: alpine
        command: ["/bin/sh", "-c", "sleep 5"] 

Pod模板中的spec.restartPolicy默认为“Always”,但对Job控制器来说只支持“Never”或“OnFailure”,因此必须显式设定restartPolicy属性的值。
apply资源清单后,job便开始执行,如果顺利执行完毕,会处于Succeed状态,job资源会被自动添加标签job-name='name',如job-name=job-example,可据此使用标签选择器查看job状态

串行、并行控制

spec.completions表示总任务数,spec.parallelism表示并行度,默认都是1,所以job在执行一次后即完成,如果parallelism设为1,completions设为5,则job会以串行的方式运行5次,如果parallelism也设为5,则会并行运行5个job实例。如果completions大于parallelism,Job控制器就会以串行方式运行多任务。
可以使用--watch选项监控job的运行状态

kubectl get jobs -l job-name=job-example --watch

删除Job

Job控制器待其Pod资源运行完成后,将不再占用系统资源。用户可按需保留或使用资源删除命令将其删除。但如果某Job控制器的容器应用总是无法正常结束运行,而其restartPolicy又定为了重启,则它可能会一直处于不停地重启和错误的循环当中。下面两个属性用于抑制这种情况的发生:
spec.activeDeadlineSeconds,用于指定job的最大执行时长,超出将被终止;
spec.backoffLimit,最大重试次数,超出后被标记为失败,默认值为6。
activeDeadlineSeconds要比backoffLimit优先级高,如果时间到了,但是backoffLimit还未到,该Job也会被强制停止。

CornJob控制器

CronJob控制器用于管理Job控制器资源的运行时间。Job控制器定义的作业任务在其控制器资源创建之后便会立即执行,但CronJob可以以类似于Linux操作系统的周期性任务作业计划(crontab)的方式控制其运行的时间点及重复运行的方式。

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: cronjob-example
  labels:
    app: cronjob1
spec:
  schedule: "* * * * *"
  jobTemplate:
    metadata:
      labels:
        app: cronjob1-job
    spec:
      template:
        spec:
          restartPolicy: Never
          containers:
          - name: job1
            image: alpine
            command: ["/bin/sh", "-c", "date; echo Hello from the kubernetes cluster; sleep 1"]

这个cronjob没分钟运行一次,schedule的语法可参照这里,schedule的时间基于 kube-controller-manager的时区。

任务启动一段时间后,可使用log命令查看pod输出:

kubectl logs cronjob-example-1620082920-vg7p8

Pod中断预算

Pod中断可大体分为两种:

  • 非自愿中断,是指那些由不可控外界因素导致的Pod中断退出操作,例如,硬件或系统内核故障、网络故障以及节点资源不足导致Pod对象被驱逐等;
  • 自愿中断,是指那些由用户特地执行的管理操作导致的Pod中断,例如排空节点、人为删除Pod对象、由更新操作触发的Pod对象重建等。
    尽管Deployment或ReplicaSet一类的控制器能够确保相应Pod对象的副本数量不断逼近期望的数量,但它却无法保证在某一时刻一定会存在指定数量或比例的Pod对象,然而这种需求在某些强调服务可用性的场景中却是必备的。
    Pod中断预算(PodDisruptionBudget,PDB)可用于为自愿中断做好预算方案(Budget),限制可自愿中断的最大Pod副本数或确保最少可用的Pod副本数,以确保服务的高可用性。

定义PDB资源时,spec字段主要嵌套使用以下三个字段:

  • selector,当前PDB对象使用的标签选择器,一般是与相关的Pod控制器使用同一个选择器。
  • minAvailable,Pod自愿中断的场景中,至少要保证可用的Pod对象数量或比例,要阻止任何Pod对象发生自愿中断,可将其设置为100%
  • maxUnavailable,Pod自愿中断的场景中,最多可转换为不可用状态的Pod对象数量或比例,0值意味着不允许Pod对象进行自愿中断,此字段与minAvailable互斥。
apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
  name: pdb1
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: myapp
学习资料

《Kubernetes实战进阶》 马永亮著

posted @ 2021-05-04 21:54  zhixin9001  阅读(342)  评论(0编辑  收藏  举报