在CaaS环境下部署Prometheus的实践经验总结


【编者的话】监控系统对于云平台的维护团队起着至关重要的作用。Docker的出现对整个生态系统产生了巨大的印象,如何对短暂存在的docker容器进行监控是本文中实践要证明的主要问题。

本文是延续我上一篇文章在CaaS环境中部署ELK stack的实践经验总结继续对CaaS平台进行聘评估。在做完对log的处理之后(上一篇文章只是一个PoC,离真正的可以放在生产环境上的log管理系统还有很长的一段距离),我把目光转向了监控系统。

监控系统对于运维团队的重要性我想大家应该都了解,个人理解一个便于使用的监控系统包括以下几个特点:
  1. 统一的界面管理,清晰的dashboard - 没有人想打开1000个浏览器页面去监控1000个服务
  2. 快速定位出问题的服务 - 此处包括与告警系统的集成以及快速定位感兴趣的机器或服务(filtering)
  3. 定制自己感兴趣的组合
  4. 能自动应对监控目标的扩容,无需手动添加新的机器或服务


我们现在使用的监控系统(xymon)是一个面向服务器的监控系统,能很好的服务那些长期存在的物理机或者虚拟机,但是对于短暂存在的容器就会遇到很多问题,所以需要转向一个面向服务的监控系统。有了以上需求,我决定使用一下Prometheus。

目前大多数监控系统都是使用客户端推送的方式,即监控程序收集监控数据之后推送到一个集中管理的监控服务器。与之相反,Prometheus采用了定期轮训的方式,Prometheus服务器定期轮训监控目标,希望通过监控目标的HTTP接口获取数据。由于我并没有把Prometheus放到一个真正的集群中做测试,所以这两种方式的优劣我目前还没法提供详细的数据。

选定目标之后,我就开始把Prometheus部署到我的测试目标灵雀云上。可能有人看到这里就准备关闭此页,原因可能如下:Prometheus已经做了容器化,把容器毫无差异的部署到不同的平台正式容器化所带来的优势,以下内容应该毫无新意。在我开始做之前我也是这个想法,所以我给自己半小时的时候部署。但真正当我开始做的时候,我才发现如下问题:
  1. Prometheus需要通过unix domain socket与docker daemon通信获得当前运行的所有docker container,这在一个共有云CaaS平台上是无法实现的。因为同一台主机上的docker daemon可能服务于不同的客户,而且同一个客户的多个docker container也可能部署在多台主机上
  2. Prometheus需要通过cgroup获取当前contaienr的metrics,此方法在共有云CaaS上同样无法实现,原因跟上一条相同。


所以对于共有云CaaS来说,我需要自定义Prometheus exporter来获取1)本用户的所有docker container 2)此container的metrics。灵雀云提供了API获取当前用户的所有服务,每个服务的实例以及每个实例的metrics,更方便的是灵雀云开源的基于python的API。在此实验中,我直接调用了alaudacli库以及prometheus_client库实现自己的exporter。具体代码可在github找到。

在部署服务的时候需要添加环境变量ALAUDA_USERNAME以及ALAUDA_PASSWORD用于认证
def alauda_login(username, password, cloud='cn', endpoint='https://api.alauda.cn/v1/'):
alaudacli.commands.login(username, password, cloud, endpoint)

登录成功之后即可获取当前用户的所有服务,其中namespace为用户名。
def alauda_service_list(namespace):
service_list = alaudacli.service.Service.list(namespace, 1)
return service_list

灵雀云的每一个服务可以有多个实例做负载均衡,而metrics是针对每一个实例统计的,所以下一步需要获取每一个服务的实例。
def alauda_instance_list(namespace, name):
service_inst = alaudacli.service.Service.fetch(name, namespace)
instances = service_inst.list_instances()
instance_list = []
for data in instances:
instance = json.loads(data.details)
instance_list.append(instance)
return instance_list

最后一步就是获取每个实例的统计数值了,此API在alaudacli当中没有实现,所以我直接调用alauda开放的API获取。
def alauda_get_instance_metrics(namespace, name, instance_uuid, start_time, end_time, interval):
service_inst = alaudacli.service.Service.fetch(name, namespace)
url = service_inst.api_endpoint + 'services/{0}/{1}/instances/{2}/metrics?start_time={3}&end_time={4}&point_per_period={5}'.format(service_inst.namespace, service_inst.name, instance_uuid, start_time, end_time, interval)
r = requests.get(url, headers=service_inst.headers)
if r.text:
    data = json.loads(r.text)
    return data
else:
    return None

得到了感兴趣的数据之后就可以把这些数据暴露给prometheus服务器以便查询(此处偷懒只把CPU和memory的数据拿出来了:))。这里要注意的是申明的每一个统计对象都是设置了label以便在prometheus上做filtering和grouping。
g_cpu_usage = Gauge("cpu_cumulative_usage", "CPU Cumulative Usage", ["service", "instance"])
g_cpu_utilization = Gauge('cpu_utilization', "CPU utilization", ["service", "instance"])
g_memory_usage = Gauge('memory_usage', "Memory Usage", ["servie", "instance"])
g_memory_utilization = Gauge('memory_utilization', "Memory Utilization", ["service", "instance"])

把serviceexporter服务部署到灵雀云上即可通过浏览器获取当前运行的所有服务的统计数据。
metrics.JPG

最后需要部署Prometheus服务,此镜像是基于prom/prometheus官方镜像修改之后的镜像。因为Prometheus服务器定期轮训监控对象的API,所以prometheus需要知道监控对象的IP地址以及端口。修改之后的镜像可以通过服务链接(link)获取到serviceexporter服务的IP地址以及端口。(此处偷懒没通过link的方式,而是直接把serviceexpoter服务的IP地址和端口写死了。。。)。

通过访问Prometheus服务器的UI可以得到每个服务图形化的统计数据。
prometheus.JPG

可以通过设置filtering只看kibana服务的统计
kibana_metrics.JPG

可以通过sum函数将多个kibana实例统计合并
sum.JPG

通过以上部署,我可以在统一的UI监控所有运行在灵雀云上的服务,并且设置相应的阈值报警(此实验中未涉及),我可以定制自己感兴趣的dashboard,快速定位可能出现问题的服务。

本实验只是一个PoC的目的,离真正的生产环境还有距离,欢迎大家提供更多意见以及解决方案。

===========================================
作者介绍
杜航,Websense云基础架构组开发经理,专注于Openstack和Docker。

0 个评论

要回复文章请先登录注册