KubeSphere v3.1.0通过集成KubeEdge,将节点和资源的管理延伸到了边缘,也是KubeSphere正式支持边缘计算的第一个版本。
本文作者也第一时间搭建和试用了边缘节点相关的功能,但是在边缘节点纳管之后遇到了一些监控的小问题,在排查过程中也顺带了解了一下KubeSphere对于边缘节点的监控原理,发出来和大家分享,方便其他的开发者能够更快的排查问题或进行二次开发。

环境版本和构成

通过KubeKey安装,参数如下,其余组件版本默认未改动。
Kubernetes : v1.19.8
KubeSphere : v3.1.0

问题现象

通过生成的keadm命令行将边缘节点加入集群,并在边缘节点上部署POD,该POD的监控信息不能显示。

监控原理

定位和解决问题之前,肯定是要先搞懂工作原理。

1. KubeEdge
KubeEdge的Edgecore组件对Kubelet进行了轻量化改造,Edgecore和Cloudcore(云端)也不在同一个Cluster网络中,通过k8s默认的方式进行metrics获取肯定是行不通的(logs和exec原理相同)。
当前KubeEdge的实现方法是kube-apiserver上的iptables转发给云端的Cloudcore,Cloudcore通过和Edgecore之间的WebSocket通道向边缘端进行消息和数据传递。
KubeEdge官方的使用手册和文档如下:
https://kubeedge.io/en/docs/advanced/metrics/

为了便于大家理解,作者画了一张图,整体的流程请参考如下:

2. Metrics-server
原生的K8S中就是通过Metrics-server这个官方组件进行节点和POD的CPU/Memory等数据的监控。
简而言之,Metrics-server通过Pull的方式去每个节点上拉取监控数据,放在自身的内存中,提供K8S的API供kubectl top这样的client来查询。
Metrics-server的详细设计,可以参考github的官方说明:
https://github.com/kubernetes-sigs/metrics-server

Metrcis-server的启动参数中,有一个参数要特别说明一下:“kubelet-use-node-status-port”。
在KubeEdge的官方文档中,也提到了启动Metrics-server时要指定该参数,至于原因文档中并未提及,这里简单说明一下。这个参数的意思是:“调用kubelet服务时,用该Node上报的port,而不是默认的port”。我们知道kubelet的metrcis接口默认是监听在10250端口的,而KubeEdge的edgecore将metrics接口默认监听在10350端口,如果不加这个参数,metrice-server就会通过类似"edgenodeIP:10250/stat/summary"这样的请求去获取监控数据,结果肯定获取失败的。
我们通过KubeSphere环境的yaml文件,也能清晰地看到这一点配置:

3. KubeSphere
上面讲到了,Metrics-server已经从KubeEdge那里获取到了边缘节点的监控数据,那么KubeSphere只要从Metrics-server提供的K8S API中即可获取到边缘节点的实时监控数据用来在前端进行展示。
稍微翻了一下KubeSphere的代码,和我们的预想是一致的,KubeSphere通过metrics-server拿到了当前版本展示的监控数据。

4. EdgeWatcher
从上述第1点KubeEdge的工作原理来看,是需要在kube-apiserver所在的节点上进行iptables转发规则设置的(将所有10350的请求都转发给Cloudcore的10003端口进行处理)。
那么每一个边缘节点加入集群的时候不可能由运维人员手动进行iptables的规则设置,所以KubeSphere就自研了EdgeWatcher这样一个组件。这个组件的目的应该是有以下几点:

  • 提供kubeedge group API(添加边缘节点时前端调用该group API)
  • 边缘节点加入集群时,设置IPtables规则(logs exec metrics都需要)
  • 验证边缘节点指定的IP是否可用,IP需要全局唯一

EdgeWatcher暂未开源,作者从社区转载了下面这张EdgeWatcher的工作原理图,供大家参考:

关于边缘节点IP需要全局唯一的问题,作者还是有很多想说的,后续有时间再开一篇,和大家一起探讨。

5. 总体概览
其实通过对上述监控组件的了解,我们也基本能勾勒出KubeSphere v3.1在基于KubeEdge的边缘集成中,所作的努力和工作。下面是作者简单画的一张整体组件架构的图,供大家参考:

问题定位

既然原理都搞清楚了,下面就简单说一下定位的过程和思路。
1. Metrics-server
首先我们判断metrics-server有没有正常提供服务,能不能获取到边缘数据。
从下面的命令结果可以看出,边缘节点(k8s-agent)的监控数据和非边缘节点的POD的监控数据都是没有问题的。

只有边缘节点上的POD的监控数据获取不到。

2. KubeEdge
再来看KubeEdge提供的10350端口的metrics服务,有没有问题。


我们可以看到,KubeEdge的edgecore提供的10350端口的服务也是没有问题的,可以从中获取到边缘节点和边缘POD(nginx-xxx)的监控数据。

3. 总结
从上面的分析可以得出以下结论:

  • Metrcis-server没问题
  • KubeEdge的edgecore在边缘节点的服务没问题
  • cloudcore和edgecore之间的通路没有问题(通过查看edgecore的日志,可以看到stat/summary的调用,但是POD的监控数据调用则没有)

最后再去确认其他可以获取边缘POD节点的信息,发现只有docker版本的差别,出问题的是v18.09.1,而正常的节点版本如下:

至此,基本能断定是docker版本过低造成的,至于是哪个接口和metrics-server不能兼容,就不花太多时间去调查分析,有经验的开发者可以留言共享一下。

结论

基于这个问题,我们对Docker版本进行了测试,最终确认在KubeSphere默认的metrics-server版本(v0.4.2)的场景下,Docker版本要大于等于v19.3.0才能支持边缘POD的监控。

后记

虽然问题不是很大,但是通过这个小问题能把边缘监控的脉络搞清楚,是比问题本身更有意义的。
通过这样的分析和总结,问题定位和二次开发的效率才会更高,希望我们社区的开发者一起把KubeSphere做得更好更完善。

zhu733756
我复现了一下,并没有发现大佬描述的问题:

1 docker 安装

sudo apt-get install docker-ce=5:19.03.9~3-0~ubuntu-focal docker-ce-cli=5:19.03.9~3-0~ubuntu-focal containerd.io

查看docker 版本

2 边缘节点 node metrics


3 边缘节点pod metrics

PS: 我的边缘节点均通过外网ip与cloudcore通信

    zhu733756 版本号看错了,我重新测一下,我看截图去了
    ———-
    更新新进展: 确实跟大佬发现的问题一样,跟内核版本和操作系统没关系,我测试centos和ubuntu两个操作系统下的docker版本都是 边缘节点所在的pod metrics为空:

    curl -ki localhost:10350/stats/summary
    {
     "node": {
      "nodeName": "edgenode-wnlb",
      "systemContainers": [
       {
        "name": "pods",
        "startTime": "2021-05-19T02:51:55Z",
        "cpu": {
         "time": "2021-05-19T02:58:41Z",
         "usageNanoCores": 0,
         "usageCoreNanoSeconds": 81040512
        },
        "memory": {
         "time": "2021-05-19T02:58:41Z",
         "availableBytes": 1033695232,
         "usageBytes": 6631424,
         "workingSetBytes": 6430720,
         "rssBytes": 1507328,
         "pageFaults": 0,
         "majorPageFaults": 0
        }
       },
       {
        "name": "kubelet",
        "startTime": "2021-05-19T02:51:55Z",
        "cpu": {
         "time": "2021-05-19T02:58:39Z",
         "usageNanoCores": 7826966,
         "usageCoreNanoSeconds": 4676221589
        },
        "memory": {
         "time": "2021-05-19T02:58:39Z",
         "usageBytes": 40861696,
         "workingSetBytes": 39350272,
         "rssBytes": 37896192,
         "pageFaults": 33726,
         "majorPageFaults": 17
        }
       },
       {
        "name": "runtime",
        "startTime": "2021-05-19T02:51:55Z",
        "cpu": {
         "time": "2021-05-19T02:58:36Z",
         "usageNanoCores": 2928595,
         "usageCoreNanoSeconds": 7161199061
        },
        "memory": {
         "time": "2021-05-19T02:58:36Z",
         "usageBytes": 212058112,
         "workingSetBytes": 98967552,
         "rssBytes": 59850752,
         "pageFaults": 94660,
         "majorPageFaults": 55
        }
       }
      ],
      "startTime": "2021-05-19T02:21:35Z",
      "cpu": {
       "time": "2021-05-19T02:58:39Z",
       "usageNanoCores": 17408633,
       "usageCoreNanoSeconds": 65648880947
      },
      "memory": {
       "time": "2021-05-19T02:58:39Z",
       "availableBytes": 557957120,
       "usageBytes": 847716352,
       "workingSetBytes": 482168832,
       "rssBytes": 149295104,
       "pageFaults": 42402,
       "majorPageFaults": 85
      },
      "network": {
       "time": "2021-05-19T02:58:39Z",
       "name": "eth0",
       "rxBytes": 222483820,
       "rxErrors": 0,
       "txBytes": 8539498,
       "txErrors": 0,
       "interfaces": [
        {
         "name": "eth0",
         "rxBytes": 222483820,
         "rxErrors": 0,
         "txBytes": 8539498,
         "txErrors": 0
        }
       ]
      },
      "fs": {
       "time": "2021-05-19T02:58:39Z",
       "availableBytes": 18767896576,
       "capacityBytes": 20749852672,
       "usedBytes": 1965178880,
       "inodesFree": 2492827,
       "inodes": 2560000,
       "inodesUsed": 67173
      },
      "runtime": {
       "imageFs": {
        "time": "2021-05-19T02:58:39Z",
        "availableBytes": 18767896576,
        "capacityBytes": 20749852672,
        "usedBytes": 133865025,
        "inodesFree": 2492827,
        "inodes": 2560000,
        "inodesUsed": 67173
       }
      },
      "rlimit": {
       "time": "2021-05-19T02:58:42Z",
       "maxpid": 32768,
       "curproc": 177
      }
     },
     #正常来说这里应该是有数据的
     "pods": []

      zhu733756 边缘节点监控数据不显示还可以使用如下方法,感谢你的指导支持。

      kubectl -n kubeedge edit cm edge-watcher


      修改完毕后重启edge-watcher-controller-manager服务

        yinmin2020 客气大佬,这是iptables转发目的地,扩展来说,应该是node节点上的ip都可以的,本身支持lb的,不是填写外网ip地址;最后,感谢两位大佬,素材我统一收集放在kubeedge集成指南,后面有需要的小伙伴可以去看看。

        6 天 后

        kubeedge v1.6.2 昨天发布,今天测试该bug已经修复,见图:

        ks-installer 镜像tag一会pr

        由于目前cloudcore image官方还没有build,但是v1.6.1是可以用的。边缘端需要升级到v1.6.2,也可以添加以下配置进行修改:

        apiVersion: v1
        kind: ConfigMap
        metadata:
          name: edge-watcher-config
          namespace: kubeedge
        data:
          version: v1.6.2
          uri: ""
          region: zh
        5 个月 后

        yinzhipeng123 改成0.0.0.0试试?

        边缘测得通过云端得ip去通信。所以云端暴露得ip,边缘需要能访问到即可。

        metrics是通过metric-server来发起的,cloudcore:tunelport中转来访问边缘测,只要边缘测和云端正常通信,应该是没有问题的。

        如果你需要再其他主机访问边缘metrics,哪得用0.,0.0.0,以及主机可通信。

          zhu733756 现在就是边缘端的监控没有,根据楼主的思路去排查,现在发现边缘端的监控信息现在暴露在边缘端的127.0.0.1上,这个如何改成0.0.0.0,改什么配置呢?

            yinzhipeng123 理解错了,以为你是要通过其他服务器来访问这台边缘测metrics。

            如果是ks安装的话,排查下metrics-server的日志,以及检查云端的iptables转发规则建立了没有?

              8 天 后
              1 个月 后

              zhu733756 大神,你好,我在Kubesphere3.2.0版本上安装kubeedge,遇到了一个问题,目前边缘节点metrics信息都有,也可以正常部署应用,但是就是访问不了log和exec命令框。

              如下图:

              目前在node 1、2、3节点上(iptables部署的节点)可以访问到边缘节点的日志,但是通过网页及api访问不到,请问是什么问题?如何排查?请您百忙之中帮帮我,谢谢