一直以来,我们用的线上 k8s 非常稳定,但是在春节期间,出现一个很奇怪的问题,那天同事在更新代码后,需要更新线上的应用,之后突然发现本地电脑执行 kubectl 一直返回 timeout 错误。
这时候,我登录 k8s master 节点机器开始查找问题,发现 kubectl 也不能使用了,这就意味着 APIServer 的接口出错了,查看监控,果然是出问题之后的监控数据全部消失了。
然后用 docker logs 查看日志,发现大量的 http status code 429 错误,这个 HTTP 429 代表的意思就是请求太频繁,导致服务器来不及处理请求了。也就是说,当前的 APIServer 接口到达处理极限了。
为了尽快处理问题,先将机器重启,结果,还是没法解决,反而是 AVG CPU load 超过 1 了,平时也就零点几,这显然是太高了。
考虑了一会儿,我觉得应该将整个 k8s 集群重新安装,恩,果然没事了,可以安心过春节了。
但是同时,由于处理太着急,一些日志也没有保留,导致无法定位真正的问题。
原因总结下来,很大一部分原因是监控没有做好,报警也没有发挥作用。
因此,我在接下来的时间里,连续部署了两套监控报警系统
收到报警,集群 APIServer HTTP 错误率到达 100%,细看还是那个 429 的 HTTP 错误,打开 master 节点的 netdata 监控图表,发现了有两个报警,提示: TCP listen overflow。
TCP 相关的基础知识就不再赘述了,这里只说一点:TCP 的 backlog 就是一个处理队列,当有新连接请求(SYN 包)来的时候,就会把请求放在 backlog 中等待处理,而假如这个队列太小又或者并发请求数又太高,就会出现这个问题。
于是直接将 TCP backlog 的数值调高,从 128 提高到 256。
echo 256 > /proc/sys/net/ipv4/tcp_max_syn_backlog
观察一阵后,问题还是存在,那么原因很显然不是这个。
于是继续观察 netdata 数据,从最上面的图表看到最下面,当看到 ETCD 这一栏监控数据的时候,发现了问题,内存从发生问题的时间点之后,几分钟内一路飙升至 500M,并一直保持不变,但是目前机器的内存使用率并没有超过 50% 。
于是我做了这么个推测:我使用的部署脚本中,会不会有参数定死了 500 M 呢?
于是查看 Etcd 启动文件:
- #!/bin/bash
- /usr/bin/docker run \
- --restart=on-failure:5 \
- --env-file=/etc/etcd.env \
- --net=host \
- -v /etc/ssl/certs:/etc/ssl/certs:ro \
- -v /etc/ssl/etcd/ssl:/etc/ssl/etcd/ssl:ro \
- -v /var/lib/etcd:/var/lib/etcd:rw \
- --memory=512M \
- --oom-kill-disable \
- --blkio-weight=1000 \
- --name=etcd1 \
- quay.io/coreos/etcd:v3.2.4 \
- /usr/local/bin/etcd \
- "$@"
命令的参数中的:--memory=512M 以及 --oom-kill-disable 引起了我的注意,这两个参数一个是限制了最大内存,另一个限制了 OOM 的时候不杀掉 Etcd,于是会出现由 OOM 造成的卡死,那么问题原因应该也就是这个了。
好了,改成 1024M,重启,问题解决。
有两方面的原因: