前言
在之前的一系列文章之后,我们对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
。
高级 liveness 探针示例
探针的定义也是如此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" # hst: 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
正常启动效果如下:
4. 删除重来
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活性和就绪性探针,感兴趣的同学可以去了解一下。