pod生命周期

1. pod的生命周期

pod生命周期_第1张图片

  • 上图主要描述在容器环境初始化完成之后,pod创建到退出的中间这段过程:

  • 从大的方向上看,pod生命周期分两个阶段:

    1. 第一阶段是初始化容器。
    2. 第二阶段是主容器的整个生命周期。
  • 在 Kubernetes 中,每个 Pod 都可以包括多个容器。pause 容器是 Kubernetes 系统自带的一个容器,它是每个 Pod 中必须存在的一个容器。pause 容器没有实际的业务逻辑,它的作用是作为所有其他容器的父进程当 Pod 中的其他容器启动时,它们会与 pause 容器共享网络和存储空间。pause 容器会先启动并进入等待状态,等待其他容器加入进来。整个 Pod 中的所有容器都共享同一个 Linux namespace 和同一个网络栈,而 pause 容器则提供了这个 namespace 和网络栈。这种设计在 Kubernetes 中被称为 Pod 共享模型

  • 对于Init Container来说,一个pod中可以定义多个初始化容器,他们必须是串行执行,只有当所有的初始化容器执行完后,对应的主容器才会启动

  • 如上图所示,会按顺序把1、2、3的InitC都执行完成之后,才进入Main Container阶段

  • Main Container生命周期又分为三个阶段:

    1. 第一阶段是运行Post-start hook,这个阶段是主容器运行之后立即需要做的事,例如从配置文件加载应用程序的配置、向外部服务注册、启动后台进程、执行数据库迁移等等。
    2. 第二阶段是主容器正常运行的阶段,在这个阶段中,我们可以定义对容器的健康状态(liveness)检查和就绪状态(readiness)检查,readiness检测成功后,Pod状态改为Ready。
    3. 第三阶段是运行pre stop hook,这个阶段主要做容器即将退出前需要做的事,比如保存数据、做一些清理工作等。
  • 对于容器的健康状态检查和就绪状态检查,我们也可以定义开始检查的延迟时长;因为有些容器存在容器显示running状态,但内部程序还没有初始化,如果立即做健康状态检查,可能存在健康状态为不健康,从而导致容器重启的状况;

2. Pod相位状态值

  • 首先在介绍 Pod 的生命周期之前,我们先了解下 Pod 的状态,因为 Pod 状态可以反映出当前我们的 Pod 的具体状态信息,也是我们分析排错的一个必备的方式。
  • 我们可以通过命令kubectl explain pod.status查看到
    pod生命周期_第2张图片
  1. Pending(挂起):Pod已被创建,但还未被调度至任何节点上。

  2. Running(运行中):Pod已经被调度至节点上,并且Pod中的所有容器都在运行中。

  3. Succeeded(成功):Pod中的所有容器都已经成功退出,并且不会再次启动。

  4. Failed(失败):Pod中的一个或多个容器已经失败并且已经退出。

  5. Unknown(未知):Pod的状态无法被获取,通常是由于控制器无法连接到Pod所在节点。

  • 除了Pod的相位,还有以下几种状态值,可以通过kubectl get pods查看以下的状态:

    1. ContainerCreating(容器创建):Pod中的一个或多个容器正在创建中。

    2. PodInitializing(pod正在初始化):Pod中的一个或多个init容器正在初始化中。

    3. Terminating(停止):Pod正在被删除,但是Pod中的容器仍在运行中。

    4. Running(运行中):所有容器都已经成功启动并正在运行中。

    5. Succeeded(成功):所有容器都已经成功退出,并且不会再次启动。

    6. Failed(失败):Pod中存在至少一个容器已经失败,并且容器无法重启。

    7. Unknown(未知):由于某种原因,Pod的状态无法被获取。

    3. Init Containers

  • 在Kubernetes中,Init Container是一种特殊类型的容器,它在Pod中的其他容器启动之前运行。Init Container的目的是在Pod中的其他容器启动之前执行一些预处理任务,例如初始化某些数据、检查依赖项是否可用等。Init Container和普通容器一样,可以使用Docker镜像,并且可以使用Kubernetes提供的各种资源和功能

  • 在一个Pod中可以定义多个Init Container,它们将按照定义的顺序依次运行。如果任何一个Init Container失败,Kubernetes将立即停止Pod中的所有容器,并将整个Pod标记为失败

  • 注意:Init Container和普通容器不同,它们的生命周期是独立的,即Init Container的生命周期结束后,Pod中的其他容器才会开始启动。因此,在编写Init Container时,需要确保它们的生命周期不会太长,否则会影响整个Pod的启动速度。

3.1. Init Containers的作用:

  • Init Containers是Kubernetes中的一种特殊容器,它们在Pod中的主容器(Main Container)启动之前运行,并且它们的生命周期是独立于主容器的。Init Containers通常用于在启动主容器之前执行某些初始化任务,例如:配置环境变量、检查依赖关系、预加载应用程序数据等。Init Containers可以帮助确保Pod中的主容器具有所需的运行环境,并且可以在主容器启动之前完成所有必要的准备工作,从而减少主容器启动失败的可能性。

4. Init Contianers实验

  • 下面我们通过实际例子来进一步认识init containers。
vim init-pod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
    version: v1
spec:
  containers:
    - name: myapp-container
      image: busybox:1.32
      command: ['sh', '-c', 'echo The app is running && sleep 3600']
  initContainers:
    - name: init-myservice
      image: busybox:1.32
      command: ['sh', '-c','until  nslookup  myservice; do echo waiting myservice; sleep 2;done;']
    - name: init-mydb
      image: busybox:1.32
      command: ['sh', '-c', 'until nslookup mydb; do echo waiting mydb; sleep 2;done;']
  • 上面的yaml,运行了一个pod。里面有一个main container,有两个init container
kubectl apply -f init-pod.yaml
  • 查看容器状态:
[root@master1 test]# kubectl get pods
NAME                        READY   STATUS     RESTARTS   AGE
xiaoyu-pod                   0/1     Init:0/2   0          71s
  • 此时无论多久,上面的容器也不会变成running状态,这是因为我这边写的两个init container的条件没有满足。
  • 第一个init container的条件是能解析myservice,第二个条件是能解析mydb。

pod生命周期_第3张图片

此处补充个小知识点,便是Linux中until的用法。

until跟while类似,都是一个固定循环。

但是until跟while又有不同,则是它们的条件满足不同。

until是直到条件为真时,打破循环。而while是条件为真时一直循环,条件为假时打破循环。

  • 查看日志
kubectl logs myapp-pod -n default -c init-myservice

pod生命周期_第4张图片

  • 日志可以看的出来现在无法解析myservice
  • 创建一个svc来解决这个问题
vim init-service.yaml

kind: Service
apiVersion: v1
metadata:
  name: myservice
spec:
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376

[root@master1 ~]# kubectl apply -f init-service.yaml
service/myservice created

[root@master1 test]# kubectl get svc
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.10.0.1      <none>        443/TCP   350d
myservice    ClusterIP   10.10.42.207   <none>        80/TCP    43s

  • 验证init c 是否有一个状态正常
[root@master1 test]# kubectl get pods
NAME        READY   STATUS     RESTARTS   AGE
myapp-pod   0/1     Init:1/2   0          9m39s      ----可以看的出来2个init c 已经有一个恢复正常了。
  • 创建一个svc来解决解析mydb的问题
vim init-db.yaml
kind: Service
apiVersion: v1
metadata:
  name: mydb
spec:
  ports:
  - protocol: TCP
    port: 80
    targetPort: 9377

[root@master1 test]# kubectl apply -f init-db.yaml      
service/mydb created

[root@master1 test]# kubectl get svc
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.10.0.1       <none>        443/TCP   350d
mydb         ClusterIP   10.10.102.245   <none>        80/TCP    70s
myservice    ClusterIP   10.10.42.207    <none>        80/TCP    12m

[root@master1 test]# kubectl get pods
NAME        READY   STATUS    RESTARTS   AGE
myapp-pod   1/1     Running   0          16m     ----可以看的出来pod已经变为Running

5. 容器探针

  • 容器探针是用于监测容器内部状态的一种机制,可以帮助容器管理器(如 Kubernetes)了解容器内部是否正常运行,并在容器出现异常时采取适当的措施。容器探针包括两种类型:存活探针(LivenessProbe)和就绪探针(readinessProbe)。

  • 存活探针(LivenessProbe):检测容器是否正在运行,如果检测到容器不可用,则kubelet会杀死容器,并且容器将受到其重启策略的影响。如果容器不提供存活探针,则默认状态为Success。

  • 就绪探针(readinessProbe):指示容器是否准备好服务请求。如果就绪探测失败,端点控制器将从与pod匹配的所有Service的端点中删除该pod的IP地址。初始延迟之前的就绪状态默认为Failure。如果容器不提供就绪探针,则默认状态为Success。

  • 容器探针是由kubelet对容器执行的定期诊断。要执行诊断,kubelet调用由容器实现的Handler。有三种类型的处理程序:
    1. ExecAction:在容器内执行指定命令。如果命令退出时返回码为0则认为诊断成功。
    2. TCPSocketAction:对指定端口上的容器的IP地址进行TCP检查。如果端口打开,则诊断被认为是成功的。
    3. HTTPGetAction:对指定的端口和路径上的容器的IP地址执行HTTP Get请求。如果响应的状态码大于等于200 且小于 400,则诊断被认为是成功的。

  • 每次探测都将获得以下三种结果之一:
    1. 成功:容器通过了诊断。
    2. 失败:容器未通过诊断。
    3. 未知:诊断失败,因此不会采取任何行动。

5.1. 就绪探针实验:

[root@master1 test]# vim readinessProbe-httget.yaml

apiVersion: v1    #API版本号,例如,Deployment资源的API版本是apps/v1,而Service资源的API版本是v1
kind: Pod   #类型/控制器
metadata:   #这个对象包含了一些元数据,例如 Pod 的名称、标签、注释等等
  name: readiness-httpget-pod   #pod名称
  namespace: default  #指定pod在哪个命名空间创建
spec:    # 这个对象包含了 Pod 的规格,例如 Pod 中包含的容器、容器的镜像、容器的端口号、容器的环境变量、资源限制等等。
  containers:
  - name: readiness-httpget-container   #容器名称
    image: nginx:latest    #指定容器镜像
    imagePullPolicy: IfNotPresent #指定容器策略为IfNotPresent,只有在本地不存在该镜像时才从镜像仓库拉取,否则使用本地缓存的镜像。
    readinessProbe:    #定义了就绪探针的配置选项
      httpGet:    #就绪探针使用 httpGet 来检查容器的状态
        port: 80  #检查的端口为 http
        path: /index1.html #检查路径为 /index1.html
      initialDelaySeconds: 1  #表示容器启动后1秒开始进行探测
      periodSeconds: 3  #表示每隔3秒进行一次探测
  • 查看pod的状态

在这里插入图片描述

  • 可以看的出来就绪状态是失败的,查看日志是哪里出现问题
    pod生命周期_第5张图片

  • 解决就绪检测的要求:
    pod生命周期_第6张图片

  • 意思是主容器的网页目录下需要有index1.html

##进入容器查看/usr/share/nginx/html/是否有index1.html
[root@master1 test]# kubectl exec readiness-httpget-pod -it  /bin/bash

kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@readiness-httpget-pod:/# cd /usr/share/nginx/html/
root@readiness-httpget-pod:/usr/share/nginx/html# ls
50x.html  index.html           ---可以看的出来没有index1.html文件
root@readiness-httpget-pod:/usr/share/nginx/html# echo "123" > index1.html  
root@readiness-httpget-pod:/usr/share/nginx/html# exit
exit

  • 查看pod状态
[root@master1 test]# kubectl get pod
NAME                    READY   STATUS    RESTARTS   AGE
readiness-httpget-pod   1/1     Running   0          5m8s  
---可以看得出来问题解决了。

5.2. 存活探针实验:

5.2.1. 实验一:

vim  livenessProbe-exec.yaml

apiVersion: v1
kind: Pod
metadata:
  name: liveness-exec-pod
  namespace: default
spec:
  containers:
  - name: liveness-exec-container
    image: nginx:latest
    imagePullPolicy: IfNotPresent
    command: ["/bin/sh","-c","touch  /tmp/live;sleep 60;rm -rf /tmp/live;sleep 3600"]
    livenessProbe:
      exec:
        command: ["test","-e","/tmp/live"]
      initialDelaySeconds: 1
      periodSeconds: 3
  • 创建pod
kubectl  apply -f livenessProbe-exec.yaml
  • 查看pod状态
[root@master1 test]# kubectl get pod -w
NAME                    READY   STATUS    RESTARTS   AGE
liveness-exec-pod       1/1     Running   0          2m43s
readiness-httpget-pod   1/1     Running   0          27m
liveness-exec-pod       1/1     Running   1          2m58s
liveness-exec-pod       1/1     Running   2          4m36s
  • 可以看的出来liveness-exec-pod过一段时间就重启了。
    pod生命周期_第7张图片
  • 创建容器时执行命令:创建/tmp/live文件,过60秒删除掉/tmp/live,而存活探针的条件是检查/tmp/live文件是否存在,如果不存在就删除掉容器,重新创建。

5.2.2. 实验二:

vim livenessProbe-httpget.yaml

apiVersion: v1
kind: Pod
metadata:
  name: liveness-httpget-pod
  namespace: default
spec:
  containers:
  - name: liveness-httpget-container
    image: nginx:latest
    imagePullPolicy: IfNotPresent
    ports:
    - name: http
      containerPort: 80
    livenessProbe:
      httpGet:
        port: http
        path: /index.html
      initialDelaySeconds: 1
      periodSeconds: 3
#表示存活探针的超时时间是 10 秒。
#如果在这个时间内没有收到来自容器的响应,就会认为存活探针失败,并且 Kubernetes 将会根据容器的重启策略进行容器的重启。
#如果这个值设置得太小,可能会导致存活探针误判为失败,从而触发不必要的容器重启;而如果设置得太大,则可能会延迟容器故障的检测和处理。
#因此,一般需要根据具体的应用情况进行调整。
      timeoutSeconds: 10

  • 创建pod
[root@master1 test]# kubectl apply -f livenessProbe-httpget.yaml
pod/liveness-httpget-pod created

[root@master1 test]# kubectl get pods
NAME                   READY   STATUS    RESTARTS   AGE
liveness-httpget-pod   1/1     Running   0          7s

  • 删除容器的index.html文件,触发存活探针的条件:
    pod生命周期_第8张图片
  • 存活探针条件是:通过 HTTP GET 请求来检查该容器的存活状态。具体来说,存活探针会向容器发送一个 HTTP GET 请求,请求的路径是 /index.html
[root@master1 test]# kubectl exec liveness-httpget-pod -it /bin/bash

root@liveness-httpget-pod:/# cd /usr/share/nginx/html/

root@liveness-httpget-pod:/usr/share/nginx/html# ls
50x.html  index.html

root@liveness-httpget-pod:/usr/share/nginx/html# rm -rf index.html  --删除index.html
root@liveness-httpget-pod:/usr/share/nginx/html# exit
exit
[root@master1 test]# kubectl get pods -w
NAME                   READY   STATUS    RESTARTS   AGE
liveness-httpget-pod   1/1     Running   0          6m23s
liveness-httpget-pod   1/1     Running   1          6m24s   --可以看的出来删除掉index.html文件后触发存活探针条件重启。

5.2.3. 实验三:

vim livenessProbe-tcp.yaml

apiVersion: v1
kind: Pod
metadata:
  name: liveness-tcp-pod
  namespace: default
spec:
  containers:
  - name: liveness-tcp-container
    image: nginx:latest
    imagePullPolicy: IfNotPresent
    livenessProbe:
      tcpSocket:
        prot: 8080
      initialDelaySeconds: 5
      periodSeconds: 3
      timeoutSeonds: 1

  • 创建pod
[root@master1 test]# kubectl apply -f livenessProbe-tcp.yaml
pod/liveness-tcp-pod created
  • 查看pod状态:
[root@master1 test]# kubectl get pods -w
NAME               READY   STATUS    RESTARTS   AGE
liveness-tcp-pod   1/1     Running   0          11s
liveness-tcp-pod   1/1     Running   1          14s
liveness-tcp-pod   1/1     Running   2          26s
  • 可以看的出来pod一直在重启
    pod生命周期_第9张图片
  • 存活探针的条件是:尝试与容器内的端口 8080 建立一个 TCP 连接,如果连接成功,则认为容器存活,而nginx创建的容器默认端口是80,所以失败,认为容器已经死亡,需要根据容器的重启策略进行重启。

6. 启动、退出动作:

pod生命周期_第10张图片

[root@master1 test]# vim  init-start.yaml
apiVersion: v1
kind: Pod
metadata:
  name: lifecycle-demo
  namespace: default
spec:
  containers:
  - name: lifecycle-demo-container
    image: nginx:latest
    imagePullPolicy: IfNotPresent
    lifecycle:
      postStart:
        exec:
          command: ["/bin/sh","-c","echo Hello from the postStart handler >>/usr/share/message"]
      preStop:
        exec:
          command: ["/bin/sh","-c","echo Hello from the poststop handler >> /usr/share/message"]
  • 创建pod
[root@master1 test]# kubectl exec lifecycle-demo -it  /bin/bash

root@lifecycle-demo:/# cat /usr/share/message
Hello from the postStart handler

你可能感兴趣的:(kubernetes,docker,运维)