k8s之pod的生命周期

pod生命周期

和一个个独立的应用容器一样,Pod 也被认为是相对临时性(而不是长期存在)的实体。 Pod 会被创建、赋予一个唯一的 ID(UID),并被调度到节点,并在终止(根据重启策略)或删除之前一直运行在该节点。

如果一个节点死掉了,调度到该节点 的 Pod 也被计划在给定超时期限结束后删除。

Pod 自身不具有自愈能力。如果 Pod 被调度到某节点 而该节点之后失效,或者调度操作本身失效,Pod 会被删除;与此类似,Pod 无法在节点资源 耗尽或者节点维护期间继续存活。Kubernetes 使用一种高级抽象,称作控制器,来管理这些相对而言可随时丢弃的 Pod 实例。

任何给定的 Pod (由 UID 定义)从不会被“重新调度(rescheduled)”到不同的节点; 相反,这一 Pod 可以被一个新的、几乎完全相同的 Pod 替换掉。 如果需要,新 Pod 的名字可以不变,但是其 UID 会不同。

如果某物声称其生命期与某 Pod 相同,例如存储卷, 这就意味着该对象在此 Pod (UID 亦相同)存在期间也一直存在。 如果 Pod 因为任何原因被删除,甚至某完全相同的替代 Pod 被创建时, 这个相关的对象(例如这里的卷)也会被删除并重建。

我们一般将Pod对象从创建到终止的这段时间范围称为Pod的生命周期,它主要包含下面的过程:

​ 1)Pod创建过程;

​ 2)运行初始化容器(init container)过程;

​ 3)运行主容器(main container):

​ ① 容器启动后钩子函数(post start)、容器终止前钩子函数(pre stop)

​ ②容器存活性探测(liveness probe)、就绪性探测(readiness probe)

​ 4) Pod终止过程。

 

 pod在生命周期内的五种状态

取值描述
Pending(挂起) Pod 已被 Kubernetes 系统接受,但有一个或者多个容器尚未创建亦未运行。此阶段包括等待 Pod 被调度的时间和通过网络下载镜像的时间。
Running(运行中) Pod 已经绑定到了某个节点,Pod 中所有的容器都已被创建。至少有一个容器仍在运行,或者正处于启动或重启状态。
Succeeded(成功) Pod 中的所有容器都已成功终止,并且不会再重启。
Failed(失败) Pod 中的所有容器都已终止,并且至少有一个容器是因为失败终止。也就是说,容器以非 0 状态退出或者被系统终止。
Unknown(未知)

因为某些原因无法取得 Pod 的状态。这种情况通常是因为与 Pod 所在主机通信失败。

 

 如果某节点死掉或者与集群中其他节点失联,Kubernetes 会实施一种策略,将失去的节点上运行的所有 Pod 的取值设置为 Failed。

  pod的创建过程

1、kubectl向apiserver发送一个创建pod的请求

2、apiserver收到请求后生成一个包含创建信息的yaml文件并写入etcd。

3、scheduler发现有新的pod要创建,经过计算再找出最适合创建的node进行创建。

4、node节点的kubelet接收到创建pod的信息后调用docker启动容器,然后将结果发送给apiserver

5、apiserver将接收到pod的信息存入etcd

Pod 状况查看

Pod 有一个 PodStatus 对象,其中包含一个 PodConditions 数组。Pod 可能通过也可能未通过其中的一些状况测试。

  • PodScheduled:Pod 已经被调度到某节点;
  • ContainersReady:Pod 中所有容器都已就绪;
  • Initialized:所有的 Init 容器 都已成功完成;
  • Ready:Pod 可以为请求提供服务,并且应该被添加到对应服务的负载均衡池中。
字段名称描述
type Pod 状况的名称
status 表明该状况是否适用,可能的取值有 "True", "False" 或 "Unknown"
lastProbeTime 上次探测 Pod 状况时的时间戳
lastTransitionTime Pod 上次从一种状态转换到另一种状态时的时间戳
reason 机器可读的、驼峰编码(UpperCamelCase)的文字,表述上次状况变化的原因
message 人类可读的消息,给出上次状态转换的详细信息

 

初始化容器(init c)

初始化容器Init Container是在Pod的主容器启动之前要运行的容器,主要是做一些主容器的前置工作,可以是一个 它具有两大特征:

初始化容器必须运行完成直至结束,如果某个初始化容器运行失败,那么Kubernetes需要重启它直至成功完成。

初始化容器必须按照定义的顺序执行,当且仅当前一个成功之后,后面一个才能运行。

初始化容器有很多应用场景,下面列出的是最常见的几种:

提供主容器镜像中不具备的工具程序或自定义代码。
初始化容器要先于应用容器串行启动并运行完成;因此可用于延后应用容器的启动直至其依赖的条件得到满足。

例:

我们先创建一个init-pod.yml 文件

apiVersion: v1
kind: Pod
metadata: 
  name: myapp-pod
  labels: 
    app: myapp
spec:
  containers:
  - name: myapp-containers
    image: busybox
    command: ['sh' ,'-c','echo the app is running && sleep 600s']
  initContainers:
  - name: init-myservice
    image: busybox
    command: ['sh','-c', 'until nslookup myservice; do echo waiting from myservice; sleep 2s ;done ']
  - name: mydb-containers
    image: busybox
    command: ['sh','-c','until nslookup mydb; do echo waiting from mydb; sleep 2s; done']

然后创建pod并查看: kubectl create -f init-pod.yml 

[root@master ~]# kubectl create -f init-pod.yml 
pod/myapp-pod created
[root@master ~]# kubectl get pod
NAME                     READY   STATUS     RESTARTS   AGE
myapp-pod                0/1     Init:0/2   0          23s
nginx-6799fc88d8-648cn   1/1     Running    0          48d

此时myapp-pod显示正在init初始化,我们describe看一下这个pod状态

[root@master ~]# kubectl describe pods myapp-pod 
Name:         myapp-pod
Namespace:    default
Priority:     0
Node:         node1/192.168.248.128
Start Time:   Mon, 27 Jun 2022 15:49:59 +0800
Labels:       app=myapp
Annotations:  cni.projectcalico.org/containerID: bdead7238a0b177ce59049c3d13a180dadd5c867ad6eb3f0aa06710585eac8c5
              cni.projectcalico.org/podIP: 10.101.149.3/32
              cni.projectcalico.org/podIPs: 10.101.149.3/32
Status:       Pending
IP:           10.101.149.3
IPs:
  IP:  10.101.149.3
Init Containers:
  init-myservice:
    Container ID:  docker://b2bcc9e7e88702bdf2fbd53fdfc5e70063d5fc3419338770f14b8b48804e4800
    Image:         busybox
    Image ID:      docker-pullable://busybox@sha256:5acba83a746c7608ed544dc1533b87c737a0b0fb730301639a0179f9344b1678
    Port:          <none>
    Host Port:     <none>
    Command:
      sh
      -c
      until nslookup myservice; do echo waiting from myservice; sleep 2s ;done 
    State:          Running
      Started:      Mon, 27 Jun 2022 15:50:25 +0800
    Ready:          False
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-trqgw (ro)
  mydb-containers:
    Container ID:  
    Image:         busybox
    Image ID:      
    Port:          <none>
    Host Port:     <none>
    Command:
      sh
      -c
      until nslookup mydb; do echo waiting from mydb; sleep 2s; done
    State:          Waiting
      Reason:       PodInitializing
    Ready:          False
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-trqgw (ro)
Containers:
  myapp-containers:
    Container ID:  
    Image:         busybox
    Image ID:      
    Port:          <none>
    Host Port:     <none>
    Command:
      sh
      -c
      echo the app is running && sleep 600s
    State:          Waiting
      Reason:       PodInitializing
    Ready:          False
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-trqgw (ro)
Conditions:
  Type              Status
  Initialized       False 
  Ready             False 
  ContainersReady   False 
  PodScheduled      True 
Volumes:
  kube-api-access-trqgw:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    ConfigMapOptional:       <nil>
    DownwardAPI:             true
QoS Class:                   BestEffort
Node-Selectors:              <none>
Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type    Reason     Age    From               Message
  ----    ------     ----   ----               -------
  Normal  Scheduled  6m12s  default-scheduler  Successfully assigned default/myapp-pod to node1
  Normal  Pulling    6m11s  kubelet            Pulling image "busybox"
  Normal  Pulled     5m46s  kubelet            Successfully pulled image "busybox" in 24.671646739s
  Normal  Created    5m46s  kubelet            Created container init-myservice
  Normal  Started    5m46s  kubelet            Started container init-myservice

此时正在启动init-myservice,由于我们还没没有创建myservice,所以init容器就一直在重启,我们看一下日志

[root@master ~]# kubectl logs myapp-pod -c init-myservice
Server:         10.96.0.10
Address:        10.96.0.10:53

** server can't find myservice.default.svc.cluster.local: NXDOMAIN

*** Can't find myservice.svc.cluster.local: No answer
*** Can't find myservice.cluster.local: No answer
*** Can't find myservice.localdomain: No answer
*** Can't find myservice.default.svc.cluster.local: No answer
*** Can't find myservice.svc.cluster.local: No answer
*** Can't find myservice.cluster.local: No answer
*** Can't find myservice.localdomain: No answer

waiting from myservice
Server:         10.96.0.10
Address:        10.96.0.10:53

** server can't find myservice.default.svc.cluster.local: NXDOMAIN

*** Can't find myservice.svc.cluster.local: No answer
*** Can't find myservice.cluster.local: No answer
*** Can't find myservice.localdomain: No answer
*** Can't find myservice.default.svc.cluster.local: No answer
*** Can't find myservice.svc.cluster.local: No answer
*** Can't find myservice.cluster.local: No answer
*** Can't find myservice.localdomain: No answer

waiting from myservice
Server:         10.96.0.10
Address:        10.96.0.10:53

** server can't find myservice.default.svc.cluster.local: NXDOMAIN

*** Can't find myservice.svc.cluster.local: No answer
*** Can't find myservice.cluster.local: No answer
*** Can't find myservice.localdomain: No answer
*** Can't find myservice.default.svc.cluster.local: No answer
*** Can't find myservice.svc.cluster.local: No answer
*** Can't find myservice.cluster.local: No answer
*** Can't find myservice.localdomain: No answer

waiting from myservice
Server:         10.96.0.10
Address:        10.96.0.10:53

** server can't find myservice.default.svc.cluster.local: NXDOMAIN

*** Can't find myservice.svc.cluster.local: No answer
*** Can't find myservice.cluster.local: No answer
*** Can't find myservice.localdomain: No answer
*** Can't find myservice.default.svc.cluster.local: No answer
*** Can't find myservice.svc.cluster.local: No answer
*** Can't find myservice.cluster.local: No answer
*** Can't find myservice.localdomain: No answer

waiting from myservice

通过日志发现myservice没有启动,所以init-myservice一直在重启,我们再将myservice创建启动后再看

[root@master ~]# cat myservice.yml 
kind: Service
apiVersion: v1
metadata:
  name: myservice
spec:
  ports: 
    - protocol: TCP
      port: 80 
      targetPort: 9376
[root@master ~]# kubectl create -f myservice.yml 
service/myservice created
[root@master ~]# kubectl get pods
NAME                     READY   STATUS     RESTARTS   AGE
myapp-pod                0/1     Init:1/2   0          22m
nginx-6799fc88d8-648cn   1/1     Running    0          49d

此时发现STATUS变成了 Init:1/2 ,说明init-myservice初始化已经完成,我们再创建mydb启动看一下

[root@master ~]# cat mydb.yml               
kind: Service
apiVersion: v1
metadata: 
  name: mydb
spec:
  ports: 
    - protocol: TCP
      port: 80
      targetPort: 9377
[root@master ~]# kubectl create -f mydb.yml 
service/mydb created
[root@master ~]# kubectl get pods           
NAME                     READY   STATUS            RESTARTS   AGE
myapp-pod                0/1     PodInitializing   0          29m
nginx-6799fc88d8-648cn   1/1     Running           0          49d

这次init容器都已经初始化完成并正在启动

[root@master ~]# kubectl get pods
NAME                     READY   STATUS    RESTARTS   AGE
myapp-pod                1/1     Running   0          32m
nginx-6799fc88d8-648cn   1/1     Running   0          49d

init初始化完成并启动容器成功

init初始化特殊说明:

在pod的启动过程中,init容器会按顺序在网络和数据卷启动之后启动,每个容器启动必须在上个容器成功退出后执行。

如果pod重启,那init容器必须重新执行

对init容器的spec修改被限制在image字段,修改其他字段不会生效,更改init容器的image字段,等于重启该pod。

 探针

为什么要有探针,因为探针可以探测pod当中的容器是否正常运行,我们知道容器启动,业务程序未必正常,因此,我们可以用livenessProbe探针来探测业务是否正常,而对于我们新建的pod如果不做就绪性探测,会被前端的service立刻关联,这样有可能导致部分客户端无法正常访问,所欲对于k8s探针主要分为两种:

  • 一种为存活性探测(livenessProbe)
  • 一种为就绪性探测(readinessProbe)
探针是由kubelet对容器执行的定期诊断,有三种类型的处理程序:

1、ExecAction:在容器内执行指定命令,如果命令退出时返回码为0则认为诊断成功。

2、TCPsocketAction:对执定端口上的容器的IP地址进行tcp检查,如果端口打开则认为是诊断成功的。

3、HTTPGetAction:对指定的端口和路径上的容器的IP地址执行HTTP get请求。如果响应的状态码大于200且小于400,则被诊断认为是成功的。

每次探测都将获得以下三种结果之一:

Success(成功): 容器通过了诊断。

Failuer(失败):  容器未通过诊断。

Unknown(未知):诊断失败,因此不会采取任何行动。

 

livenessProbe:指容器是否正在运行。如果存活探测失败,则kubelet会杀死容器,并且容器将受到其重启策略的影响。

例1:ExecAction

复制代码
[root@master ~]# cat livenessprobe-exec.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: livenessprobe-pod
  namespace: default
  labels:
    app: liveness
spec:
  containers:
  - name: livenessprobe-container
    image: busybox
    imagePullPolicy: IfNotPresent
    command: ["/bin/sh","-c","touch /tmp/test.txt;sleep 20; rm -rf /tmp/test.txt;sleep 3600"] #容器内部创建一个/tmp/test.txt的文件然后休眠20秒,删除/tmp/test.txt,然后再休眠3600秒
    livenessProbe:
      exec: 
        command: ["test","-e","/tmp/test.txt"] #判断容器内/tmp/test.txt文件是否存在
      initialDelaySeconds: 2  #容器启动后延迟2秒开始检查
      periodSeconds: 2      #检查的重复时间为2秒一次
      failureThreshold: 3   #探测最大次数,默认是3次,超过3次失败就会重启该pod

验证:可以看到由于文件被删除已经crash了,并且重启了6次
[root@master ~]# kubectl get pods
NAME                        READY   STATUS             RESTARTS   AGE
livenessprobe-pod           0/1     CrashLoopBackOff   6          10m
复制代码

例2:HttpGetAction

复制代码
[root@master ~]# cat livenessprobe-gethttp.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: livenessprobe-gethttp-pod
  namespace: default
  labels:
    app: liveness-gethttp
spec:
  containers:
  - name: livenessprobe-gethttp-container
    image: nginx
    imagePullPolicy: IfNotPresent
    livenessProbe:
      initialDelaySeconds: 2
      periodSeconds: 2
      failureThreshold: 3
      httpGet:
        port: 80
        path: /index.html
容器跑起来之后删除/usr/share/nginx/html/index.html文件,然后稍等片刻


验证:可以看到容器被重启了一次然后就一直正常运行 [root@master ~]# kubectl get pods NAME READY STATUS RESTARTS AGE livenessprobe-gethttp-pod 1/1 Running 1 14m
复制代码

readinessProbe:指示容器是否准备好请求服务,如果就绪探测失败,端点控制器将从pod匹配的所有service的端点中删除该pod的ip地址。

 
[root@master ~]# cat readinessprobe-gethttp.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: livenessprobe-gethttp-pod
  namespace: default
  labels:
    app: liveness-gethttp
spec:
  containers:
  - name: livenessprobe-gethttp-container
    image: nginx
    imagePullPolicy: IfNotPresent
    readinessProbe: 
      initialDelaySeconds: 2
      periodSeconds: 2
      failureThreshold: 3
      httpGet:
        port: 80
        path: /index.html


验证:
1.连入容器删除index.html文件 [root@master ~]# kubectl exec -it livenessprobe-gethttp-pod -- /bin/bash root@livenessprobe-gethttp-pod:/# cd /usr/share/nginx/html/ root@livenessprobe-gethttp-pod:/usr/share/nginx/html# ls 50x.html index.html root@livenessprobe-gethttp-pod:/usr/share/nginx/html# rm -rf index.html root@livenessprobe-gethttp-pod:/usr/share/nginx/html# exit
2.查看pod状态 [root@master ~]# kubectl get pods -o wide -w NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES livenessprobe-gethttp-pod 1/1 Running 0 6s 10.244.1.38 node1 <none> <none> livenessprobe-gethttp-pod 0/1 Running 0 24s 10.244.1.38 node1 <none> <none> 3.随后我们在在容器里创建出index.html文件,然后在观察pod [root@master ~]# kubectl get pods -o wide -w NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES livenessprobe-gethttp-pod 1/1 Running 0 6s 10.244.1.38 node1 <none> <none> livenessprobe-gethttp-pod 0/1 Running 0 24s 10.244.1.38 node1 <none> <none> livenessprobe-gethttp-pod 1/1 Running 0 2m48s 10.244.1.38 node1 <none> <none>

pod的终止过程

1. 用户向apiserver发送删除pod对象的命令

2. apiserver中的pod对象信息会随着时间的推移而更新,在宽限期内(默认是30s),pod被视为dead

3. 将pod标记为terminating(正在删除)状态

4. kubelet在监控到pod对象转为terminating状态的同时启动pod关闭过程

5. 端点控制器监控到pod对象的关闭行为时将其从所有匹配到此端点的service资源的端点列表中移除

6. 如果当前pod对象定义了 preStop钩子处理器,则在其标记为terminating后即会以同步的方式启动执行

7. pod对象中的容器进程收到停止信号

8. 宽限期结束后,若pod中还存在仍在运行的进程,那么pod对象会收到立即终止的信号

9. kubelet请求apiserver将此pod资源的宽限期设置为0,从而完成删除操作,此时pod对于用户已不可见

 

posted @ 2022-06-29 14:11  李志锋  阅读(880)  评论(0编辑  收藏  举报