使用Pod探针让服务更可靠
在默认情况下,Kubernetes启动Pod成功后,便认为它是可用的,Service会将Pod加入服务,流量就会进入到启动的Pod中。
这其实会造成一些服务不可靠的情况,比如:
- 当我们用Deployment滚动升级的过程中,会遇到服务短暂性不可用,然后又恢复了。一个web服务,可能会出现502 Bad Gateway的一瞬间。
- 当一个Pod运行了一段时间后,应用程序由于各种原因已经处于不可用状态,需要重启,然而Pod还存活着,Kubernetes依旧认为它是可用的。
- 应用程序并不能成功启动,导致Pod在启动后又挂掉,陷入一个不断循环的过程。
可以看出,一个服务可不可用,并不能单纯地使用是否启动成功作为判断,对此,k8s有Pod专门的探针来检测。
探针的类型
探针有两种,Liveness
和Readiness
,通过官网的介绍,我们明确得到:
- Liveness: 让kubelet知道什么时候重启容器。比如,可以解决当一个应用程序虽然处于运行状态,实际却无法提供服务的情况。
- Readniess:让kubelet知道容器是否已经准备好接受流量。Service的负载均衡会使用这个状态来决定是否将Pod作为服务的后端,或者什么时候将其剔除。
如何配置探针
首先我们要先理解好两种探针的区别,清楚我们的目的是什么,想要达到什么样的效果,然后配置对应的探针。
两种探针在配置上是一样的,只是配置的名字不同而已,我们这里只列出Liveness怎么配置。
因为Pod可以配置多个Container,所以探针的具体配置是在每个Container之中。
探针有三种试探方式:
- exec:执行命令
- httpGet:使用HTTP请求
- tcpSocket:使用TCP检测
下面三个探针方式的配置例子来自k8s官网。
用命令来检测
exec是通过执行命令来检测,命令执行成功时返回0,则认为探测成功。
下面的配置是用exec作为探测的例子:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-exec
spec:
containers:
- name: liveness
image: k8s.gcr.io/busybox
args:
- sh
- -c
- touch 30; rm -rf healthy; sleep 600 healthy; sleep
livenessProbe:
exec:
command:
- cat
- healthy
initialDelaySeconds: 5
periodSeconds: 5
容器启动时,会生成/tmp/healthy
文件,然后在30秒后,将文件删除,并且先别退出,等待600秒。
liveness的配置中,initialDelaySeconds指定了启动容器后先等待5秒,然后再执行探针,periodSeconds代表执行探针的频率,这里是5秒一次。
具体的执行过程这里就不展示了,从结果上看:启动后的30秒内,探针的检测都是正常的,在第35秒后,会显示liveness探针失败,容器被删掉并重建。
用HTTP请求检测
还可以用http get请求作为检测:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-http
spec:
containers:
- name: liveness
image: k8s.gcr.io/liveness
args:
- /server
livenessProbe:
httpGet:
path: /healthz
port: 8080
httpHeaders:
- name: Custom-Header
value: Awesome
initialDelaySeconds: 3
periodSeconds: 3
对于httpGet探针来说,返回状态码在200到400间,就会认为是成功的。状态码没有更改选项
。
该程序的源码如下:1
2
3
4
5
6
7
8
9
10http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
duration := time.Now().Sub(started)
if duration.Seconds() > 10 {
w.WriteHeader(500)
w.Write([]byte(fmt.Sprintf("error: %v", duration.Seconds())))
} else {
w.WriteHeader(200)
w.Write([]byte("ok"))
}
})
代码可以看出,在程序启动的10秒内都是正常的,10秒后,会返回500的状态码,这个时候,探针会失败,容器将被杀掉并重启。
用TCP连接检测
使用TCP进行检测的方式是,只要通过指定的端口,能成功建立socket,则认为是成功的,否则认为失败。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22apiVersion: v1
kind: Pod
metadata:
name: goproxy
labels:
app: goproxy
spec:
containers:
- name: goproxy
image: k8s.gcr.io/goproxy:0.1
ports:
- containerPort: 8080
readinessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 15
periodSeconds: 20
在这个例子里,同时存在了readinessProbe和livenessProbe,它们都是一样的,只要端口8080能成功建立连接,探针便是成功的。
使用命名端口
这个配置是针对httpGet和tcpSocket探针的,对于上面的port配置,都是配置一个具体端口号,我们也可以通过ContainerPort来配置它。比如:1
2
3
4
5
6
7
8
9ports:
- name: liveness-port
containerPort: 8080
hostPort: 8080
livenessProbe:
httpGet:
path: /healthz
port: liveness-port
其他配置参数
从上面的例子我们看到了探针的一些其他配置参数,这里列出探针的所有具体配置项:
配置项 | 描述 |
---|---|
initialDelaySeconds | 探针在容器启动后的多少秒才开始执行 |
periodSeconds | 探针执行频率。默认是10秒,最小1秒。 |
timeoutSeconds | 探测超时时间。默认1秒,最小1秒。 |
successThreshold | 探测失败后,最少连续探测成功多少次才被认定为成功。默认是1。对于liveness必须是1。最小值是1。 |
failureThreshold | 探测成功后,最少连续探测失败多少次才被认定为失败。默认是3。最小值是1。 |
HTTP probe 中可以给 httpGet设置其他配置项:
配置项 | 描述 |
---|---|
host | 连接的主机名,默认连接到pod的IP。你可能想在http header中设置”Host”而不是使用IP。 |
scheme | 连接使用的schema,默认HTTP。 |
path | 访问的HTTP server的path。 |
httpHeaders | 自定义请求的header。HTTP运行重复的header。 |
port | 访问的容器的端口名字或者端口号。端口号必须介于1和65535之间。 |
总结
到这里,探针的相关内容都已经列出来了。我们要明确两种探针对应着什么样的效果:
- Liveness: 让kubelet知道什么时候重启容器。比如,可以解决当一个应用程序虽然处于运行状态,实际却无法提供服务的情况。
- Readniess:让kubelet知道容器是否已经准备好接受流量。Service的负载均衡会使用这个状态来决定是否将Pod作为服务的后端,或者什么时候将其剔除。
让它们相互之间配合,让我们的服务更加可靠。
参考
Configure Liveness and Readiness Probes
配置Pod的liveness和readiness探针
- 本文链接:https://keepmoving.ren/kubernetes/use-pod-probe/
- 版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 CN 许可协议。转载请注明出处!