06.Pod控制器


控制器

在Kubernetes中运⾏了⼀系列控制器来确保集群的当前状态与期望状态保持⼀致,它们就是Kubernetes集群内部的管理控制中⼼或者说是”中⼼⼤脑”。例如,ReplicaSet控制器负责维护集群中运⾏的Pod数量;Node控制器负责监控节点的状态,并在节点出现故障时,执⾏⾃动化修复流程,确保集群始终处于预期的⼯作状态。

  • ReplicationController 和 ReplicaSet
  • Deployment
  • DaemonSet
  • StateFulSet
  • Job/CronJob
  • Horizontal Pod Autoscaling

ReplicationController

​ ReplicationController(RC)⽤来确保容器应⽤的副本数始终保持在⽤户定义的副本数,即如果有容器异常退出,会⾃动创建新的Pod来替代;⽽如果异常多出来的容器也会⾃动回收;

​ 在新版本的Kubernetes中建议使⽤ReplicaSet(RS)来取代ReplicationController。ReplicaSet跟ReplicationController没有本质的不同,只是名字不⼀样,并且ReplicaSet⽀持集合式的selector;

apiVersion: v1
kind: ReplicationController
metadata:
  name: rc-demo
spec:
  replicas: 3
  selector:
    app: rc-demo
  template:
    metadata:
      name: rc-demo
      labels:
        app: rc-demo
    spec:
      containers:
        - name: rc-demo-container
          image: aaronxudocker/myapp:v1.0
          ports:
            - containerPort: 80
            
# kubectl delete pod rc-demo-fl7vb
# kubectl label pod rc-demo-fl7vb app=rc-demo1 --overwrite

RS控制器

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: rc-ml-demo
spec:
  replicas: 3
  selector:
    matchLabels:
      app: rc-ml-demo
  template:
    metadata:
      name: rc-ml-demo
      labels:
        app: rc-ml-demo
    spec:
      containers:
        - name: rc-ml-demo-container
          image: aaronxudocker/myapp:v1.0
          ports:
            - containerPort: 80

selector.matchExpressions
rs在标签选择器上,除了可以定义键值对的选择形式,还支持matchExpressions字段,可以提供多种选择。
目前支持的操作包括:

  • In:label的值在某个列表中
  • NotIn:label的值不在某个列表中
  • Exists:某个label存在
  • DoesNotExist:某个label不存在
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: rc-me-demo
spec:
  replicas: 3
  selector:
    matchExpressions:
      - key: app
        operator: Exists
  template:
    metadata:
      name: rc-me-demo
      labels:
        app: rc-me-demo
    spec:
      containers:
        - name: rc-me-demo-container
          image: aaronxudocker/myapp:v1.0
          ports:
            - containerPort: 80
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: rc-me-in-demo
spec:
  replicas: 3
  selector:
    matchExpressions:
      - key: app
        operator: In
        values:
        - spring-k8s
        - xixixi
  template:
    metadata:
      name: rc-me-in-demo
      labels:
        app: rc-me-in-demo
    spec:
      containers:
        - name: rc-me-in-demo-container
          image: aaronxudocker/myapp:v1.0
          ports:
            - containerPort: 80

Deployment

声明性的东⻄是对终结果的陈述,表明意图⽽不是实现它的过程。在Kubernetes中,这就是说“应该有⼀个包含三个Pod的ReplicaSet”。
命令式充当命令。声明式是被动的,⽽命令式是主动且直接的:“创建⼀个包含三个Pod的ReplicaSet”。

$ kubectl replace -f deployment.yaml

$ kubectl apply -f deployment.yaml

$ kubectl diff -f deployment.yaml

替换⽅式

  • kubectl replace:使⽤新的配置完全替换掉现有资源的配置。这意味着新配置将覆盖现有资源的所有字段和属性,包括未指定的字段,会导致整个资源的替换
  • kubectl apply:使⽤新的配置部分地更新现有资源的配置。它会根据提供的配置文件或参数,只更新与新配置中不同的部分,⽽不会覆盖整个资源的配置

字段级别的更新

  • kubectl replace:由于是完全替换,所以会覆盖所有字段和属性,⽆论是否在新配置中指定
  • kubectl apply:只更新与新配置中不同的字段和属性,保留未指定的字段不受影响

部分更新

  • kubectl replace:不⽀持部分更新,它会替换整个资源的配置
  • kubectl apply:⽀持部分更新,只会更新新配置中发⽣变化的部分,保留未指定的部分不受影响

与其他配置的影响

  • kubectl replace:不考虑其他资源配置的状态,直接替换资源的配置
  • kubectl apply:可以结合使⽤-f或-k参数,从文件或⽬录中读取多个资源配置,并根据当前集群中的资源状态进⾏更新

Deployment介绍

Deployment为Pod和ReplicaSet提供了⼀个声明式定义(declarative)⽅法,⽤来替代以前的ReplicationController来⽅便的管理应⽤。典型的应⽤场景包括:

  • 定义Deployment来创建Pod和ReplicaSet
  • 滚动升级和回滚应⽤
  • 扩容和缩容
  • 暂停和继续Deployment

image-20240911095809938

apiVersion: apps/v1
kind: Deployment
metadata:
  labels: 
    app: myapp-deploy
  name: myapp-deploy
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myapp-deploy
  template:
    metadata:
      labels:
        app: myapp-deploy
    spec:
      containers:
      - name: myapp
        image: aaronxudocker/myapp:v1.0
        resources:
          limits:
            memory: "128Mi"
            cpu: "500m"
        ports:
        - containerPort: 80

更新策略

Deployment可以保证在升级时只有⼀定数量的Pod是down的。默认的,它会确保⾄少有比期望的Pod数量少⼀个是up状态(最多⼀个不可⽤)

Deployment同时也可以确保只创建出超过期望数量的⼀定数量的Pod。默认的,它会确保最多比期望的Pod数量多⼀个的Pod是up的(最多1个surge)

未来的Kuberentes版本中,将从1-1变成25%-25%。目前的版本已经支持。

kubectlexplaindeploy.spec.strategy.type

  • Recreate

    • 在创建出新的Pod之前会先杀掉所有已存在的Pod
  • rollingUpdate

    • 滚动更新,就是杀死一部分,就启动一部分,在更新过程中,存在两个版本Pod

    • maxSurge:指定超出副本数有⼏个,两种⽅式:1、指定数量2、百分比

    • maxUnavailable:最多有⼏个不可⽤

$ kubectl create -f deployment.yaml --record
# --record 参数可以记录命令,可以看到每次revision的变化

$ kubectl scale deployment myapp-deploy --replicas 10

$ kubectl autoscale deployment myapp-deploy --min=10 --max=15 --cpu-percent=80

$ kubectl set image deployment/myapp-deploy myapp=aaronxudocker/myapp:v2.0

$ kubectl rollout history deployment/myapp-deploy

$ kubectl rollout undo deployment/myapp-deploy

可以通过设置.spec.revisionHistoryLimit项来指定deployment最多保留多少revision历史记录。默认的会保留所有的revision;如果将该项设置为0,Deployment就不允许回退了

金丝雀部署

⾦丝雀部署的名字灵感来源于17世纪英国矿井⼯⼈使⽤⾦丝雀作为⽡斯检测指标的传统⽅法。⾦丝雀对⽡斯这种⽓体⼗分敏感,空⽓中哪怕有极其微量的⽡斯,⾦丝雀也会停⽌歌唱。⽽当⽡斯含量超过⼀定限度时,虽然⼈类毫⽆察觉,⾦丝雀却早已毒发⾝亡。在采矿设备相对简陋的条件下,⼯⼈们每次下井都会带上⼀只⾦丝雀作为“⽡斯检测指标”,以便在危险状况下紧急撤离。

⾦丝雀部署的核⼼思想是在实际运⾏环境中的⼀⼩部分⽤户或流量上测试新版本的软件,⽽⼤部分⽤户或流量仍然使⽤旧版本。通过对新版本进⾏有限范围的实时测试和监控,可以及早发现潜在的问题,并减少对整个系统的冲击。

image-20240911143520378

$ kubectl patch deployment myapp-deploy -p '{"spec":{"strategy":{"rollingUpdate":{"maxSurge":1,"maxUnavailable":0}}}}'
# 允许pod多出预期1个,不允许少一个

$ kubectl patch deployment myapp-deploy --patch '{"spec": {"template": {"spec": {"containers": [{"name": "myapp","image":"aaronxudocker/myapp:v2.0"}]}}}}'   &&  kubectl rollout pause deploy  myapp-deploy
# 修改镜像为v2.0版本,并且立马停止回滚,可以看到pod数量复合上面的设置

$ kubectl rollout resume deploy myapp-deploy
# 恢复回滚动作

回滚相关的命令

$ kubectl rollout status deployment myapp-deploy
# 查看上次回滚的状态

$ kubectl rollout history deployment/myapp-deploy
# 查看回滚的历史记录,需要配合--record使用

$ kubectl rollout undo deployment/myapp-deploy --to-revision=2
# 状态回退到李四记录里面的2的状态

$ kubectl rollout pause deployment/myapp-deploy
# 暂停回滚

DaemonSet

DaemonSet确保全部(或者⼀些)Node上运⾏⼀个Pod的副本。当有Node加入集群时,也会为他们新增⼀个Pod。当有Node从集群移除时,这些Pod也会被回收。删除DaemonSet将会删除它创建的所有Pod

使⽤DaemonSet的⼀些典型⽤法:

  • 运⾏集群存储daemon,例如在每个Node上运⾏glusterdceph
  • 在每个Node上运⾏⽇志收集daemon,例如fluentdlogstash
  • 在每个Node上运⾏监控daemon,例如PrometheusNode Exporter、collectd、Datadog代理、NewRelic代理,或Gangliagmond
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: deamonset-demo
  namespace: default
  labels:
    app: deamonset-demo
spec:
  selector:
    matchLabels:
      app: deamonset-demo
  template:
    metadata:
      labels:
        app: deamonset-demo
    spec:
      containers:
      - name: deamonset-demo
        image: aaronxudocker/myapp:v1.0

Job

Job负责批处理任务,即仅执⾏⼀次的任务,它保证批处理任务的⼀个或多个Pod成功结束

特殊说明

  • spec.template格式同Pod
  • RestartPolicy仅⽀持Never或OnFailure
  • 单个Pod时,默认Pod成功运⾏后Job即结束
  • .spec.completions标志Job结束需要成功运⾏的Pod个数,默认为1
  • .spec.parallelism标志并⾏运⾏的Pod的个数,默认为1
  • spec.activeDeadlineSeconds标志失败Pod的重试最⼤时间,超过这个时间不会继续重试

案例:使用马青公式计算圆周率后一千位,可以用来看下节点的计算能力

​ 这个公式由英国天文学教授约翰·⻢青于1706年发现。他利⽤这个公式计算到了100位的圆周率。⻢青公式每计算⼀项可以得到1.4位的⼗进制精度。因为它的计算过程中被乘数和被除数都不⼤于⻓整数,所以可以很容易地在计算机上编程实现

apiVersion: batch/v1
kind: Job
metadata:
  name: job-demo
spec:
  template:
    metadata:
      name: job-demo-pod
    spec:
      containers:
      - name: job-demo
        image: aaronxudocker/tools:maqingpythonv1
      restartPolicy: Never

Job负责批处理任务,即仅执⾏⼀次的任务,它保证批处理任务的⼀个或多个Pod成功结束

错误的Job任务

apiVersion: batch/v1
kind: Job
metadata:
  name: rand
spec:
  template:
    metadata:
      name: rand
    spec:
      containers:
      - name: rand
        image: aaronxudocker/tools:randexitv1
        args: ["--exitcode=1"]
      restartPolicy: Never

Job控制器会记录成功的次数

$ kubectl get job 
NAME   COMPLETIONS   DURATION   AGE
rand   0/1           30s        30s

改为产生随机返回值

apiVersion: batch/v1
kind: Job
metadata:
  name: rand
spec:
  completions: 10
  parallelism: 5
  template:
    metadata:
      name: rand
    spec:
      containers:
      - name: rand
        image: aaronxudocker/tools:randexitv1
      restartPolicy: Never

可以看到并行启动5个pod,直到成功为止

$ kubectl get job -w
NAME   COMPLETIONS   DURATION   AGE
rand   2/10          24s        24s
rand   2/10          50s        50s
rand   2/10          52s        52s
rand   2/10          58s        58s
rand   2/10          59s        59s
rand   3/10          59s        59s
rand   3/10          60s        60s
rand   5/10          60s        60s
rand   5/10          61s        61s
rand   5/10          62s        62s
rand   5/10          67s        67s
rand   5/10          68s        68s
rand   8/10          68s        68s
rand   8/10          69s        69s
rand   8/10          69s        69s


$ kubectl get job -o yaml
......
  spec:
    backoffLimit: 6
# 6次尝试失败,就达到尝试上限

CronJob

CronJob管理基于时间的Job,即:

  • 在给定时间点只运⾏⼀次
  • 周期性地在给定时间点运⾏

使⽤条件:当前使⽤的Kubernetes集群,版本>=1.8(对CronJob)

典型的⽤法如下所⽰:

  • 在给定的时间点调度Job运⾏
  • 创建周期性运⾏的Job,例如:数据库备份、发送邮件
  • .spec.schedule:调度,必需字段,指定任务运⾏周期,格式同Cron
  • .spec.jobTemplate:Job模板,必需字段,指定需要运⾏的任务,格式同Job
  • .spec.startingDeadlineSeconds:启动Job的期限(秒级别),该字段是可选的。如果因为任何原因⽽错过了被调度的时间,那么错过执⾏时间的Job将被认为是失败的。如果没有指定,则没有期限
  • .spec.concurrencyPolicy:并发策略,该字段也是可选的。它指定了如何处理被CronJob创建的Job的并发执⾏。只允许指定下⾯策略中的⼀种:

    • Allow(默认):允许并发运⾏Job
    • Forbid:禁⽌并发运⾏,如果前⼀个还没有完成,则直接跳过下⼀个
    • Replace:取消当前正在运⾏的Job,⽤⼀个新的来替换
    • 注意,当前策略只能应⽤于同⼀个CronJob创建的Job。如果存在多个CronJob,它们创建的Job之间总是允许并发运⾏。
  • .spec.suspend:挂起,该字段也是可选的。如果设置为true,后续所有执⾏都会被挂起。它对已经开始执⾏的Job不起作⽤。默认值为false

  • .spec.successfulJobsHistoryLimit.spec.failedJobsHistoryLimit:历史限制,是可选的字段。它们指定了可以保留多少完成和失败的Job。默认情况下,它们分别设置为31。设置限制的值为0,相关类型的Job完成后将不会被保留
apiVersion: batch/v1
kind: CronJob
metadata:
  name: cronjob-demo
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    spec:
      completions: 3
      template:
        spec:
          containers:
          - name: cronjob-demo-container
            image: aaronxudocker/tools:busybox
            args:
            - /bin/sh
            - -c
            - date; echo Hello from the Kubernetes cluster
          restartPolicy: OnFailure

创建job操作应该是幂等的

Horizontal Pod Autoscaler(HPA)

​ 在前面的课程中,我们已经可以实现通过手工执行kubectl scale命令实现Pod扩容或缩容,但是这显然不符合Kubernetes的定位目标—自动化、智能化。 Kubernetes期望可以实现通过监测Pod的使用情况,实现pod数量的自动调整,于是就产生了Horizontal Pod Autoscaler(HPA)这种控制器。

​ HPA可以获取每个Pod利用率,然后和HPA中定义的指标进行对比,同时计算出需要伸缩的具体值,最后实现Pod的数量的调整。其实HPA与之前的Deployment一样,也属于一种Kubernetes资源对象,它通过追踪分析RC控制的所有目标Pod的负载变化情况,来确定是否需要针对性地调整目标Pod的副本数,这是HPA的实现原理。

image-20240912140819583

查看pod的资源

# 由于没安装metrics服务,所以无法查看pod资源情况
$ kubectl top pod myapp-deploy-57bff895d5-cvlmg
error: Metrics API not available

安装metrics-server

$ wget https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.7.2/components.yaml

# 修改配置文件
- args:
  - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname,InternalDNS,ExternalDNS
  - --kubelet-insecure-tls
  image: registry.k8s.io/metrics-server/metrics-server:v0.7.2
  
$ kubectl apply -f components.yaml

$ kubectl get pod -n kube-system |grep metrics
metrics-server-5c7fbc6ff6-fssfd            1/1     Running   0             2m42s

# 使用kubectl top node 查看资源使用情况
$ kubectl top node
NAME       CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%   
master01   116m         2%     1943Mi          55%       
node01     48m          1%     961Mi           27%       
node02     61m          1%     1161Mi          32%

$ kubectl top pod myapp-deploy-57bff895d5-cvlmg
NAME                            CPU(cores)   MEMORY(bytes)   
myapp-deploy-57bff895d5-cvlmg   0m           4Mi

准备deployment和service资源

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-pod
  template:
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
      - name: nginx
        image: aaronxudocker/myapp:v1.0
        resources:
          limits:
            cpu: "1"
          requests:
            cpu: "100m"

创建service并且查看

$ kubectl expose deployment nginx --type=NodePort --port=80

$ kubectl get deployment,pod,svc
NAME                           READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx          1/1     1            1           114s

NAME                                READY   STATUS    RESTARTS   AGE
pod/nginx-7b4664bb57-pgllw          1/1     Running   0          114s

NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)        AGE
service/nginx        NodePort    10.8.51.98   <none>        80:30482/TCP   37s

创建HPA资源

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: hpa-demo
spec:
  minReplicas: 1  #最小pod数量
  maxReplicas: 10 #最大pod数量
  behavior:
    scaleUp:
      stabilizationWindowSeconds: 10 # 在连续10秒内稳定后才考虑进一步扩展操作
      policies:
      - type: Percent
        value: 100 # 当超过当前副本数的100%才进行扩展 
        periodSeconds: 3 # 两次扩容之间的最小时间间隔
    scaleDown:
      stabilizationWindowSeconds: 300 # 在连续300秒内稳定后才考虑缩减操作
      policies:
      - type: Percent
        value: 10 # 当低于当前副本数的10%才进行缩减 
        periodSeconds: 3 # 两次缩减之间的最小时间间隔
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 10 # CPU平均利用率目标设为10%
  scaleTargetRef:   # 指定要控制的nginx信息
    apiVersion: apps/v1
    kind: Deployment
    name: nginx

查看hpa资源

$ kubectl get hpa -w
NAME       REFERENCE          TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
hpa-demo   Deployment/nginx   0%/10%    1         10        1          20s

使用压力测试工具

$ ab -c 1000 -n 1000000 http://192.168.173.100:30482/

$ kubectl get hpa -w
NAME       REFERENCE          TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
hpa-demo   Deployment/nginx   0%/10%    1         10        1          20s
hpa-demo   Deployment/nginx   1%/10%    1         10        1          105s
hpa-demo   Deployment/nginx   366%/10%   1         10        1          2m
hpa-demo   Deployment/nginx   522%/10%   1         10        2          2m15s
hpa-demo   Deployment/nginx   352%/10%   1         10        4          2m30s
hpa-demo   Deployment/nginx   189%/10%   1         10        8          2m45s
hpa-demo   Deployment/nginx   103%/10%   1         10        10         3m
hpa-demo   Deployment/nginx   68%/10%    1         10        10         3m15s

压力测试停止之后

$ kubectl get hpa -w
NAME       REFERENCE          TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
hpa-demo   Deployment/nginx   0%/10%     1         10        10         8m45s
hpa-demo   Deployment/nginx   0%/10%     1         10        9          9m
hpa-demo   Deployment/nginx   0%/10%     1         10        8          9m15s
hpa-demo   Deployment/nginx   0%/10%     1         10        7          9m30s
hpa-demo   Deployment/nginx   0%/10%     1         10        6          9m45s
hpa-demo   Deployment/nginx   0%/10%     1         10        5          10m
hpa-demo   Deployment/nginx   0%/10%     1         10        4          10m
hpa-demo   Deployment/nginx   0%/10%     1         10        3          10m
hpa-demo   Deployment/nginx   0%/10%     1         10        2          10m
hpa-demo   Deployment/nginx   0%/10%     1         10        1          11m

文章作者: AaronXu
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 AaronXu !
评论
 上一篇
07.Service 07.Service
概念以及原理KubernetesService定义了这样⼀种抽象: ​ ⼀个Pod的逻辑分组,⼀种可以访问它们的策略,通常称为微服务。这⼀组Pod能够被Service访问到,通常是通过LabelSelector
2024-09-17
下一篇 
05.Pod生命周期 05.Pod生命周期
Pod生命周期 init容器与普通的容器非常像,除了如下两点: init容器总是运行到成功完成为止 每个init容器都必须在下一个init容器启动之前成功完成 如果Pod的Init容器失败,Kubernetes会不断地重启该Pod,直到
2024-09-17
  目录