经过前面的一系列文章,我们对k8s应该也算是简单的入门了。本文开始,会逐步开始讲解一些进阶的知识点。在前面的文章中,我们主要是围绕如何完整地发布一个可对外访问的服务。其中重点是以springboot+vuejs前后端分离项目为主的。后续的文章也会是围绕springboot+vuejs,不过会基于其扩展一些新的服务,如redis、rabbitmq、elk等。
健康检查(Health Check)是让系统知道您的应用实例是否正常工作的简单方法。 如果您的应用实例不再工作,则其他服务不应访问该应用或向其发送请求。 相反,应该将请求发送到已准备好的应用程序实例,或稍后重试。 系统还应该能够使您的应用程序恢复健康状态。
默认情况下,当 Pod 中的所有容器启动时,Kubernetes 开始向 Pod 发送流量,并在崩溃时重新启动容器。如果Pod启动后就立即对外服务,其实是不太合理的。因为Pod启动成功并不代表容器里面部署的服务就能对外服务了,比如springboot项目,容器启动成功后,springboot启动需要一些初始化工作,真正要能对外访问,快则需要几秒,慢则需要十几、二十秒,甚至更久。 Kubernetes 在设计上已经考虑到了这点,它可以通过创建自定义运行状况检查来使部署更加健壮 。这里涉及到一个关键字:容器探针。
探针是由 kubelet
对容器执行的定期诊断。要执行诊断,kubelet
调用由容器实现的 Handler
。有三种类型的处理程序:
ExecAction
:在容器内执行指定命令。如果命令退出时返回码为 0 则认为诊断成功。CPSocketAction
:对指定端口上的容器的 IP 地址进行 TCP 检查。如果端口打开,则诊断被认为是成功的。HTTPGetAction
:对指定的端口和路径上的容器的 IP 地址执行 HTTP Get 请求。如果响应的状态码大于等于200 且小于 400,则诊断被认为是成功的。每次探测都将获得以下三种结果之一:
Kubelet 可以选择是否执行在容器上运行的两种探针执行和做出反应:
livenessProbe
(存活探针):指示容器是否正在运行。如果存活探测失败,则 kubelet 会杀死容器,并且容器将受到其 重启策略的影响。如果容器不提供存活探针,则默认状态为 Success
。readinessProbe
(就绪探针):指示容器是否准备好服务请求。如果就绪探测失败,端点控制器将从与 Pod 匹配的所有 Service 的端点中删除该 Pod 的 IP 地址。初始延迟之前的就绪状态默认为 Failure
。如果容器不提供就绪探针,则默认状态为 Success
。探针的定义,也是k8s编排的重要内容。
apiVersion: apps/v1
kind: Deployment
metadata:
name: mldong-admin
namespace: mldong-admin-test
spec:
selector:
matchLabels:
app: mldong-admin
replicas: 1
template:
metadata:
labels:
app: mldong-admin
spec:
containers:
- name: mldong-admin
env:
- name: TZ
value: Asia/Shanghai
image: registry.cn-zhangjiakou.aliyuncs.com/mldong/java/mldong-admin:202007220017_c608761
livenessProbe:
httpGet:
# 当没有定义 "host" 时,使用 "PodIP"
# host: my-host
# 当没有定义 "scheme" 时,使用 "HTTP" scheme 只允许 "HTTP" 和 "HTTPS"
# scheme: HTTPS
path: /healthz # 这要求服务得有这个接口地址
port: 8080 # 服务对应的端口
httpHeaders: # 可以携带请求头
- name: X-Custom-Header
value: Awesome
initialDelaySeconds: 30 #第一次健康检查的时间
periodSeconds: 5 #检查周期
timeoutSeconds: 5 #检查超时时间
successThreshold: 1 #成功次数判定成功
failureThreshold: 1 #失败次数判定失败
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
name: port
protocol: TCP
command: ["/bin/sh"]
args: ["-c", "set -e && java -jar app.jar --spring.profiles.active=test --server.port=8080"]
探针类型livenessProbe
和readinessProbe
,与容器定义的image同级,两者可同时存在,前者是定义存活探针, 健康状态检查,周期性检查服务是否存活,检查结果失败,将重启容器 。后者是定义就绪探针, 可用性检查,周期性检查服务是否可用,不可用将从service的endpoints中移除 。
如上,定义了一个存活探针livenessProbe
,其使用的httpGet
的方式去检查的,请求路径为/healthz
,端口为8080
,请求头httpHeaders
为X-Custom-Header=Awesome
。第一次健康检查的时间initialDelaySeconds
为pod启动后30s后进行检测;检查周期periodSeconds
为5s;检查超时时间timeoutSeconds
为5s;成功次数successThreshold
为1判定成功;失败次数failureThreshold
为1判定失败。
检查方式说明:
httpGet
检测某个 http 请求的返回状态码 2xx,3xx正常, 4xx,5xx错误参数说明
参数 | 默认值 | 说明 |
---|---|---|
host | 当没有定义 “host” 时,使用 “PodIP” | 请求域名 |
scheme | HTTP | 只允许 “HTTP” 和 “HTTPS” |
path | / | 请求地址,这需要接口服务中有该请求地址 |
port | 80 | 服务对应的端口 |
httpHeaders | 无 | 请求头name/value |
样例:
httpGet:
path: /healthz
port: 8080
httpHeaders:
- name: X-Custom-Header
value: Awesome
exec
执行一段命令 返回值为0, 非0参数说明:
参数 | 默认值 | 说明 |
---|---|---|
command | 要执行的命令,数组 |
样例:
exec: #执行方式
command: #初始命令
- cat
- /tmp/healthy
tcpSocket
测试某个端口是否能够连接参数说明:
参数 | 默认值 | 说明 |
---|---|---|
port | 80 | 端口 |
样例:
tcpSocket:
port: 80
检查规则说明
参数 | 默认值 | 说明 |
---|---|---|
initialDelaySeconds | 第一次健康检查的时间,太小的话,可能会造成pod无限重启。 | |
periodSeconds | 检查周期 | |
timeoutSeconds | 检查超时时间 | |
successThreshold | 1 | 成功次数判断成功 |
failureThreshold | 1 | 失败次数判断失败 |
在实战前,先学习如下命令:
for a in {1..10};do curl http://vueadmin.mldong.com/api/login;date +"%Y%m%d%H%M%S";sleep 2;done;
每隔2秒钟进行一次接口访问,循环10次。
效果图如下:
v1.yaml
cat << EOF > /mldong/k8s/mldong-probe/v1.yaml
apiVersion: v1
kind: Namespace
metadata:
name: mldong-probe
---
apiVersion: v1
kind: Service
metadata:
name: mldong-admin-nodeport
namespace: mldong-probe
spec:
type: NodePort
ports:
- port: 8080
targetPort: 8080
selector:
app: mldong-admin
---
apiVersion: v1
kind: Service
metadata:
name: mldong-admin
namespace: mldong-probe
spec:
type: ClusterIP
ports:
- port: 8080
protocol: TCP
targetPort: 8080
selector:
app: mldong-admin
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mldong-admin
namespace: mldong-probe
spec:
selector:
matchLabels:
app: mldong-admin
replicas: 1
template:
metadata:
labels:
app: mldong-admin
spec:
containers:
- name: mldong-admin
env:
- name: TZ
value: Asia/Shanghai
image: registry-vpc.cn-zhangjiakou.aliyuncs.com/mldong/java/mldong-admin:202007220017_c608761
livenessProbe:
tcpSocket:
port: 8080 # 服务对应的端口
initialDelaySeconds: 15 #第一次健康检查的时间
periodSeconds: 5 #检查周期
timeoutSeconds: 5 #检查超时时间
successThreshold: 1 #成功次数判定成功
failureThreshold: 1 #失败次数判定失败
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
name: port
protocol: TCP
command: ["/bin/sh"]
args: ["-c", "set -e && java -jar app.jar --spring.profiles.active=test --server.port=8080"]
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
name: mldong-admin-ingress
namespace: mldong-probe
spec:
rules:
- host: a.test.com
http:
paths:
- backend:
serviceName: mldong-admin
servicePort: 8080
path: /
EOF
kubectl get pods -A -w | grep mldong-probe
kubectl apply -f v1.yaml
正常启动效果如下:
kubectl delete -f v1.yaml
修改成其他非服务端口
tcpSocket:
port: 8081
kubectl apply -f v1.yaml
效果如下:
其实就是监听的服务不存在,重启容器。
最后清一下空间
kubectl delete -f v1.yaml
新建v2.yaml
cat << EOF > /mldong/k8s/mldong-probe/v2.yaml
apiVersion: v1
kind: Namespace
metadata:
name: mldong-probe
---
apiVersion: v1
kind: Service
metadata:
name: mldong-admin-nodeport
namespace: mldong-probe
spec:
type: NodePort
ports:
- port: 8080
targetPort: 8080
selector:
app: mldong-admin
---
apiVersion: v1
kind: Service
metadata:
name: mldong-admin
namespace: mldong-probe
spec:
type: ClusterIP
ports:
- port: 8080
protocol: TCP
targetPort: 8080
selector:
app: mldong-admin
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mldong-admin
namespace: mldong-probe
spec:
selector:
matchLabels:
app: mldong-admin
replicas: 1
template:
metadata:
labels:
app: mldong-admin
spec:
containers:
- name: mldong-admin
env:
- name: TZ
value: Asia/Shanghai
image: registry-vpc.cn-zhangjiakou.aliyuncs.com/mldong/java/mldong-admin:202007220017_c608761
readinessProbe:
tcpSocket:
port: 8080 # 服务对应的端口
initialDelaySeconds: 15 #第一次健康检查的时间
periodSeconds: 5 #检查周期
timeoutSeconds: 5 #检查超时时间
successThreshold: 1 #成功次数判定成功
failureThreshold: 1 #失败次数判定失败
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
name: port
protocol: TCP
command: ["/bin/sh"]
args: ["-c", "set -e && java -jar app.jar --spring.profiles.active=test --server.port=8080"]
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
name: mldong-admin-ingress
namespace: mldong-probe
spec:
rules:
- host: a.test.com
http:
paths:
- backend:
serviceName: mldong-admin
servicePort: 8080
path: /
EOF
/etc/hosts
新增一行,即1中配置的host
另外开启一个终端,执行如下命令
for a in {
1..30};do curl http://a.test.com/api/login;date +"%Y%m%d%H%M%S";sleep 2;done;
旧终端执行如下命令
kubectl apply -f v2.yaml
效果如下:
开始服务不存在,访问的是nginx-ingress的默认服务。服务正常启动后,接口访问正常。这里只是演示单个服务启动的样例。其实在我们做系统版本升级的时候也是这样子的。比如现在服务版本1要升级到服务版本2,我们只需要修改一下镜像的版本,然后再执行kubectl apply -f k8s.yaml
。这样新的服务版本就可以做到不停服更新了。
最后清一下空间
kubectl delete -f v2.yaml
https://gitee.com/mldong/mldong
https://gitee.com/mldong/mldong-vue
本文简单介绍了k8s的健康检查-存活探针与就绪探针,并简单地做了一下案例演示。使用存活探针与就绪探针的目的都是为了让我们的服务更健壮。大家可以根据自身服务的情况去选择使用哪一种类型的探针和检查方式。据说Spring Boot 2.3提供K8s活性和就绪性探针,感兴趣的同学可以去了解一下。