Kubernetes默认的健康检查是监控容器的ENTRYPOINT执行的程序是否正常(返回0),可以添加自定义健康检查以便符合我们真实需求。
当kill掉容器ENTRYPOINT执行的进程时,容器会被终止,k8s会尝试自动重启该容器。
k8s健康检查
cmd检查方式
web-dev-cmd.yaml
1 | #deploy |
这里主要关注
livenessProbe
节点。可以看到这里通过shell脚本来监控java服务是否正常。
initialDelaySeconds
: 检查前等待时间periodSeconds
: 检查间隔时间failureThreshold
: 失败次数(阈值)successThreshold
: 成功次数(阈值)timeoutSeconds
: 超时时间
我们可以进到docker容器中,查看该shell健康检查命令执行的效果。
可以先执行该命令,然后用echo $?
查看返回的结果,预期是0。
http检查方式
web-dev-http.yaml
1 | #deploy |
这里重点关注
livenessProbe
节点,可以看到这次是监控http下的8080端口,看是否可以正常访问/examples/index.html
这个页面。如果可以,则代表容器是健康的。
注意:如果
initialDelaySeconds
或failureThreshold
参数设置得过小,则可能导致容器还没启动完就被判断成异常
而被反复重启。
tcp检查方式
web-dev-tcp.yaml
1 | apiVersion: apps/v1 |
通过监控TCP端口来实现健康检查,这里监控的是8080端口。
优化健康检查
我们发现,当容器一旦启动了(端口ok),即使还没启动好,k8s还是会将它暴露给前端,这时候如果访问,肯定是不能工作的。我们可以简单地修改yaml文件,添加
readinessProbe
节点,这样就可以完美解决这个问题了。
livenessProbe
: 负责告诉k8s什么时候需要重启;readinessProbe
: 负责告诉k8s什么时候服务准备好了,可以对外暴露;
修改后的web-dev-tcp.yaml
文件内容如下:
1 | apiVersion: apps/v1 |
注:web服务一般会采用
http
的方式监控。
健康检查最佳实践
当某些服务不正常时的处理方法:
- 如果不是频繁发生的:调节livenessProbe参数,比如将等待时间增大,看问题是否缓解;
- 如果问题频繁发生:将livenessProbe执行的
监控脚本
改成总是成功的,这样容器就不会被重启了,这样有助于分析具体问题的原因;
k8s调度策略
k8s的调度逻辑流程图。
节点(Node)亲和性(nodeAffinity)
web-dev-node.yaml
1 | apiVersion: apps/v1 |
这里重点关注
affinity.nodeAffinity
节点。
requiredDuringSchedulingIgnoredDuringExecution
: 必须满足的条件;如果条件没有满足,则k8s没有办法调度,容器会始终处于Pending
状态;preferredDuringSchedulingIgnoredDuringExecution
: 推荐条件,没有匹配也没关系;
Pod亲和性
web-dev-pod.yaml
1 | apiVersion: apps/v1 |
podAffinity
: 指明了当前这个deployment倾向于跟带有web-demo
标签的deployment放在同一个节点上运行(topologyKey: kubernetes.io/hostname
)
污点 & 污点容忍
可以在node上标记上污点,如果pod没有指明污点容忍,则不会被调度到这个node上。
通过taint
关键字可以给node打污点。
1 | kubectl taint nodes <节点名> gpu=true:NoSchedule |
配置web-dev-taint.yaml
文件,添加污点容忍。
1 | apiVersion: apps/v1 |
从配置中可以看到,我们添加了一个
tolerations
节点,并配置了相关参数,以匹配之前配置的污点node,这样k8s就可以将deployment调度到这个污点node上了。
部署策略实践
K8s支持的部署策略:
- 滚动更新(Rolling Update)
- 重建(Recreate)
利用k8s的labelSelector还可以实现:
- 蓝绿部署
- 金丝雀部署
重建部署(Recreate)
web-recreate.yaml
1 | #deploy |
可以看到这个配置文件里有一个
strategy.type: Recreate
, 配置了这个选项后,一旦任何时候重新部署应用,k8s都会先将所有该应用的实例停掉,然后再重新启动一批实例,而不像rolling update那样边停边起。
带来的问题:服务会间断。
滚动更新(Rolling Update)
web-rollingupdate.yaml
1 | #deploy |
对于滚动部署(
rollingUpdate
)来说,可以配置maxSurge
(最大超出实例比例)和maxUnavailable
(最大不可用实例),k8s有默认的滚动更新配置。
暂停更新
通过rollout pause
关键字可以暂停部署。
1 | kubectl rollout pause deploy <deployment名> -n <namespace名> |
恢复更新
通过rollout resume
关键字可以恢复暂停的部署。
1 | kubectl rollout resume deploy <deployment名> -n <namespace名> |
回滚更新
通过rollout undo
关键字可以恢复暂停的部署。
1 | kubectl rollout undo deploy <deployment名> -n <namespace名> |
蓝绿部署
思路:假设原来的部署是green,新部署一套blue的。测试完毕后,通过修改labelSelector
,将流量切换到blue部署,就起到蓝绿部署的效果了。
配置green版本
web-bluegreen.yaml
1 | #deploy |
注:这里比之前多了一个
version: v1.0
的标签。
现在为部署创建service:
bluegreen-service.yaml
1 |
|
可以看到,在service中,同样选择带有
version: v1.0
的部署。
配置blue版本
修改web-bluegreen.yaml
文件,创建一个web-bluegreen-v2
的部署,其对应的version: v2.0
,假设这个就是我们的blue部署。
同样部署到k8s上。
1 | kubectl apply -f web-bluegreen.yaml |
查看pod情况:
1 | kubectl get pods -n dev |
可以看到,原来的green部署(web-bluegreen
)跟新的blue部署(web-bluegreen-v2
)都正常调度起来了。
修改bluegreen-service.yaml
文件,将流量切换到带有标签version: v2.0
的部署上。
重新部署service后,服务无滚动切换,流量立刻切换到新版本了。
金丝雀部署
修改bluegreen-service.yaml
文件,将version
节点去掉,这时再部署,流量会轮流导入到1.0和2.0的部署上,进而实现金丝雀部署的效果。