pod的生命周期

文档参考: https://kubernetes.io/zh/docs/concepts/workloads/pods/pod-lifecycle/

  • 有些pod(比如跑httpd服务),正常情况下会一直运行中,但如果手动删除它,此pod会终止
  • 也有些pod(比如执行计算任务),任务计算完后就会自动终止

上面两种场景中,pod从创建到终止的过程就是pod的生命周期。

容器启动

  1. pod中的容器在创建前,有初始化容器(init container)来进行初始化环境
  2. 初化完后,主容器(main container)开始启动>
  3. 主容器启动后,有一个post start的操作(启动后的触发型操作,或者叫启动后钩子)
  4. post start后,就开始做健康检查
  • 第一个健康检查叫存活状态检查(liveness probe ),用来检查主容器存活状态的
  • 第二个健康检查叫准备就绪检查(readiness probe),用来检查主容器是否启动就绪

容器终止

  1. 可以在容器终止前设置pre stop操作(终止前的触发型操作,或者叫终止前钩子)
  2. 当出现特殊情况不能正常销毁pod时,大概等待30秒会强制终止
  3. 终止容器后还可能会重启容器(视容器重启策略而定)。

回顾容器重启策略

  • Always:表示容器挂了总是重启,这是默认策略
  • OnFailures:表容器状态为错误时才重启,也就是容器正常终止时不重启
  • Never:表示容器挂了不予重启
  • 对于Always这种策略,容器只要挂了,就会立即重启,这样是很耗费资源的。所以Always重启策略是这么做的:第一次容器挂了立即重启,如果再挂了就要延时10s重启,第三次挂了就等20s重启...... 依次类推

HealthCheck健康检查

当Pod启动时,容器可能会因为某种错误(服务未启动或端口不正确)而无法访问等。

Health Check方式

kubelet拥有两个检测器,它们分别对应不同的触发器(根据触发器的结构执行进一步的动作)

方式 说明
Liveness Probe(存活状态探测) 检查后不健康,重启pod(参照容器重启策略)
readiness Probe(就绪型探测) 检查后不健康,将容器设置为Notready;如果使用service来访问,流量不会转发给此种状态的pod

Probe探测方式

方式 说明
Exec 执行命令
HTTPGet http请求某一个URL路径
TCP tcp连接某一个端口

案例1: liveness-exec

参考: https://kubernetes.io/zh/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/

1, 准备YAML文件

[root@master ~]# vim pod-liveness-exec.yml

apiVersion: v1
kind: Pod
metadata:
  name: liveness-exec
  namespace: default
spec:
  containers:
  - name: liveness
    image: busybox
    imagePullPolicy: IfNotPresent
    args:
    - /bin/sh
    - -c
    - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
    livenessProbe:
      exec:
        command:
        - cat
        - /tmp/healthy
      initialDelaySeconds: 5 # pod启动延迟5秒后探测
      periodSeconds: 5 						# 每5秒探测1次

2, 应用YAML文件

[root@master1 ~]# kubectl apply -f pod-liveness-exec.yml

3, 通过下面的命令观察

[root@master1 ~]# kubectl describe pod liveness-exec

image.png

看到40s前被调度以node1节点,3s前健康检查出问题

4, 过几分钟再观察

[root@master1 ~]# kubectl describe pod liveness-exec

image.png

[root@master1 ~]# kubectl get pod image.png

看到重启3次,慢慢地重启间隔时间会越来越长

拓展: 容器重启策略验证

vim pod-liveness-exec.yml

apiVersion: v1
kind: Pod
metadata:
  name: liveness-exec
  namespace: default
spec:
  restartPolicy: Never	# 把容器重启策略由默认的always改为Never
  containers:
  - name: liveness
    image: busybox
    imagePullPolicy: IfNotPresent
    args:
    - /bin/sh
    - -c
    - touch /tmp/healthy; sleep 10; rm -rf /tmp/healthy; sleep 300
    livenessProbe:
      exec:
        command:
        - cat
        - /tmp/healthy
      initialDelaySeconds: 5                         
      periodSeconds: 5                                 

验证结果为:

kubectl describe pod liveness-exec

image.png

等会再看下

kubectl describe pod liveness-exec

image.png

kubectl get pod

image.png

  • 容器健康检查出现问题后,不再重启,也不会继续sleep 600秒,而是直接关闭了

案例2: liveness-httpget

1, 编写YMAL文件

[root@master1 ~]# vim pod-liveness-httpget.yml

apiVersion: v1
kind: Pod
metadata:
  name: liveness-httpget
  namespace: default
spec:
  containers:
  - name: liveness
    image: nginx:1.15-alpine
    imagePullPolicy: IfNotPresent
    ports:							    # 指定容器端口,这一段不写也行,端口由镜像决定 
    - name: http						# 自定义名称,不需要与下面的port: http对应
      containerPort: 80					# 类似dockerfile里的expose 80
    livenessProbe:
      httpGet:                       # 使用httpGet方式
        port: http           # http协议,也可以直接写80端口
        path: /index.html               # 探测家目录下的index.html
      initialDelaySeconds: 3            # 延迟3秒开始探测
      periodSeconds: 5                  # 每隔5s钟探测一次

2, 应用YAML文件

[root@master1 ~]# kubectl apply -f pod-liveness-httpget.yml

3, 验证查看

[root@master1 ~]# kubectl get pods

image.png

4, 交互删除nginx里的主页文件

[root@master1 ~]# kubectl exec -it liveness-httpget -- rm -rf /usr/share/nginx/html/index.html

5, 验证查看会发现

kubectl describe pod liveness-http |tail

image.png

[root@master1 ~]# kubectl get pod

image.png

只restart一次

案例3: liveness-tcp

1, 编写YAML文件

[root@master1 ~]# vim pod-liveness-tcp.yml

apiVersion: v1
kind: Pod
metadata:
  name: liveness-tcp
  namespace: default
spec:
  containers:
  - name: liveness
    image: nginx:1.15-alpine
    imagePullPolicy: IfNotPresent
    ports:
    - name: http
      containerPort: 80
    livenessProbe:
      tcpSocket:                        # 使用tcp连接方式
        port: 80                        # 连接80端口进行探测
      initialDelaySeconds: 3
      periodSeconds: 5

2, 应用YAML文件创建pod

[root@master1 ~]# kubectl apply -f pod-liveness-tcp.yml

3, 查看验证

[root@master1 ~]# kubectl get pod

image.png

4, 交互关闭nginx

[root@master1 ~]# kubectl exec -it liveness-tcp -- /usr/sbin/nginx -s stop

5, 再次验证查看

image.png

[root@master ~]# kubectl get pod

image.png 也只重启1次,重启后重新初始化了

案例4: readiness

1, 编写YAML文件

[root@master1 ~]# vim pod-readiness-httpget.yml

apiVersion: v1
kind: Pod
metadata:
  name: readiness-httpget
  namespace: default
spec:
  containers:
  - name: readiness
    image: nginx:1.15-alpine
    imagePullPolicy: IfNotPresent
    ports:
    - name: http
      containerPort: 80
    readinessProbe:     # 这里由liveness换成了readiness
      httpGet:
        port: http
        path: /index.html
      initialDelaySeconds: 3
      periodSeconds: 5

2, 应用YAML文件

[root@master1 ~]# kubectl apply -f pod-readiness-httpget.yml

3, 验证查看

[root@master1 ~]# kubectl get pod

4, 交互删除nginx主页

[root@master1 ~]# kubectl exec -it readiness-httpget -- rm -rf /usr/share/nginx/html/index.html

5, 再次验证

image.png

[root@master1 ~]# kubectl get pod

image.png READY状态为0/1

6, 交互创建nginx主页文件再验证

[root@master1 ~]# kubectl exec -it readiness-httpget -- touch /usr/share/nginx/html/index.html
[root@master1 ~]# kubectl get pod

image.png

READY状态又为1/1了

案例5: readiness+liveness综合

1, 编写YAML文件

[root@master1 ~]# vim pod-readiness-liveiness.yml
apiVersion: v1
kind: Pod
metadata:
  name: readiness-liveness-httpget
  namespace: default
spec:
  containers:
  - name: readiness-liveness
    image: nginx:1.15-alpine
    imagePullPolicy: IfNotPresent
    ports:
    - name: http
      containerPort: 80
    livenessProbe:
      httpGet:
        port: http
        path: /index.html
      initialDelaySeconds: 1
      periodSeconds: 3
    readinessProbe:
      httpGet:
        port: http
        path: /index.html
      initialDelaySeconds: 5
      periodSeconds: 5

2, 应用YAML文件

[root@master1 ~]# kubectl apply -f pod-readiness-liveiness.yml

3, 验证

[root@master1 ~]# kubectl get pod |grep readiness-liveness-httpget

image.png

post-start

1, 编写YAML文件

[root@master1 ~]# vim pod-poststart.yml
apiVersion: v1
kind: Pod
metadata:
  name: poststart
  namespace: default
spec:
  containers:
  - name: poststart
    image: nginx:1.15-alpine
    imagePullPolicy: IfNotPresent
    lifecycle:                                       # 生命周期事件
      postStart:
        exec:
          command: ["mkdir","-p","/usr/share/nginx/html/haha"]

2, 应用YMAL文件

[root@master1 ~]# kubectl apply -f pod-poststart.yml

3, 验证

[root@master1 ~]# kubectl get pods |grep poststart

image.png

[root@master1 ~]# kubectl exec -it poststart -- ls /usr/share/nginx/html -l

image.png 有创建haha此目录

pre-stop

容器终止前执行的命令

1, 编写YAML文件

[root@master1 ~]# vim prestop.yml
apiVersion: v1
kind: Pod
metadata:
  name: prestop
  namespace: default
spec:
  containers:
  - name: prestop
    image: nginx:1.15-alpine
    imagePullPolicy: IfNotPresent
    lifecycle:                                       # 生命周期事件
      preStop:                                       # preStop
        exec:
          command: ["/bin/sh","-c","sleep 60000000"]     # 容器终止前sleep 60000000秒

2, 应用YAML文件创建pod

[root@master1 ~]# kubectl apply -f prestop.yml

3, 删除pod验证

[root@master1 ~]# kubectl delete -f prestop.yml

image.png

#会在这一步等待一定的时间(大概30s-60s左右)才能删除,说明验证成功

结论: 当出现特殊情况不能正常销毁pod时,大概等待30秒会强制终止

pod 故障排查

状态 描述
Pending pod创建已经提交到Kubernetes。但是,因为某种原因而不能顺利创建。例如下载镜像慢,调度不成功。
Running pod已经绑定到一个节点,并且已经创建了所有容器。至少有一个容器正在运行中,或正在启动或重新启动。
completed Pod中的所有容器都已成功终止,不会重新启动。
Failed Pod的所有容器均已终止,且至少有一个容器已在故障中终止。也就是说,容器要么以非零状态退出,要么被系统终止。
Unknown 由于某种原因apiserver无法获得Pod的状态,通常是由于Master与Pod所在主机kubelet通信时出错。
CrashLoopBackOff 多见于CMD语句错误或者找不到container入口语句导致了快速退出,可以用kubectl logs 查看日志进行排错
  • kubectl describe pod pod名
  • kubectl logs pod [-c CONTAINER]
  • kubectl exec POD [-c CONTAINER] --COMMAND [args...]