Pod创建流程、常见状态、健康检查-Day 04

1. pod的调度流程及常见状态

1.1 pod的调度流程

在这里插入图片描述
在这里插入图片描述

1.2 pod常见状态

状态描述
UnschedulablePod不能被调度,kube-scheduler没有匹配到合适的node节点
PodScheduledpod正处于调度中,在kube-scheduler刚开始调度的时候,还没有将pod分配到指定的node,在筛选出合适的节点后就会更新etcd数据,将pod分配到指定的node(该状态基本看不见,因为快)
Pending正在创建Pod但是Pod中的容器还没有全部被创建完成=[处于此状态的Pod应该检查Pod依赖的存储是否有权限挂载等
FailedPod中有容器启动失败而导致pod工作异常
Unknown由于某种原因无法获得pod的当前状态,通常是由于与pod所在的node节点通信错误
Initialized所有pod中的初始化容器已经完成了
ImagePullBackOffPod所在的node节点下载镜像失败
RunningPod内部的容器已经被创建并且启动
Ready表示pod中的容器已经可以提供访问服务
Errorpod 启动过程中发生错误
NodeLostPod 所在节点失联
WaitingPod等待启动
TerminatingPod正在被销毁
CrashLoopBackOffpod崩溃,但是kubelet正在将它重启
InvalidImageNamenode节点无法解析镜像名称导致的镜像无法下载
ImageInspectError无法校验镜像,镜像不完整导致
ErrImageNeverPull策略禁止拉取镜像,镜像中心权限是私有等
RegistryUnavailable镜像服务器不可用,网络原因或harbor宕
ErrImagePull镜像拉取出错,超时或下载被强制终止
CreateContainerConfigError不能创建kubelet使用的容器配置
CreateContainerError创建容器失败
RunContainerErrorpod运行失败,容器中没有初始化PID为1的守护进程等
ContainersNotInitializedpod没有初始化完毕
ContainersNotReadypod没有准备完毕
ContainerCreatingpod正在创建中
PodInitializingpod正在初始化中
DockerDaemonNotReadynode节点decker服务没有启动
NetworkPluginNotReady网络插件没有启动

1.3 容器常见状态

(1)Waiting (等待)
如果容器并不处在 Running 或 Terminated 状态之一,它就处在 Waiting 状态。
处于Waiting状态的容器仍在运行完成启动所需的操作:例如, 从某个容器镜像仓库拉取容器镜像,或者向应用 Secret 数据等等。
当你使用 kubectl describe po 来查询包含 Waiting 状态的容器的 Pod 时,你也会看到一个 Reason 字段,其中给出了容器处于等待状态的原因。


(2)Running(运行中)
“Running” 状态表示容器正在正常运行。如果配置了postStart钩子,那么它已经执行并完成了。
当使用kubectl describe po查询容器处于Running状态的Pod时,还可以看到容器何时进入Running状态的信息。


(3)Terminated(已终止)
处于Terminated状态的容器开始执行,然后运行到完成或由于某种原因失败。
当您使用kubectl describe po查询具有已终止容器的Pod时,您将看到原因、退出代码以及该容器执行周期的开始和结束时间。
如果容器配置了preStop钩子,则该钩子会在容器进入terminate状态之前运行。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2. pause容器及init容器

2.1 pause容器

2.1.1 pause容器简介

Pause容器,又叫Infra容器,是pod的基础容器,镜像体积只有几百KB左右,配置在kubelet中,主要的功能是初始化pod底层的运行环境(一个pod中多个容器的网络通信)。


Infra容器被创建后会初始化Network Namespace,之后当前pod中的其它容器就可以加入到Infra容器中共享Infra容器的网络了,
因此如果一个Pod中的两个容器A和B,那么关系如下:
(1)A容器和B容器能够直接使用localhost通信;
(2)A容器和B容器可以可以看到网卡、IP与端口监听信息。
(3)Pod只有一个IP地址,也就是该Pod的 Network Namespace对应的IP 地址(由Infra 容器初始化并创建)。
(4)k8s环境中的每个Pod有一个独立的IP地址(前提是地址足够用),并且此IP被当前Pod中所有容器在内部共享使用。
(5)pod删除后Infra容器随机被删除,其IP被回收。

通过查找容器进程的服务进程,就能找到pause容器进程
在这里插入图片描述

2.1.2 pause共享的ns

Pause容器共享的Namespace:
(1)NET Namespace:Pod中的多个容器共享同一个网络命名空间,即使用相同的IP和端口信息。
(2)IPC Namespace:Pod中的多个容器可以使用System V IPC或POSIX消息队列进行通信。
(3)UTS Namespace:pod中的多个容器共享一个主机名。
MNT Namespace、PID Namespace、User Namespace未共享。

在这里插入图片描述

2.1.3 验证

2.1.3.1 创建一个tomcat容器
[root@k8s-harbor01 deployment]# cat deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: tomcat-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: tomcat-deploy
  template:
    metadata:
      labels:
        app: tomcat-deploy
    spec:
      containers:
      - name: tomcat-deploy
        image: tomcat
        ports:
        - containerPort: 8080

[root@k8s-harbor01 deployment]# kubectl apply -f deploy.yaml
deployment.apps/tomcat-deployment created
[root@k8s-harbor01 deployment]# kubectl get po
NAME                                 READY   STATUS    RESTARTS   AGE
tomcat-deployment-599f745cc4-xn54m   1/1     Running   0          3m10s
2.1.3.2 进入容器查看容器网卡
[root@k8s-harbor01 deployment]# kubectl exec -it tomcat-deployment-599f745cc4-xn54m -- /bin/bash
root@tomcat-deployment-599f745cc4-xn54m:/usr/local/tomcat# cat /sys/class/net/eth0/iflink
57 # 这个编号对应当前容器的eth0网卡,在宿主机上的网卡编号就是57
2.1.3.3 查看宿主机容器网卡
[root@k8s-harbor01 deployment]# kubectl get po -o wide
NAME                                 READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
tomcat-deployment-599f745cc4-xn54m   1/1     Running   0          11m   10.200.135.178   k8s-node03   <none>           <none>

[root@k8s-harbor01 deployment]# ssh k8s-node03
Last login: Thu May 25 17:24:16 2023 from k8s-harbor01
[root@k8s-node03 ~]# ip a|grep 57:
57: calib44f23a4e38@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default # 这就是tomcat容器的eth0网卡
# 这样也能看,效果都一样
[root@k8s-node03 ~]# ip link show|grep 57:
57: calib44f23a4e38@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default

在这里插入图片描述

2.1.3.4 查看netns
[root@k8s-node03 ~]# ll /run/netns/ # 这里就是pod的ns文件,都是由宿主机创建的,不要去动这些文件
总用量 0
-r--r--r-- 1 root root 0 424 22:15 cni-19be88c2-cbc9-7dcd-fee5-d018a75095b6
-r--r--r-- 1 root root 0 65 20:08 cni-47896629-30db-34f1-7eca-d73814d68d0e

# 上面这些文件都是可以在pod中调用的
[root@k8s-node03 ~]# nsenter --net=/run/netns/cni-47896629-30db-34f1-7eca-d73814d68d0e ip a # 通过这条命令,就能在这些文件中找到我们pod的ip
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000
    link/ipip 0.0.0.0 brd 0.0.0.0
4: eth0@if57: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether ba:61:9b:a6:b1:8f brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.200.135.178/32 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::b861:9bff:fea6:b18f/64 scope link
       valid_lft forever preferred_lft forever

# 如果容器运行时是docker,就用下面这种方式查看
[root@k8s-harbor01 deployment]# nsenter --net=/run/docker/netns/16dadafbaea5 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
214: eth0@if215: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:ac:17:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.23.0.3/16 brd 172.23.255.255 scope global eth0
       valid_lft forever preferred_lft forever

2.1.4 pause容器-配置示例

这里直接用docker容器演示

2.1.4.1 准备nginx动静分离配置文件
[root@k8s-harbor01 ~]# cat nginx.conf
error_log stderr;
events { worker_connections 1024; }
http {
  access_log /dev/stdout;
  server {
    listen 80 default_server;
    server_name www.mysite.com;
    location / {
      index index.html index.php;
      root /usr/share/nginx/html;
    }
    location ~ \.php$ {
      root /usr/share/nginx/html;
      fastcgi_pass 127.0.0.1:9000;
      fastcgi_index index.php;
      fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
      include fastcgi_params;
    }
  }
}
2.1.4.2 部署pause容器
[root@k8s-harbor01 ~]# docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.8

[root@k8s-harbor01 ~]# docker run -d -p 81:80 --name pause-container-test registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.8
86be2e080eaca3576ec02c247c3a42151df3966515a5338606828e096fd8fbea
[root@k8s-harbor01 ~]# docker ps -l
CONTAINER ID   IMAGE                                                           COMMAND    CREATED         STATUS         PORTS                               NAMES
86be2e080eac   registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.8   "/pause"   3 seconds ago   Up 2 seconds   0.0.0.0:81->80/tcp, :::81->80/tcp   pause-container-test
2.1.4.3 部署nginx 容器,并使用paush容器网络
[root@k8s-harbor01 ~]# docker run -d --name nginx-container-test \
-v `pwd`/nginx.conf:/etc/nginx/nginx.conf \
--net=container:pause-container-test \
nginx:1.20.2

[root@k8s-harbor01 ~]# docker ps -l
CONTAINER ID   IMAGE          COMMAND                  CREATED              STATUS          PORTS     NAMES
58b715305b95   nginx:1.20.2   "/docker-entrypoint.…"   About a minute ago   Up 59 seconds             nginx-container-test

在这里插入图片描述

2.1.4.4 部署php容器,并使用paush容器网络
[root@k8s-harbor01 ~]# echo 'php test!' > index.php
[root@k8s-harbor01 ~]# cat index.php
php test!

[root@k8s-harbor01 ~]# docker run -d --name php-container-test --net=container:pause-container-test -v `pwd`/index.php:/usr/share/nginx/html/index.php php:5.6.40-fpm
9fd6835a2c1789e020e10e40bd9ac065fe1e9725f3282f36d6ccd6f6661fc66e

[root@k8s-harbor01 ~]# docker ps -l
CONTAINER ID   IMAGE            COMMAND                  CREATED         STATUS         PORTS     NAMES
9fd6835a2c17   php:5.6.40-fpm   "docker-php-entrypoi…"   4 seconds ago   Up 3 seconds             php-container-test

[root@k8s-harbor01 ~]# curl 10.31.200.104:81/index.php
php test!
2.1.4.5 为什么我通过81可以访问nginx和php

主要是下图,搭配这个参数:–net=container:pause-container-test # 使用pause-container-test的网络,所以我访问pause的81,能访问到nginx和php容器


另外,从后2张图,也可以看出,nginx和php确实是共享的pause的网络的,因为ip都和pause的一样。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.2 init容器

2.2.1 init容器简介

和pause容器不通,init容器是一个非必须容器。

2.2.2 init容器的作用

(1)可以为业务容器提前准备好业务容器的运行环境,比如将业务容器需要的配置文件提前生成并放在指定位置、检查数据权限或完整性、软件版本等基础运行环境。。
(2)可以在运行业务容器之前准备好需要的业务数据,比如从OSS下载、或者从其它位置copy。
(3)检查依赖的服务是否能够访问(A依赖B,init先检查B是不是能够访问)。

2.2.3 init容器的特点

(1)一个pod可以有多个业务容器以及多个init容器,但是每个init容器和业务容器的运行环境都是隔离的。
(2)init容器会比业务容器先启动。
(3)init容器运行成功之后才会继续运行业务容器。
(4)如果一个pod有多个init容器,则需要从上到下逐个运行并且全部成功,最后才会运行业务容器。
(5)init容器不支持探针检测(因为初始化完成后就退出再也不运行了)。

2.2.4 示例-使用init容器

2.2.4.1 创建init容器
[root@k8s-harbor01 deployment]# cat init-container.yaml
kind: Deployment
apiVersion: apps/v1
metadata:
  labels:
    app: myserver-myinit
  name: myserver-myinit-deployment-name
  namespace: myserver
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myserver-myinit-frontend
  template:
    metadata:
      labels:
        app: myserver-myinit-frontend
    spec:
      containers: # 这里表示业务容器
        - name: myserver-myinit-container
          image: nginx:1.20.0
          #imagePullPolicy: Always
          volumeMounts:
          - mountPath: "/usr/share/nginx/html/myserver"
            name: myserver-data
          - name: tz-config
            mountPath: /etc/localtime
      initContainers: # 注意这里,init容器必备字段,该字段表示当前容器为init容器(就算init容器字段定义在业务容器字段下面,也会先启动并执行init容器)
        - name: init-web-data # init容器 1,执行命令来初始化数据(此处为演示,工作中使用害得根据实际需求来)
          image: centos:7.9.2009
          command: ['/bin/bash','-c',"for i in `seq 1 10`;do echo '<h1>'$i web page at $(date +%Y%m%d%H%M%S) '<h1>' >> /data/nginx/html/myserver/index.html;sleep 1;done"] # 该命令的作用是循环10次,生成10次时间戳到index.html中
          volumeMounts: # 这里一定要配置数据持久化,不然init容器运行接触,生成的数据就没了
          - mountPath: "/data/nginx/html/myserver"
            name: myserver-data
          - name: tz-config
            mountPath: /etc/localtime
        - name: change-data-owner # init容器 2,修改数据文件权限
          image: busybox:1.28
          command: ['/bin/sh','-c',"/bin/chmod 644 /data/nginx/html/myserver/* -R"]
          volumeMounts:
          - mountPath: "/data/nginx/html/myserver"
            name: myserver-data
          - name: tz-config
            mountPath: /etc/localtime
      volumes: # 这里一定要配置数据持久化,不然init容器运行接触,生成的数据就没了
      - name: myserver-data
        hostPath:
          path: /tmp/data/html
      - name: tz-config
        hostPath:
          path: /etc/localtime

---
kind: Service
apiVersion: v1
metadata:
  labels:
    app: myserver-myinit-service
  name: myserver-myinit-service-name
  namespace: myserver
spec:
  type: NodePort
  ports:
  - name: http
    port: 80
    targetPort: 80
  selector:
    app: myserver-myinit-frontend

[root@k8s-harbor01 deployment]# kubectl apply -f init-container.yaml
deployment.apps/myserver-myinit-deployment-name created
service/myserver-myinit-service-name created

[root@k8s-harbor01 deployment]# kubectl get po,svc -A -o wide |grep myinit
myserver      pod/myserver-myinit-deployment-name-69b944f77-98vn5   1/1     Running   0             11m   10.200.135.179   k8s-node03     <none>           <none>
myserver      service/myserver-myinit-service-name   NodePort    10.100.61.196    <none>        80:31662/TCP                 11m   app=myserver-myinit-frontend

2.2.4.2 访问测试
[root@k8s-harbor01 deployment]# ssh k8s-node03
Last login: Mon Jun  5 20:43:39 2023 from k8s-harbor01

[root@k8s-node03 ~]# ll /tmp/data/html/
总用量 4
-rw-r--r-- 1 root root 381 67 20:26 index.html
[root@k8s-node03 ~]# cat /tmp/data/html/index.html
<h1>1 web page at 20230607202551 <h1>
<h1>2 web page at 20230607202552 <h1>
<h1>3 web page at 20230607202553 <h1>
<h1>4 web page at 20230607202554 <h1>
<h1>5 web page at 20230607202555 <h1>
<h1>6 web page at 20230607202556 <h1>
<h1>7 web page at 20230607202557 <h1>
<h1>8 web page at 20230607202558 <h1>
<h1>9 web page at 20230607202559 <h1>
<h1>10 web page at 20230607202600 <h1>

[root@k8s-node03 ~]# curl 10.31.200.112:31662/myserver/
<h1>1 web page at 20230607202551 <h1>
<h1>2 web page at 20230607202552 <h1>
<h1>3 web page at 20230607202553 <h1>
<h1>4 web page at 20230607202554 <h1>
<h1>5 web page at 20230607202555 <h1>
<h1>6 web page at 20230607202556 <h1>
<h1>7 web page at 20230607202557 <h1>
<h1>8 web page at 20230607202558 <h1>
<h1>9 web page at 20230607202559 <h1>
<h1>10 web page at 20230607202600 <h1>
[root@k8s-node03 ~]#

3. 健康检查(了解)

3.1 什么是健康检查

(1)由发起者对容器进行周期性健康状态检测。
(2)周期检测相当于人类的周期性体检。
(3)每次检测相当于人类每次体检的内容。

3.2 配置docker-compose健康检查

[root@k8s-harbor01 docker-compose-health-check]# cat docker-compose.yaml 
version: '3.6'
services:
  nginx-service:
    image: nginx:1.20.2
    container_name: nginx-web1
    expose:
      - 80
      - 443
    ports:
      - "81:80"
      - "443:443"
    restart: always
    healthcheck: #添加服务健康状态检查
      test: ["CMD","curl","-f","http://localhost"]
      interval: 5s #健康状态检查的间隔时间,默认为30s
      timeout: 5s #单次检查的失败超时时间,默认为30s
      retries: 3 #连续失败次数默认3次,当连续失败retries次数后将容器置为unhealthy状态
      start_period: 60s #60s后每间隔interval的时间检查一次,连续retries次后才将容器置为unhealthy状态,   但是start_period时间内检查成功就认为是检查成功并装容器置于healthy状态

[root@k8s-harbor01 docker-compose-health-check]# docker-compose up -d
Creating nginx-web1 ... done

[root@k8s-harbor01 docker-compose-health-check]# docker-compose ps
   Name                 Command                  State                                       Ports                                 
-----------------------------------------------------------------------------------------------------------------------------------
nginx-web1   /docker-entrypoint.sh ngin ...   Up (healthy)   0.0.0.0:443->443/tcp,:::443->443/tcp, 0.0.0.0:81->80/tcp,:::81->80/tcp  # 注意看 Up (healthy),这表示健康检查通过了

3.3 在dockerfile中配置健康检查

3.3.1 准备dockerfile

[root@k8s-harbor01 docker-compose-health-check]# cat Dockerfile
FROM nginx:1.20.2

maintainer "jack 2973707860@qq.com"

HEALTHCHECK --interval=5s --timeout=2s --retries=3 \
CMD curl --silent --fail localhost:80 || exit 1

3.3.2 构建镜像

[root@k8s-harbor01 docker-compose-health-check]# docker build -t nginx-health-check:1.20.2 .
Sending build context to Docker daemon  3.584kB
Step 1/3 : FROM nginx:1.20.2
 ---> 50fe74b50e0d
Step 2/3 : maintainer "jack 2973707860@qq.com"
 ---> Running in a79bf2fe1d4f
Removing intermediate container a79bf2fe1d4f
 ---> eca49207f9f4
Step 3/3 : HEALTHCHECK --interval=5s --timeout=2s --retries=3 CMD curl --silent --fail localhost:80 || exit 1
 ---> Running in 5d9476caf6c7
Removing intermediate container 5d9476caf6c7
 ---> 4ba27810ca8e
Successfully built 4ba27810ca8e
Successfully tagged nginx-health-check:1.20.2

3.3.3 运行容器

[root@k8s-harbor01 docker-compose-health-check]# docker run -d --name nginx-health-check nginx-health-check:1.20.2
17dfdaf417570381b24c1c2d15ba8de9a068596927c5445768e0a0251fe7f80a
[root@k8s-harbor01 docker-compose-health-check]# docker ps -l # 通过(health: starting),可以看出容器正在健康检查中
CONTAINER ID   IMAGE                       COMMAND                  CREATED         STATUS                            PORTS     NAMES
17dfdaf41757   nginx-health-check:1.20.2   "/docker-entrypoint.…"   3 seconds ago   Up 2 seconds (health: starting)   80/tcp    nginx-health-check

[root@k8s-harbor01 docker-compose-health-check]# docker ps -l # 通过(healthy) 看出容器健康检查已经通过了
CONTAINER ID   IMAGE                       COMMAND                  CREATED              STATUS                        PORTS     NAMES
17dfdaf41757   nginx-health-check:1.20.2   "/docker-entrypoint.…"   About a minute ago   Up About a minute (healthy)   80/tcp    nginx-health-check

# 清理环境
[root@k8s-harbor01 docker-compose-health-check]# docker rm -f 17dfdaf41757
17dfdaf41757
[root@k8s-harbor01 docker-compose-health-check]# docker rmi nginx-health-check:1.20.2
Untagged: nginx-health-check:1.20.2
Deleted: sha256:4ba27810ca8ecd81bdd5572323974bc2fba1729ed4bc13fe8746c3152d98eeba
Deleted: sha256:eca49207f9f4cf6c040912f9f6761736dcb989c42377bf2e0ef5f7cabb6fd49e

3.3.4 修改dockerfile,使得健康检查失败

[root@k8s-harbor01 docker-compose-health-check]# cat Dockerfile
FROM nginx:1.20.2

maintainer "jack 2973707860@qq.com"

HEALTHCHECK --interval=5s --timeout=2s --retries=3 \
CMD curl --silent --fail localhost:81 || exit 1 # 让健康检查探测81端口,这样就会失败

[root@k8s-harbor01 docker-compose-health-check]# docker build -t nginx-health-check:1.20.2 .

[root@k8s-harbor01 docker-compose-health-check]# docker run -d --name nginx-health-check nginx-health-check:1.20.2
7f2545336dcfb80fcd51799aba6eee7e8ce380a61bd71f8a0d0d6e6362a74004

[root@k8s-harbor01 docker-compose-health-check]# docker ps -l # 通过(unhealthy) 可以看到健康检查失败了
CONTAINER ID   IMAGE                       COMMAND                  CREATED          STATUS                      PORTS     NAMES
7f2545336dcf   nginx-health-check:1.20.2   "/docker-entrypoint.…"   17 seconds ago   Up 16 seconds (unhealthy)   80/tcp    nginx-health-check
[root@k8s-harbor01 docker-compose-health-check]# 

3.3.5 docker健康检查状态总结

(1)在检测通过之前容器处于starting状态。
(2)检测通过(检测返回状态码为 0)之后为healthy状态。
(3)检测失败(检测返回状态码为 1)之后为unhealthy状。

4. pod生命周期、探针简介、类型及示例

4.1 pod生命周期

pod的生命周期(pod lifecycle)
从podstart时候可以配置postStart检测,
运行过程中可以配置livenessProbe和readinessProbe,
最后在stop前可以配置preStop操作。

在这里插入图片描述

4.2 容器探针

probe 是由 kubelet 对容器执行的定期诊断。 要执行诊断,kubelet 既可以在容器内执行代码,也可以发出一个网络请求(kubelet调用由容器实现的Handler(处理程序),也称为Hook(钩子),有四种类型的处理程序,如下)。

4.2.1 检查机制(探测方法)

使用探针来检查容器有四种不同的方法。 每个探针都必须准确定义为这四种机制中的一种

(1)exec # 在容器内执行指定命令,如果命令退出时返回码为0则认为诊断成功。
(2)tcpsocket # 对指定端口上的容器的IP地址进行TCP检查,如果端口打开,则诊断被认为是成功的。
(3)httpGet:# 对指定端口和路径上Pod的IP地址执行HTTP GET请求。如果响应的状态码大于等于200且小于400,则认为诊断成功。
(4)grpc # 使用gRPC执行远程过程调用。目标应执行gRPC运行状况检查。如果响应的状态为SERVING,则认为诊断成功。


注意: 和其他机制不同,exec 探针的实现涉及每次执行时创建/复制多个进程。 因此,在集群中具有较高 pod 密度、较低的 initialDelaySeconds 和 periodSeconds 时长的时候, 配置任何使用 exec 机制的探针可能会增加节点的 CPU 负载。 这种场景下,请考虑使用其他探针机制以避免额外的开销。

4.2.2 探测结果

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

(1)Success(成功):容器通过了诊断。
(2)Failure(失败):容器未通过诊断。
(3)Unknown(未知):诊断失败,因此不会采取任何行动(这种状态会导致重启策略失效)。
通过kubectl describe po,在事件中可以获取探测结果

4.2.3 pod重启策略

Pod一旦配置探针,在检测失败时候,会基于restartPolicy对Pod进行下一步操作:
(1)Always:当容器异常时,k8s自动重启该容器,ReplicationController/Replicaset/Deployment,默认为Always。
(2)OnFailure:当容器失败时(容器停止运行且退出码不为0),k8s自动重启该容器。
(3)Never:不论容器运行状态如何都不会重启该容器,Job或CronJob。

4.2.4 镜像拉取策略

(1)IfNotPresent:node节点没有此镜像就去指定的镜像仓库拉取,node有就使用node本地镜像。
(2)Always:每次重建pod都会重新拉取镜像。
(3)Never:从不到镜像中心拉取镜像,只使用本地镜像。

4.2.5 探针类型

注意:探针作用受到重启策略影响

(1)startupProbe: 启动探针,kubernetes v1.16引入。
判断容器内的应用程序是否已启动完成,如果配置了启动探测,则会先禁用所有其它的探测,直到startupProbe检测成功为止,
如果startupProbe探测失败,则kubelet将杀死容器,容器将按照重启策略进行下一步操作,如果容器没有提供启动探测,则默认状态为成功。


(2)livenessProbe: 存活探针。
检测容器容器是否正在运行,如果存活探测失败,则kubelet会杀死容器,并且容器将受到其重启策略的影响,如果容器不提供存活探针,则默认状态为 Success。
livenessProbe用于控制是否重启pod,并且重启前会把pod从svc的ep中移除。


(3)readinessProbe: 就绪探针
如果就绪探测失败,端点控制器将从与Pod匹配的所有Service的端点中删除该Pod的IP地址,这样外部请求就不会打到就绪探测失败的pod上。
初始延迟之前(就是我们设置的延迟检查时间)的就绪状态默认为Failure(失败),如果容器不提供就绪探针,则默认状态为Success,就算pod异常,还是会被加入到svc中。
readinessProbe用于控制pod是否添加至service。


(4)grpc存活探针:1.24 beta版
结合livenessProbe使用,如果你的应用实现了 gRPC 健康检查协议, kubelet 可以配置为使用该协议来执行应用存活性检查。
你必须启用 GRPCContainerProbe 特性门控 才能配置依赖于 gRPC 的检查机制。

4.2.6 探针参数

在Kubernetes1.20版本之前,exec探针会忽略timeoutSeconds: 探针会无限期地持续运行,甚至可能超过所配置的限期,直到返回结果为止。

探针有很多配置字段,可以使用这些字段精确的控制存活和就绪检测的行为:
https://kubernetes.io/zh-cn/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/

参数描述
initialDelaySeconds: 120初始化延迟时间(通常为60-120s),告诉kubelet在执行第一次探测前应该等待多少秒,默认是0秒,最小值是0(因为服务启动是需要时间的,如果服务还没起来就检查,那么肯定是检查失败的)
periodSeconds: 60探测周期间隔时间(通常30-60s),指定了kubelet应该每多少秒秒执行一次存活探测,默认是10秒,最小值是1
timeoutSeconds: 5单次探测超时时间。探测超时的秒数,超过该秒数就判定为失败,默认为1秒,最小值为1。
successThreshold: 1从失败转为成功的重试次数。探测器在失败后,被视为成功的最小连续成功数,默认值是1(重试探测成功后,才会把pod加入到svc中),存活和启动探测的这个值必须是1,最小值是1。
failureThreshold: 3探针连续失败了failureThreshold次之后(从成功转为失败的次数),K8s认为总体上检查已失败:容器状态未就绪、不健康、不活跃。对于启动探针或存活探针而言,如果至少有failureThreshold个探针已失败,K8s会将容器视为不健康并为这个特定的容器触发重启操作。kubelet会考虑该容器的terminationGracePeriodSeconds设置。对于失败的就绪探针,kubelet继续运行检查失败的容器,并继续运行更多探针;因为检查失败,kubelet将Pod的Ready状况设置为false。默认值是3,最小值是1。
terminationGracePeriodSeconds为kubelet配置从为失败的容器触发终止操作到强制容器运行时停止该容器之前等待的宽限时长(删除容器前,先等待terminationGracePeriodSeconds秒,再删除,期间pod状态会变更为Terminating)。 默认值是继承Pod级别的terminationGracePeriodSeconds值(如果不设置则为30秒),最小值为 1。

4.2.7 探针http配置参数

HTTP 探测器可以在httpGet上配置额外的字段

参数描述
host:连接使用的主机名,默认是Pod的 IP,也可以在HTTP头中设置 “Host” 来代替
scheme: http用于设置连接主机的方式(HTTP协议还是HTTPS协议),默认是HTTP协议
path: /monitor/index.html访问HTTP服务的路径,默认为/
httpHeaders:请求中自定义的 HTTP 头,HTTP头字段
port: 80访问容器的端口号或者端口名,如果数字必须在1~65535之间

4.2.8 探针示例

通过:journalctl -f -u kubelet命令,可以看到详细的健康检查过程

4.2.8.1 http Probe

livenessProbe

# 编辑yaml
[root@k8s-harbor01 health-check]# cat http-probe.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment-http-probe
  namespace: myserver
spec:
  replicas: 1
  selector:
    matchLabels: #rs or deployment
      app: deployment-http-probe
  template:
    metadata:
      labels:
        app: deployment-http-probe
    spec:
      containers:
      - name: deployment-http-probe
        image: nginx:1.20.2
        ports:
        - containerPort: 80
        #readinessProbe:
        livenessProbe: # 存活探针
          httpGet: # 对指定端口和路径执行HTTPGet请求,响应的状态码大于等于200且小于400,则诊断被认为是成功。
            path: /index.html # 探测的路径
            port: 80 # 探测的端口
          initialDelaySeconds: 5 # pod启动5秒后开始第一次探测
          periodSeconds: 3 # 后续每隔3秒探测一次
          timeoutSeconds: 1 # 单次探测超时时间为1s(超过1s没有返回结果就认为失败了)
          successThreshold: 1 # 从失败转为成功的重试次数,这里只要有1次成功,会把pod加入svc
          failureThreshold: 3 # 连续探测失败3次(从成功到失败,每一次失败会重启一次pod中的容器,重启容器只会替换文件系统,其他不变),重启一次pod,重启次数达到3次后,进行第4次探测时,pod状态会变成CrashLoopBackOff(变成CrashLoopBackOff时会把pod从svc的ep中移除)
---
apiVersion: v1
kind: Service
metadata:
  name: deployment-http-probe-nodeport
  namespace: myserver
spec:
  ports:
  - name: http
    port: 81
    targetPort: 80
    protocol: TCP
  type: NodePort
  selector:
    app: deployment-http-probe


# 创建容器
[root@k8s-harbor01 health-check]# kubectl apply -f http-probe.yaml 
deployment.apps/deployment-http-probe configured
service/deployment-http-probe-nodeport created
[root@k8s-harbor01 health-check]# kubectl get po,svc -n myserver
NAME                                         READY   STATUS    RESTARTS   AGE
pod/deployment-http-probe-558556777c-m4jrj   1/1     Running   0          28s

NAME                                     TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
service/deployment-http-probe-nodeport   NodePort   10.100.213.84   <none>        81:31118/TCP   9s

# 访问测试
[root@k8s-harbor01 health-check]# curl -I 10.31.200.110:31118
HTTP/1.1 200 OK
Server: nginx/1.20.2
Date: Tue, 13 Jun 2023 08:56:20 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 16 Nov 2021 14:44:02 GMT
Connection: keep-alive
ETag: "6193c3b2-264"
Accept-Ranges: bytes

# 删除/index.html,验证健康检查
[root@k8s-harbor01 health-check]# grep '/index.html' http-probe.yaml
            path: /index.html-xx # 探测的路径 ## 修改一下path

[root@k8s-harbor01 health-check]# kubectl apply -f http-probe.yaml 
deployment.apps/deployment-http-probe configured
service/deployment-http-probe-nodeport unchanged

[root@k8s-harbor01 health-check]# kubectl get po -o wide -n myserver -w # 这里可以看到pod一直在重启,且超过3次后,pod状态变成CrashLoopBackOff
NAME                                   READY   STATUS    RESTARTS   AGE   IP              NODE         NOMINATED NODE   READINESS GATES
deployment-http-probe-8766f88b-lhhxl   1/1     Running   0          3s    10.200.85.236   k8s-node01   <none>           <none>
deployment-http-probe-8766f88b-lhhxl   1/1     Running   1 (1s ago)   13s   10.200.85.236   k8s-node01   <none>           <none>
deployment-http-probe-8766f88b-lhhxl   1/1     Running   2 (0s ago)   24s   10.200.85.236   k8s-node01   <none>           <none>
deployment-http-probe-8766f88b-lhhxl   1/1     Running   3 (0s ago)   36s   10.200.85.236   k8s-node01   <none>           <none>
deployment-http-probe-8766f88b-lhhxl   0/1     CrashLoopBackOff   3 (0s ago)   48s   10.200.85.236   k8s-node01   <none>           <none>
deployment-http-probe-8766f88b-lhhxl   1/1     Running            4 (26s ago)   74s   10.200.85.236   k8s-node01   <none>           <none>
deployment-http-probe-8766f88b-lhhxl   0/1     CrashLoopBackOff   4 (0s ago)    87s   10.200.85.236   k8s-node01   <none>           <none>
deployment-http-probe-8766f88b-lhhxl   1/1     Running            5 (54s ago)   2m21s   10.200.85.236   k8s-node01   <none>           <none>
deployment-http-probe-8766f88b-lhhxl   0/1     CrashLoopBackOff   5 (1s ago)    2m34s   10.200.85.236   k8s-node01   <none>           <none>
deployment-http-probe-8766f88b-lhhxl   1/1     Running            6 (81s ago)   3m54s   10.200.85.236   k8s-node01   <none>           <none>
deployment-http-probe-8766f88b-lhhxl   0/1     CrashLoopBackOff   6 (1s ago)    4m7s    10.200.85.236   k8s-node01   <none>           <none>

在这里插入图片描述
在这里插入图片描述

readinessProbe

# 编辑yaml.参数和livenessProbe相同
[root@k8s-harbor01 health-check]# cat http-probe.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment-http-probe
  namespace: myserver
spec:
  replicas: 1
  selector:
    matchLabels: #rs or deployment
      app: deployment-http-probe
  template:
    metadata:
      labels:
        app: deployment-http-probe
    spec:
      containers:
      - name: deployment-http-probe
        image: nginx:1.20.2
        ports:
        - containerPort: 80
        readinessProbe: # 就绪探针
        #livenessProbe: # 存活探针
          httpGet: # 对指定端口和路径执行HTTPGet请求,响应的状态码大于等于200且小于400,则诊断被认为是成功。
            path: /index.html # 探测的路径
            port: 80 # 探测的端口
          initialDelaySeconds: 5 # pod启动5秒后开始第一次探测
          periodSeconds: 3 # 后续每隔3秒探测一次
          timeoutSeconds: 1 # 单次探测超时时间为1s
          successThreshold: 1 # 从失败转为成功的重试次数,这里只要有1次成功,就会把pod加入svc
          failureThreshold: 2 # 从成功到失败的次数,这里为2次。(注意:对于失败的就绪探针,kubelet继续运行检查失败的容器,并继续运行更多探针;因为检查失败,kubelet将Pod的Ready状况设置为false。第一次探测失败,就会把异常的pod ip从ep中移除)
---
apiVersion: v1
kind: Service
metadata:
  name: deployment-http-probe-nodeport
  namespace: myserver
spec:
  ports:
  - name: http
    port: 81
    targetPort: 80
    protocol: TCP
  type: NodePort
  selector:
    app: deployment-http-probe

# 创建容器
[root@k8s-harbor01 health-check]# kubectl get po -n myserver
NAME                                     READY   STATUS    RESTARTS   AGE
deployment-http-probe-785fcf6b5d-6jknd   1/1     Running   0          12s # 只有健康检查通过,READY才会变成1/1,pod才会加入到svc中对外提供服务

# 调整yaml,让健康检查失败
[root@k8s-harbor01 health-check]# grep path http-probe.yaml
            path: /index.html-xx # 修改成一个不存在的文件
[root@k8s-harbor01 health-check]# kubectl apply -f http-probe.yaml 
deployment.apps/deployment-http-probe configured
service/deployment-http-probe-nodeport unchanged

# 查看健康检查情况
[root@k8s-harbor01 health-check]# kubectl get po -n myserver 
NAME                                     READY   STATUS    RESTARTS   AGE
deployment-http-probe-579754c465-svv47   0/1     Running   0          110s # 因为只有就绪探针,所以即使健康检查不通过,容器也不会重启,只是不会把异常pod加入svc中
deployment-http-probe-785fcf6b5d-6jknd   1/1     Running   0          14h

# 查看svc
[root@k8s-harbor01 health-check]# kubectl get po -n myserver -o wide
NAME                                     READY   STATUS    RESTARTS   AGE    IP               NODE         NOMINATED NODE   READINESS GATES
deployment-http-probe-579754c465-svv47   0/1     Running   0          3m4s   10.200.135.184   k8s-node03   <none>           <none>
deployment-http-probe-785fcf6b5d-6jknd   1/1     Running   0          14h    10.200.85.224    k8s-node01   <none>           <none>
[root@k8s-harbor01 health-check]# kubectl get ep -n myserver # 可以看到ep中只有正常的那个pod
NAME                             ENDPOINTS          AGE
deployment-http-probe-nodeport   10.200.85.224:80   15h

在这里插入图片描述
在这里插入图片描述

4.2.8.2 tcp Probe

适合用于检测没有api的服务:mysql、redis等中间件

livenessProbe

# 编辑yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myserver-tcp-probe
  namespace: myserver
spec:
  replicas: 1
  selector:
    matchLabels: #rs or deployment
      app: myserver-tcp-probe
  template:
    metadata:
      labels:
        app: myserver-tcp-probe
    spec:
      containers:
      - name: myserver-tcp-probe
        image: nginx:1.20.2
        ports:
        - containerPort: 80
        livenessProbe:
        #readinessProbe:
          tcpSocket: # 指定涉及TCP端口的操作(不管是存活探针还是就绪探针,tcp探测这里都是tcpSocket)
            port: 80 # 探测的端口(相当于就是telnet 检测,端口通,探测就成功)
            #port: 8080
          initialDelaySeconds: 5 # 容器启动5秒后开始第一次探测
          periodSeconds: 3 # 后续每隔3秒探测一次
          timeoutSeconds: 5 # 单次探测超时时间为5s
          successThreshold: 1 # 从失败转为成功的重试次数为1次,这里只要有1次成功,就会把pod加入svc
          failureThreshold: 3 # 连续探测失败3次(从成功到失败),重启一次,重启次数达到3次后,进行第4次探测时,pod状态会变成CrashLoopBackOff(重启前会把pod从svc的ep中移除)

---
apiVersion: v1
kind: Service
metadata:
  name: myserver-tcp-probe
  namespace: myserver
spec:
  ports:
  - name: http
    port: 80
    targetPort: 80
    protocol: TCP
  type: NodePort
  selector:
    app: myserver-tcp-probe

# 创建pod
[root@k8s-harbor01 health-check]# kubectl apply -f tcp-Probe.yaml 
deployment.apps/myserver-tcp-probe created
service/myserver-tcp-probe created

# 查看pod创建情况
[root@k8s-harbor01 health-check]# kubectl get po -n myserver
NAME                                  READY   STATUS    RESTARTS   AGE
myserver-tcp-probe-5b4c66c764-shsvv   1/1     Running   0          88s
[root@k8s-harbor01 health-check]# kubectl get ep -n myserver
NAME                 ENDPOINTS          AGE
myserver-tcp-probe   10.200.85.225:80   107s

[root@k8s-harbor01 health-check]# ssh k8s-node01
[root@k8s-node01 ~]# curl -I 10.31.200.110:30414
HTTP/1.1 200 OK
Server: nginx/1.20.2
Date: Wed, 14 Jun 2023 02:33:22 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 16 Nov 2021 14:44:02 GMT
Connection: keep-alive
ETag: "6193c3b2-264"
Accept-Ranges: bytes

# 修改yaml,让健康检查失败
[root@k8s-harbor01 health-check]# grep 8080 tcp-Probe.yaml
            port: 8080 # nginx是没有8080端口的,所以健康检查肯定失败

# 应用yaml
[root@k8s-harbor01 health-check]# kubectl apply -f tcp-Probe.yaml
deployment.apps/myserver-tcp-probe configured
service/myserver-tcp-probe unchanged

# 查看pod状态
[root@k8s-harbor01 health-check]# kubectl get po,ep -n myserver # 可以看到,重启超过3次后,pod状态变成了CrashLoopBackOff,并且pod ip也从ep中移除了
NAME                                      READY   STATUS    RESTARTS      AGE
pod/myserver-tcp-probe-779cf77548-64jsd   1/1     Running   3 (10s ago)   46s

NAME                           ENDPOINTS           AGE
endpoints/myserver-tcp-probe   10.200.135.185:80   10m
[root@k8s-harbor01 health-check]# kubectl get po,ep -n myserver
NAME                                      READY   STATUS             RESTARTS     AGE
pod/myserver-tcp-probe-779cf77548-64jsd   0/1     CrashLoopBackOff   3 (4s ago)   52s

NAME                           ENDPOINTS   AGE

livenessProbe

# 主要功能其实都一样,就是探测方式不同
## 编辑yaml
[root@k8s-harbor01 health-check]# cat tcp-Probe.yaml
……省略部分内容
        #livenessProbe:
        readinessProbe:
……省略部分内容

# 应用并查看pod状态
[root@k8s-harbor01 health-check]# kubectl apply -f tcp-Probe.yaml
deployment.apps/myserver-tcp-probe created
service/myserver-tcp-probe created
[root@k8s-harbor01 health-check]# kubectl get po -n myserver
NAME                                  READY   STATUS    RESTARTS   AGE
myserver-tcp-probe-76c97b6c8d-p9dsl   0/1     Running   0          3s
[root@k8s-harbor01 health-check]# kubectl get po,ep -n myserver
NAME                                      READY   STATUS    RESTARTS   AGE
pod/myserver-tcp-probe-76c97b6c8d-p9dsl   0/1     Running   0          7s

NAME                           ENDPOINTS   AGE
endpoints/myserver-tcp-probe               7s
4.2.8.3 exec Probe

有时候只检查端口是否存活可能不准,所以可以通过执行命令的方式来判断

[root@k8s-harbor01 health-check]# cat exec-Probe.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myserver-exec-probe
  namespace: myserver
spec:
  replicas: 1
  selector:
    matchLabels: #rs or deployment
      app: myserver-exec-probe
  template:
    metadata:
      labels:
        app: myserver-exec-probe
    spec:
      containers:
      - name: myserver-exec-probe
        image: redis
        ports:
        - containerPort: 6379
        livenessProbe:
        #readinessProbe:
          exec:
            command:
            - /usr/local/bin/redis-cli  # 执行redis客户端命令来判断redis是否正常
            - quit # 进入命令行后退出
          initialDelaySeconds: 5
          periodSeconds: 3
          timeoutSeconds: 5
          successThreshold: 1
          failureThreshold: 3
      
---
apiVersion: v1
kind: Service
metadata:
  name: myserver-exec-probe
  namespace: myserver
spec:
  ports:
  - name: http
    port: 6379
    targetPort: 6379
    protocol: TCP
  type: NodePort
  selector:
    app: myserver-exec-probe

[root@k8s-harbor01 health-check]# kubectl apply -f exec-Probe.yaml # 这里pod正常运行了,就说明redis-cli命令是可以执行的
01 health-check]# kubectl get po -n myserver
NAME                                   READY   STATUS    RESTARTS   AGE
myserver-exec-probe-55dd79dc68-xk5pg   1/1     Running   0          85s

# 在pod中的话就相当于这样
[root@k8s-harbor01 health-check]# kubectl exec -it -n myserver myserver-exec-probe-55dd79dc68-xk5pg -- /bin/bash
root@myserver-exec-probe-55dd79dc68-xk5pg:/data# redis-cli # 进去
127.0.0.1:6379> quit # 退出
root@myserver-exec-probe-55dd79dc68-xk5pg:/data# exit
exit

# 调整yaml,让健康检查失败
[root@k8s-harbor01 health-check]# grep -rni redis-cli exec-Probe.yaml
25:            - /apps/redis/bin/redis-cli
26:            #- /usr/local/bin/redis-cli

# 应用yaml
[root@k8s-harbor01 health-check]# kubectl apply -f exec-Probe.yaml 

# 查看pod
[root@k8s-harbor01 health-check]# kubectl get po,ep -n myserver
NAME                                      READY   STATUS    RESTARTS        AGE
pod/myserver-exec-probe-b4f6df994-rzzrh   1/1     Running   1 (6m26s ago)   26m

NAME                            ENDPOINTS             AGE
endpoints/myserver-exec-probe   10.200.135.186:6379   33m

## 上面可以看到,pod并没有按照我们的预期进行重启,这是为什么呢?执行describe看看
 Warning  Unhealthy  4m26s (x882 over 48m)  kubelet            (combined from similar events): Liveness probe errored: rpc error: code = Unknown desc = failed to exec in container: failed to start exec "d64f5c97a95e3a48a9f90d0ff310ee4e9e81839f4ac9c3ec36d4f17d05259c64": OCI runtime exec failed: exec failed: unable to start container process: exec: "/apps/redis/bin/redis-cli": stat /apps/redis/bin/redis-cli: no such file or directory: unknown 
# 从这里的输出可以看到,明明已经存活探测失败了,为什么没有按照重启策略配置来进行重启。
# 因为是因为信息末尾的 “unknown ”。
# 官方文档明确指出探测的结果只会有3种,成功、失败、未知,当探测结果为未知(code = Unknown)的时候,是不会采取行动的,也就是说,不会按照我们预期的配置进行重启。
4.2.8.4 startup Probe

只有启动探测通过了,才能执行后面的存活探测和就绪探测
只要通过了一次,后续就不会再执行了(只在pod初次启动时执行)

[root@k8s-harbor01 health-check]# cat startupProbe.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myserver-startup-probe
  namespace: myserver
spec:
  replicas: 1
  selector:
    matchLabels: #rs or deployment
      app: myserver-startup-probe
  template:
    metadata:
      labels:
        app: myserver-startup-probe
    spec:
      containers:
      - name: myserver-startup-probe
        image: nginx:1.20.2
        ports:
        - containerPort: 80
        startupProbe: # 只有startupProbe探测通过后,才会执行存活探测和就绪探测,启动探测期间会形成一个死锁,让存活和就绪无法执行
          httpGet:
            path: /index.html
            port: 80
          initialDelaySeconds: 5 #首次检测延迟5s
          failureThreshold: 3  #从成功转为失败的次数
          periodSeconds: 3 #探测间隔周期


---
apiVersion: v1
kind: Service
metadata:
  name: myserver-startup-probe
  namespace: myserver
spec:
  ports:
  - name: http
    port: 80
    targetPort: 80
    protocol: TCP
  type: NodePort
  selector:
    app: myserver-startup-probe


[root@k8s-harbor01 health-check]# kubectl get po -n myserver
NAME                                      READY   STATUS    RESTARTS   AGE
myserver-startup-probe-7997667cf5-44hbs   1/1     Running   0          97s

4.2.9 探针综合使用(startup、liveness、readiness)

startup的参数和探测方法,和存活和就绪是相同的,这里不另外演示了。
说下这3中探针同时存在时的优先级:
(1)不管initialDelaySeconds配置成多少,最先执行的就是startup。
(2)如果存活和就绪的initialDelaySeconds相同,秒级别情况下,它俩并行加载,毫秒级别下,就绪先加载,然后是存活加载,但是存活不会等到就绪成功后才加载(Caution: Liveness probes do not wait for readiness probes to succeed. If you want to wait before executing a liveness probe you should use initialDelaySeconds or a startupProbe.)。
(3)通过调整initialDelaySeconds可以控制存活和就绪探针的先后加载顺序。


上述结论,全部通过不断测试,再观察kubelet日志得出。

4.2.9 探针应用场景

4.2.9.1 什么时候使用存活探针

如果容器中的进程在遇到问题或变得不正常时能够自行崩溃,则不一定需要活动探测;
kubelet 将根据 Pod 的 restartPolicy 自动执行正确的操作。


如果希望在探测失败时终止并重新启动容器,请指定活动探测,并指定“始终”或“失败时”的restartPolicy 。

4.2.9.2 什么时候使用就绪探针

(1)如果希望仅在探测成功时才开始向Pod发送流量,请指定就绪探测。
在这种情况下,就绪探测可能与存活探测相同,但是规范中存在就绪探测意味着Pod将在不接收任何流量的情况下启动,并且只有在就绪探测成功后才开始接收流量。


(2)如果你的应用对后端服务有严格的依赖,你可以同时实现一个存活探测和一个就绪度探测。
当应用本身运行正常时,存活探测就会通过,但就绪探测会额外检查每个所需的后端服务是否可用。
这可以避免将流量定向到只能响应错误消息的pod。

4.2.9.3 什么时候使用启动探针

启动探针对于那些容器需要很长时间才能投入使用的pod非常有用。
您可以配置一个单独的配置,以便在容器启动时探测它,而不是设置一个较长的活动间隔,从而允许比活动间隔所允许的时间更长。


如果容器的启动时间通常超过initialDelaySeconds + failureThreshold × periodSeconds,则应该指定一个启动探针,该探针检查与存活探针相同的端点。
cat 默认值为10秒。
然后,您应该将其failureThreshold设置得足够高,以允许容器启动,而无需更改存活探测的默认值。这有助于防止死锁。

4.2.9.4 什么时候使用 httpProbe 探测方法

如果存在api接口或者url,推荐使用httpProbe。
常见的如nginx服务,或者自定义了health接口的java服务等。

4.2.9.5 什么时候使用 tcpProbe 探测方法

像mysql、redis这种中间件,可以使用tcpProbe,通过连接端口的方式来判断服务是否健康。
没有自定义health接口的业务服务(如java)也可以用该方式。

4.2.9.6 什么时候使用 execProbe 探测方法

像mysql、redis这种中间件,除了可以使用tcp方式探测端口,也可以通过exec执行他们的客户端命令来检测。

4.2.10 探针总结

(1)kubelet 使用启动探测器(startupProbe)可以知道应用程序容器什么时候启动了。
如果配置了这类探测器,就可以控制容器在启动成功后再进行存活性和就绪检查, 确保这些存活、就绪探测器不会影响应用程序的启动。
这可以用于对慢启动容器进行存活性检测,避免它们在启动运行之前就被杀掉。


(2)kubelet 使用存活探测器来知道什么时候要重启容器。
例如,存活探测器可以捕捉到死锁(应用程序在运行,但是无法继续执行后面的步骤)。 这样的情况下重启容器有助于让应用程序在有问题的情况下更可用。


(3)kubelet 使用就绪探测器可以知道容器什么时候准备好了并可以开始接受请求流量, 当一个 Pod 内的所有容器都准备好了,才能把这个 Pod 看作就绪了。
这种信号的一个用途就是控制哪个 Pod 作为 Service 的后端。 在 Pod 还没有准备好的时候,会从 Service 的负载均衡器中被剔除的。

4.3 postStart和preStop处理函数

官方文档:https://kubernetes.io/zh-cn/docs/tasks/configure-pod-container/attach-handler-lifecycle-event/#define-poststart-and-prestop-handlers

4.3.1 简介

(1)postStart:Pod启动后立即执行指定的操作(如果有init容器,那么它是在init容器之后执行)
Pod被创建后立即执行,即不等待pod中的服务启动完成。
如果postStart执行失败pod不会继续创建。


(2)preStop:Pod停止前(容器删除前)立即执行指定的操作
在pod被停止之前执行。
如果preStop一直执行不完成,则最后宽限2秒后强制删除。


由于可以配置init容器,所以poststart相对来说用的不多,更多的还是prestop

4.3.2 示例

[root@k8s-harbor01 health-check]# cat postStart-preStop.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myserver-poststart-poststop
  labels:
    app: myserver-poststart-poststop
  namespace: myserver
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myserver-poststart-poststop
  template:
    metadata:
      labels:
        app: myserver-poststart-poststop
    spec:
      terminationGracePeriodSeconds: 60
      containers:
      - name: myserver-poststart-poststop
        image: tomcat:7.0.94-alpine
        lifecycle: # 定义容器生命周期
          postStart: # 启动时的操作,但是它是在init容器之后执行
            exec:
             #command: 模拟把自己注册到注册在中心
              command: ["/bin/sh", "-c", "echo 'Hello from the postStart handler' >> /usr/local/tomcat/webapps/ROOT/index.html"]

            #httpGet:
            #  #path: /monitor/monitor.html
            #  host: www.magedu.com
            #  port: 80
            #  scheme: HTTP
            #  path: index.html
          preStop:
            exec:
             #command: 模拟在服务关闭前把自己从注册中心移除,这样就可以让新的流量不调度到该pod上
              command:
                - /bin/bash
                - -c
                - 'sleep 10000000'
              #command: ["/usr/local/tomcat/bin/catalina.sh","stop"]
              #command: ['/bin/sh','-c','/path/preStop.sh']
        ports:
          - name: http
            containerPort: 8080

---
apiVersion: v1
kind: Service
metadata:
  name: myserver-poststart-poststop
  namespace: myserver
spec:
  ports:
  - name: http
    port: 80
    targetPort: 8080
    protocol: TCP
  type: NodePort
  selector:
    app: myserver-poststart-poststop


[root@k8s-harbor01 health-check]# kubectl apply -f postStart-preStop.yaml
deployment.apps/myserver-poststart-poststop created
service/myserver-poststart-poststop created
[root@k8s-harbor01 health-check]# kubectl get po -n myserver
NAME                                           READY   STATUS    RESTARTS   AGE
myserver-poststart-poststop-75846cdc9d-p2764   1/1     Running   0          4s

# 检查poststart
[root@k8s-harbor01 health-check]# kubectl exec -it -n myserver myserver-poststart-poststop-75846cdc9d-p2764 -- cat /usr/local/tomcat/webapps/ROOT/index.html
Hello from the postStart handler

# 测试prestop
## 这里要开2个窗口,因为sleep 10000000,但是实际上宽限期只有30s,所以30s后,这个pod才能被删除
[root@k8s-harbor01 ~]# kubectl get po -n myserver
NAME                                           READY   STATUS              RESTARTS   AGE
myserver-poststart-poststop-75846cdc9d-p2764   1/1     Terminating         0          3m12s
myserver-poststart-poststop-75846cdc9d-wj8fh   0/1     ContainerCreating   0          40s

4.3.3 定义优雅下线功能

参考:https://www.modb.pro/db/405280

应用发版是常规不能再常规的操作,通常情况下都是滚动更新的方式上线,也就是先起一个新应用,再删一个老应用。


如果这时候老应用有部分的流量,突然把老应用的进程杀了,这部分流量就无法得到正确的处理,部分用户也会因此受到影响。


怎么才会不受影响呢?


假如我们在停止应用之前先告诉网关或者注册中心,等对方把我们应用摘除后再下线,这样就不会有任何流量受到影响了。


在K8S中,当我们要删除Pod的时候,Pod会变成Terminating状态,kubelet看到Pod的状态如果为Terminating,就会开始执行关闭Pod的流程,给Pod发SIGTERM信号,如果达到宽限期Pod还未结束就给Pod发SIGKILL信号,从Endpoints中摘除Pod等。


这里我们可以结合prestop,来定义结束前的操作,假设我们使用nacos作为服务注册中心,可以在prostop中线告诉nacos服务要下线了,这样就不怕pod异常期间,还有流量过来。如下:

lifecycle:
  preStop:
    exec:
      command:
        - /bin/sh
        - -c
        - "curl -X DELETE your_nacos_ip:8848/nacos/v1/ns/instance?serviceName=nacos.test.1&ip=${POD_IP}&port=8880&clusterName=DEFAULT" && sleep 30

4.4 Pod的终止流程

https://cloud.google.com/blog/products/containers-kubernetes/kubernetes-best-practices-terminating-with-grace
https://kubernetes.io/zh-cn/docs/concepts/workloads/pods/pod-lifecycle/#pod-termination

(1)创建pod
向API-Server提交创建请求、API-Server完成鉴权和准入并将事件写入etcd
kube-scheduler完成调度流程
kubelet创建并启动pod、然后执行postStart(有钩子才会执行)
周期进行livenessProbe(有探针才会执行)
进入running状态
readinessProbe(有探针才会执行)检测通过后,service关联pod接受客户端请求


(2)删除pod
向API-Server提交删除请求、API-Server完成鉴权和准入并将事件写入etcd
Pod被设置为”Terminating”状态(terminationGracePeriodSeconds参数控制,默认30s)、从service的Endpoints列表中删除并不再接受客户端请求。


pod执行PreStop(有钩子才会执行)
kubelet向pod中的容器发送SIGTERM信号(正常终止信号)终止pod里面的主进程,这个信号让容器知道自己很快将会被关闭
terminationGracePeriodSeconds: 60 #可选终止等待期(pod删除宽限期),如果有设置删除宽限时间,则等待宽限时间到期,否则最多等待30s,Kubernetes等待指定的时间称为优雅终止宽限期,默认情况下是30秒,值得注意的是 “等待期与preStop Hook和SIGTERM信号” 并行执行,即Kubernetes可能不会等待preStop Hook完成(最长30秒之后主进程还没有结束就就强制终止pod)。
SIGKILL信号被发送到Pod,并删除Pod。

在这里插入图片描述
在这里插入图片描述

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Pod 处于 CrashLoopBackOff 状态通常是由于容器在启动后立即崩溃或退出导致的。kube-proxy 是 Kubernetes 中的一个组件,负责实现集群内部的网络代理和负载均衡功能。当 kube-proxy 所在的 Pod 处于 CrashLoopBackOff 状态时,可能会导致集群内部的网络通信出现问题。 要解决 kube-proxy Pod 的 CrashLoopBackOff 状态,可以按照以下步骤进行排查和修复: 1. 查看 Pod 的日志:使用 kubectl logs 命令查看 kube-proxy Pod 的日志,可以获取更多关于崩溃原因的信息。例如,执行以下命令获取 kube-proxy Pod 的日志: ``` kubectl logs <kube-proxy-pod-name> -n <namespace> ``` 2. 检查容器配置:检查 kube-proxy 容器的配置是否正确。确保容器的启动命令、环境变量和配置文件等都正确设置。 3. 检查资源限制:检查 kube-proxy Pod 的资源限制是否过高,可能导致 Pod 在启动时无法满足资源需求而崩溃。可以尝试调整资源限制或增加集群的资源配额。 4. 检查依赖组件:检查 kube-proxy 所依赖的其他组件(如 kubelet、etcd 等)是否正常运行。如果依赖组件出现故障或配置错误,可能会导致 kube-proxy Pod 无法正常启动。 5. 检查网络配置:检查集群的网络配置是否正确,包括网络插件、网络策略等。错误的网络配置可能导致 kube-proxy Pod 无法正常工作。 6. 重启 kube-proxy Pod:如果以上步骤都没有解决问题,可以尝试删除并重新创建 kube-proxy Pod。执行以下命令删除 kube-proxy Pod: ``` kubectl delete pod <kube-proxy-pod-name> -n <namespace> ``` 以上是解决 kube-proxy Pod 处于 CrashLoopBackOff 状态的一般步骤,具体的解决方法可能因实际情况而异。如果问题仍然存在,建议查看更详细的日志信息或向 Kubernetes 社区寻求帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值