强大的自愈能力是Kubernetes这类容器编排引擎的⼀个重要特性。自愈的默认实现方式是自动重启发生故障的容器。除此之外,用户还可以利用Liveness和Readiness探测机制设置更精细的健康检查,进而实现:
(1)零停机部署。
(2)避免部署无效的镜像。
(3)更加安全的滚动升级。
1.1 默认的健康检查
默认情况下,每个容器启动时都会执行一个进程,由Dockerfile中的CMD或ENTRYPOINT指定。如果进程退出时的返回码不为0,则认为容器发生了故障,K8S会根据重启策略(restartPolicy)重启容器。
vi healthcheck.yaml
apiVersion: v1
kind: Pod
metadata:
name: healthcheck-demo
labels:
test: healthcheck
spec:
restartPolicy: OnFailure
containers:
- name: healthcheck
image: busybox
imagePullPolicy: IfNotPresent
args:
- /bin/sh
- -c
- sleep 10; exit 1
Pod的restartPolicy设置为OnFailure,默认为Always。sleep10;exit1模拟容器启动10秒后发生故障。
执行kubectlapply创建Pod,命名为healthcheck。
[root@k8s-master ~]# kubectl get pod healthcheck-demo
NAME READY STATUS RESTARTS AGE
healthcheck-demo 0/1 CrashLoopBackOff 3 101服务器托管网s
可看到容器当前已经重启了3次。
在上面的例子中,容器进程返回值非零,必须等到进程退出后的返回值是非零才会触发重启策略,不能直接监测容器是否是健康。
K8S中有没有更好的机制能够实现智能一点的健康检查呢?答案就是使用Liveness与Readinesss。
1.2 Liveness探测
Liveness的参数:
initialDelaySeconds:容器启动后第一次执行探测是需要等待多少秒,看运行的服务而定。
periodSeconds:执行探测的频率,默认是10秒,最小1秒。
timeoutSeconds:探测超时时间,默认1秒,最小1秒。
successThreshold:探测失败后,最少连续探测成功多少次才被认定为成功,默认是1,对于liveness必须是1,最小值是1。
failureThreshold:探测成功后,最少连续探测失败多少次才被认定为失败。默认是3。最小值是1.
vi liveness-demo.yml
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-demo
spec:
containers:
- name: liveness
image: busybox
args:
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -rf/tmp/healthy; sleep 10
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 10
periodSeconds: 5
这里启动pod后会创建文件夹 /tmp/healthy,30秒后删除,在我们的设置中,如果 /tmp/healthy 存在,则认为容器处于正常状态,否则认为发生故障。
需要注意的就是livenessProbe部分的定义了:
(1)探测方法:通过cat命令查看/tmp/healthy是否存在;如果返回值为0,则探测成功;否则,探测失败;
(2)initialDelaySeconds: 10 => 容器启动10秒之后开始执行liveness探测;
(3)periodSeconds: 5 => 每5秒执行一次liveness探测;如果连续执行3次探测都失败,那么就会杀掉并重启容器;
下面快速地验证一下:
[root@k8s-master ~]# kubectl describe pod liveness-demo
deployment.apps/httpd configured
Normal Pulling 71s (x4 over 4m29s) kubelet, k8s-node2 Pulling image "busybox"
Normal Pulled 44s (x4 over 4m27s) kubelet, k8s-node2 Successfully pulled image "busybox"
Normal Created 44s (x4 over 4m27s) kubelet, k8s-node2 Created container liveness
Normal Started 44s (x4 over 4m27s) kubelet, k8s-node2 Started container liveness
Warning BackOff 2s (x7 over 2m49s) kubelet, k8s-node2 Back-off restarting failed container
[root@k8s-master ~]# kubectl get pod liveness-demo
NAME READY STATUS RESTARTS AGE
liveness-demo 1/1 Running 4 5m46s
1.3 Readiness探测
用户通过Liveness探测可以告诉Kubernetes什么时候通过重启容器实现自愈;Readiness探测则是告诉Kubernetes什么时候可以将容器加入到Service负载均衡池中,对外提供服务。
vi readiness-demo.yml
apiVersion: v1
kind: Pod
metadata:
labels:
test: readiness
name: readiness-demo
spec:
containers:
- name: readiness
image: busybox
args:
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -rf/tmp/healthy; sleep 10
readinessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 10
periodSeconds: 5
这个配置文件只是将前面例⼦中的liveness替换为了readiness。
[root@k8s-master ~]# kubectl get pod readiness-demo
NAME READY STATUS RESTARTS AGE
readiness-demo 1/1 Running 1 107s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled unknown> default-scheduler Successfully assigned default/readiness-demo to k8s-node2
Normal Pulling 61s (x3 over 3m13s) kubelet, k8s-node2 Pulling image "busybox"
Normal Pulled 44s (x3 over 2m51s) kubelet, k8s-node2 Successfully pulled image "busybox"
Normal Created 44s (x3 over 2m51s) kubelet, k8s-node2 Created container readiness
Normal Started 44s (x3 over 2m51s) kubelet, k8s-node2 Started container readiness
Warning BackOff 4s (x2 over 73s) kubelet, k8s-node2 Back-off restarting failed container
Warning Unhealthy 4s kubelet, k8s-node2 Readiness probe failed: OCI runtime exec failed: exec failed: unable to sta
(1)刚被创建时,其READY状态为不可用;
(2)15秒(initialDelaySeconds + periodSe服务器托管网conds = 10 + 5 = 15)之后,第一次进行Readiness探测成功,其READY状态变为可用。
(3)30秒之后,/tmp/healthy被删除,连续3次Readiness探测均失败后,其READY状态又变为了不可用。
与Liveness的对比
Liveness与Readiness都是K8S的Health Check机制,Liveness探测是重启容器,而Readiness探测则是将容器设置为不可用,不让其再接受Service转发的请求。
Liveness与Readiness是独立执行的,二者无依赖,可以单独使用也可以同时使用。
1.4 Health Check在Scale Up中的应用
对于多副本应用,当执行ScaleUp操作时,新副本会作为backend被添加到Service的负载均衡中,与已有副本⼀起处理客户的请求。考虑到应用启动通常都需要⼀个准备阶段,比如加载缓存数据、连接数据库等,从容器启动到真正能够提供服务是需要⼀段时间的。我们可以通过Readiness探测判断容器是否就绪,避免将请求发送到还没有准备好的backend。
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 3
selector:
matchLabels:
run: web
template:
metadata:
labels:
run: web
spec:
containers:
- name: web
image: myhttpd
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /healthy
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
name: web-svc
spec:
selector:
run: web
ports:
- protocol: TCP
port: 8080
targetPort: 8080
重点关注readinessProbe部分。这里我们使用了不同于exec的另⼀种探测方法httpGet。
Kubernetes对于该方法探测成功的判断条件是http请求的返回代码在200〜400之间。
上⾯配置的作用是:
(1)容器启动10秒之后开始探测。
(2)如果http://[container_ip]:8080/healthy返回代码不是200〜 400,表示容器没有就绪,不接收Serviceweb-svc的请求。
(3)每隔5秒探测⼀次。
(4)直到返回代码为200〜400,表明容器已经就绪,然后将其加入
到web-svc的负载均衡中,开始处理客户请求。
(5)探测会继续以5秒的间隔执行,如果连续发生3次失败,容器又
会从负载均衡中移除,直到下次探测成功重新加入。
1.5 Health Check在Rolling Update中的应用
假设现在有一个正常运行的多副本应用,我们要对其进行滚动更新即Rolling Update,K8S会逐步用新Pod替换旧Pod,结果就有可能发生这样的一个场景:
(1)正常情况下新副本需要10秒钟完成准备工作,在此之前无法响应业务请求。
(2)当所有旧副本被替换之后,而新的Pod由于人为配置错误一直无法启动,因此整个应用将无法处理请求,无法对外提供服务,后果很严重!
如果正确配置了HealthCheck,新副本只有通过了Readiness探测才会被添加到Service;如果没有通过探测,现有副本不会被全部替换,业务仍然正常进行。
因此,Readiness探测还提供了用于避免滚动更新中出现这种情况的一些解决办法,比如maxSurge和maxUnavailable两个参数,用来控制副本替换的数量。
继续以上面的YAML配置文件为例,重点关注strategy部分:
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
strategy:
rollingupdate:
maxSurge: 25%
maxUnavailable: 25%
replicas: 3
selector:
matchLabels:
run: web
template:
metadata:
labels:
run: web
spec:
containers:
- name: web
image: myhttpd
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /healthy
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
name: web-svc
spec:
selector:
run: web
ports:
- protocol: TCP
port: 8080
targetPort: 8080
(1)maxSurge:25%=>控制滚动更新过程中副本总数超过预期(这里预期是10个副本replicas:10)的上限,可以是数值也可以是百分比,然后向上取整。这里写的百分比,默认值是25%;
如果预期副本数为10,那么副本总数的最大值为RoundUp(10+1025%)=13个。
(2)maxUnavailable:25%=>控制滚动更新过程中不可用的副本(这里预期是10个副本replicas:10)占预期的最大比例,可以是数值也可以是百分比,然后向下取整,同样地默认值也是25%;
如果预期副本总数为10,那么可用的副本数至少要为10-roundDown(1025%)=10-2=8个。
综上看来,maxSurge的值越大,初始创建的新副本数量就越多;maxUnavaliable值越大,初始销毁的旧副本数量就越多;
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
相关推荐: 从 MongoDB 到 PostgreSQL 的大迁移
国产数据库圈,为啥那么多水货?” 原文链接,文章来自 Infisical,一家做密钥管理的开源商业公司,主要对标的是 HashiCorp Vault。 Infisical 在过去一年里迅速发展,平台现在每天处理超过 5000 万个密钥,将应用程序配置和私密数据…