写点什么

有道 Kubernetes 容器 API 监控系统设计和实践

发布于: 2021 年 03 月 11 日
有道 Kubernetes 容器API监控系统设计和实践

本期文章,我们将给大家分享有道容器服务 API 监控方案,这个方案同时具有轻量级和灵活性的特点,很好地体现了 k8s 集群化管理的优势,解决了静态配置的监控不满足容器服务监控的需求。并做了易用性和误报消减、可视化面板等一系列优化,目前已经超过 80%的容器服务已经接入了该监控系统。


来源/ 有道技术团队微信公众号

作者/ 郭超容 王伟静

编辑/ hjy


1.背景


Kubernetes 已经成为事实上的编排平台的领导者、下一代分布式架构的代表,其在自动化部署、监控、扩展性、以及管理容器化的应用中已经体现出独特的优势。


在 k8s 容器相关的监控上, 我们主要做了几块工作,分别是基于 prometheus 的 node、pod、k8s 资源对象监控,容器服务 API 监控以及基于 grafana 的业务流量等指标监控。


在物理机时代,我们做了分级的接口功能监控——域名级别接口监控和机器级别监控,以便在某个机器出现问题时,我们就能快速发现问题。


上图中,左边是物理机时代对应的功能监控,包括域名级别接口监控和 3 台物理机器监控。右边是对应的 k8s 环境,一个 service 的流量会由 k8s 负载均衡到 pod1,pod2,pod3 中,我们分别需要添加的是 service 和各个 pod 的监控。


由于 K8s 中的一切资源都是动态的,随着服务版本升级,生成的都是全新的 pod,并且 pod 的 ip 和原来是不一样的。


综上所述,传统的物理机 API 不能满足容器服务的监控需求,并且物理机功能监控需要手动运维管理,为此我们期望设计一套适配容器的接口功能监控系统,并且能够高度自动化管理监控信息,实现 pod API 自动监控。

2.技术选型

为了满足以上需求,我们初期考虑了以下几个方案。


  • 手动维护各个 service 和 pod 监控到目前物理机使用的 podmonitor 开源监控系统。

  • 重新制定一个包含 k8s 目录树结构的系统,在这个系统里面看到的所有信息都是最新的, 在这个系统里面,可以做我们的目录树中指定服务的发布、功能监控、测试演练等。

  • 沿用 podmonitor 框架,支持动态获取 k8s 集群中最新的服务和 pod 信息,并更新到监控系统中。

2.2 方案分析

  • 针对方案一,考虑我们服务上线的频率比较高,并且 k8s 设计思想便是可随时自动用新生成的 pod(环境)顶替原来不好用的 pod,手动维护 pod 监控效率太低,该方案不可行。

  • 第二个方案应该是比较系统的解决办法,但需要的工作量会比较大,这种思路基本全自己开发,不能很好的利用已有的功能监控系统,迁移成本大。

  • 于是我们选择了方案三,既能兼容我们物理机的接口功能监控方案,又能动态生成和维护 pod 监控。

3.整体设计思路


k8s 监控包括以下几个部分:

其中 API 功能监控,是我们保证业务功能正确性的重要监控手段。


通常业务监控系统都会包含监控配置、数据存储、信息展示,告警这几个模块,我们的 API 功能监控系统也不例外。


我们沿用 apimonitor 框架功能,并结合了容器服务功能监控特点,和已有的告警体系,形成了我们容器 API 功能监控系统结构:


首先介绍下目前我们物理机使用的 apimonitor 监控:一个开源的框架

https://gitee.com/ecar_team/apimonitor


可以模拟探测 http 接口、http 页面,通过请求耗时和响应结果来判断系统接口的可用性和正确性。支持单个 API 和多个 API 调用链的探测。


如下图所示,第一行监控里面监控的是图片翻译服务域名的地址,后边的是各台物理机的 ip:端口。


点开每条监控


我们沿用 apimonitor 框架的大部分功能,其中主要的适配和优化包括:


  • 监控配置和存储部分:一是制定容器服务 service 级别监控命名规则:集群.项目.命名空间.服务;(和 k8s 集群目录树保持一致,方便根据 service 生成 pod 监控),二是根据 service 监控和 k8s 集群信息动态生成 pod 级别监控,

  • 监控执行调度器部分不用改动

  • 信息展示部分,增加了趋势图和错误汇总图表

  • 告警部分,和其它告警使用统一告警组。

4.具体实践操作

4.1 添加 service 级别 API 监控告警

需要为待监控服务,配置一个固定的容 service 级别监控。


service 级别监控命名规则:集群.项目.命名空间.服务


以词典查词服务为例,我们配置一条 service 级别的多 API 监控(也可以是单 API 监控)

· 单 API:一个服务只需要加一条 case 用

· 多 API:如果一个服务需要加多条功能 case


其中“所属系统” 是服务所属的告警组,支持电话、短信、popo 群、邮件等告警方式(和其它监控告警通用)


任务名称:取名规则,rancher 中 k8s 集群名字.项目名字.命名空间名字.service 名字(一共四段)


告警消息的字段含义:

docker-dict:告警组,订阅后会收到告警消息

k8s-prod-th:集群

dict: 项目

dict:命名空间

data-server:workload名字

data-server-5b7d996f94-sfjwn:pod名字

{} :接口返回内容, 即:response.content

http://dockermonitor.xxx.youdao.com/monitorLog?guid=61bbe71eadf849558344ad57d843409c&name=k8s-prod-th.dict.dict.data-server.data-server-5b7d996f94-sfjwn : 告警详细链接

4.2 自动生成 pod API 监控

自动生成下面三行监控任务:(第一行监控是按上面方法配置的容器 service ip 监控,后边三行是自动生成 pod 监控任务 )



监控 service 级别是单 API,则自动生成的是单 API,service 级别是多 API,则自动生成的是多 API 监控。


自动生成的 pod 级别监控,除了最后两行标红处(ip: port)和 service 级别不一样,其他都一样。


实现 pod 自动生成的方法

  • 给 podmonitor(改框架是 java 语言编写的),增加一个 java 模块,用来同步 k8s 信息到 podmonitor 中。考虑到修改 podmonitor 中数据这个行为,本身是可以独立于框架的,可以不修改框架任何一行代码就能实现数据动态更新。

  • 对比 podmonitor 数据库和 k8s 集群中的信息,不一致的数据,通过增删改查 db,增加 pod 的监控。由于数据之间存在关联性,有些任务添加完没有例行运行,故采用了方法三。

  • 对比 podmonitor 数据库和 k8s 集群中的信息,不一致的数据,通过调用 podmonitor 内部接口添加/删除一项监控,然后调接口 enable /disable job 等。按照可操作性难易, 我们选择了方法三


针对于 k8s 集群中查到的一条 pod 信息:总共有三种情况:

  • 对于表中存在要插入 pod 的监控信息记录,并且 enable 状态为 1。则认为该 pod 的监控不需要改变

  • 对于表中存在要插入 pod 的监控信息记录(删除操作并不会删除源数据信息),并且 enable 状态为 0。则认为该 pod 的监控已被删除或者被停止。调用删除操作, 清空 QRTZ (例行任务插件)表中的响应内容, 调用 delete db 操作清出监控信息相关表中的内容(使得监控记录不至于一直在增长)

  • 对于表中不存在 pod 相关信息记录, 则需要新增加的一个 pod。调用 post 创建监控任务接口(根据 service 监控配置), 并调用 get 请求设置接口为监控 enabled 状态。


另外对于已经在物理机 podmonitor 中添加了监控的服务,提供了一个小脚本,用于导出物理机 podmonitor 域名级别监控到 docker monitor 监控中。

5.难点和重点问题解决

5.1 误报消减

5.1.1 上线告警抑制

由于服务重启期间,会有 removing 状态和未 ready 状态的 pod,在 dockermonitor 系统中存在记录,会引起误报。

我们的解决方法是提供一个通用脚本,根据 k8s 服务的存活检查时间,计算容器服务的发布更新时间,确定再自动开启服务监控的时机。实现在服务重启时间段,停止该服务的接口功能告警;存活检查时间过了之后,自动开启监控。

如下如所示,即 Health Check 中的 Liveness Check 检查时间。


在我们上线发布平台上衔接了该告警抑制功能。


5.1.2 弹性扩缩容告警抑制

原来我们通过查询 rancher 的 API 接口得到集群中全量信息,在我们服务越来越多之后, 查询一次全量信息需要的时间越来越长,基本需要 5min 左右。在这个过程中,存在 docker-monitor 和 k8s 集群中的信息不一致的情况。一开始试图通过按照业务分组,并行调用 rancher 接口得到业务 k8s 集群信息。时间从 5min 缩短到 1min 多钟。误报有一定的减少, 但从高峰期到低谷期时间段, 仍然会有若干 pod 在 k8s 集群中缩掉了, 但 docker-monitor 中仍有相应的告警。


在调研了一些方案之后,我们通过 k8s 增量事件(如 pod 增加、删除)的机制,拿到集群中最新的信息,pod 的任何变更,3s 钟之内就能拿到。


通过 es 的查询接口,使用 filebeat-system 索引的日志, 把 pod 带有关键字 Releasing address using workloadID (更及时),或 kube-system 索引的日志: Deleted pod: xx delete 。


通过这个方案,已经基本没有误报。

5.2 策略优化

  • 为了适配一些 API 允许一定的容错率,我们在 apimonitor 框架中增加了重试策略(单 API 和多 API 方式均增加该功能)

  • 为了适配各类不同业务,允许设置自定义超时时间


5.3 易用性

增加复制等功能,打开一个已有的告警配置,修改后点击复制, 则可创建一个新的告警项

使用场景: 在多套环境(预发、灰度和全量)监控,以及从一个相似 API 接口微调得到新 API 监控


5.4 业务适配

精品课对服务的容器化部署中使用了接口映射机制,使用自定义的监听端口来映射源端口,将 service 的监听端口作为服务的入口 port 供外部访问,如下图所示。当 service 的监听端口收到请求时,会将请求报文分发到 pod 的源端口,因此对 pod 级别的监控,需要找到 pod 的源端口。


我们分析了 rancher 提供的服务 API 文件后发现,在端口的配置信息中,port.containerPort 为服务的监听端口,port.sourcePort 为 pod 的监听端口,port.name 包含 port.containerPo

-rt 和 port.sourcePort 的信息,由此找到了 pod 的源端口与 service 监听端口的关键联系,从而实现了对精品课服务接入本平台的支持。

6.上线效果

1.容器服务 API 监控统一,形成一定的规范,帮助快速发现和定位问题。

通过该容器 API 监控系统,拦截的典型线上问题有:

· xx 上线误操作

· 依赖服务 xxxlib 版本库问题

· dns server 解析问题

· xxx 服务 OOM 问题

· xxx 服务堆内存分配不足问题

· xx 线上压测问题

· 多个业务服务日志写满磁盘问题

· 各类功能不可用问题

·


2.同时增加了 API 延时趋势图标方便评估服务性能:


错误统计表方便排查问题:


结合我们 k8s 资源对象监控,和 grafana 的业务流量等指标监控,线上故障率显著减少,几个业务的容器服务 0 故障。

7.总结与展望

7.1 总结

本期文章中我们介绍了基于静态 API 监控和 K8s 集群化管理方案,设计了实时的自动容器 API 监控系统。


通过上述方案,我们能够在业务迁移容器后,很快地从物理机监控迁移到容器监控。统一的监控系统,使得我们线上服务问题暴露更及时、故障率也明显减少

7.2 展望

  • 自动同步 k8s 服务健康检查到 docker-monitor 系统,保证每一个服务都有监控。

  • 集成到容器监控大盘中,可以利用大盘中 k8s 资源目录树,更快查找指定服务,以及关联服务的 grafana 指标等监控。

  • 自动恢复服务,比如在上线指定时间内,发生 API 监控告警,则自动回滚到上一版本,我们希望监控不仅能发现问题,还能解决问题。


监只是手段,控才是目标。

8.结语

Docker 技术将部署过程代码化和持续集成,能保持跨环境的一致性,在应用开发运维的世界中具有极大的吸引力。


而 k8s 做了 docker 的集群化管理技术,它从诞生时就自带的平台属性,以及良好的架构设计,使得基于 K8s 容器可以构建起一整套可以解决上述问题的“云原生”技术体系,也降低了我们做持续集成测试、发布、监控、故障演练等统一规划和平台的难度。目前有道业务服务基本都上线到容器,后续我们将陆续迁移基础服务,实现整体的容器化。


我们也会不断积极拥抱开源,借鉴业界成功案例,寻找适合我们当前业务发展需要的理想选型。


-END-

发布于: 2021 年 03 月 11 日阅读数: 2048
用户头像

高效学习,从有道开始 2021.03.10 加入

分享有道人的技术思考与实践。

评论

发布
暂无评论
有道 Kubernetes 容器API监控系统设计和实践