Kubernetes中几种常见的健康检查机制
时间:2023-09-11 08:07:00
为了防止生产环境中的生产环境pod突然挂断,通常需要搭配一些安全策略!
三大探针
K8s中对于pod资源对象的健康状况检测提供了三种类型probe(探针)执行对pod健康监测:
1) livenessProbe探针
可根据用户自定义规则确定pod如果livenessProbe探针发现容器不健康,kubelet如果一个容器不包启策略来决定。如果不包括容器livenessProbe探针,则kubelet会认为容器livenessProbe探针的返回值总是成功的。
2) readinessProbe探针
也可以根据用户的自定义规则来判断pod如果检测失败,控制器是否健康pod从对应service的endpoint删除列表中的任何请求将不再调度到此Pod直到下一次探测成功。
3) startupProbe探针(主要用于容器中的服务启动缓慢,但被其他两个指针重启)
启动检查机制,应用一些启动缓慢的业务,避免业务长时间启动而被上面两类探针kill掉下来,这个问题也可以用另一种方式解决,也就是说,在定义上述两种探针机制时,期定义初始化时间。在所有其他探针被推迟之前,可以定义一个启动探针 Pod 完成启动。
在这个时候我们把startupProbe和livenessProbe结合使用可以在很大程度上解决我们的问题。
每种检测方法可支持以下相同的检测参数控制检查时间
:
initialDelaySeconds:第一次用启动时间的初始第一次探测间隔,防止健康检查失败;
periodSeconds:检查间隔,执行多久probe默认检查为10s;
timeoutSeconds:检查超时长度,检测应用程序timeout后为失败;
successThreshold:成功探测阈值意味着检测多少次健康正常,默认检测一次;
支持以下三种探测方法:
1)Exec:
通过执行命令的方式来检查服务是否正常,比如使用cat命令查看pod是否存在重要的配置文件,如果存在,则表示pod健康。反之亦然。
Exec探测方式的yaml文件语法如下:
spec: containers: – name: liveness image: k8s.gcr.io/busybox args: – /bin/sh – -c – touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600 livenessProbe: #选择livenessProbe的探测机制 exec: #执行下列命令 command: – cat – /tmp/healthy initialDelaySeconds: 5 在容器运行5秒后开始探测 periodSeconds: 5 #每次检测的时间间隔为5秒
在上述配置文件中,如果容器运行5秒后每5秒检测一次,则检测机制为cat命令返回的值为0,表示健康,非0则表示异常。
2)Httpget:
通过发送http/https请求检查服务是否正常,返回状态码为200-399表示容器健康(注)http get类似于命令curl -I)。
Httpget探测方式的yaml文件语法如下:
spec: containers: – name: liveness image: k8s.gcr.io/liveness livenessProbe: #采用livenessProbe机制探测 httpGet: #采用httpget的方式 scheme:HTTP #也支持指定协议https path: /healthz #检测是否可以访问网页根目录healthz网页文件 port: 8080 #监控端口为8080 initialDelaySeconds: 3 3秒后,开始探测 periodSeconds: 3 #检测频率为3秒
在上述配置文件中,探测方法发送到项容器HTTP GET请求是8080端口下的请求healthz文件,返回任何大于或等于200和小于400的状态代码表示成功。任何其他代码表示异常。
3)tcpSocket:
通过容器的IP和Port执行TCP检查,如果能够建立TCP连接表明容器是健康的HTTPget探测机制有些相似,tcpsocket适用于健康检查TCP业务。
tcpSocket探测方式的yaml文件语法如下:
spec: containers: – name: goproxy image: k8s.gcr.io/goproxy:0.1 ports: – containerPort: 8080 #这里使用了两种探测机制,都是为了建立容器的8080端口TCP连接 readinessProbe: tcpSocket: port: 8080 initialDelaySeconds: 5 periodSeconds: 10 livenessProbe: tcpSocket: port: 8080 initialDelaySeconds: 15 periodSeconds: 20
在上述的yaml在配置文件中,使用了两种探针,容器启动5秒后,kubelet第一个将被发送readinessProbe如果检测成功,探针将连接到容器的8080端口pod为了健康,十秒后,kubelet第二次连接。
除了readinessProbe探针外,容器启动15秒后,kubelet第一个将被发送livenessProbe如果连接失败,探针仍然试图连接容器的8080端口。
探针探测的结果无非是以下三者之一:
? Success:Container通过检查;
? Failure:Container检查不合格;
? Unknown:没有检查,所以没有采取任何措施(通常我们没有定义探针检测,默认为成功)。
如果以上不够透彻,可以移动其官网文档:Kubernetes.io
滚动更新
每一次只更新给定副本当中的一小部分的副本,直到所有副本更新完成(不需停机,保证了副本的可用性
)
[root@server1 ~]# vim httpdv1.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpd
spec:
selector:
matchLabels:
run: httpd
revisionHistoryLimit: 10 #当前版本最多向前回滚10个version
replicas: 3
template:
metadata:
labels:
run: httpd
spec:
containers:
- name: httpd
image: httpd:2.4.37
ports:
- containerPort: 80
[root@server1 ~]# cp httpdv1.yml httpdv2.yml && cp httpdv1.yml httpdv3.yml
[root@server1 ~]# cat httpdv2.yml | grep image
image: httpd:2.4.38
[root@server1 ~]# tail httpdv3.yml | grep image
image: httpd:2.4.39
[root@server1 ~]# kubectl apply -f httpdv1.yml --record --record:在滚动更新结束以后会被记录下来
[root@server1 ~]# kubectl get pods -o wide
[root@server1 ~]# kubectl get deployments.apps httpd -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
httpd 3/3 3 3 2m51s httpd httpd:2.4.37 run=httpd
版本更新
[root@server1 ~]# kubectl apply -f httpdv2.yml
[root@server1 ~]# kubectl get pods -o wide -w
httpd-789c766d45-qrwm2 0/1 Terminating 0 6m37s 10.244.1.2 server3
^C[root@server1 ~]# kubectl get deployments.apps httpd -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
httpd 3/3 3 3 7m47s httpd httpd:2.4.38 run=htt
[root@server1 ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
httpd-566b58fd6d 3 3 3 4m55s
httpd-789c766d45 0 0 0 8m23s
回滚
[root@server1 ~]# kubectl apply -f httpdv3.yml --record
deployment.apps/httpd configured
[root@server1 ~]# kubectl get pods -o wide -w
···
[root@server1 ~]# kubectl get deployments.apps httpd -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
httpd 3/3 3 3 11m httpd httpd:2.4.39 run=httpd
[root@server1 ~]# kubectl rollout history deployment httpd //查看升级历史
REVISION CHANGE-CAUSE
1 kubectl apply --filename=httpdv1.yml --record=true
2 <none>
3 kubectl apply --filename=httpdv3.yml --record=true
[root@server1 ~]# kubectl rollout undo deployment httpd --to-revision=1 //回滚到版本1
deployment.apps/httpd rolled back
[root@server1 ~]# kubectl get pods -w
···会很快,因为只是切换到了本地httpd-789c766d45
root@server1 ~]# kubectl get deployments.apps httpd -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
httpd 3/3 3 3 13m httpd httpd:2.4.37 run=httpd
[root@server1 ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
httpd-566b58fd6d 0 0 0 10m
httpd-789c766d45 3 3 3 14m
httpd-8ccdfc8f9 0 0 0 4m58s
[root@server1 ~]# kubectl describe deployments.apps httpd kubectl delete -f httpdv1.yml
Normal ScalingReplicaSet 8m5s deployment-controller Scaled up replica set httpd-8ccdfc8f9 to 1
Normal ScalingReplicaSet 7m26s deployment-controller Scaled down replica set httpd-566b58fd6d to 2
Normal ScalingReplicaSet 3m55s (x10 over 7m26s) deployment-controller (combined from similar events): Scaled down replica set httpd-8ccdfc8f9 to 0
具体实践
Liveness探针
用户自定义判断容器是否健康的条件,如果判断失败则重启容器
!
[root@server1 ~]# vim pod.yml
apiVersion: v1
kind: Pod
metadata:
name: liveness #liveness:存活性
labels:
test: liveness
spec:
restartPolicy: OnFailure
containers:
- name: liveness
image: busybox #使用command字段指定要运行的程序,而args字段则可用于指定传递给程序的选项和参数。
args: #在Kubernetes系统上创建Pod资源时,也能够向容器化应用传递命令行参数,甚至指定运行其它应用程序,相关的字段分别为pods.spec.containers.command和pods.spec.containers.args。
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 3000000 #创建文件三十秒后再删除(sleep目的保持容器运行)
由上述的示例可见,Kubernetes配置文件中的command对应于Dockerfile中的ENTRYPOINT,而配置文件的args则对应于Dockerfile中的CMD。在Kubernetes中只给出command字段时,他会覆盖Dockerfile中的ENTRYPOINT和CMD,只给出args字段时,它仅覆盖CMD,而同时给出command和args时,它会对应覆盖ENTRYPOINT和CMD。
livenessProbe: #容器内检查机制
failureThreshold: 3 #当Pod成功启动且检查失败时,Kubernetes将在放弃之前尝试failureThreshold次。放弃生存检查意味着重新启动Pod。而放弃就绪检查,Pod将被标记为未就绪。默认为3.最小值为1。
exec: #使用命令去检查
command:
- cat #使用cat命令去检查文件是否存在
- /tmp/healthy
httpGet: # 通过http get的方式访问容器IP地址,并指定端口和路径,如果响应码会2xx或3xx视为成功
path: string # 访问路径,也就是UPI示例:/index.html
port: number # 访问端口
host: string # 访问的主机名,默认为容器IP,可不设
scheme: string # 用于连接的协议,默认为http,可不设
httpHeaders: # 自定义请求头
- name: string # 名称
value: string # 值
tcpSocket: # 通过tcp协议对端口进行检测如果端口可以连通就视为检测成功
port: number
# 检测参数配置
initialDelaySeconds: 10 #容器初始化完成后,延迟多久后在检查
periodSeconds: 5 #每隔5秒检查一次(默认失败三次后进行重启容器) 10-->15-->20 35->40>45(三次重启容器)
timeoutSeconds: 5 #用来表示监测的超时时间,如果超过这个时长后,则认为监测失败
successThreshold: 1 #失败后检查成功的最小连续成功次数。默认为1.活跃度必须为1。最小值为1。
[root@server1 ~]# kubectl apply -f pod.yml
[root@server1 ~]# kubectl get pod -w //需要耐心等待(它会等待十秒进行健康检查)如果遇到错误就重启容器。每隔五秒检查一次~
NAME READY STATUS RESTARTS AGE
liveness 1/1 Running 0 11s
liveness 1/1 Running 1 89s
liveness 1/1 Running 2 2m57s
[root@server1 ~]# kubectl describe pod
Warning Unhealthy 4s (x11 over 4m29s) kubelet Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory
[root@server1 ~]# kubectl delete -f pod.yml
Readiness探针
Rolling update的判断条件,告诉你容器什么进入ready状态
,什么时候对外提供服务,什么时候接收service发来的请求!
[root@server1 ~]# vim pod.yml
apiVersion: v1
kind: Pod
metadata:
name: readiness
labels:
test: readiness
spec:
restartPolicy: OnFailure
containers:
- name: liveness
image: busybox
args:
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 3000000 #创建文件过三十秒再删除(在进行健康检查)
readinessProbe:
exec:
command:
- cat #检查文件
- /tmp/healthy
initialDelaySeconds: 10 #延迟多久启动
periodSeconds: 5 #每隔5秒检查一次
[root@server1 ~]# kubectl apply -f pod.yml
[root@server1 ~]# kubectl get pod -o wide -w
NAME READY STATUS RESTARTS AGE IP NODE
readiness 0/1 Running 0 22s 10.244.1.5 server3
readiness 1/1 Running 0 30s 10.244.1.5 server3
readiness 0/1 Running 0 60s 10.244.1.5 server3 //60秒代表不可用状态(不会去重启容器)
^C[root@server1 ~]# kubectl delete -f pod.yml "两者唯一区别是探测失败后的行为"
滚动更新的健康检查机制
[root@server1 ~]# vim apps.v1.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
spec:
selector:
matchLabels:
run: app
replicas: 10
template:
metadata:
labels:
run: app
spec:
containers:
- name: app
image: busybox
args:
- /bin/sh
- -c
- sleep 10; touch /tmp/healthy; sleep 3000000
readinessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 10 #延迟十秒后在检查(Service一般都是10秒后对外提供服务)
periodSeconds: 5
复制yaml文件进行应用并对比
[root@server1 ~]# cp apps.v1.yaml apps.v2.yaml
[root@server1 ~]# vim apps.v2.yaml
- sleep 3000000
# 应用
[root@server1 ~]# kubectl apply -f apps.v1.yaml
[root@server1 ~]# kubectl get pods -o wide //会发现有10个Pod处于ready
···
[root@server1 ~]# kubectl apply -f apps.v2.yaml //会先删除两个旧Pod,在增加5个新Pod
[root@server1 ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
app-666cf4456d-4n9p9 1/1 Running 0 4m59s 10.244.1.9 server3 <none> <none>
app-666cf4456d-54nhq 1/1 Running 0 4m59s 10.244.1.7 server3 <none> <none>
app-666cf4456d-d5h7b 1/1 Running 0 4m59s 10.244.2.3 server2 <none> <none>
app-666cf4456d-gnz79 1/1 Running 0 4m59s 10.244.2.4 server2 <none> <none>
app-666cf4456d-hb8vs 1/1 Running 0 4m59s 10.244.1.8 server3 <none> <none>
app-666cf4456d-jt6jt 1/1 Running 0 5m 10.244.2.6 server2 <none> <none>
app-666cf4456d-mwkxt 1/1 Running 0 5m 10.244.1.6 server3 <none> <none>
app-666cf4456d-qpwhp 1/1 Running 0 5m 10.244.2.5 server2 <none> <none>
app-8484d5555c-fd6dt 0/1 Running 0 99s 10.244.2.9 server2 <none> <none>
app-8484d5555c-rpqgh 0/1 Running 0 99s 10.244.1.11 server3 <none> <none>
app-8484d5555c-vmg8n 0/1 Running 0 99s 10.244.2.8 server2 <none> <none>
app-8484d5555c-vwpx7 0/1 Running 0 99s 10.244.1.12 server3 <none> <none>
app-8484d5555c-wxcxs 0/1 Running 0 99s 10.244.2.10 server2 <none> <none>
[root@server1 ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
app-666cf4456d 8 8 8 5m41s
app-8484d5555c 5 5 0 2m21s
[root@server1 ~]# kubectl get deployments.apps app Healthy健康检查机制,保留了大量的旧版本,业务没有因为更新而中断
NAME READY UP-TO-DATE AVAILABLE AGE
app 8/10 5 8 6m38s “更新后的版本不能对外提供服务”
[root@server1 ~]# kubectl describe deployments.apps app
Replicas: 10 desired | 5 updated | 13 total | 8 available | 5 unavailable
StrategyType: RollingUpdate
RollingUpdateStrategy: 25% max 不可用, 25% max surge(副本超越期望值百分比)
改变更新策略
[root@server1 ~]# kubectl delete -f apps.v1.yaml
[root@server1 ~]# vim apps.v1.yaml
spec:
strategy: #策略
rollingUpdate:
maxSurge: 35%
maxUnavailable: 35%
[root@server1 ~]# kubectl apply -f apps.v1.yaml
[root@server1 ~]# kubectl describe deployments.apps app
RollingUpdateStrategy: 35% max unavailable, 35% max surge
Talent determines the upper limit, effort determines the lower limit. Come on!