基于Kubernetes的PaaS平台提供的监控服务


概述

我一直在负责维护的PaaS平台引入了Kubernetes作为底层支持,可以借助Kubernetes的生态做更多的事情,这篇博客主要介绍如何为普通用户提供图表监控服务(承接上一篇提供Dashboard支持)。默认读者有能力自己搭建Kubernetes集群以及初级的监控系统,以及可以简单的使用PromQL,因为博客主要想介绍的内容不在此。


我早于Dashboard就增加了这个功能,但是讲解起来实在复杂。一直拖着没写,今天有空,正好来分享一下吧。

方案拓扑

这里我懒一下,不想画图了。
1.jpg

图中是整个方案的左半边,由采集工具采集机器以及容器信息,上传至Prometheus中,右下角的Grafana通过PromQL查询以及展示数据,下面两个部分会简单介绍Prometheus以及Grafana,但重点在后面哈。

朴素的收集与展示工具Prometheus

这是一张Ingress的CPU利用率统计图:
2.png

朴素的原因主要是这个工具做作用是收集数据,每次只能查询一条语句,而且没有什么历史记录功能,权限控制几乎没有,这样基础的工具肯定不能直接提供给用户。

漂亮的展示工具Grafana

3.png

相比上面简陋的图片,Grafana的功能就强大很多了,可以展示多张图表,而且有了权限控制,非常适合建立大盘监控,对于PaaS平台中的每个用户来讲,看到自己应用的监控是多么美妙的一件事。

-----------

如果仅仅是介绍到这里,大家在自己的Kubernetes集群中鼓捣一下应该很快就可以用了,我们既然作为PaaS平台的开发者,自然要考虑多用户以及多应用的组织管理方式,呈现给用户需要的资料的同时,也要保证用户以及应用间不会相互影响。没错这与上一篇Dashboard支持方案类似,也要进行权限设计以及控制。

权限同步策略

PaaS平台的权限系统

在PaaS平台中,假设我们有一个用户A,他拥有自己的一个或多个应用群组(G1,G2),每个群组中部署了一系列应用程序(a1,a2……)。

Grafana中的权限系统

在Grafana权限系统中,有一些Teams,用户可以属于一个或多个Team。
4.png

每个Folder可以拥有一个或多个Dashboard。

5.png

映射

考虑到上述的关系,我们的思路就很明确了,我的设计方案是:
  1. 用户的每个群组对应一个Team,该Team拥有一个Folder的访问权限
  2. 每个应用拥有一个Dashboard


你也可以使用别的设计方案(比如说不要Folder,每个Team拥有一些Dashboard),上述方案只是我想方便管理,每个Team拥有自己的Folder。

Grafana相关类库及其使用

我用的是Python定时同步权限以及图表信息,当时也想过用Golang,但我说真的,这种代码用Python太适合了。下面的部分太过于偏了,建议不要去纠结,你大概率用不上,肯定要自己去读文档的。
grafana-api==1.0.3  # 用来与Grafana API通信  
grafanalib==0.5.7   # 创建Grafana图表

User,Team,Folder创建

# 下面是一个team的创建,其他类似
def ensure_team(g_api, team_name):
team_id = -1
try:
    # {'message': 'Team created', 'teamId': 121}
    g_team = g_api.teams.add_team({'name': team_name})
    team_id = g_team['teamId']
except GrafanaClientError as e:
    if e.status_code == 409:
        # 'Client Error 409: Team name taken'
        g_team = g_api.teams.get_team_by_name(team_name)[0]
        team_id = g_team['id']
assert team_id != -1
return team_id

Folder与Team权限同步

# 下面是同步team以及其用户,因为用户有可能增减,需要对应的增减
def sync_user_team(g_api, team_id, user_ids):
orig_members = g_api.teams.get_team_members(team_id)
now_user_ids = set(user_ids)
orig_user_ids = set([u['userId'] for u in orig_members])

for user_id in now_user_ids - orig_user_ids:
    try:
        g_api.teams.add_team_member(team_id, user_id)
    except GrafanaBadInputError:
        pass

for user_id in orig_user_ids - now_user_ids:
    g_api.teams.remove_team_member(team_id, user_id)

# 下面是同步folder以及team权限,所有普通用户只有只读权限
def sync_folder_permission(folder, team_id=None):
# https://grafana.com/docs/grafana/latest/http_api/folder_permissions/
g_api = get_grafana_api()  # type: GrafanaFace
permissions = []
if team_id != None:
    permissions.append({
        "teamId": team_id,
        "permission": 1  # 只有查看权限
    })

g_api.folder.update_folder_permissions(
    folder['uid'],
    {
        "items": permissions,
    }


Dashboard页面设计以及同步

这部分其实挺难的,我想使用类似声名式的写法,类似kubectl apply -f xxx.yaml,不过Grafana的API太难用了,一种解决方案是:导入Dashboard图表数据,可以看到我这里的API都是手动加的。
def sync_dashboard_data(dashboard_uid, folder_id, dashboard_json_data, inputs=[]):
"""同步dashboard的组信息以及dashboard的pannel数据信息
"""
g_api = get_grafana_api()  # type: GrafanaFace
d = g_api.dashboard.get_dashboard(dashboard_uid)

data = {
    'dashboard': dashboard_json_data,
    'folderId': folder_id,
    "inputs": inputs,
    'overwrite': True
}
put_dashboard_path = "/dashboards/import"
r = g_api.api.POST(put_dashboard_path, json=data)

# 数据样式的生成请参考这里:
# https://github.com/weaveworks/grafanalib/blob/master/grafanalib/tests/examples/example-elasticsearch.dashboard.py

最终效果

针对我们系统中的每个应用,基本都有这么一张图表:
6.png

常用的图表推荐

我平时作为管理员一般也不会看每个应用,可能看个大概吧。

Ingress

https://github.com/kubernetes/ ... .json
7.png

node_exporter

https://github.com/rfrail3/gra ... .json
8.png

总结

这篇文章我主要想介绍下我们的系统是如何设计的,希望能够在大家设计系统接入方案时能有所参考,也欢迎大家留言讨论。

顺便吐槽一下Grafana,居然不能设置URL头像(为了改头像我都去读Grafana代码了,发现不能修改),真是令人生气!

原文链接:https://corvo.myseu.cn/2021/01/06/2021-01-06-基于Kubernetes的PaaS平台提供的监控服务/,作者:corvofeng

0 个评论

要回复文章请先登录注册