容器重启的直接原因:云应用配置了健康检查,且健康检查存活探针失败,被集群自动重启。
详情请参考:云应用健康检查配置。健康检查配置示例:
检查延迟:容器启动后多少s开始进行健康检查。
检查间隔:健康检查开始后,按照固定间隔进行轮询,每隔xx秒检查一次。
超时时间:超过多少时间没有返回(http)或者没有正常退出(shell脚本),则认为该次检查超时(失败)。
失败次数阈值:连续轮询多少次均失败后则认为健康检查失败,达到重启条件,集群对容器进行重启。
注:容器启动后,内部的应用进程也是刚启动,很可能没有启动完成,比如Java web还在启动Servlet、nodejs可能还在npm install,所以需要设置一定的检查延迟。
健康检查能在一定程度上维护应用稳定,比如容器中的Java进程因为OOM被内核kill,如果不设置健康检查,容器就不会重启。但是如果容器不重启,就会一直宕机着(也就是容器是存在着,但是里面的应用进程没有了),无法对外提供服务。
那么,现在的问题是需要定位到健康检查失败的原因,这里只能提供一些常见源头的排查思路:
1)健康检查设置不合理,比如健康检查的延迟时间设置太短,服务还没有启动起来,健康检查就开始了,进而导致失败;比如健康检查超时时间设置太短,健康检查本身的执行如果有一定耗时,超过了设置的超时时间,也算失败,比如运行一段时间后,应用性能开始下降,导致健康检查也超时。
2)应用进程OOM,Java类型应用比较容器出现的(当然,PHP也有可能)。一般是由于容器规格和JVM进程的启动参数配置不够,可以适当进行优化。结合应用基础监控,观察内存使用趋势;可以为集群配置事件告警,当有OOM事件或者容器重启事件发生时,会有告警消息推送。
3)应用自身问题或下游服务异常,举个例子,云应用中访问RDS,如果RDS某个时刻性能特别差,云应用自身吞吐不够,整体huang住,新的请求均会失败,健康检查探针也会失败,进而导致容器重启。需要关注服务响应性能,建议接入ARMS应用监控(收费云产品),可以对应用性能有直观的监控,同时特需要自行观察下游服务的监控信息。
4)宿主机docker daemon或者kubelet的一些内核异常,出现概率较小。这里也是推荐为集群配置事件告警,宿主机ECS出现一些问题时,能够及时感知。
应用发布后,过了一段时间来看,实例的名称、IP、创建时间自己变了?
很可能是因为原Pod实例被驱逐,集群重新调度创建了新的实例。除开手动排空节点(将宿主机上的容器驱逐出本宿主机),该现象一般是由于节点上某些资源使用达到了某个阈值,集群按照一定的调度策略,将节点上的一些Pod实例赶出去,然后由集群重新调度新的实例分配到其他节点。最常见的是磁盘,默认的docker容器运行在系统盘,当系统盘磁盘使用量超过90%时,节点上的实例会被驱逐。驱逐重新调度再启动的过程中,会对线上业务产生影响。
解决方案:
1)优化容器本身对磁盘等资源的占用、使用数据盘等,参考磁盘占用较大的原因。
2)为集群和应用配置事件告警,分别配置应用和集群(节点)维度的事件告警后,应用的Pod发生驱逐、节点资源不足(或者磁盘回收失败)等事件就能第一时间感知。比如类似的事件:
2020-07-21 10:24:43.000 [Event] Type: Warning, Reason: Evicted, Message: The node was low on resource: ephemeral-storage. The node had condition: [DiskPressure],表示节点磁盘使用率比较高 failed to garbage collect required amount of images 磁盘不足引起集群对磁盘进行回收(无用的镜像和容器),回收失败则会告警
PS: 对于已经被驱逐的Pod,可以在“失败实例”中看到,建议手动清理,去过集群上被驱逐的失败Pod膨胀,会影响集群自身性能。
1)使用自定义镜像,在自定义镜像中dockerfile中指定自己需要的hosts,参考如下:
RUN echo "192.168.1.37 testgitlab.kuaidihelp.com" >> /etc/hosts
关于自定义镜像制作:点击查看。
注,如果之前使用的是官方镜像,可以base官方镜像来制作你的自定义镜像,dockerfile可以这样写:
// 前缀registry.cn-zhangjiakou.aliyuncs.com不变,后面"jstopen/tomcat8:1.0.0"为使用的官方镜像 FROM registry.cn-zhangjiakou.aliyuncs.com/jstopen/tomcat8:1.0.0 RUN echo "192.168.1.37 testgitlab.kuaidihelp.com" >> /etc/hosts
2)使用yaml类型部署配置,在容器spec中定义hostAliases。
kind: Deployment apiVersion: extensions/v1beta1 metadata: name: stilton labels: app: cheese spec: replicas: 2 selector: matchLabels: app: cheese template: metadata: labels: app: cheese spec: containers: - name: cheese image: errm/cheese:stilton ports: - containerPort: 80 hostAliases: - ip: 127.0.0.1 hostnames: - myadded.examplehostname
可以在容器内通过调用系统环境变量,获取以下信息:
1)容器IP => JST_POD_IP;
2)宿主机ECS IP => JST_NODE_IP;
3)容器名称 => JST_POD_NAME;
4)容器所属Namespace => JST_POD_NAMESPACE。
如下图所示:
1. 检查实例是否成功发布,状态是否正常,异常状态下无法远程登录。
应用-环境管理-实例列表:
若容器实例状态非正常,请先解决容器部署问题,更多请参考:点击查看。
2. 如果实例正常(如上图所示),通常是因为手动操作了ECS安全组,宿主机ECS不在集群安全组导致的。
注:上述截图中容器实例的宿主机IP即为实例所在ECS的内网IP,通过该IP可以找到ECS。
1)找到该环境实例所属的容器集群,集群详情页找到相关的VPC和安全组信息。
2)聚石塔控制台-安全组管理,找到对应的VPC和安全组,检查ECS是否在安全组中,没有的话添加一下。
https://console.cloud.tmall.com/component/securityGroup#/
容器中的文件支持中文,容器操作系统本身需要支持中文编码(可以在容器中执行locale命令查看)、同时应用本身如tomcat等也需要配置中文编码。注:聚石塔官方镜像均支持中文UTF-8编码,使用官方镜像的应用可以在容器中执行locale名称查看。
1. 使用的聚石塔官方镜像,聚石塔官方镜像基本都支持中文编码(在容器中执行locale命令进行确认)。
如果是已经支持了中文编码的官方镜像,请确认应用自身编码配置。
另外可以在环境配置中新增一个环境变量,LANG=en_US.UTF-8;或者在Java启动参数中加上。
-Dfile.encoding=UTF-8。修改环境变量等配置后需要重新部署后生效。
2. 如果使用的自定义镜像,请自行解决。