存活探针(Liveness)、就绪探针(Readiness)、启动探针(Startup)
就绪探针与存活探针的最大区别
存活探针是将检查失败的容器杀死,创建新的启动容器来保持pod正常工作;
就绪探针是,当就绪探针检查失败,并不重启容器,而是将pod移出服务,就绪探针确保服务中的pod都是可用的,确保客户端只与正常的pod交互并且客户端永远不会知道系统存在问题。
一、存活探针(Liveness Probe)
存活探针
用于判断容器是否存活(running状态),如果LivenessProbe探针探测到容器不健康,则kubelet杀掉该容器,并根据容器的重启策略做相应的处理。如果一个容器不包含LivenessProbe探针,则kubelet认为该容器的LivenessProbe探针返回的值永远是“Success”。
探测机制
Kubernetes支持如下三种探测机制。
-
HTTP GET:向容器发送HTTP GET请求,如果Probe收到2xx或3xx,说明容器是健康的。
-
TCP Socket:尝试与容器指定端口建立TCP连接,如果连接成功建立,说明容器是健康的。
-
Exec:Probe执行容器中的命令并检查命令退出的状态码,如果状态码为0则说明容器是健康的。
HTTP GET (生产环境建议使用 httpGet探针 进行探测)
HTTP GET方式是最常见的探测方法,其具体机制是向容器发送HTTP GET请求,如果Probe收到2xx或3xx,说明容器是健康的,定义方法如下所示。
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: rs-nginx-http
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: nginx-rs
matchExpressions:
- {
key: env, operator: In, values: [dev]}
template:
metadata:
labels:
app: nginx-rs
env: dev
spec:
containers:
- image: nginx:1.7.9
name: nginx-container
ports:
- containerPort: 80
livenessProbe: #为容器定义一个存活探针
httpGet: #探针类型为httpGet探针
# host: 10.244.0.49 #指定主机,默认是pod的ip,一般省略不写
path: / #路径
port: 80 #端口
initialDelaySeconds: 15 #初始延时时间为15s
periodSeconds: 5 #探测周期
timeoutSeconds: 2 #超时时间
failureThreshold: 9 #失败次数
存活探针属性说明
initialDelaySeconds:表示在容器启动后延时多久秒才开始探测;
periodSeconds:表示执行探测的频率,即间隔多少秒探测一次,默认间隔周期是10秒,最小1秒;
timeoutSeconds:表示探测超时时间,默认1秒,最小1秒,表示容器必须在超时时间范围内做出响应,否则视为本次探测失败;
successThreshold:表示最少连续探测成功多少次才被认定为成功,默认是1,对于liveness必须是1,最小值是1;
failureThreshold:表示连续探测失败多少次才被认定为失败,默认是3,连续3次失败,k8s 将根据pod重启策略对容器做出决定;
注意:定义存活探针时,一定要设置initialDelaySeconds属性,该属性为初始延时,如果不设置,默认容器启动时探针就开始探测了,这样可能会存在应用程序还未启动就绪,就会导致探针检测失败,k8s就会根据pod重启策略杀掉容器然后再重新创建容器的莫名其妙的问题。
在生产环境中,一定要定义一个存活探针。
exec探针
exec探针是通过在容器内执行shell命令,根据命令退出状态码是否为0判定成功失败;
[root@master ~]# cat rs_nginx.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: rs-nginx-http
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: nginx-rs
matchExpressions:
- {
key: env, operator: In, values: [dev]}
template:
metadata:
labels:
app: nginx-rs
env: dev
spec:
containers:
- image: nginx:1.7.9
name: nginx-container
ports:
- containerPort: 80
livenessProbe: #定义探针
exec: #探针类型为exec探针
command:
- cat #表示cat /usr/share/nginx/html/index.html文件,根据命令执行
- /usr/share/nginx/html/index.html #结果返回状态是否非0来表示探针状态
initialDelaySeconds: 8 #初始延时,表示容器启动15秒后才开始探测
periodSeconds: 3 #探测周期,3秒探测一次
timeoutSeconds: 2 #超时时间为2秒,表示必须2秒内做出回应,否则将视本次探测失败
failureThreshold: 1 #连续失败次数,表示连续失败1次就定义为失败,k8s将根据pod重启机制
#做出是否重启容器的就决定
#下面将进入容器内部删除 /usr/share/nginx/html/index.html文件,看探针是否生效
[root@master ~]# kubectl exec rs-nginx-http-2rng2 -it -- bash #进入容器
root@rs-nginx-http-2rng2:/# rm -rf /usr/share/nginx/html/index.html #删除/usr/share/nginx/html/index.html
root@rs-nginx-http-2rng2:/# exit #退出容器
[root@master ~]# kubectl get pods #查看pod
NAME READY STATUS RESTARTS AGE
pod/rs-nginx-http-2rng2 1/1 Running 1 (11s ago) 74s #发现pod的容器重启过一次
pod/rs-nginx-http-bgr4m 1/1 Running 0 74s
pod/rs-nginx-http-cv9bv 1/1 Running 0 74s
[root@master ~]# kubectl describe pod/rs-nginx-http-2rng2 #查看pod信息,可以看出探针探测失败,容器被重新启动了
................
Restart Count: 1
Liveness: exec [cat /usr/share/nginx/html/index.html] delay=8s timeout=2s period=3s #success=1 #failure=1
................................
Normal Pulled 9m32s (x2 over 10m) kubelet Container image "nginx:1.7.9" already present on machine
Normal Created 9m32s (x2 over 10m) kubelet Created container nginx-container
Warning Unhealthy 9m32s kubelet Liveness probe failed: cat: /usr/share/nginx/html/index.html: No such file or directory
Normal Killing 9m32s kubelet Container nginx-container failed liveness probe, will be restarted
Normal Started 9m31s (x2 over 10m) kubelet Started container nginx-container
[root@master ~]#
tcpSocket探针
tcpSocket探针,根据容器的IP地址、端口发起tcp Socket链接,探测是否能成功与容器的端口建立tcp Socket链接;
[root@master ~]# cat rs_nginx.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: rs-nginx-http
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: nginx-rs
matchExpressions:
- {
key: env, operator: In, values: [dev]}
template:
metadata:
labels:
app: nginx-rs
env: dev
spec:
containers:
- image: nginx:1.7.9
name: nginx-container
ports:
- containerPort: 80
livenessProbe: #定义存活探针
tcpSocket: #探针类型为tcpSocket探针
# host: 10.244.0.49 #指定主机,默认是pod的ip,一般省略不写
port: 80 #探测与80端口是否能成功建立tcp链接
initialDelaySeconds: 8
periodSeconds: 3
timeoutSeconds: 2
failureThreshold: 1
二、就绪探针(Readiness Probe)
就绪探针
用于判断容器是否启动完成(ready状态),可以接收请求。如果ReadinessProbe探针检测到失败,则Pod的状态被修改。Endpoint Controller将从Service的Endpoint中删除包含该容器所在Pod的Endpoint。
我们知道,当一个pod启动后,就会立即加入service的endpoint ip列表中,并开始接收到客户端的链接请求,假若此时pod中的容器的业务进程还没有初始化完毕,那么这些客户端链接请求就会失败,为了解决这个问题,kubernetes提供了就绪探针来解决这个问题的。
在pod中的容器定义一个就绪探针,就绪探针周期性检查容器,如果就绪探针检查失败了,说明该pod还未准备就绪,不能接受客户端链接,则该pod将从endpoint列表中移除,被剔除了service就不会把请求分发给该pod,然后就绪探针继续检查,如果随后容器就绪,则再重新把pod加回endpoint列表。
务必定义就绪探针
首先,如果没有定义就绪探针,那么新创建的pod就会立即加入到service的endpoint列表,如果容器里的业务程序需要很长时间才能开始处理传入的链接,而此时service又将客户端连接转发给了该pod,那么客户端就会看到“连接被拒绝”等类型的错误,所以,为每个容器定义一个就绪探针是很有必要的,即使是定义一个简单的http get 探针。
在生产环境中,一般会让开发提供容器的健康检查接口,在spring boot已经有原生的健康检查接口,所有然开发定义健康检查接口后我们再使用http get方法来定义我们的探针。
就绪探针的三大类型
就绪探针也有三种类型,exec,httpGet和tcpSocket。
exec:执行容器中的命令并检查命令退出的状态码,如果状态码为0则说明容器已经准备就绪;
httpGet:向容器的ip,端口、路径发送http get请求,通过响应的http状态码是否位于200-400之间判断容器是否准备就绪;
tcpSocke:向容器的IP地址、端口发起tcp socket链接,如果能正常建立链接,则认为容器已经准备就绪。
就绪探针的属性
就绪探针的附加属性有以下几个:
initialDelaySeconds:延时秒数,即容器启动多少秒后才开始探测,不写默认容器启动就探测;
periodSeconds :执行探测的频率(秒),默认为10秒,最低值为1;
timeoutSeconds :超时时间,表示探测时在超时时间内必须得到响应,负责视为本次探测失败,默认为1秒,最小值为1;
failureThreshold :连续探测失败的次数,视为本次探测失败,默认为3次,最小值为1次;
successThreshold :连续探测成功的次数,视为本次探测成功,默认为1次,最小值为1次;
创建一个exec存活探针
exec存活探针,执行容器中的命令并检查命令退出的状态码,如果状态码为0则说明容器已经准备就绪;
下面使用deployment部署3个有exec就绪探针的pod(service已经存在了),如下所示:
[root@master ~]# cat deplyment_nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-nginx
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx:1.7.9
name: nginx-container
readinessProbe: #定义exec探针
initialDelaySeconds: 5 #容器启动5秒后才开始探测
periodSeconds: 10 #探针周期为10s探测一次
timeoutSeconds: 2 #超时时间,2秒得不到响应则视为探测失败
failureThreshold: 3 #连续探测失败3次,视为本次探测失败
successThreshold: 1 #探测成功1次则视为本次探测成功
exec: #探针类型为exec
command: #执行的命令是ls /var/ready
- ls
- /var/ready
ports:
- name: http
containerPort: 80
[root@master ~]# kubectl get pods #查看pod,发现没有一个是ready状态的
NAME READY STATUS RESTARTS AGE
deployment-nginx-68bb45dd46-5rj7c 0/1 Running 0 3m1s
deployment-nginx-68bb45dd46-78ld2 0/1 Running 0 3m1s
deployment-nginx-68bb45dd46-gnnhn 0/1 Running 0 3m1
[root@master ~]# kubectl describe pods deployment-nginx-68bb45dd46-5rj7c |tail -n 3 #查看某个pod的详细信息,显示存活探针检测失败了
Normal Created 5m7s kubelet Created container nginx-container
Normal Started 5m7s kubelet Started container nginx-container
Warning Unhealthy 2m18s (x22 over 5m6s) kubelet Readiness probe failed: ls: cannot access /var/ready: No such file or directory
[root@master ~]#
[root@master ~]# kubectl get ep svc-rc-nginx-nodeport #查看service的endpoint列表,显示没有任何pod ip列表可用
NAME ENDPOINTS AGE
svc-rc-nginx-nodeport 6h32m
# 现在,我们手动在某个pod中创建一个/var/ready文件,这样pod就会处于准备就绪状态,service就能成功添加该pod
[root@master ~]# kubectl exec deployment-nginx-68bb45dd46-5rj7c -- touch /var/ready #为该pod创建/var/ready文件
[root@master ~]# kubectl get pods,ep -o wide #查看该pod,发现pod已处于就绪状态
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/deployment-nginx-68bb45dd46-5rj7c 1/1 Running 0 8m52s 10.244.1.77 node1 <none>
pod/deployment-nginx-68bb45dd46-78ld2 0/1 Running 0 8m52s 10.244.1.76 node1 <none>
pod/deployment-nginx-68bb45dd46-gnnhn 0/1 Running 0 8m52s 10.244.2.38 node2 <none>
NAME ENDPOINTS AGE #endpoint已经有该pod的ip端口
endpoints/svc-rc-nginx-nodeport 10.244.1.77:80 6h36m
[root@master ~]#
创建一个httpGet存活探针
httpGet存活探针,向容器发送http get请求,通过响应的http状态码判断容器是否准备就绪;
下面使用deployment部署3个有httpGet就绪探针的pod,如下所示:
..........
containers:
- image: nginx:1.7.9
name: nginx-container
readinessProbe: #定义探针
httpGet: # 探针类型为httpGet
# host: 10.244.0.49 #指定主机,默认是pod的ip,一般省略不写
path: /read
port: 80
...........
创建一个tcpSocket存活探针
tcpSocket存活探针,打开一个tcp连接到容器的指定端口,如果连接已建立,则认为容器已经准备就绪。
下面使用deployment部署有tcpSocket就绪探针的pod,如下所示:
..........
containers:
- image: nginx:1.7.9
name: nginx-container
readinessProbe: #定义探针
tcpSocket: # 探针类型为tcpSocket
# host: 10.244.0.49 #指定主机,默认是pod的ip,一般省略不写
port: 80
...........
三、启动探针(StartupProbe)
启动探针
指示容器中的应用是否已经启动。如果提供了启动探针(startup probe),则禁用所有其他探针,直到它成功为止。如果启动探针失败,kubelet 将杀死容器,容器服从其重启策略进行重启。如果容器没有提供启动探针,则默认状态为成功Success。
startupProbe 启动探针,startupProbe探针是1.16版本加入的探针,用于判断容器进程是否已经启动,是为了解决程序启动时间很长,启动慢等问题的,当配置了startupProbe启动探针,会先禁用其他探针,直到startupProbe探针成功,成功后将退出不在进行探测,如果startupProbe探针探测失败,pod将会重启。