问题1: k8s环境下,服务使用node:xxx-alpine镜像,服务间访问报错: getaddrinfo EAI_AGAIN

问题2: 非alpine镜像, 使用clusterip访问频繁出现超时问题: connect ECONNRESET,read ECONNRESET还有服务本身axios报的timeout

问题3: 非alpine镜像, 使用dns访问报错: getaddrinfo ENOTFOUND

详细背景见: https://github.com/k3s-io/k3s/issues/5897

问题4: coreDns报错出现error: [ERROR] plugin/errors: 2 . NS: read udp 10.42.2.5:38764->183.60.82.98:53: i/o timeout

[DONE]记录问题解决过程

问题1问题排查/解决过程

  1. 现象1: 问题发生在流量高峰阶段
  2. 现象2: 压测tps,200线程仅30多每秒, 吞吐量极差
  3. 现象3: 是偶尔性的, 200线程50次仅发现十几条这样的报错日志

原因描述(备注: 该原因分析, 仅针对node:alpine镜像在对dns解析报错eai_again的问题, 在后文我发现换了debian也有同样的错误, 所以这个问题也不排除是coreDns出了问题)

参考链接: https://github.com/nodejs/docker-node/issues/1030#issuecomment-956122581

我们所有的程序相互都是以http协议进行接口交互, 而k8s提供的service为每一组pod提供了dns

当A调用B时,

调用方式即如下: http://B.default.svc.cluster.local:<port>

当A尝试与B.default.svc.cluster.local建立 HTTP 连接的时候
必须查找 IP,因此 lib/dns.js(Node 的一部分)包装了 Node 的引擎函数
然后通过调用 getaddrinfo() 进行实际查找
后者取决于动态链接的 libc(alpine使用的并不是像其他系统一样的传统的libc)
还有一个问题:Alpine 的 musl libc 不完全支持 DNS 解析的所有功能,例如当使用多个 DNS 服务器或搜索命令时

参考链接中提到两种可能的解决方案:
**A)**不要使用不完全支持 libc 功能(例如 Alpine)的最小基础镜像,而是切换到 Debian、Ubuntu、Ubi 等“slim”变体。
**B)**在构建 Node.js 引擎二进制文件时,将 libc 的 getaddrinfo() 静态链接到二进制文件中。这不会使用动态链接的 musl libc 代码。

问题2、3、4问题排查/解决过程

  1. 首先确认pod的dnsPolicy,为ClusterFirst(默认)

  2. 查看系统日志, 有error提示, 但是通过该 issue来看, 似乎问题不在这里

1
2
Aug 15 21:51:12 k3s-prod-master3 k3s: W0815 21:51:12.632215    2021 watcher.go:220] watch chan error: etcdserver: mvcc: required revision has been compacted
Aug 15 21:51:18 k3s-prod-master3 k3s: W0815 21:51:18.566631 2021 watcher.go:220] watch chan error: etcdserver: mvcc: required revision has been compacted
  1. 查看coredns的日志,通过日志,又去检查了10.42.2.5所在节点,服务器带宽较低
1
2
3
# kubectl logs coredns-7448499f4d-pswcf -n kube-system

error: [ERROR] plugin/errors: 2 . NS: read udp 10.42.2.5:38764->183.60.82.98:53: i/o timeout
  1. 随即手动进入容器curl集群内部接口 - 正常;curl集群外部第三方服务接口 - 响应较慢

  2. 查看coreDns的监控, 是否超标

我们现在coreDns的资源即副本数如下, 猜测是由于CoreDNS副本数不足、业务请求量高等情况导致的CoreDNS负载高, 才发生的报错(但Prometheus查并没啥异样...高峰期0.38左右的cpu和20多m内存, 并没到限制值)

1
2
3
4
5
6
7
8
spec:
replicas: 1
resources:
limits:
memory: 170Mi
requests:
cpu: 100m
memory: 70Mi
  1. 进行dns debug: https://kubernetes.io/docs/tasks/administer-cluster/dns-debugging-resolution/,请求均正常响应
  • dnsutils-pod.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion: v1
kind: Pod
metadata:
name: dnsutils
namespace: default
spec:
containers:
- name: dnsutils
image: e2eteam/jessie-dnsutils:1.0
command:
- sleep
- "3600"
imagePullPolicy: IfNotPresent
restartPolicy: Always
  • kubectl exec -i -t dnsutils -- nslookup dns
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 使用dig命令, status为NOERROR, 循环看了1000次
kubectl exec -i -t dnsutils -- sh -c 'while true; do dig +all sapi-tenant-part.sopei-biz.svc.cluster.local google.com google.com; sleep 1; done'
```
; <<>> DiG 9.9.5-9+deb8u19-Debian <<>> +all a sapi-tenant-part.sopei-biz.svc.cluster.local
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 36446
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available
```

# 使用nslookup命令
kubectl exec -i -t dnsutils -- nslookup kubernetes.default
```
Server: xxx
Address: xxx#53

Name: kubernetes.default.svc.cluster.local
Address: xxx
[root@VM-30-197-centos ~]# kubectl exec -it dnsutils -- nslookup sapi-part-category.sopei-biz.svc.cluster.local
Server: xxx
Address: xxx#53

Name: sapi-part-category.sopei-biz.svc.cluster.local
Address: xxx
```

补充1

  • 暂时是将所有的dns地址换成了service的cluster ip了, 并且发现吞吐量是使用dns时候的5倍之多, 感觉就是dns解析这里出了问题

补充2

  • 在将内存最小最大都调至210,再进行压测还是会有getaddrinfo enotfount这种问题,且内存占用资源还不到限制额度的7分之一,而且使用clusterIp访问方式压测第2番之后,发现流量过大会有如下问题

    服务间接性timeout: connect ECONNRESET,read ECONNRESET还有服务本身axios报的timeout

    以下问题是因为重启了coreDns导致,忽略

    发现了coreDns的error日志

    1
    2
    3
    4
    5
    6
    .:53(53即dns端口)
    [INFO] plugin/reload: Running configuration MD5 = 442b35f70385f5c97f2491a0ce8a27f6
    CoreDNS-1.8.3
    linux/amd64, go1.16, 4293992
    [ERROR] plugin/errors: 2 4227623083530362207.3296446569099129492. HINFO: read udp 10.42.2.219:48721->xxx:53: i/o timeout
    [ERROR] plugin/errors: 2 4227623083530362207.3296446569099129492. HINFO: read udp 10.42.2.219:58867->xxx:53: i/o timeout

补充3

  • 按照官方的建议将版本升至1.24.3,并加egrees-selector-mode: flase参数, 再次进行压测, 还是会有超时问题, 所以想着是不是节点之间的网络有问题

这里将所有的agent节点pod迁移到master, 并停止调度, 再次进行压测

1
2
3
4
5
6
7
8
# 配置不可调度
echo k3s-prod-node1 k3s-prod-node2 k3s-prod-node3|xargs -n 1 kubectl cordon
# 取消不可调度
echo k3s-prod-node1 k3s-prod-node2 k3s-prod-node3|xargs -n 1 kubectl uncordon
# 驱逐已经运行的业务容器(排除daemonset)
echo k3s-prod-node1 k3s-prod-node2 k3s-prod-node3|xargs -n 1 kubectl drain --ignore-daemonsets
# 如果想删除node 节点,则进行这个步骤
kubectl delete node k3s-prod-node1
  1. 使用clusterip的方式压测, timeout问题消失, 大胆断定之前服务间接性timeout问题是因为node节点和master节点之间connect存在互通问题(目前是node和master之间使用nginx进行负载, 而nginx所在服务器资源占用比较严重)
  2. 使用dns的方式进行压测, 服务出现间接性的getaddrinfo ENOTFOUND错误

补充4(第三个问题)

  • 第三个问题: 如果使用dns访问, 服务将偶现getaddrinfo enotfound

肯定还是dns解析问题, 然后顺着https://stackoverflow.com/questions/70913822/kubernetes-k3s-pod-gets-enotfound-after-5-20-hours-of-airing-time去了解下nodelocalcache, 安装, 并进行压测, 此问题消失

关于NodeLocalCache, 站内查看NodeLocalCache

补充5(第四个问题)

可以使用log插件将请求详情记录下日志,来分析异常的原因; 但需要注意的是开启log插件调试可能会消耗10%左右的cpu资源, 建议调试完之后关闭

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 通过修改kubernetes的configmap中的coredns配置来开启日志功能,无需重启coredns
kubectl edit configmaps -n kube-system coredns
# 使用log插件,默认记录所有类型的日志,指定只记录错误相关的信息
log {
class denial error
}
# 只打印拒绝了的, 并且是example.org下的请求
log example.org {
class denial
}

# forward . /etc/resolv.conf: 代表当访问外部域名时,域名查询请求转移到预定义DNS服务器(/etc/resolv.conf中指定的nameserver),请求在这几个nameserver间随机分发
# cat /etc/resolv.conf
# nameserver 211.136.17.107
# nameserver 211.136.20.203

问题1:通过错误日志error: [ERROR] plugin/errors: 2 . NS: read udp 10.42.2.5:38764->183.60.82.98:53: i/o timeout,随即去检查10.42.2.5所在节点,发现出网带宽较低,ssh进入当前节点,进行curl外部第三方服务接口时发现响应也较慢

问题2(属于资源浪费,不能算问题):发现些外部域名末尾加了本不该加的svc.cluster.local, 如下

1
2
[INFO] 10.42.3.0:41390 - 37462 "AAAA IN cmq-gz.public.tencenttdmq.com.cluster.local. tcp 61 false 65535" NXDOMAIN qr,aa,rd 154 0.000066155s "0"
[INFO] 10.42.1.0:37098 - 9090 "A IN api.weixin.qq.com.xxx.svc.cluster.local. tcp 63 false 65535" NXDOMAIN qr,aa,rd 156 0.000095249s "0"

原因是因为DNS的无意义请求(其实这个本质上不是问题, 但是产生了资源的浪费)

具体原因和解决方案见本站关于Dns解析的一些认识

参考:

  1. https://kubernetes.io/docs/tasks/administer-cluster/nodelocaldns/
  2. https://www.suse.com/support/kb/doc/?id=000020174

使用镜像(1.22.8): https://hub.docker.com/r/dyrnq/k8s-dns-node-cache/tags