ACK KubeSkoop(原ACK Net Exporter)是阿里云容器服务开源的网络监控和问题诊断套件,帮助您监测和快速排查集群中的网络疑难问题。本文介绍在ACK托管集群中使用KubeSkoop的最佳实践,帮助您快速上手并解决实际问题。
背景信息
KubeSkoop提供了基于eBPF的深度网络监控、网络连通性诊断、抓包、延迟探测等一系列能力,对外提供Prometheus指标和异常事件。KubeSkoop通过守护进程Pod的方式运行在节点上,借助eBPF技术,采集节点的信息并聚合到具体的Pod中,提供标准化的接口,实现对网络高阶信息的观测。KubeSkoop的核心架构如下图所示。
安装与配置ACK KubeSkoop组件
安装ACK KubeSkoop组件
登录容器服务管理控制台,在左侧导航栏选择集群列表。
在集群列表页面,单击目标集群名称,然后在左侧导航栏,单击组件管理。
在组件管理页面搜索ACK KubeSkoop,找到对应组件并单击安装。
在安装组件 ACK KubeSkoop页面中单击确认。
配置KubeSkoop组件
您可以执行如下命令,通过ConfigMap方式配置KubeSkoop组件。
kubectl edit cm kubeskoop-config -n ack-kubeskoop
您也可以通过控制台配置KubeSkoop组件。
登录容器服务管理控制台,在左侧导航栏单击集群列表。
在集群列表页面,单击目标集群名称,然后在左侧导航栏,选择
。在配置项页面,设置命名空间为ack-kubeskoop,然后搜索kubeskoop-config,单击kubeskoop-config右侧操作列下的编辑。
在编辑面板配置参数,然后单击确定。KubeSkoop支持的配置项及其含义如下:
参数
描述
默认值
debugmode
是否开启调试模式。取值:
false:不开启调试模式。
true:开启调试模式。开启后,支持DEBUG级别的日志,调试接口,Go pprof和gops诊断工具。
false
port
指标服务的端口,提供HTTP服务。
9102
enableController
是否启用控制器组件。控制器负责与Kubernetes API交互,执行监控或管理任务。
true
controllerAddr
控制器服务的地址,用于定位Kubeskoop控制器组件。
dns:kubeskoop-controller:10263
metrics.probes
需要收集的监控指标类型列表,每个probe对应一个指标类别。
- name: conntrack - name: qdisc - name: netdev - name: io - name: sock - name: tcpsummary - name: tcp - name: tcpext - name: udp - name: rdma
可参见探针,指标和事件了解相应探针详情。
在ConfigMap更新完成后,无需重启ACK KubeSkoop组件,组件将会自动热重载变更,打开或关闭对应的探针。
配置ARMS Prometheus大盘
登录ARMS控制台。
在左侧导航栏,单击接入管理。
在接入管理界面中,单击新增接入,在接入中心搜索框中搜索KubeSkoop,单击ACK KubeSkoop网络监控。
在弹出的ACK KubeSkoop 网络监控页面中,选择待接入的容器服务集群,填入接入名称后,单击确定开启KubeSkoop监控。
登录容器服务管理控制台,在左侧导航栏单击集群列表。
在集群列表页面,单击目标集群名称,然后在左侧导航栏,选择 。
单击其他页签,在大盘列表中可以看到KubeSkoop创建的节点和Pod监控大盘。
关于阿里云Prometheus监控的更多使用说明,请见使用阿里云Prometheus监控。
KubeSkoop使用说明
手动查看KubeSkoop的监控指标
KubeSkoop提供适配Prometheus格式的监控数据,在安装完KubeSkoop后,您可以通过访问任意一个KubeSkoop的Pod实例的服务端口获取到全部的指标信息:
可执行如下命令获取到所有KubeSkoop实例。
kubectl get pod -n ack-kubeskoop -o wide | grep kubeskoop-agent
预期输出:
kubeskoop-agent-2chvw 1/1 Running 0 43m 172.16.16.xxx cn-hangzhou.172.16.16.xxx <none> <none> kubeskoop-agent-2qtbf 1/1 Running 0 43m 172.16.16.xxx cn-hangzhou.172.16.16.xxx <none> <none> kubeskoop-agent-72pgf 1/1 Running 0 43m 172.16.16.xxx cn-hangzhou.172.16.16.xxx <none> <none>
执行如下命令,获取指标信息,需要将命令中的
172.16.xxx.xxx
替换为上一步中获取到的KubeSkoop实例的地址。curl http://172.16.16.xxx:9102/metrics
KubeSkoop提供的监控指标数据格式如下:
kubeskoop_netdev_rxbytes{k8s_namespace="",k8s_node="cn-hangzhou.172.16.16.xxx",k8s_pod=""} 2.970963745e+09
如何使用ACK KubeSkoop定位容器网络中的偶发疑难问题
以下内容提供了针对部分云原生典型问题的排查指南,结合ACK KubeSkoop,帮助您快速获取与问题有关的信息。
DNS超时相关问题
在云原生环境中,DNS服务超时问题会导致服务的访问失败,出现DNS访问超时的常见原因有:
DNS服务响应的速度较慢,无法在程序的超时时间到达前完成一次DNS查询。
由于发送端的问题,没有顺利或者及时发送DNS Query报文。
服务端及时响应了报文,但是由于发送端本身的内存不足等问题出现了丢包。
您可以借助以下几个指标来帮助排查偶发的DNS超时问题:
指标名称 | 说明 |
kubeskoop_pod_udpsndbuferrors | UDP协议通过网络层方法发送时出现报错的次数。 |
kubeskoop_pod_udpincsumerrors | UDP接收报文时出现CSUM校验错误的次数。 |
kubeskoop_pod_udpnoports | 网络层调用 |
kubeskoop_pod_udpinerrors | UDP接收报文时出现错误的次数。 |
kubeskoop_pod_udpoutdatagrams | UDP协议通过网络层方法成功发送报文的数量。 |
kubeskoop_pod_udprcvbuferrors | UDP在将应用层协议数据拷贝到Socket接收队列时由于队列不足导致的报错次数。 |
由于云原生环境中很多服务依赖于CoreDNS提供域名解析服务,在出现DNS问题时,如果出现问题的DNS请求与CoreDNS有关,您需要同时观察CoreDNS相关Pod的上述指标的异常情况。
Nginx Ingress HTTP响应状态码499/502/503/504相关问题
云原生环境下,Ingress网关或者其他担任Proxy/Broker作用的代理服务出现偶发的异常是较为常见的疑难问题,对于Nginx Ingress及以Nginx为底座的其他代理服务中,499/502/503/504问题是最为常见的四类,他们各自表征的含义如下:
499
:当请求Nginx的客户端在Nginx没有进行回复的时候就关闭了TCP连接,常见原因包括:客户端连接建立之后,发送请求较晚,导致Nginx回复过程中就达到了Client Timeout,常见于Android客户端的异步请求框架中。
服务端在连接建立后,连接的处理较慢,需要深入排查。
服务端在向上游Upstream的后端发起请求时,后端处理较慢。
502
:场景多见于Nginx与Upstream后端之间连接层面的问题,例如连接建立失败,或者后端异常的关闭,常见原因包括:后端配置的DNS域名解析失败,通常在使用Kubernetes Service作为后端时会出现。
与Upstream之间建立连接失败。
Upstream的请求或者响应过大,无法分配到内存等干扰正常业务交互的现象。
503
:在Nginx中,用于提示客户端所有的Upstream均出现了不可用的情况,在云原生场景下,有一些特定的含义,常见原因包括:没有可用的后端,这种情况通常出现较少。
流量过大,被Ingress的Limit Req所限制。
504
:用于表征Nginx与Upstream相关的业务报文出现超时的问题,常见原因为Upstream返回的业务报文没有及时到达。
在遇到上述几类问题时,您需要先收集一些通用的信息用于界定问题发生的可能范围与下一步排查方向:
Nginx提供的access_log信息,尤其是
request_time
、upstream_connect_time
与upstrem_response_time
。Nginx提供的error_log信息,在问题发生时是否有异常的报错信息出现。
如果配置了Liveness或者Readness健康检查,可查看健康检查。
在上述信息的基础上,在可能出现连接失败时,您需要按照问题的具体现象关注以下指标的变化:
指标名称 | 说明 |
kubeskoop_tcpext_listenoverflow | 当LISTEN状态的Sock接受连接时出现半连接队列溢出时会计数。 |
kubeskoop_tcpext_listendrops | 当LISTEN状态的Sock创建SYN_RECV状态的Sock失败时会计数。 |
kubeskoop_netdev_txdropped | 网卡发送错误并产生丢弃的次数。 |
kubeskoop_netdev_rxdropped | 网卡接收错误并产生丢弃的次数。 |
kubeskoop_tcp_activeopens | 单个Pod内TCP成功发起SYN初次握手的次数,不包括SYN的重传,但是连接建立失败也会导致这个指标上升。 |
kubeskoop_tcp_passiveopens | 单个Pod内TCP完成握手并成功分配Sock的累积值,通常可以理解为成功新建连接的数量。 |
kubeskoop_tcp_retranssegs | 单个Pod内重传的总报文数,这里已经跟据TSO进行了提前的分片计算。 |
kubeskoop_tcp_estabresets | 单个Pod内异常关闭TCP连接的次数,这里仅仅从结果层面统计。 |
kubeskoop_tcp_outrsts | 单个Pod内TCP发送的Reset报文次数。 |
kubeskoop_conntrack_invalid | 在CT创建过程中由于各种原因无法建立,但是报文并未被丢弃的次数。 |
kubeskoop_conntrack_drop | 由于CT创建过程中无法建立而丢弃报文的次数。 |
针对出现了类似Nginx响应慢的情况时,例如虽然出现了超时,但是Nginx的request_time
很短的情况,您可以关注以下指标的变化:
指标名称 | 说明 |
kubeskoop_tcpsummary_tcpestablishedconn | 当前存在的ESTABLISHED状态的TCP连接数量。 |
kubeskoop_pod_tcpsummarytcptimewaitconn | 当前存在的TIMEWAIT状态的TCP连接数量。 |
kubeskoop_tcpsummary_tcptimewaitconn | 当前处ESTABLISHED状态的TCP连接的发送队列中存在的数据包的Bytes总数。 |
kubeskoop_tcpsummary_tcprxqueue | 当前处ESTABLISHED状态的TCP连接的接收队列中存在的数据包的Bytes总数。 |
kubeskoop_tcpext_tcpretransfail | 重传报文返回除了EBUSY之外的报错时计数,说明重传无法正常完成。 |
在上述指标信息的基础上,根据指标在对应问题时间点的变化,可以缩小排查的范围。
TCP Reset报文相关问题
TCP Reset报文是TCP协议中用于对非预期情况做响应的动作,通常会对用户程序造成以下的影响:
connection reset by peer
报错,通常出现在Nginx等C lib依赖的业务中。Broken pipe
报错,通常出现在Java或Python等封装TCP连接的业务中。
云原生网络环境中,出现Reset报文的常见原因有很多,以下列举了几种常见的Reset报文成因:
服务端的异常,导致无法正常提供服务,例如配置的TCP使用的内存不足等原因,这一类情况通常会主动发送Reset。
在使用Service或负载均衡时,由于Endpoint或者Conntrack等有状态的机制出现异常而转发到了非预期的后端。
安全原因导致的连接释放。
在NAT环境,高并发等场景下出现防止回绕序号(Protection Against Wrapped Sequence Numbers,以下简称PAWS)或者序号回绕现象。
使用TCP Keepalive进行连接保持,但是长时间没有进行正常业务通信的情况。
为了快速区分以上不同的根因,您可以收集一些基本的信息指标:
梳理Reset报文产生时网络的客户端和服务端之间的拓扑结构。
关注以下指标的变化:
指标名称
说明
kubeskoop_tcpext_tcpabortontimeout
由于keepalive/window probe/重传的调用超过上限发送Reset时会更新此计数。
kubeskoop_tcpext_tcpabortonlinger
TCP的Linger2选项开启后,快速回收处于FIN_WAIT2的连接时发送Reset的次数。
kubeskoop_tcpext_tcpabortonclose
状态机之外的原因关闭TCP连接时,仍有数据没有读取而发送Reset报文,则会进行指标计数。
kubeskoop_tcpext_tcpabortonmemory
在需要分配tw_sock/tcp_sock等逻辑中有由于tcp_check_oom出发内存不足而发送Reset结束连接的次数。
由于Linger/Linger2选项开启而通过Reset进行连接的快速回收时发送Reset的计数。
kubeskoop_tcpext_tcpackskippedsynrecv
在SYN_RECV状态的Sock不回复ACK的次数。
kubeskoop_tcpext_tcpackskippedpaws
由于PAWS机制触发校正,但是OOW限速限制了ACK报文发送的次数。
kubeskoop_tcp_estabresets
单个Pod内异常关闭TCP连接的次数,这里仅仅从结果层面统计。
kubeskoop_tcp_outrsts
单个Pod内TCP发送的Reset报文次数。
偶发网络延迟抖动相关问题
网络偶发延迟抖动类问题是云原生环境中最为常见和最难定位的一类问题,成因的现象极多,同时出现延迟可能会导致上述的三种问题的产生。容器网络场景下,节点内部出现的网络延迟通常包含以下几种原因:
出现某个RT调度器管理的实时进程执行时间过久,导致业务进程或网络内核线程出现排队较长或者处理较慢的现象。
进程本身出现了偶发外部调用耗时久的现象,如云盘响应慢,RDS的RTT偶发增加等常见原因,导致请求处理较慢。
节点本身配置问题导致节点内不同CPU/不同NUMA Node之间负载不均,高负载的系统出现卡顿。
内核的有状态机制引发的延迟,如Conntrack的Confirm操作,大量Orphan Socket影响了正常的Socket查找等。
面对此类问题,尽管表现为网络问题,其最终的原因通常是由于OS的其他原因导致,您可以关注以下指标来缩小排查的范围:
指标名称 | 说明 |
kubeskoop_io_ioreadsyscall | 进程进行文件系统读操作,如read,pread的次数。 |
kubeskoop_io_iowritesyscall | 进程进行文件系统写操作,如write,pwrite的次数。 |
kubeskoop_io_ioreadbytes | 进程从文件系统,通常是块设备中读取的Bytes数量。 |
kubeskoop_io_iowritebytes | 进程向文件系统进行写入的Bytes数量。 |
kubeskoop_tcpext_tcptimeouts | CA状态并未进入recovery/loss/disorder时触发,当SYN报文未得到回复时进行重传会计数。 |
kubeskoop_tcpsummary_tcpestablishedconn | 当前存在的ESTABLISHED状态的TCP连接数量。 |
kubeskoop_tcpsummary_tcptimewaitconn | 当前存在的TIMEWAIT状态的TCP连接数量。 |
kubeskoop_tcpsummary_tcptxqueue | 当前处于ESTABLISHED状态的TCP连接的发送队列中存在的数据包的Bytes总数。 |
kubeskoop_tcpsummary_tcprxqueue | 当前处于ESTABLISHED状态的TCP连接的接收队列中存在的数据包的Bytes总数。 |
kubeskoop_softnet_processed | 单个Pod内所有CPU处理的从网卡放入CPU的Backlog的报文数量。 |
kubeskoop_softnet_dropped | 单个Pod内所有CPU丢弃的报文数量。 |
客户案例分析
以下为部分容器网络客户借助ACK KubeSkoop进行疑难问题排查分析的案例,您可以比对现象进行参考。
案例一:偶发DNS Timeout问题
问题现象
客户A发现异常,现象为有偶发的DNS解析超时,用户业务采用PHP,DNS服务为配置CoreDNS。
排查过程
根据客户描述,与客户沟通后获取客户监控中的DNS相关数据。
分析客户报错时间点内数据,发现以下问题。
报错时间内
kubeskoop_udp_noports
增加1,指标整体较小。kubeskoop_packetloss_total
指标加1,丢包数变化较少。
客户反馈配置的DNS地址为公网某服务商地址,结合监控信息,判断客户报错根因为DNS请求返回较慢,用户态超时返回后,DNS回包到达。
案例二:Java应用偶发连接失败问题
问题现象
客户B发现异常,现象为出现偶发的Tomcat不可用,每次出现持续时间约为5~10s。
排查过程
经过日志分析,确认现象发生时,客户的Java Runtime正在进行GC操作。
KubeSkoop监控部署后发现客户在问题的时间点
kubeskoop_tcpext_listendrops
指标有明显的上升。经过分析后得出结论,客户的Java Runtime进行GC操作时,处理请求的速度变慢,导致请求的释放变慢,但是请求的新建并没有被限制,因此产生了大量的链接,将Listen Socket的Backlog打满后产生溢出,导致
kubeskoop_tcpext_listendrops
上升。此问题中,客户的连接堆积持续时间短,且本身处理能力没有问题,因此建议客户调整Tomcat相关参数后,解决了客户问题。
案例三:某客户偶发网络延迟抖动问题
问题现象
客户C发现异常,现象为客户应用于Redis之间的请求出现了偶发的RTT增高导致业务超时,但是无法复现。
排查过程
经过日志分析,客户出现了偶发的Redis请求超过300ms的总响应时间的情况。
部署KubeSkoop后,从监控中发现了kubeskoop_virtcmdlatency_latency指标在问题发生时有增长,增长的le(Prometheus监控中的Level)为18与15。经过换算得知此时出现过两次延迟较高的虚拟化调用,其中le为15的产生了36ms以上的延迟,而le为18的产生了200ms以上的延迟。
由于内核的虚拟化调用执行时会占据CPU,无法被抢占,因此客户的偶发延迟是由于Pod的批量增删过程中有一些虚拟化调用执行过久导致。
案例四:Ingress Nginx偶发健康检查失败问题
问题现象
Ingress机器有偶发的健康检查失败并伴随着业务请求失败的问题。
排查过程
部署监控后发现出现的问题是多个指标有异常的变化。
kubeskoop_tcpsummary_tcprxqueue
与kubeskoop_tcpsummary_tcptxqueue
均出现了上升。kubeskoop_tcpext_tcptimeouts
出现了上升。kubeskoop_tcpsummary_tcptimewaitconn
下降,kubeskoop_tcpsummary_tcpestablishedconn
上升。
经过分析后确认在问题发生的时间点,内核工作正常,连接建立正常,但进程的运行出现了异常,包括处理收取Socket中的报文以及实际执行报文的发送操作,推测此时用户进程存在调度问题或者限制问题。
建议用户查看Cgroup的监控后发现客户在问题时间点出现了CPU Throttled现象,证明此时出现了偶发的用户进程由于Cgroup原因无法得到调度的现象。
参见启用CPU Burst性能优化策略,为Ingress配置CPU Burst功能后,解决了这一类问题。