【Kubernetes系列五】pod控制器

pod控制器
pod控制器由master的kube-controller-manager组件提供,常见的此类别的控制器有ReplicationController、ReplicaSet、Deployment、DaemonSet、StatefulSet、Job和ConJob等,它们分别以不同的方式管理pod资源对象。

1.ReplicaSet控制器

(1) ReplicaSet概述
简称RS,是pod控制器类型的一种实现,用于确保由其管控的pod对象副本数在任一时刻都能精确满足期望的数量。ReplicaSet控制器资源启动后会查找集群中匹配其标签选择器的pod资源对象,当前活动对象的数量与其期望的数量不吻合时,多则删除,少则通过pod模板创建以补足,等pod资源副本数量符合期望值后即进入下一轮和解循环。

RS的副本数量、标签选择器甚至是pod模板都可以随时按需进行修改,不过仅改动期望的副本数量会对现存的pod副本产生直接影响。修改标签选择器可能会使得现有的pod副本的标签变得不在匹配,此时rs控制器要做的不过是不再计入它们而已。另外,在创建完成后,rs也不再关注pod对象中的实际内容,因此pod模板的改动也只会对后来新建的pod副本产生影响。相比较于手动创建和管理pod资源来说,rs能够实现以下功能:

1、确保pod资源对象的数量反映期望值:rs需要确保由其控制运行的pod副本数量精确吻合配置中定义的期望值,否则就会自动补足所缺或终止所余。
2、确保pod监控运行:探测到由其管控的pod对象因其所在的工作节点故障而不可用时,自动请求由调度器于其他工作节点创建缺失的pod副本。
3、弹性伸缩:业务规模因各种原因经常存在明显波动,在波峰或波谷期间,可以通过rs控制器动态调整相关pod资源对象数量。此外,在必要时还可以通过hpa(HroizontalPodAutoscaler)控制器实现pod资源规模的自动伸缩。

(2) 创建ReplicaSet
类似于pod资源,创建rs控制器对象同样可以使用yaml或json格式的清单文件定义其配置,而后使用相关的创建命令来完成资源创建。

replicas:期望的pod对象副本数
selector:当前控制器匹配pod对象副本的标签选择器,支持matchLabels和matchExpressions两种匹配机制。
template:用于补足pod副本数量时使用的pod模板资源。
minReadySeconds:新建的pod对象,在启动后的多长时间内如果其容器未发生崩溃等异常情况即被视为就绪;默认0s,表示一旦就绪性探测成功,即被视作可用。

示例:

~]# cat rs-example.yaml
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:v1
        ports:
        - name: http
          containerPort: 80
~]# kubectl apply -f rs-example.yaml
~]# kubectl get replicaset -o wide
NAME                  DESIRED   CURRENT   READY   AGE     CONTAINERS   IMAGES                 SELECTOR
rs-example            2         2         2       5m20s   myapp        ikubernetes/myapp:v1   app=rs-demo

(3) RS管控下的pod对象
实际中存在着不少可能导致pod对象数目与期望值不符合的可能性,如pod对象的意外删除、pod对象标签的变动、控制器的标签选择器变动、甚至是工作节点故障等。rs控制器的和解循环过程能够实时监控到这些异常,并及时启动和解操作。

a.缺少pod副本
任何原因导致相关pod对象丢失,都会由RelicaSet控制器自动补足
例如:手动删除一个pod对象

~]# kubectl delete pods rs-example-c5k89
pod "rs-example-c5k89" deleted
~]# kubectl get pods -l app=rs-demo -o wide
NAME               READY   STATUS    RESTARTS   AGE     IP           NODE               NOMINATED NODE
rs-example-679xq   1/1     Running   0          52s     10.244.1.9   node01.ilinux.io   <none>
rs-example-sxq7x   1/1     Running   0          9m56s   10.244.3.7   node03.ilinux.io   <none>

例如:修改pod标签

~]# kubectl label pods rs-example-679xq app= --overwrite
pod/rs-example-679xq labeled
~]# kubectl get pods -l app=rs-demo -o wide
NAME               READY   STATUS    RESTARTS   AGE    IP            NODE               NOMINATED NODE
rs-example-d9j9z   1/1     Running   0          2m1s   10.244.2.25   node02.ilinux.io   <none>
rs-example-sxq7x   1/1     Running   0          17m    10.244.3.7    node03.ilinux.io   <none>

b.多出pod副本
一旦被标签选择器匹配到的pod资源数量因任何原因超出期望值,多余的部分都将被控制器自动删除。这就意味着,任何自助式的活本隶属于其他控制器的pod资源,其标签变动的结果一旦匹配到了其他的副本数足额的控制器,就会导致这类pod资源被删除

~]# kubectl label pods pod-example app=rs-demo

c.查看pod资源变动的相关事件

~]# kubectl describe replicasets/rs-example

(4) 更新Replicaset控制器
rs控制器的核心组成部分是标签选择器、副本数量及pod模板,但更新操作一般是围绕raplicas和template两个字段值进行的,改动pod模板的定义对已经创建完成的活动对象无效,但在用户逐个关闭其旧版本的pod资源后就能以新代旧,实现控制器下应用版本的滚动升级。另外,修改副本数量也就意味着应用规模的扩展或收缩。

a.更改pod模板:升级应用
rs控制器的pod模板可随时按需修改,但它仅影响这之后由其新建的pod对象,对已有的副本不会产生作用。

~]# cat rs-example-v2.yaml
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: nginx
        image: ikubernetes/myapp:v2
        ports:
        - name: http
          containerPort: 80

对新版本的清单文件执行kubectl apply或kubectl replace命令即可完成控制器资源的修改操作。不过控制器管控的现存pod对象仍未改变。
~]# kubectl replace -f rs-example-v2.yaml

此时,手动删除控制器现有的pod对象,并由控制器基于新的pod模板自动创建出足额的pod副本即可完成一次应用的升级。

实际使用时,还需要更完善的机制,即便是仅执行了一到多次删除操作,手动执行更替操作也并非一项轻松任务。更高级别的pod控制器deployment能够实现更完善的滚动更新和回滚,并为用户提供自定义更新策略的接口。而且,还可以实现蓝绿部署、金丝雀部署和灰度部署等。

b.扩容和缩容
改动rs对象配置中期望的pod副本数量会由控制器实时做出响应,从而实现应用规模的水平伸缩。replicas的修改及应用方式同pod模板,不过,kubectl还提供了一个专用的子命令scale用于实现应用规模的伸缩,它支持从清单文件中获取新的目标副本数量,也可以直接在命令行通过“--replicas”选项进行读取。
例如:把rs-example控制器的pod副本数量提升到5个

~]# kubectl scale replicasets rs-example --replicas=5
replicaset.extensions/rs-example scaled
~]# kubectl get replicasets rs-example
NAME         DESIRED   CURRENT   READY   AGE
rs-example   5         5         5       3h25m

收缩同理
~]# kubectl scale replicasets rs-example --replicas=3
replicaset.extensions/rs-example scaled

c.删除ReplicaSet控制器
使用kubectl delete命令删除rs对象时默认会一并删除其管控的各pod对象。又是,考虑到这些pod资源未必由其创建,或者即使由其创建却也并非其自身的组成部分。故而使用“--cascade=false”选项,取消级联删除相关的pod对象。

~]# kubectl delete replicasets rs-example --cascade=false

尽管rs控制器功能强大,但在实践中,它却并非时用户直接使用的控制器,而是deployment。

2.Deployment控制器

简写为deploy,是k8s控制器的另一种实现,它构建于ReplicaSet之上,可为pod和rs资源提供声明式更新。
deploy控制器资源的大部分功能均可通过调用ReplicaSet来实现,同时,还增添了部分特性:

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

(1) 创建deployment
Deployment构建于ReplicaSet之上,其spec字段中嵌套使用的字段包含了rs控制器支持的replicas、selector、template和minReadySeconds,它也正是利用这些信息完成了其二级资源rs对象的创建
示例:

~]# cat myapp-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deploy
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: ikubernetes/myapp:v1
        ports:
        - containerPort: 80
          name: http
~]# kubectl apply -f myapp-deploy.yaml --record
~]# kubectl get deployment

(2) 更新策略
depoly只需要由用户指定在pod模板中要改动的内容交由其自动完成更新,更新应用程序的规模也只需要修改期望的副本数量,余下的事情交给deploy控制器即可。

deploy控制器支持两种更新策略:滚动更新和重新创建,默认为滚动更新。重新创建即首先删除现有的pod对象,而后由控制器基于新模板重新创建出新版本资源对象。通常,只应该在应用的新旧版本不兼容时才会使用recreate策略。

滚动更新在删除一部分旧版本pod资源的同时,补充创建一部分新版本的pod对象进行应用升级,其优势是升级期间,容器中应用提供的服务不会中断,但要求应用程序能够应对新旧版本同时工作的情形。

deploy控制器的滚动更新操作并非在同一个rs控制器对象下删除并创建pod资源,而是将它们分置于两个不同的控制器之下:旧控制器的pod对象数量不断减少的同时,新控制器的pod对象数量不断增加,直到旧控制器不再拥有pod对象,而新控制器的副本数量变得完全符合期望值为止。

滚动更新时,应用升级期间还要确保可用的pod对象数量不低于某阈值以确保可以持续处理客户端的服务请求,变动的方式和pod对象的数量范围将通过spec.strategy.rollingUpdate.maxSurge和spec.rollingUpdate.maxUnavailable两个属性协同进行定义。

maxSurge:指定升级期间存在的总pod对象数量最多可超出期望值的个数,其值可以是0或正整数,也可以是一个期望值的百分比
maxUnavailable:升级期间正常可用的pod副本数(包括新旧版本)最多不能低于期望数值的个数,其值可以是0或正整数,也可以是一个期望值的百分比;默认值为1.
maxSurge和maxUnavailable属性的值不可同时为0,否则pod对象的副本数在符合用户期望的数量后无法做出合理变动以进行滚动更新操作。

配置时,用户还可以使用deploy控制器的spec.minReadySeconds属性来控制应用的升级速度。新旧更替过程中,新创建的pod对象一旦成功响应就绪探测即被视为可用,而后即可立即开始下一轮的替换操作。而spec.minReadySeconds能够定义在新的pod对象来让k8s在每次创建出pod资源后都要等上一段时长后再开始下一轮的更替,这个时间长度的理想值是等到pod对象中的应用已经可以接受并处理请求流量。

deploy控制器也支持用户保留其滚动更新历史中的旧rs对象版本,控制器可保存的历史版本数量由spec.revisionHistoryLimit属性进行定义。在创建deploy对象时使用“--record”选项来保存版本升级的历史。

(3) 升级deplyment
修改pod模板相关的配置参数便能完成deploy控制器资源的更新,对deploy控制器资源的修改尤其适合使用apply和patch命令来进行;
当然,如何仅是修改容器镜像,'set image'命令更为易用

接下来更新此前创建的deployment控制器deployment-example来了解更新操作过程

设置更新后容器等待时长

~]# kubectl patch deployments myapp-deploy -p '{"spec": {"minReadySeconds": 5}}'

修改myapp容器的镜像

方式一:~]# kubectl patch deployments myapp-deploy -p '{"spec":{"containers":["name": "myapp","imagee""ikubernetes/myapp:v2"]}}'
方式二:~]# kubectl set image deployments myapp-deploy myapp=ikubernetes/myapp:v2

查看更新过程

~]# kubectl roolout status deployment myapp-deploy
~]# kubectl get deployments myapp-deploy --watch

ps:滚动更新时,myapp-deploy会创建一个新的replicaset控制器对象来管控新版本的pod对象

(4) 金丝雀发布
deploy控制器还支持自定义控制更新过程中的滚动节奏,如暂停(pause)或继续(resume)更新操作,尤其时借助于maxSurge和maxUnavailable属性还能实现更为精巧的过程控制。例如,待第一批新pod对象创建完成后立即暂停更新过程,此时,仅存在一小部分新版本的应用,主体部分还是旧版本。然后再根据用户特征精心筛选出小部分用户的请求路由至新版本的pod应用,并持续观察其是否能稳定低按期望的方式运行。确定没有问题后再继续完成余下pod资源的滚动更新,否则立即回滚更新操作,这便是金丝雀发布。

金丝雀发布过程,通常采用'先添加,后删除,且可用pod资源对象不低于期望值'的方式运行,例如:
将deployment控制器的maxSurge属性值设置为1,maxUnavaiable属性值设置为0

~]# kubectl patch deployments myapp-deploy -p '{"spec":{"strategy":{"roollingUpdate": {"maxSurge": 1, "maxUnavaiable": 0} }}}'

启动更新过程,并在修改相应容器的镜像版本后立即暂停更新进度,它会在启动第一批新版本pod对象的创建操作之后转为暂停状态。注意必须设置minReadySeconds等待时长

~]# kubectl set image deployments myapp-deploy myapp=ikubernetes/myapp:v3 && kubectl roolout pause deployments deployment-deploy
~]# kubectl rollput status deployments myapp-deploy

此时pod副本为4,通过service或Ingress资源及相关路由策略等设定,引入流量到这些pod上进行发布验证,运行一段时间后,确认没问题,继续更新

~]# kubectl rollout resume deployments myapp-deploy

(5) deployment回滚
若因各种原因导致滚动更新无法正常进行,则应将应用回滚到之前的版本,或者回滚到由用户指定的历史记录中的版本,可使用命令“kubectl rollout undo”完成

~]# kubectl rollout undo deployments myapp-deploy
也可使用选项“--to-version=*”来指定版本
~]# kubectl rollout history deployments myapp-deploy
deployment.extensions/myapp-deploy 
REVISION  CHANGE-CAUSE
1         <none>
2         <none>
~]# kubectl rollout undo deployments myapp-deploy --to-version=2

回滚操作中,其revision记录中的信息会发生变动,回滚操作会被当作一次滚动更新追加进历史记录中,而被回滚的条目则会被删除。
需要注意的是,如果此前的滚动更新过程处于暂停状态,那么回滚操作就需要先将pod模板的版本改回到之前的版本,然后继续更新,否则,其将一直处于暂停状态无法回滚。

(6) 扩容和缩容
通过修改spec.replicas即可修改deploy中pod资源副本数量,它将实时作用于控制器并直接生效。
deploy是声明式配置,replicas属性的值可直接修改资源配置文件,然后使用kubectl apply进行应用,也可以使用kubectl edit对其进行实时修改。
另外,kubectl scale命令是专用于扩展某些控制器类型的应用规模的,包括deploy和job等。而deploy通过replicaset控制其pod资源,因此扩缩容的方式是相同的。

3. DaemonSet控制器

DaemonSet用于再集群中的全部节点上同时运行一份指定的pod资源副本,后续新加入的工作节点也会自动创建一个相关的pod对象,当从集群中移除节点时,此类pod对象也将被自动回收而无须重建。也可以使用节点选择器及节点标签指定仅在部分具有特定特征的节点上运行指定的pod对象。通常运行那些执行系统级操作任务的应用,具体如下:

1、运行集群存储的守护进程,如在各个节点上运行glusterfs或ceph
2、在各个节点上运行日志收集守护进程,如fluentd和logstash
3、在各个节点上运行监控系统的代理守护进程,如Prometheus Node Exporter、collectd、Datadog agent、New Relic agent或Ganlia gmond等

(1) 创建DaemonSet资源对象
spec字段中嵌套使用的字段同样主要包含pod控制器资源支持的selector、template和minReadySeconds,并且功能和用法基本相同,但不支持使用replicas。
示列:

~]# cat filebeat-ds.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: filebeat-ds
  labels:
    app: filebeat
spec:
  selector:
    matchLabels:
      app: filebeat
  template:
    metadata:
      labels:
        app: filebeat
      name: filebeat
    spec: 
      containers:
      - name: filebeat
        image: ikubernetes/filebeat:5.6.5-alpine
        env:
        - name: REDIS_HOST
          value: db.linux.io:6379
        - name: LOG_LEVEL
          value: info
~]# kubectl apply -d filebeat-ds.yaml
daemonset.apps/filebeat-ds created

(2) 更新DaemonSet对象
DaemonSet同样支持更新机制,相关配置定义在spec.updateStrategy嵌套字段中。目前,支持RollingUpdate(滚动更新)和OnDelete(删除时更新)两种策略,滚动更新为默认策略,工作逻辑类似于deploy,不过仅支持使用maxUnavailable属性定义最大不可用Pod资源副本数,默认为1,而删除时更新的方式则是在删除相应节点的pod资源后重建并更新为新版本。
默认的滚动更新策略是一次删除一个工作节点上的pod资源,待其新版本pod资源重建完成后再开始操作另一个工作节点上的pod资源。也可以使用minReadySeconds字段控制滚动更新节奏,必要时可以执行暂停和继续操作。

4.Job控制器

Job控制器用于调配pod对象运行一次性任务,容器中的进程在正常运行结束后不会对其进行重启,而是将pod对象置于completed状态。若容器中的进程因错误而终止,则需要依据配置确定重启与否,未运行完成的pod对象因其所在的节点故障而意外终止后会被重新调度。
实践中,有的作业任务可能需要运行不止一次,用户可以配置它们以串行或并行的方式运行。这种类型的job控制器对象有两种:
单工作队列的串行式job:即以多个一次性的作业方式串行执行多次作业,直至满足期望的次数
多工作队列的并行式job:这种方式可以设置工作队列数,即作业数,每个队列仅负责运行一个作业。

(1) 创建Job对象
job控制器的spec字段内嵌的必要字段仅为template,它的使用方式与deploy并无不同。job会为其pod对象自动添加“job-name=JOB_NAME”和“controller-uid=UID”标签,并使用标签选择器完成对controller-uid标签的关联。job位于API群组“batch/v1”之内
示列:Pod模板中的spec.restartPolicy默认为Always,这对job控制器来说并不适用,因此需要设定为Never或OnFailure

~]# cat job-example.yaml
apiVersion:batch/v1
kind: job
metadata:
  name: job-example
spec:
  template:
    spec:
      containers:
      - name: myjob
        image: alpine
        command: ["/bin/sh", "-c", "sleep 120"]
      restartPolicy: Never
~]# kubectl apply -f job-example.yaml

~]# kubectl get jobs job-example

(2) 并行式Job
将并行度属性spec.parallelism的值设置为1,并设置总任务数spec.completion属性便能够让job控制器以串行方式运行多任务:

apiVersion: batch/v1
kind: job
metadata:
  name: job-multi
spec:
  completions: 5
  parallelism: 2
  backoffLimit: 5
  activeDeadlineSeconds: 100
  template:
    spec:
      containers:
      - name: myjob
        image: alpine
        command: ["/bin/sh", "-c", "sleep 120"]
      restartPolicy: OnFailure

(3) job扩容
job控制器的spec.parallelism定义的并行度表示同时运行的pod对象数,此属性值支持运行时调整从而改变其队列总数,实现扩容和缩容。使用kubectl scale --replicas命令即可

~]# kubectl scale jobs job-multi --replicas=2

(4) 删除Job

job控制器待其pod资源运行完成后,将不再占用系统资源,用户可按需保留或使用资源删除命令将其删除。如果job控制器的容器应用总是无法正常结束运行,而restartPolicy又定义了重启,则它可能会一直处于不停地重启和错误的循环中:

spec.activeDeadlineSeconds:job的deadline,用于为其指定最大活动时间长度,超出此时长的作业将被终止
spec.backoffLimit: 将作业标记为失败状态之前的重试次数,默认值为6。

如上文(2)中示例配置中,其失败重试次数为5次,并且如果超出100s时间仍未运行完成,那么其将被终止。

5.CronJob控制器

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

cronjob对象支持使用的时间格式类似于crontab,略有不同的是,cronjob控制器在指定的时间点时,“?”和“*”的意义相同,都表示任何可用的有效值

(1) 创建cronjob对象
cronjob控制器的spec字段可嵌套使用以下字段:

jobTemplate:job控制器模板,用于为cronjob控制器生成job对象;必选字段
schedule:cron格式的作业调度运行时间点;必选字段
concurrencyPolicy:并发执行策略,可用值有Allow、Forbid和Replace,用于定义前一次作业运行尚未完成时是否以及如何运行后一次的作业
failedJobHistoryLimit:为失败的任务执行保留的历史记录数,默认为1
successfulJobHistoryLimit:为成功的任务执行保留的历史记录数,默认为3
startingDeadlineSeconds:因各种原因缺失执行作业的时间点所导致的启动作业错误的超时时长,会被计入错误历史记录
suspend:是否挂起后续的任务执行,默认为false,对运行中的作业不会产生影响

示列:

~]# cat cronjob-example
apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: cronjob-example
  labels:
    app: mycronjob
spec:
  schedule: "*/2 * * * *"
  jobTemplate:
    metadata:
      labels:
        app: mycronjob-jobs
    spec:
      parallelism: 2
      template:
        spec:
          containers:
          - name: myjob
            image: alpine
            command:
            - /bin/sh
            - -c
            - date; echo Hello from k8s cluster; sleep 10
          restartPolicy: OnFailure
~]# kubectl apply -f cronjob-example
~]# kubectl get cronjobs cronjob-example
NAME              SCHEDULE      SUSPEND   ACTIVE   LAST SCHEDULE   AGE
cronjob-example   */2 * * * *   False     0        <none>          22s
SCHEDULE:调度时间点
SUSPEND:后续任务是否处于挂起状态,即暂停任务的调度和运行
ACTIVE:表示活动状态的job对象的数量

ps:kubernetes 1.8起,cronjob资源所在的api资源组从batch/v2alpha1移至batch/v1beta1中,查看资源也需要使用--api-version选项指定所在资源组,如:kubectl explain cronjob --api-version='batch/v1beta1'

(2) CronJob的控制机制

CronJob控制器以job控制器资源为其管控对象,并借助它管理pod资源对象。因此,要使用类似”kubectl get jobs -l app=*“的命令来查看cronjob控制器创建的job资源对象。不过,只有相关的job对象被调度执行时,此命令才能将其正常列出。可列出的job对象的数量取决于cronjob资源的spec.successfulJobsHistoryLimit的属性值,默认为3。

如果作业重复执行时指定的时间点较近,而作业执行时长跨过了其两次执行的时间长度,则会出现两个job对象同时存在的情形。有些job对象可能会存在无法或不能同时运行的情况,这个时候就要通过spec.concurrencyPolicy属性控制作业并存的机制,其默认值为Allow,即允许前后job,甚至属于同一个cronjob的更多job同时运行。其他两个可用值中,forbid用于禁止前后两个job同时运行,如果前一个尚未结束,后一个则不予启动(跳过),replace用于让后一个job取代前一个,即终止前一个并启动后一个。

posted @ 2022-04-15 20:22  彬彬l  阅读(157)  评论(0编辑  收藏  举报