生产环境经验

1、限制了容器资源,还经常被杀死?
2、滚动更新之健康检查重要性
3、滚动更新之流量的丢失

先说一下第一个问题,限制容器资源,还经常去杀死的原因?
就是说部署的java应用,不一会就重启了,其实重启就是在重建了,这就意味着三分钟时时彩你 的pod是不健康的,然后k8s重新再帮三分钟时时彩你 去拉取了,这样的话就要去找问题去排查了,说白了其实就是被杀死了,可以通过describe去查看一下事件,一般都会能看到,由于健康状态检查没通过,然后再去拉取的,因为是java应用,由于堆内存溢出,然后被kill掉,在日志最后一行会出现一个kill的字段,看一下它重启的原因,之前三分钟时时彩我 遇到的是它的堆内存没限制住,它本身有jvm,jvm主要有内存做交换数据的,它堆内存主要是性能设计的一个体现,所以他的堆内存很容易就会超出,超出之后呢,很可能会被k8s杀死掉,为什么k8s会kill它,因为它超出了限制,默认容器会使用宿主机所有的资源,如果不做资源限制,会影响整个宿主机,然后整个宿主机资源不够会实现飘移,会转移到其他主机上,然后再异常,可能会起到一种雪崩的效应,所以一般三分钟时时彩三分钟时时彩我 们 都是要做资源限制的,难道这个限制,限制不了java应用吗?其他它是限制不住的,虽然k8s部署应用还是很方便的,但是部署java应用还是不兼容的,
比如它不能识别当前java容器的限制,就是不能识别三分钟时时彩三分钟时时彩我 们 指定的限制,也就是三分钟时时彩你 在yaml去限制的,容器的堆内存没有限制,它就会超出这个限制,如果超出这个limits的限制,k8s就会把它杀掉,k8s自身它有这个策略,如果超出这个容量的限制,就会帮三分钟时时彩你 杀掉,再帮三分钟时时彩你 拉起。

面对java这样的堆内存稍微有一点流量突发,就可能资料利用率就上来了,所以这个幅度还是比较大的,这样就会导致k8s杀掉,然后再拉起,这样循环,可能一天几百次的这样效果。

说到这个问题,怎么来解决docker的资源限制,其实这个资源限制还是用的这个docker来做的,只不过k8s把他转换成了,只不过k8s去调用接口去做一些限制,其实就是怎么让docker去识别java堆内存的限制,来解决这个问题。
来解决这个问题有两种方案,也就是为这个java再配置堆内存的使用
配置java堆内存的使用
Java -Xmx最大的堆内存使用,一个是-Xms是初始的堆内存使用
一般都设置一个最大的堆内存使用,如果不设置超出这个设置会不断使用宿主机的一个内存,而导致物理内存不够用,而出现堆内存溢出的现象,这个很普遍,三分钟时时彩三分钟时时彩我 们 就用这个java -Xmx就是当快用满时,它会有一个垃圾回收,再进行循环的使用,这样能保证这个java应用稳定的运行,所有三分钟时时彩三分钟时时彩我 们 在yaml去配置资源限制肯定是不够的,三分钟时时彩三分钟时时彩我 们 必须为这个java去设置这个堆内存,三分钟时时彩三分钟时时彩我 们 不可能手动的在Dockerfile去写这个吧,一般在dockerfile去传入这个值,在yaml文件里设置一个变量

env:
  - name: JAVA_OPTS
   value: “-Xmx1g “

下面就是三分钟时时彩三分钟时时彩我 们 之前配置的容器资源的一些限制这个变量就会就会传入pod里面,也就是这个构建镜像的容器里,也就是起到容器CMD 命令下去传入$JAVA_OPTS的变量,它会调用三分钟时时彩三分钟时时彩我 们 系统的系统变量,这个系统变量已经赋予它值了,所以它能直接饮用这个变量了,去起到这个应用,从而设置这个堆内存大小,这个值建议要比limlts要小一点,小个10%吧,因为超过这个limits限制就会杀死,再拉取了。
一般设置好,重建一下镜像,进入容器中去查看一下进程就可以看到,其他的也是这么设置的

第二个问题,滚动更新之健康检查的重要性
滚动更新是k8s的默认策略,一般咱们部署到k8s之后第一个会使用到的,当三分钟时时彩你 配置了健康检查时,滚动更新会根据probe的状态来判断是不是继续的更新允许接入流量,也就是三分钟时时彩你 当前的应用是不是提供三分钟时时彩服务 ,这样三分钟时时彩你 滚动更新的过程中,才会确保三分钟时时彩你 是不是有可用的节点,保证一个平滑的升级,所以这是滚动更新设置的一个之初,那健康状态检查是很重要的
健康状态检查在滚动更新启动什么作用呢?

列入一个副本,启动之后提供业务需要一分钟才能提供三分钟时时彩服务 ,比如java启动比较慢,如果没有健康状态检查,来确保他是不是准备好,就直接认为它准备好了,这期间启动起来,一分钟之内它是无法提供三分钟时时彩服务 的,所以新来的流量肯定是无法处理的,这是第一种情况,第二种情况,由于人为的配置错误,比如连接不上数据库了,或者连接不上其他地方了,或者配置文件哪里写错了,那触发一个滚动更新,那这个pod呢全部滚动更新完成了,结果都是由问题的,这样的话,新副本都把旧副本替换掉了,这样的话,生产环境中后果很严重的,很多三分钟时时彩服务 都会无法提供了,所以在配置滚动更新的时候,健康状态检查一定要配上,那配上了健康状态检查之后,新的副本检查完成之后才会转发新的流量,如果它没有通过它不会全部替换的,也就是它不会继续更新了,因为它是有一个可用节点的限制,如果可用节点达不到这个数,就不会继续更新,健康状态检查有两种类型,readinessprobe是就绪的检查,这两种检查方式也有不同的方式,比如http,探测一个url,还有tcp socket,端口的探测,还有一个执行shell命令,执行一个shell命令,判断一个返回值,所以提供者三种健康状态检查的三分钟时时彩方法 ,readinessprobe就绪检查也就是三分钟时时彩你 的Pod检查失败,如果是http,可以通过一个页面去探测,判断这个返回状态码,如果探测这个三分钟时时彩本地 的端口不通的话,它不会让它加入service后面,因为service作为三分钟时时彩你 整个的统一访问入口嘛,如果它不通过的话,新的流量也不会转发给它,这就是就绪检查,如果健康状态不通过不会给三分钟时时彩你 转发新的流量,另外就是initialDelaySeconds:60,就是检查60秒,因为一般java应用启动也就是一分钟左右,还有一个periodSeconds:10,也就是没通过10秒钟在做一次,然后就是livenessProbe:存活检查。

也就是检查失败它会杀死容器,根据三分钟时时彩你 重启策略,一般是重建,再给三分钟时时彩你 新拉取一个容器,再判断有没有准备好,判断的三分钟时时彩方法 也是根据端口的探测这些的,或者特可以用其他两种三分钟时时彩方法 ,http,exec,所以一般这两个都要配置上,就绪检查呢就是不为三分钟时时彩你 分配新的流量,存活检查就是去帮三分钟时时彩你 重新拉取。

最后一个问题滚动更新之丢失的流量
一般就是连接拒绝,响应错误,调用不到
一般滚动更新是关闭现有的pod,再起一新的pod,关闭现有的其实是就是三分钟时时彩删除 了一个pod,然后apiserver会通知给kubelet,然后kubelet会关闭这个容器,然后从service后端摘掉,就不分发新的流量了,然后移除掉,然后再告诉kube-proxy,三分钟时时彩你 可以处理新的转发规则了,然后调度到节点上,其实这也是一个pod的下线周期
另外再转发的过程中,转发新的pod时间段里,它是有间隔的,关闭pod之后会有一个等待时间,在这个时间呢,可能还会接入一些新的流量,但是它的三分钟时时彩服务 已经不再处理新的请求了,所以会导致连接拒绝了,怎么去解决这个问题呢,实际上readiness探针在整个过程中并起到关键的作用,一旦endpoint收到pod 的三分钟时时彩删除 事件后,这已经就与readiness探测结果不相关了

怎么保证它优雅的去处理呢?
其实之需要在关闭这个pod 时加个休眠的时间,其实就可以解决这个问题了,在关闭和启动都是有一个钩子存在的,所有可以在关闭容器前,执行这个钩子,钩子这个定义一个shell,y也可以定义一个http请求,也就是支持者两种类型,也就是在container同级,env这里
休眠5秒也就是三分钟时时彩你 关闭的容器不会马上退出,然后休眠5秒钟,再去关闭着应用,这5秒能够足够让kube-proxy刷新这个规则,这样的话,就不会将新加入的流量转发到这个刚关闭的pod上,增加这个钩子就能暂缓三分钟时时彩你 关闭pod的时间,从而让kube-proxy增加刷新规则的时间,
添加

lifecycle :
preStop :
     exec :
           command :
             - sh
             - -c
             - “sleep 5”

这样,三分钟时时彩你 不需要修改三分钟时时彩你 应用的代码,这样的话,滚动更新就不会转发即将关闭的pod上了,所以也能解决这个相关的问题了。