K8S动手教程2.5:Pod健康检查

内容摘要

健康检查


在前面讲解容器的时候,讲到了容器的自动重启特性,K8S也提供了该特性,并做了加强。Pod使用健康检查来保证容器的可用性,健康检查可以保证Pod保持可用性,能使业务达到几乎无间断使用。下面我们通过实验给大家展示该特性。


测试环境

参考前面章节,创建两节点K8S集群。1个作为控制节点,1个作为主节点。


测试镜像构建

Dockerfile配置如下:

FROM node:7
ADD app.js /app.js
ENTRYPOINT ["node", "app.js"]

app.js文件内容如下:

const http = require('http');
const os = require('os');​
console.log("server starting...");​
var requestCount = 0;​
var handler = function(request, response) {
console.log("Received request from " + request.connection.remoteAddress);
requestCount++;
if (requestCount > 3) {
response.writeHead(500);
response.end("I'm not well. Please restart me!");

return;
}
response.writeHead(200);
response.end("You've hit " + os.hostname() + "\\n");
};​
var www = http.createServer(handler);
www.listen(8080);

上面的程序当访问超过3次时,报500错误。

构建镜像,名字为health_image:latest,记得推送到自己的仓库。

注意:由于现在是两节点K8S集群,如果想要测试比较顺畅,建议在两个节点都构建镜像。


创建Pod

配置Pod yaml文件,内容为:

apiVersion: v1
kind: Pod
metadata:
name: health1
spec:
containers:
- image: huqianakls/health_image:latest
name: health1
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
protocol: TCP
livenessProbe:
httpGet:
path: /
port: 8080

配置说明:

livenessProbe下就是健康检查配置,它也被叫做存储探针。httpGet表示使用http的方式检查容器是否健康,path是访问路径。从配置可以看出,健康检查会访问app.js文件中接口,该接口在访问3次以后,会返回500错误,此时容器会处于不正常状态。

运行该Pod,观察健康检查如何发生作用。

观察步骤如下:

1、运行起来以后,等待容器状态变为Runing;

2、等待一段时间后,使用kubectl describe 和 kubectl get pod命令查看Pod;

K8S动手教程2.5:Pod健康检查

注意RESTARTS列,表示重启次数,大概在1分钟的时候,容器重启了一次。

查询详情,结果如下:

[root@K8S001 test]# kubectl describe pod health1
Name: health1
Namespace: default
Node: k8s002/172.18.152.17
Start Time: Wed, 25 Sep 2019 17:02:40 +0800
Labels: <none>
Annotations: <none>
Status: Running
IP: 192.168.3.68
Containers:
health1:
Container ID: docker://392a855539b87a97daece7a2e266672f24526e6b9480b84a0ac8c90b085afc5e
Image: huqianakls/health_image:latest
Image ID: docker://sha256:3a39fed53d94518c36ad96f7c38ae6e400307000f89db7165b4e937689da77b6
Port: 8080/TCP
Host Port: 0/TCP
State: Running
Started: Wed, 25 Sep 2019 17:05:37 +0800
Last State: Terminated
Reason: Error
Exit Code: 137
Started: Wed, 25 Sep 2019 17:04:07 +0800
Finished: Wed, 25 Sep 2019 17:05:37 +0800
Ready: True
Restart Count: 2
Liveness: http-get http://:8080/ delay=0s timeout=1s period=10s #success=1 #failure=3
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-6fqw2 (ro)
Conditions:
Type Status
Initialized True
Ready True
PodScheduled True
Volumes:
default-token-6fqw2:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-6fqw2
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>

Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 4m default-scheduler Successfully assigned health1 to k8s002
Normal SuccessfulMountVolume 4m kubelet, k8s002 MountVolume.SetUp succeeded for volume "default-token-6fqw2"
Normal Pulled 1m (x3 over 4m) kubelet, k8s002 Container image "huqianakls/health_image:latest" already present on machine
Normal Created 1m (x3 over 4m) kubelet, k8s002 Created container
Normal Started 1m (x3 over 4m) kubelet, k8s002 Started container
Normal Killing 1m (x2 over 2m) kubelet, k8s002 Killing container with id docker://health1:Container failed liveness probe.. Container will be killed and recreated.
Warning Unhealthy 23s (x9 over 3m) kubelet, k8s002 Liveness probe failed: HTTP probe failed with statuscode: 500
/<none>/<none>/<none>/<none>

说明:

1、注意上面的Last State属性,显示了上一次容器最后的状态。退出码是137,表示容器错误退出,137是由128+9得到,这说明容器是由外部信号终止,9是SIGKILL的信号编号,表示该容器被强制停止。

2、Events属性下的信息,最后一行明确说明该容器的状态码是500,健康检查失败,容器失败。

3、Liveness属性,是健康检查策略策略,这里配置为:

http-get http://:8080/ delay=0s timeout=1s period=10s #success=1 #failure=3

这些参数我们没有配置,是默认的。


存活探针策略

策略主要包括以下参数:

initialDelaySeconds:kubelet系统组件初次检查Pod延迟时间,比如配置5秒,表示kubelet等待5秒后,才做健康检查。如果设置为0,表示容器启动后就启动检查;

periodSeconds:检查时间间隔,即隔多少时间后,检查一次,最小值为1,默认值为10。上面的Pod中,period就是10;

timeoutSeconds:检查超时时间,如果超过该时间,即为失败,最小值为1,默认值为1;

successThreshold:成功阈值,最小值默认值都是1,对于Liveness而言,必须为1;

failureThreshold:允许失败次数,在确定容器不正常需要重启容器时,允许失败的次数,超过它,容器会重启。最小值为1,默认值为3。

下面举例实验一下上面的参数。

创建Pod,配置内容为:

apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-exec
spec:
containers:
- name: liveness
image: busybox:musl
args:
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5

livenessProbe 参数下给的是另一种检查方式:命令,通过检查命令的退出码确定是否健康,退出码为0表示健康,其他退出码表示失败。

上面的配置通过判断/tmp/healthy文件是否存在判断Pod是否健康。

容器的启动命令会创建该文件,但是30秒后,会删除,容器之后会重启。


健康检查方式

上面已经使用了两种健康检查方式,下面我们梳理一下:

1、http get

访问容器的IP地址,发送http get请求,如果响应状态码为2XX或者3XX,那么就认为该容器健康,否则认为失败,重启容器;

2、exec

执行命令,通过退出码判断容器是否健康,为0表示健康,其他表示失败;

3、TCP

通过与容器指定端口建立TCP连接来判断容器是否健康,如果连接成功,则容器健康,否则重启容器。

下面我们测试下第3中方式:

创建Pod,配置为:

apiVersion: v1
kind: Pod
metadata:
name: health2
spec:
containers:
- image: httpd
name: health2
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
protocol: TCP
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 15
periodSeconds: 20

该容器暴露的端口为80,我们的存活探针配置的是8080,因此健康检查失败。

运行该Pod,过会儿查询该容器:

K8S动手教程2.5:Pod健康检查

该容器已经重启了两次。

查询该Pod详情,结果如下:

[root@K8S001 test]# kubectl describe pod health2
Name: health2
Namespace: default
Node: k8s002/172.18.152.17
Start Time: Wed, 25 Sep 2019 18:44:41 +0800
Labels: <none>
Annotations: <none>
Status: Running
IP: 192.168.3.71
Containers:
health2:
Container ID: docker://c6046bf54f46b7b1ac786b77afa17be4122594644ca1f7383e5ad8f1d25eb4ba
Image: httpd
Image ID: docker-pullable://httpd@sha256:39d7d9a3ab93c0ad68ee7ea237722ed1b0016ff6974d80581022a53ec1e58797
Port: 80/TCP
Host Port: 0/TCP
State: Running
Started: Wed, 25 Sep 2019 18:51:13 +0800
Last State: Terminated
Reason: Completed
Exit Code: 0
Started: Wed, 25 Sep 2019 18:50:33 +0800
Finished: Wed, 25 Sep 2019 18:51:13 +0800
Ready: True
Restart Count: 5
Liveness: tcp-socket :8080 delay=15s timeout=1s period=20s #success=1 #failure=3
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-6fqw2 (ro)
Conditions:
Type Status
Initialized True
Ready True
PodScheduled True
Volumes:
default-token-6fqw2:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-6fqw2
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s

node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 6m default-scheduler Successfully assigned health2 to k8s002
Normal SuccessfulMountVolume 6m kubelet, k8s002 MountVolume.SetUp succeeded for volume "default-token-6fqw2"
Normal Pulling 6m kubelet, k8s002 pulling image "httpd"
Normal Pulled 3m kubelet, k8s002 Successfully pulled image "httpd"
Normal Created 1m (x4 over 3m) kubelet, k8s002 Created container
Normal Started 1m (x4 over 3m) kubelet, k8s002 Started container
Normal Killing 1m (x3 over 2m) kubelet, k8s002 Killing container with id docker://health2:Container failed liveness probe.. Container will be killed and recreated.
Normal Pulled 1m (x3 over 2m) kubelet, k8s002 Container image "httpd" already present on machine
Warning Unhealthy 44s (x9 over 3m) kubelet, k8s002 Liveness probe failed: dial tcp 192.168.3.71:8080: getsockopt: connection refused
/<none>/<none>/<none>/<none>

从Event属性可以看出,重启原因是无法联通8080端口。

Last State属性内容为: Liveness: tcp-socket :8080 delay=15s timeout=1s period=20s #success=1 #failure=3

可以看出此时的健康检查方式是tcp。


Kubelet

Kubelet是具体操控存活探针的系统组件,该组件在每个节点上都有,并且相互之间没有直接联系。kubelet也会具体管理Pod的运行重启等。每个节点管理的Pod是不同的。

下面们做个实验,停止运行Pod的节点,看容器是否可以重启。

上面我们的应用都被调度到k8s002工作节点,下面我们删除该节点,大家可以在阿里云上释放该节点,之后,我们在在控制节点查看Pod,结果如下:

K8S动手教程2.5:Pod健康检查

大家可以看到,health2重启次数为7次,不管你隔多久时间查询,你会发现这个次数不会变,仍旧是7,说明该Pod之后再也没有重启。原因是该Pod由k8s002节点上的Kubelet管理,现在该节点被删除了,因此,不会再重启该容器。

从这里可以也可以看出,还需要更好的机制来解决这个问题,在节点出问题后,该节点上的容器能够在其他节点运行起来。K8S提供了这种机制,即副本控制器。下节我们将进入该内容的学习。


实验

1、创建Pod,使用存活探针;

2、观察存活探针工作机制;


分享到:


相關文章: