Kubernetes学习笔记(三):部署托管的Pod -- 存活探针、ReplicationController、ReplicaSet、DaemonSet、Job、CronJob

存活探针

Kubernetes可以通过存活探针(liveness probe)检查容器是否存活。如果探测失败,Kubernetes将定期执行探针并重新启动容器。
官方文档请见:https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/
存活探针分为三种:

  • exec:在容器内执行任意命令,并检查命令的退出状态码,为0则成功,否则失败。
  • httpGet:执行http get请求,http code大于等于200并且小于400表示成功,否则失败。
  • tcp:尝试与指定端口建立socket连接,建立成功则探测成功,否则失败。

exec探针

从官网复制个yaml,但是要将image从k8s.gcr.io/busybox更改为busybox。

-> [[email protected]] [~] cat exec-liveness.yaml
apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-exec
spec:
  containers:
  - name: liveness
    image: busybox
    args:
    - /bin/sh
    - -c
    - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
    livenessProbe:
      exec:
        command:
        - cat
        - /tmp/healthy
      initialDelaySeconds: 5
      periodSeconds: 5

运行然后30秒后查看

-> [[email protected]] [~] k create -f exec-liveness.yaml
pod/liveness-exec created

-> [[email protected]] [~] k describe po liveness-exec
.......
    Liveness:       exec [cat /tmp/healthy] delay=5s timeout=1s period=5s #success=1 #failure=3
.......
Events:
  Type     Reason     Age                            From               Message
  ----     ------     ----                           ----               -------
  Normal   Scheduled                        default-scheduler  Successfully assigned default/liveness-exec to kube1.vm
  Normal   Pulling                          kubelet, kube1.vm  Pulling image "busybox"
  Normal   Pulled                           kubelet, kube1.vm  Successfully pulled image "busybox"
  Normal   Created                          kubelet, kube1.vm  Created container liveness
  Normal   Started                          kubelet, kube1.vm  Started container liveness
  Warning  Unhealthy   (x3 over )  kubelet, kube1.vm  Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory
  Normal   Killing                          kubelet, kube1.vm  Container liveness failed liveness probe, will be restarted

前30秒,/tmp/healthy是存在的,探针返回成功。30秒后,因为/tmp/healthy不存在了,所以一直失败,直到失败3次后重启。

livenessProbe下的字段

这时候kubectl explain po.spec.containers.livenessProbe就派上了用场。

  • exec:exec探针配置
  • httpGet:httpGet探针配置
  • tcpSocket:tcpSocket探针配置
  • initialDelaySeconds:初始延迟时间,在此时间内不进行探测,给程序预留启动时间。
  • periodSeconds:探测周期,默认10s
  • timeoutSeconds:超时时间,默认1s
  • failureThreshold:被认为失活的最小连续失败次数,默认3次
  • successThreshold:失败后被认为存活的最小连续成功次数,默认为1次。

这些参数在上面的kubectl describe的结果中的Liveness字段有:

exec [cat /tmp/healthy] delay=5s timeout=1s period=5s #success=1 #failure=3

注意事项

  • 一定要检查程序的内部,而没有外界因素影响。
    例如,当服务器无法连接到数据库时,前端服务的探针不应返回失败。因为问题在数据库,重启前端服务也无法解决问题。
  • 无须再探针中实现重试
  • 探针要轻量

ReplicationController

ReplicationController是一种Kubernetes资源,可以确保他的pod始终处于运行状态。

ReplicationController描述文件分为三大部分:

  • label selector(标签选择器):用于确定ReplicationController管理哪些pod
  • replica count(副本个数):指定运行pod的数量
  • pod template(pod模板):用于创建pod

ReplicationController的目的就是创建和管理若干个pod副本,它会持续监控正在运行的pod列表,保证标签选择器匹配的pod数量与副本个数一致。如果少于副本数量,就要根据pod模板创建新的副本;如果多余副本数量,就要删除多余的pod。

数量少的原因可能是:

  • 增加了副本个数
  • pod所在的工作节点出现故障
  • pod的标签更改了,导致pod与ReplicationController的标签选择器不再匹配了。此时,如果它不被任何ReplicationController的标签选择器匹配,它就称为一个孤儿了。

数量多的原因可能是:

  • 减少了副本个数
  • 新建的pod与该ReplicationController的标签选择器匹配
  • 已存在的pod标签修改后与该ReplicationController的标签选择器匹配

nginx-rc.yaml

API服务器会检查模板中的标签是否与selector匹配,如果不匹配是无法创建的。可以不指定selector,它会根据模板中的labels自动配置。

apiVersion: v1
kind: ReplicationController
metadata:
  name: nginx-rc
spec:
  replicas: 3	# 副本数量
  selector:	# pod选择器,决定RC的操作对象
    app: nginx
  template:	# pod模板
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx
          ports:
            - containerPort: 80

使用ReplicationController

创建ReplicationController

-> [[email protected]] [~] k create -f nginx-rc.yaml
replicationcontroller/nginx-rc created

查看pod,确实新建了3个pod。

-> [[email protected]] [~] k get po --show-labels
NAME             READY   STATUS              RESTARTS   AGE   LABELS
nginx-rc-2c47w   0/1     ContainerCreating   0          5s    app=nginx
nginx-rc-jrcl2   0/1     ContainerCreating   0          5s    app=nginx
nginx-rc-qgchh   0/1     ContainerCreating   0          5s    app=nginx

查看ReplicationController,rc是ReplicationController的简写。

-> [[email protected]] [~] k get rc
NAME       DESIRED   CURRENT   READY   AGE
nginx-rc   3         3         3       5m58s

查看详情

-> [[email protected]] [~] k describe rc nginx-rc
Name:         nginx-rc
Namespace:    default
Selector:     app=nginx
Labels:       app=nginx
Annotations:  
Replicas:     3 current / 3 desired				# 当前数量、期望数量
Pods Status:  3 Running / 0 Waiting / 0 Succeeded / 0 Failed	# 各种状态下的数量
Pod Template:
  Labels:  app=nginx
  Containers:
   nginx:
    Image:        nginx
    Port:         80/TCP
    Host Port:    0/TCP
    Environment:  
    Mounts:       
  Volumes:        
Events:
  Type    Reason            Age    From                    Message
  ----    ------            ----   ----                    -------
  Normal  SuccessfulCreate  7m26s  replication-controller  Created pod: nginx-rc-2c47w
  Normal  SuccessfulCreate  7m26s  replication-controller  Created pod: nginx-rc-jrcl2
  Normal  SuccessfulCreate  7m26s  replication-controller  Created pod: nginx-rc-qgchh

可以搞一些破坏,比如更改、删除pod的标签,或者干脆删除pod。ReplicationController会因为当前数量与期望数量不符而创建新的副本。

控制器如何创建的pod

控制器通过创建一个新的副本代替被删除的副本时,它并没有对删除本身做出反应,而是针对由此产生的状态——副本数量不足做出反应。
虽然控制器会立即受到pod被删除的通知,但这并不是它创建新副本的原因。该通知会触发控制器检查实际的副本数量并采取相应措施。

kubectl edit

kubectl edit rc nginx-rc可以在编辑器中打开nginx-rc的yaml配置,修改在保存后会立刻做出改变。

-> [[email protected]] [~] k edit rc nginx-rc
replicationcontroller/nginx-rc edited
通过KUBE_EDITOR环境变量可以指定用什么编辑器打开。

kubectl scale

可以使用kubectl scale命令进行扩缩容。

-> [[email protected]] [~] k scale rc nginx-rc --replicas=6
replicationcontroller/nginx-rc scaled

以上操作会修改spec.replicas字段,就像通过kubectl edit修改一样。

删除ReplicationController

使用 kubectl delete 删除ReplicationController时,pod也会被删除。但由于pod是被ReplicationController创建的而不是它的组成部分,所以可以通过指定--cascade=false而不删除pod。

注意事项

  • pod永远不会被重新安置到另一个节点。
  • 虽然一个pod没有绑定在ReplicationController上,但该pod在metadata.ownerReferences引用它。

ReplicaSet

ReplicationController最终将要被弃用,代替它的是ReplicaSet。它们的行为完全相同,但是ReplicaSet的选择器更具有表达力。

nginx-rs.yaml

让我们来看一个ReplicaSet的描述文件:

apiVersion: apps/v1	# api版本与ReplicationController不同
kind: ReplicaSet
metadata:
  name: nginx-rs
spec:
  replicas: 3
  selector:		# ReplicaSet的pod选择器有matchLabels和matchExpressions,与ReplicationController的是相似的,但更强大
    matchLabels:
      app: nginx
  template:		# 模板内容是一致的
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx
          ports:
            - containerPort: 80

主要区别在于pod选择器。ReplicaSet的创建于ReplicationController一样,缩写是rs,就不再赘叙了。

matchExpressions

上面描述文件的选择器使用matchExpressions可以改为:

  selector:
    matchExpressions:
      - key: app
        operator: In
        values:
          - nginx

每个表达式都必须包含key、operator(运算符),有可能包含values(取决于运算符),运算符有以下四种:

  • In:Label的值必须与values中的一个相等
  • NotIn:Label的值不能与values中的任何一个相等
  • Exists:Pod必须包含一个指定名称的标签,values无所谓
  • DoesNotExists:Pod不得包含指定名称的标签,values不能指定

DaemonSet

DaemonSet与ReplicaSet的不同在于,DaemonSet可以让pod在集群的每个节点上运行,有且只有一个。

如果节点下线,DaemonSet不会在其他地方重建pod;如果集群新加入了一个节点,DaemonSet会立刻部署一个新的pod。如果有人删除了pod,DaemonSet会建立一个新的。

这些pod通常用于执行系统级别或基础结构相关的工作,如日志收集和资源监控。典型的例子就是Kubernetes自己的kube-proxy。

如果想让DaemonSet只在特定节点运行pod,需要通过pod模板中的nodeSelector属性指定。

DaemonSet中没有期望副本数的概念,它不需要。因为它的工作是确保有一个匹配它选择器的pod在节点上运行。

nginx-ds.yaml

可能这里用继续用nginx作为例子不太恰当,但目前我们关注的重点是DaemonSet,继续吧。。。

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: nginx-ds
spec:			# 去掉了replicas,因为不需要
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      nodeSelector:	# 添加了一个节点的标签选择器,选择只部署地区在在北京的节点上
        region: "beijing"
      containers:
        - name: nginx
          image: nginx
          ports:
            - containerPort: 80

创建DaemonSet

先给kube1.vm打个标签

-> [[email protected]] [~] k label node kube1.vm region=beijing
node/kube1.vm labeled

-> [[email protected]] [~] k get node -L region
NAME       STATUS   ROLES    AGE   VERSION   REGION
kube0.vm   Ready    master   40h   v1.17.3
kube1.vm   Ready       40h   v1.17.3   beijing
kube2.vm   Ready       40h   v1.17.3

提交描述文件

-> [[email protected]] [~] k create -f nginx-ds.yaml
daemonset.apps/nginx-ds created

-> [[email protected]] [~] k get ds,po -o wide
NAME                      DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR    AGE   CONTAINERS   IMAGES   SELECTOR
daemonset.apps/nginx-ds   1         1         1       1            1           region=beijing   52s   nginx        nginx    app=nginx

NAME                 READY   STATUS    RESTARTS   AGE   IP            NODE       NOMINATED NODE   READINESS GATES
pod/nginx-ds-5z95c   1/1     Running   0          52s   10.244.1.24   kube1.vm              

给kube2.vm也打个标签

-> [[email protected]] [~] k label node kube2.vm region=beijing
node/kube2.vm labeled

-> [[email protected]] [~] k get ds,po -o wide
NAME                      DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR    AGE    CONTAINERS   IMAGES   SELECTOR
daemonset.apps/nginx-ds   2         2         1       2            1           region=beijing   113s   nginx        nginx    app=nginx

NAME                 READY   STATUS              RESTARTS   AGE    IP            NODE       NOMINATED NODE   READINESS GATES
pod/nginx-ds-5z95c   1/1     Running             0          113s   10.244.1.24   kube1.vm              
pod/nginx-ds-b46lb   0/1     ContainerCreating   0          3s             kube2.vm              

Job

Job可以运行一种pod,在该pod内的进程成功结束时,不再重启。一旦任务完成,pod就被认为处于完成状态。

比如可以使用在将一些数据导出到其他地方,这个工作可能会持续几个小时。

我们基于busybox镜像,sleep一段时间用于模拟这个操作。

job.yaml

apiVersion: batch/v1
kind: Job
metadata:
  name: job
spec:
  template:			# 没有指定selector,会根据pod标签中自动创建
    metadata:
      labels:
        app: job
    spec:
      restartPolicy: OnFailure	# 执行遇到异常则重启,默认为Always。
      containers:
        - name: sleepbusybox
          image: busybox
          command: ["/bin/sh","-c","sleep 60;echo this is busybox"]

restartPolicy表示pod的重启策略,默认Always,其他两项为OnFailure和Never。

运行查看

创建job

-> [[email protected]] [~] k create -f job.yaml
job.batch/job created

60秒内查看:

-> [[email protected]] [~] k get job,pod
NAME            COMPLETIONS   DURATION   AGE
job.batch/job   0/1           14s        14s

NAME            READY   STATUS    RESTARTS   AGE
pod/job-4sfv4   1/1     Running   0          14s

60秒后查看:

-> [[email protected]] [~] k get job,pod
NAME            COMPLETIONS   DURATION   AGE
job.batch/job   1/1           68s        71s

NAME            READY   STATUS      RESTARTS   AGE
pod/job-4sfv4   0/1     Completed   0          71s

使用jsonpath获取 pod name 查看log

-> [[email protected]] [~] k logs $(k get po --selector=app=job --output=jsonpath={.items..metadata.name})
this is busybox

completions与parallelism

job描述文件下的spec有两个字段:

  • completions:job要确保完成多少个pod,默认为1。
  • parallelism:最多并行运行多少个pod,默认为1。

job-batch.yaml

apiVersion: batch/v1
kind: Job
metadata:
  name: job-batch
spec:
  completions: 5
  parallelism: 2
  template:
    # 与job.yaml相同

activeDeadlineSeconds

job.spec.activeDeadlineSeconds属性来限制Job在集群中的存活时间,超过此值,所有的pod都被终止。Job的status变为 type: Failed,reason: DeadlineExceeded

CronJob

与Linux的crontab类似,使pod可以在特定时间运行,或者周期运行。

cronjob.yaml

这个描述文件是个套娃。。

CronJob包含job的模板,也就是jobTemplate;job里还包含pod的模板,也就是template。

schedule字段中的值是"分 小时 每月第几天 月份 星期几",详情请参考Linux crontab。

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: cron-job
spec:
  schedule: "*/3 * * * * "	# 每三分钟运行一次
  jobTemplate:			# job的模板
    spec:
      template:			# pod的模板
        metadata:
          labels:
            app: job-in-cron
        spec:
          restartPolicy: OnFailure
          containers:
            - name: sleepbusybox
              image: busybox
              command: ["/bin/sh","-c","sleep 60;echo this is busybox"]

运行

创建cron-job

-> [[email protected]] [~] k create -f cronjob.yaml
cronjob.batch/cron-job created

等了几分钟

-> [[email protected]] [~] k get all
NAME                            READY   STATUS      RESTARTS   AGE
pod/cron-job-1590053040-pqhhh   0/1     Completed   0          97s

NAME                            COMPLETIONS   DURATION   AGE
job.batch/cron-job-1590053040   1/1           68s        97s

NAME                     SCHEDULE       SUSPEND   ACTIVE   LAST SCHEDULE   AGE
cronjob.batch/cron-job   */3 * * * *    False     0        105s            4m39s

又等了几分钟

-> [[email protected]] [~] k get all
NAME                            READY   STATUS              RESTARTS   AGE
pod/cron-job-1590053040-pqhhh   0/1     Completed           0          3m4s
pod/cron-job-1590053220-whflp   0/1     ContainerCreating   0          3s

NAME                            COMPLETIONS   DURATION   AGE
job.batch/cron-job-1590053040   1/1           68s        3m4s
job.batch/cron-job-1590053220   0/1           3s         3s

NAME                     SCHEDULE       SUSPEND   ACTIVE   LAST SCHEDULE   AGE
cronjob.batch/cron-job   */3 * * * *    False     1        12s             6m6s

可以看到就当前的描述文件而言,cron-job每次创建一个job,job创建一个pod的运行。

startingDeadlineSeconds

cronjob.spec.startingDeadlineSeconds规定pod必须预定时间之后的startingDeadlineSeconds秒内运行,超过此时间则不运行,并将其显示未Failed。

小结

  • 使用存活探针检查容器是否存活。
  • ReplicationController创建并管理Pod,但并不是绑定关系。它始终保持期望数量的副本正在运行。
  • ReplicationController将被弃用,ReplicaSet拥有更强的标签选择器。
  • DaemonSet会在每个节点上保持运行有且只有一个Pod,可以通过nodeSelector让其只在特定节点运行。
  • Job创建Pod运行完成后,Pod为为Completed状态。completions与parallelism指定需要完成的数量与并行度。
  • restartPolicy:默认Always,还有OnFailure、Never。
  • CronJob创建Job,Job创建Pod。
  • 命令:edit、scale

你可能感兴趣的:(Kubernetes学习笔记(三):部署托管的Pod -- 存活探针、ReplicationController、ReplicaSet、DaemonSet、Job、CronJob)