V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Goodapp
V2EX  ›  推广

基于网络抓包实现 kubernetes 中微服务的应用级监控

  •  1
     
  •   Goodapp · 2016-12-30 11:35:26 +08:00 · 2921 次点击
    这是一个创建于 2887 天前的主题,其中的信息可能已经有所发展或是发生改变。

    微服务是什么?

    此话题不是本文重点,如你还不知道。请谷歌一波,会有遍地的解释。引用下图说明下微服务可能呈现的形态: 2016123064266service.png

    微服务监控的挑战

    监控的目的是为了让集群中所有的服务组件,不管是 HTTP 服务,数据库服务,还是中间件服务。都能够健康稳定得运行,能发现问题,遇到问题能找到原因。
    在过去,监控工具侧重于基础设施或单一软件组件以及衡量运营健康。这些工具在实现这一目标方面只取得了一定的成功,但是对于单一的,传统的应用程序和基础设施来说效果不错。微服务的出现暴露了工具中的弱点。
    现在,组件托管在位于私有云,公共云或两者的混合体之间的虚拟化机器或容器内。获悉我并不需要关心服务 cpu 用了多少,内存用了多少?确保这些服务相互通信以提供所需的结果需要从监控的角度重要看几件事情:

    1. 微服务集群中是否所有的服务的吞吐率,响应时间都正常?
    2. 服务调用线中哪些线负载过大,哪些线负载过小?
    3. 服务的错误率,例如 HTTP 500 错误。

    我们想要监控分析应用,从它的服务状态出发是否更直接呢?

    已有监控方案

    目前有些厂商提出了微服务的监控解决方案。

    • 从 APM 角度监控服务端到端状态。
    • 为每种类型服务开发 agent 收集应用状态信息。
      • 通过产生统一的应用日志分析监控方案
      • 其他方案

    每一种商业或开源方案都有它的优势所在。可以根据你的需求来进行选择。例如你的所有服务都是自己研发,日志标准一致 or 能够统一处理。所有访问信息都能打出日志,那么我认为日志分析可能是你最适合的方案。但是对于公有云平台,那就不同了。

    好雨云帮采用的方案

    好雨云帮提供了公有云和私有化的部署方式,平台内部署的服务各式各样。各种通信协议,各种日志标准。我们怎么实现对所有服务的应用状态监控?好雨云帮完善的租户网络,环境隔离,因此我们提供用户在自己环境下安装自己的监控组件,我们的基础数据收集是通过网络分析。下文详细讲解:

    kubernetes POD 共享机制

    kubernetes 中 pod 内容器共享网络空间,挂在卷等为我们监控 pod 内主服务容器提供方便。其实按照官方对 pod 的定义的使用面来说:

    * content management systems, file and data loaders, local cache managers, etc.
    * log and checkpoint backup, compression, rotation, snapshotting, etc.
    * data change watchers, log tailers, logging and monitoring adapters, event publishers, etc.
    * proxies, bridges, and adapters
    * controllers, managers, configurators, and updaters
    

    pod 内除了主服务外我们可以部署一些附属服务。之前的文章我谈过使用 pod 的插件服务收集处理日志。今天我再谈使用 pod 的网络便利监控主服务应用级指标。

    通过共享的网卡抓包分析网络流量反应应用状况

    我们拿一个 http 服务为例,我们监控网络流量能拿到几乎所有访问和服务返回信息。例如 1 分钟内多少request,分别请求哪些path,多长时间服务返回了。返回状态码等等信息。
    要获得以上的数据,我们需要获取到网络包,解码网络包然后获得 http 协议数据。
    我们WatchData服务容器与应用容器在同 pod 中,经过应用容器eth0网卡的流量我们再WatchData容器中eth0网卡获取。通过解码网络包获取 http 报文头关键信息,每一个Response形成一个消息发送到 server 端完成分析,存储然后形成连续的实时的监控数据。下图展现个简要的整体架构图:

    2016123050718pod.jpeg

    当然,上文已经说了,我们采取此方案主要就是为了能够监控各种应用,只是http怎么行。不通的通信应用使用不同的通信协议,比如mysql的协议,mongodb的协议。TCP/IP网络协议栈分为应用层(Application)、传输层(Transport)、网络层(Network)和链路层(Link)四层。。我们抓取到的网络包信息也是四层模型。

    网络抓包 Golang 实现

    使用 golang 实现网络抓包非常容易。得益于谷歌的包:

    github.com/google/gopacket
    github.com/google/gopacket/layers
    github.com/google/gopacket/pcap
    

    这里我举一个监听网卡的 Demo 主要代码

    //device 网卡名
    if handle, err := pcap.OpenLive(device, int32(n.Option.Snaplen), true, n.Option.TimeOut); err != nil {
    			log.With("error", err.Error()).Errorln("PCAP OpenLive Error.")
    			return 1
    		} else if err := handle.SetBPFFilter(n.Option.Expr); err != nil { // optional
    			log.With("error", err.Error()).Errorln("PCAP SetBPFFilter Error.", n.Option.Expr)
    			return 1
    		} else {
    			log.Infoln("Start listen the device ", device)
    			packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
    			go func(close chan struct{}, h *pcap.Handle) {
    				for {
    					select {
    					case packet := <-packetSource.Packets():
    						n.handlePacket(packet) // Do something with a packet here.
    					case <-close:
    						log.Infoln("stop listen the device.")
    						h.Close()
    						return
    					}
    				}
    			}(n.Option.Close, handle)
    		}
    

    这段代码就是监听某个网卡,通过n.Option.Expr规则过滤点无用网络包,规则语法与 linux tcpdump 一样。参考:PCAP-FILTER 接收到网络包一般有多种类型: 2 层模型的包,和 4 层模型的包。如果你不关注 tcp 握手这种类型的包你只需要关注具有四层模型的网络包。 n.handlePacket(packet)处理网络包。

    app := packet.ApplicationLayer()
    	if app != nil {
    		//log.With("type", app.LayerType().String()).Infoln("Receive a application layer packet")
    		//log.Infoln(packet.String())
    		go func() {
    			sd := &SourceData{
    				Source:      app.Payload(),
    				ReceiveDate: packet.Metadata().Timestamp,
    			}
    			tran := packet.TransportLayer()
    			if tran != nil {
    				src, dst := tran.TransportFlow().Endpoints()
    				sd.SourcePoint = &src
    				sd.TargetPoint = &dst
    				if tran.LayerType().Contains(layers.LayerTypeTCP) {
    					tcp := &layers.TCP{}
    					err := tcp.DecodeFromBytes(tran.LayerContents(), gopacket.NilDecodeFeedback)
    					if err != nil {
    						log.With("error", err.Error()).Errorln("Decode bytes to TCP error")
    					} else {
    						sd.TCP = tcp
    					}
    				}
    			}
    			netL := packet.NetworkLayer()
    			if netL != nil {
    				src, dst := packet.NetworkLayer().NetworkFlow().Endpoints()
    				sd.SourceHost = &src
    				sd.TargetHost = &dst
    			}
    			decode := FindDecode(n.Option.Protocol)
    			if decode != nil {
    				decode.Decode(sd)
    			} else {
    				log.Debugf("%s protol can not be supported \n", n.Option.Protocol)
    			}
    		
    

    如上代码简单处理四层模型网络包。一般你可以从网络层获取双方 ip 地址,从传输层获取双方端口以及 tcp 包的相关信息。从应用层获取应用数据。 具体的怎么优化和实践就留给大家自己尝试吧。

    网络抓包监控的优缺点

    优点:

    1. 应用无关性,监控工具通用性强。
    2. 数据全面性,你可以获取很多直接和间接反应应用状态的数据。
    3. 不侵入代码,一般不影响网络。
    4. 高并发下不影响应用。

    缺点:

    1. 资源消耗,抓包分析包是一个物理资源消耗的过程。
    2. 需要自己开发。

    总之,就像上文说得一样。如果你的需求只是想监控一个应用。你就别考虑这个方案了。如果你想监控集群中所有应用,你可以尝试。

    云盟认证成员barnett

    目前尚无回复
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3758 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 10:40 · PVG 18:40 · LAX 02:40 · JFK 05:40
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.