从零构建企业级多云监控平台:架构设计与实战经验
三国演义开篇有云:"天下大势,分久必合,合久必分。"这句话用来形容企业监控领域,再贴切不过。
当基础设施从单体应用演进到微服务,从单一机房迁移到多云环境,监控工具也随之碎片化:CloudWatch 管 AWS 资源、Prometheus 管 Kubernetes、ELK 管日志、各业务系统各自为政。每个工具都很专业,但"分"久了,问题就来了 -- 出了故障,你得在五六个控制台之间来回切换;想看全局视图,根本没有;成本数据散落各处,月底才知道超支。
这篇文章记录我独立构建 CTMT(Centralized Monitor)监控平台的完整历程。从为什么要"合",到怎么"合",再到"合"了之后发现的问题和反思。不是为了证明自己的方案多好,而是真实地分享一个人从零到一做企业级监控的经验与教训。
一、监控孤岛:分久必合的痛点
在动手之前,先说说当时面临的现状。公司的云基础设施分布在多个 AWS 账号中:
- 资源分散:生产环境、预生产环境、开发环境各自独立的 AWS 账号
- 集群众多:每个环境有独立的 EKS 集群、RDS 实例、EC2 实例
- 服务碎片化:SQS 队列、S3 存储桶、Lambda 函数散布各处
- 流程割裂:GitLab CI/CD Pipeline 的状态需要单独查看
监控工具的现状是典型的"诸侯割据":
| 监控维度 | 使用工具 | 痛点 |
|---|---|---|
| AWS 资源指标 | CloudWatch Console | 每个账号要单独登录,无法跨账号对比 |
| Kubernetes 集群 | kubectl + Prometheus | 命令行操作,非运维人员无法使用 |
| 业务日志 | CloudWatch Logs / EFK | 查询复杂,缺乏统一入口 |
| 成本管理 | AWS Cost Explorer | 数据滞后,缺乏按产品维度的实时视图 |
| CI/CD 状态 | GitLab Web UI | 需要逐个项目查看,无全局视图 |
| 证书管理 | 手动检查 | 容易遗忘,证书过期导致故障 |
这种"分治"状态带来的直接后果:
- 故障排查时间长 -- 一个请求链路可能跨越三个控制台
- 自助能力缺失 -- 非运维人员(开发、测试、管理层)无法自助查看资源状态
- 成本失控 -- 月底才发现某个环境的 NAT Gateway 流量暴涨
- 标签治理困难 -- 未打标签的资源越来越多,成本归属不清
所以,"合"不是为了技术炫技,而是实实在在的业务需求。
二、业界方案横向对比
在决定自研之前,我调研了业界主流的监控方案。坦白说,每个方案都有其优势,自研并不一定是最优选择。
2.1 商业方案
| 方案 | 优势 | 劣势 | 适用场景 |
|---|---|---|---|
| Datadog | 全栈可观测性,APM + 日志 + 指标一体化;700+ 集成;强大的告警和 AI 异常检测 | 价格昂贵(按主机/容器计费,大规模部署成本高);数据驻留在海外,合规风险;中国区支持有限 | 预算充足的中大型企业,追求开箱即用 |
| New Relic | 全栈可观测性;100GB/月免费额度;APM 能力强 | 超出免费额度后价格陡增;中国区网络延迟;学习曲线较陡 | 需要深度 APM 的团队 |
| AWS CloudWatch | 与 AWS 服务原生集成;无需额外部署;Container Insights 支持 EKS | 跨账号体验差;自定义仪表盘能力弱;告警规则不够灵活;无法监控非 AWS 资源 | 纯 AWS 环境,监控需求简单 |
2.2 开源方案
| 方案 | 优势 | 劣势 | 适用场景 |
|---|---|---|---|
| Grafana + Prometheus | 开源免费;生态丰富;Grafana 可视化能力极强;支持多数据源 | 需要自行运维 Prometheus;大规模下存储和查询性能是挑战;告警配置复杂 | 有运维能力的团队,Kubernetes 原生监控 |
| Zabbix | 老牌开源监控;支持 Agent/SNMP/JMX 多种采集方式;模板丰富 | 架构偏传统,云原生支持弱;UI 老旧;大规模部署性能瓶颈 | 传统 IDC 环境,物理机/虚拟机监控 |
| SigNoz / Uptrace | 基于 OpenTelemetry;APM + 日志 + 指标;开源自托管 | 社区相对年轻;生产环境案例较少;文档不够完善 | 追求开源全栈可观测性的新项目 |
2.3 为什么选择自研
说实话,如果今天重新做这个决定,我可能会选择 Grafana + CloudWatch 数据源 + 自定义 Panel 的方案。但当时选择自研,有几个现实原因:
- 网络限制:公司在中国区(AWS CN Region),Datadog/New Relic 等 SaaS 方案网络不稳定
- 认证需求:需要深度集成 LDAP 企业认证,商业方案的 SSO 集成成本高
- 定制需求:需要自定义的业务监控视图(如按产品线的成本分析、未打标签资源检测)
- 生态限制:Grafana 当时对 AWS 中国区的支持不够完善
- 个人成长:作为基础设施工程师,我想通过这个项目提升全栈开发能力
这些理由有合理的部分,也有主观的部分。后面的"反思"章节会详细讨论这个决策的得失。
三、整体架构设计
CTMT 采用前后端分离架构。后端基于 Django REST Framework 提供 API,前端基于 Vue.js 2 + Element UI + ECharts 实现可视化。整个系统由我一个人设计和开发。
3.1 技术栈选择
| 层级 | 技术选型 | 选择理由 |
|---|---|---|
| 后端框架 | Django 3.2 + DRF | Python 生态与 AWS SDK(boto3)、K8s Client 天然契合,DRF 快速构建 REST API |
| 前端框架 | Vue.js 2.5 + Element UI | 组件化开发效率高,Element UI 提供完整的管理后台组件 |
| 数据可视化 | ECharts | 图表类型丰富,支持大数据量渲染,中文文档完善 |
| 认证 | ldap3 | 企业 LDAP 目录服务集成,实现统一认证 |
| AWS 交互 | boto3 + eks-token | 官方 SDK,支持 Assume Role 跨账号访问 |
| K8s 交互 | kubernetes Python Client | 官方客户端,支持动态 kubeconfig 加载 |
| 部署 | Docker + EKS + GitLab CI | 容器化部署,与现有 CI/CD 流程集成 |
3.2 部署架构
前后端分别容器化,部署在 EKS 集群中,通过 Ingress 暴露服务:
四、核心功能实现
4.1 LDAP 认证集成
企业级应用的第一道门槛是认证。接入公司的 LDAP 目录服务,实现统一登录,避免维护独立的用户体系。
# 认证模块核心逻辑
from ldap3 import Server, Connection, ALL
from django.conf import settings
def ldap_login(username, password):
"""LDAP 认证 - 验证用户凭证"""
try:
server = Server(
settings.LDAP_SERVER,
get_info=ALL,
use_ssl=True,
port=settings.LDAP_PORT
)
# 构造用户 DN (Distinguished Name)
user_dn = f"{settings.LDAP_USER_ATTR}={username},{settings.LDAP_BASE_DN}"
conn = Connection(
server,
user=user_dn,
password=password,
auto_bind=True
)
conn.unbind()
return True
except Exception as e:
# 不记录具体错误信息,避免泄露 LDAP 结构
return False
关键设计决策:
- SSL 强制:生产环境必须使用 LDAPS(端口 636),确保密码传输安全
- 信息隐藏:错误处理不暴露 LDAP 目录结构信息
- Token 机制:认证成功后生成 JWT Token,后续请求携带 Token 验证
4.2 AWS 跨账号访问(IAM Assume Role)
监控多个 AWS 账号的资源,不能在每个账号创建 Access Key(安全隐患大)。正确做法是使用 IAM Role 的 Assume Role 机制:
# 跨账号访问核心实现
import boto3
def assume_role(account_id, role_name, session_name="ctmt"):
"""通过 STS AssumeRole 获取目标账号的临时凭证"""
sts_client = boto3.client('sts')
role_arn = f"arn:aws:iam::{account_id}:role/{role_name}"
assumed_role = sts_client.assume_role(
RoleArn=role_arn,
RoleSessionName=session_name
)
return assumed_role['Credentials']
def get_client(service_name, credentials, region='cn-north-1'):
"""使用临时凭证创建 AWS 服务客户端"""
return boto3.client(
service_name,
aws_access_key_id=credentials['AccessKeyId'],
aws_secret_access_key=credentials['SecretAccessKey'],
aws_session_token=credentials['SessionToken'],
region_name=region
)
def ret_client(aws_env, target):
"""根据环境名获取对应 AWS 客户端,映射关系通过配置文件管理"""
role_name = 'monitoring-readonly'
env_account_map = {
'prod': 'PROD_ACCOUNT_ID',
'dev': 'DEV_ACCOUNT_ID',
'staging': 'STAGING_ACCOUNT_ID',
'preprod': 'PREPROD_ACCOUNT_ID'
}
account_id = env_account_map.get(aws_env)
if not account_id:
raise ValueError(f"未知环境: {aws_env}")
credentials = assume_role(account_id, role_name)
return get_client(target, credentials)
安全要点:
- 最小权限原则 -- 监控 Role 只有只读权限,无法修改任何资源
- 临时凭证 -- 有效期 1 小时,自动过期,无需手动轮换
- 信任策略 -- 限制只有监控账号的特定 Role 才能 Assume
- ExternalId -- 防止"混淆代理人"攻击
4.3 RDS 监控实现
RDS 是最核心的监控对象之一。通过 CloudWatch Metrics API 批量获取多个实例的 CPU、磁盘、连接数指标。
# RDS 监控 - 批量指标查询
from datetime import datetime, timedelta
def generate_metric_data_queries(instances, metric_name, stat, unit, namespace):
"""构建 CloudWatch 批量查询请求,一次 API 调用获取多个实例的同一指标"""
queries = []
for inst in instances:
queries.append({
'Id': inst['name'].replace('-', '_'),
'MetricStat': {
'Metric': {
'Namespace': namespace,
'MetricName': metric_name,
'Dimensions': [{
'Name': 'DBInstanceIdentifier',
'Value': inst['name']
}]
},
'Period': 300, # 5 分钟粒度
'Stat': stat,
'Unit': unit
},
'ReturnData': True,
})
return queries
def get_rds_metrics(rds_list, client):
"""
获取 RDS 实例的核心监控指标:
- FreeStorageSpace: 剩余磁盘空间
- CPUUtilization: CPU 使用率
- DatabaseConnections: 活跃连接数
"""
result = []
# 1. 磁盘空间
queries = generate_metric_data_queries(
rds_list, 'FreeStorageSpace', 'Average', 'Bytes', 'AWS/RDS'
)
response = client.get_metric_data(
MetricDataQueries=queries,
StartTime=datetime.utcnow() - timedelta(minutes=30),
EndTime=datetime.utcnow(),
ScanBy='TimestampAscending'
)
for r in response['MetricDataResults']:
if r['Values']:
free_gb = round(r['Values'][0] / 1024**3, 2)
total = next(
(i['rds_storage'] for i in rds_list if i['name'] == r['Label']), 0
)
result.append({
'name': r['Label'],
'free': free_gb,
'used': round(total - free_gb, 2),
'disk_percent': round((total - free_gb) / total * 100, 2) if total else 0
})
# 2. CPU 利用率、3. 连接数 (类似逻辑,合并到 result)
result.sort(key=lambda x: x.get('cpu_percent', 0), reverse=True)
return result
RDS 监控的关键指标与告警阈值:
| 指标 | CloudWatch MetricName | 告警阈值 | 影响 |
|---|---|---|---|
| CPU 利用率 | CPUUtilization | > 80% 持续 5min | 查询变慢,可能需要升级实例规格 |
| 磁盘空间 | FreeStorageSpace | 剩余 < 20% | 写入失败,需要扩容或清理 |
| 连接数 | DatabaseConnections | > 最大连接数 80% | 新连接被拒绝,检查连接池配置 |
| 读/写延迟 | ReadLatency/WriteLatency | > 20ms | IO 瓶颈,考虑使用 Provisioned IOPS |
| 副本延迟 | ReplicaLag | > 60s | 读副本数据不一致,检查主库负载 |
4.4 Kubernetes 多集群监控
连接多个 EKS 集群是技术难点之一。每个集群需要动态获取访问 Token,构造 kubeconfig,然后通过 Kubernetes Python Client 操作。
# EKS 多集群连接
from kubernetes import client, config
from eks_token import get_token
def get_k8s_client(env):
"""
动态连接到指定环境的 EKS 集群
流程: Assume Role -> 获取集群信息 -> 获取 Token -> 构造 kubeconfig
"""
# 1. 获取目标账号凭证
credentials = assume_role(ENV_CONFIG[env]['account_id'], 'monitoring-readonly')
# 2. 获取 EKS 集群 endpoint 和 CA
eks_client = get_client('eks', credentials)
cluster = eks_client.describe_cluster(
name=ENV_CONFIG[env]['cluster_name']
)['cluster']
# 3. 获取访问 Token
role_arn = f"arn:aws:iam::{ENV_CONFIG[env]['account_id']}:role/monitoring-readonly"
token = get_token(ENV_CONFIG[env]['cluster_name'], role_arn)['status']['token']
# 4. 动态构造 kubeconfig
kubeconfig = {
'apiVersion': 'v1',
'clusters': [{
'cluster': {
'certificate-authority-data': cluster['certificateAuthority']['data'],
'server': cluster['endpoint']
},
'name': 'target',
}],
'contexts': [{'context': {'cluster': 'target', 'user': 'monitor'}, 'name': 'ctx'}],
'current-context': 'ctx',
'kind': 'Config',
'users': [{'name': 'monitor', 'user': {'token': token}}],
}
config.load_kube_config_from_dict(kubeconfig)
return client.CoreV1Api()
def list_pods(env, namespace):
"""获取指定环境和命名空间的 Pod 列表"""
v1 = get_k8s_client(env)
pods = v1.list_namespaced_pod(namespace=namespace).items
result = []
for pod in pods:
info = {
'name': pod.metadata.name,
'image': pod.spec.containers[0].image.split(':')[-1],
'node': pod.spec.node_name
}
if pod.status.container_statuses:
cs = pod.status.container_statuses[0]
info['status'] = 'Running' if cs.ready else 'NotReady'
info['restarts'] = cs.restart_count
if cs.state.running:
info['start_time'] = cs.state.running.started_at.strftime('%Y-%m-%d %H:%M')
else:
info['status'] = pod.status.reason or 'Pending'
info['restarts'] = 0
result.append(info)
return result
4.5 成本监控与标签治理
云成本管理是这个平台的一大亮点。通过 Cost Explorer API 按产品线维度分析成本,同时检测未打标签的资源。
# 成本分析 - 按产品线维度
def get_cost_by_product(period, client):
"""获取按产品标签分组的成本数据,支持 DAILY 和 MONTHLY 两种粒度"""
now = datetime.now()
days = 365 if period == 'MONTHLY' else 180
response = client.get_cost_and_usage(
TimePeriod={
'Start': (now - timedelta(days=days)).strftime('%Y-%m-%d'),
'End': now.strftime('%Y-%m-%d')
},
Granularity=period,
Metrics=['BlendedCost'],
GroupBy=[{
'Type': 'TAG',
'Key': 'CostCenter:Product' # 按产品标签分组
}]
)
# 转换为 ECharts 堆叠柱状图数据格式
return {'costs': series_data, 'times': time_labels}
# 未打标签资源检测
def detect_untagged_resources(aws_env):
"""扫描指定环境中未打成本标签的资源,帮助推动标签治理"""
client = ret_client(aws_env, 'resourcegroupstaggingapi')
TARGET_TAG = 'CostCenter:Product'
untagged = []
EXCLUDED = ['cloudformation', 'ssm', 'iam', 'kms', 'backup', 'events', 'glue', 'vpc/']
paginator = client.get_paginator('get_resources')
for page in paginator.paginate():
for mapping in page['ResourceTagMappingList']:
arn = mapping['ResourceARN']
tags = mapping.get('Tags', [])
has_tag = any(t['Key'] == TARGET_TAG for t in tags)
is_excluded = any(ex in arn for ex in EXCLUDED)
if not has_tag and not is_excluded:
untagged.append(arn)
return untagged
成本监控的实际效果:
- 异常发现:发现某环境 NAT Gateway 流量异常,月成本从 $200 涨到 $800,及时排查定位
- 标签治理:未打标签资源从最初的 200+ 降到 20 以内,成本归属清晰度大幅提升
- 成本透明:按产品线的成本趋势图让管理层能直观看到各业务线的云支出
五、前端实现
5.1 路由与页面结构
前端采用 Vue Router 管理路由,按监控维度组织页面层级:
// 路由结构(简化)
export default new Router({
routes: [
{
path: '/aws',
component: Main,
children: [
{ path: 'rds', component: () => import('@/main/aws/Rds.vue') },
{ path: 'ec2', component: () => import('@/main/aws/Ec2.vue') },
{ path: 'sqs', component: () => import('@/main/aws/Sqs.vue') },
{ path: 'cost', component: () => import('@/main/aws/Cost.vue') },
{ path: 'tag', component: () => import('@/main/aws/Tag.vue') },
{ path: 's3', component: () => import('@/main/aws/s3.vue') },
{ path: 'elasticache', component: () => import('@/main/aws/Elasticache.vue') },
{ path: 'lambda', component: () => import('@/main/aws/Lambda.vue') },
{ path: 'nat', component: () => import('@/main/aws/Nat.vue') },
{ path: 'certificate', component: () => import('@/main/aws/Certificate.vue') },
{ path: 'ecr', component: () => import('@/main/aws/Ecr.vue') }
]
},
{
path: '/kubernetes',
component: Main,
children: [
{ path: 'prod', component: () => import('@/main/kubernetes/Prod.vue') },
{ path: 'staging', component: () => import('@/main/kubernetes/Staging.vue') },
{ path: 'preprod', component: () => import('@/main/kubernetes/Preprod.vue') },
{ path: 'dev', component: () => import('@/main/kubernetes/Dev.vue') }
]
},
{
path: '/gitlab',
component: Main,
children: [
{ path: 'pipeline', component: () => import('@/main/gitlab/Pipeline.vue') },
{ path: 'deployfrequency', component: () => import('@/main/gitlab/Deployfrequency.vue') },
{ path: 'failurerate', component: () => import('@/main/gitlab/Failurerate.vue') }
]
},
{
path: '/business',
component: Main,
children: [
{ path: 'apigateway', component: () => import('@/main/business/Apigateway.vue') },
{ path: 'efk', component: () => import('@/main/business/Efk.vue') },
{ path: 'bill', component: () => import('@/main/business/Bill.vue') }
]
}
]
})
5.2 数据可视化
使用 ECharts 实现多种图表,配合 Element UI 的 Table 和 Progress 组件展示监控数据:
// RDS 监控页面示例(简化)
export default {
data() {
return {
awsEnv: 'prod',
rdsList: [],
detailVisible: false
}
},
methods: {
async fetchRdsData() {
const { data } = await this.$http.post('/api/rds/list', {
aws_env: this.awsEnv
})
this.rdsList = data
},
getProgressColor(pct) {
if (pct < 50) return '#67c23a' // 绿色 - 健康
if (pct < 80) return '#e6a23c' // 黄色 - 警告
return '#f56c6c' // 红色 - 危险
},
async showDetail(rds) {
this.detailVisible = true
this.$nextTick(() => {
// 初始化 ECharts 折线图
// 展示 CPU/磁盘/连接数的时间序列数据
})
}
},
mounted() {
this.fetchRdsData()
}
}
前端的一个特色功能是音频告警 -- 当检测到 Pipeline 失败或 Pod CrashLoopBackOff 时,页面会播放告警音效,确保值班人员不会错过关键事件。
六、系统不足与诚实反思
写技术文章容易陷入"报喜不报忧"的陷阱。这一节我想诚实地谈谈这个系统的不足,以及如果重来一次,我会怎么做。
6.1 架构层面的不足
| 问题 | 现状 | 理想方案 |
|---|---|---|
| 无数据缓存层 | 每次请求都直接调用 AWS API,响应慢且容易触发限流 | 引入 Redis 缓存,对不常变化的数据设置 TTL |
| 无异步任务队列 | 所有数据获取都是同步的,页面加载慢 | 使用 Celery + Redis 做异步任务,定时预拉取数据 |
| 无时序数据存储 | 不存储历史数据,无法做趋势分析 | 引入 InfluxDB 或 Prometheus 存储时序数据 |
| 单点部署 | 后端只有一个 Pod,无高可用 | 至少 2 副本 + HPA 自动扩缩容 |
| 无 APM 集成 | 监控平台自身缺乏可观测性 | 接入 OpenTelemetry,监控自身的请求延迟和错误率 |
6.2 代码层面的不足
- 缺乏单元测试 -- 作为一个人的项目,测试覆盖率几乎为零。重构时心里没底,只能靠手动验证
- 前端组件复用率低 -- 很多 Vue 组件之间有大量重复代码(比如各环境的 Kubernetes 页面),应该抽象为通用组件
- 错误处理不统一 -- 后端的异常处理比较随意,没有统一的错误码和错误响应格式
- 前端状态管理缺失 -- 没有使用 Vuex,组件间的数据传递依赖 props 和事件,复杂场景下维护困难
- API 设计不够 RESTful -- 部分接口用 POST 传参数,实际上应该用 GET + Query Parameters
6.3 功能层面的不足
- 告警能力弱 -- 只有前端音频告警,没有集成邮件、企业微信、PagerDuty 等通知渠道
- 无 RBAC 权限控制 -- 所有登录用户看到的内容一样,无法按角色限制访问范围
- 无审计日志 -- 谁在什么时间查看了什么数据,没有记录
- 不支持自定义仪表盘 -- 页面布局是固定的,用户无法自定义关注的指标组合
6.4 如果重来一次
如果让我重新设计这个系统,架构会有很大不同:
核心改进思路:
- Grafana 替代自研前端 -- Grafana 的仪表盘能力远超手写的 Vue 页面,且支持用户自定义
- Prometheus + CloudWatch Exporter -- 解决数据缓存和历史趋势问题
- 保留自定义 API 层 -- 处理 Grafana 无法直接实现的业务逻辑(标签治理、成本分析、LDAP 集成)
- Celery 异步任务 -- 定时预拉取数据,避免用户等待
但话说回来,自研的过程让我对监控体系有了深入理解,对 AWS 服务、Kubernetes API、前端可视化都有了实战经验。这些经验是用 Grafana 开箱即用所无法获得的。
七、与业界方案的差距
客观地说,CTMT 与 Datadog、Grafana Cloud 这样的成熟方案相比,差距是全方位的:
| 能力维度 | CTMT | Datadog | Grafana Stack |
|---|---|---|---|
| 数据采集 | 实时 API 调用,无缓存 | Agent 采集,自动发现 | Exporter + ServiceMonitor |
| 可视化 | 固定页面布局 | 自定义仪表盘 + Notebook | 高度可定制仪表盘 |
| 告警 | 仅前端音频 | 多渠道 + AI 异常检测 | AlertManager 多渠道 |
| APM | 无 | 分布式追踪 + Profiling | Tempo 分布式追踪 |
| 日志 | 基础查询 | 全文检索 + 关联分析 | Loki 日志聚合 |
| 扩展性 | 需要改代码 | 700+ 开箱即用集成 | 丰富的插件生态 |
| 运维成本 | 低(自托管) | 高(按量付费) | 中(需要运维基础设施) |
| 定制化 | 完全可控 | 受限于平台能力 | 高(开源可改) |
CTMT 的优势在于:完全可控、深度集成企业 LDAP、针对性的成本分析和标签治理功能。但在通用监控能力上,差距确实很大。
八、生产环境最佳实践
8.1 安全加固
- HTTPS 强制:所有 API 请求必须使用 HTTPS
- CORS 配置:限制跨域访问来源
- 输入验证:所有用户输入必须验证和清理
- 日志脱敏:避免记录敏感信息(密码、Token)
- 定期审计:定期审查 IAM 角色权限和访问日志
8.2 性能优化
- 数据缓存:对不常变化的数据(如 RDS 实例列表)进行缓存
- 批量查询:使用 CloudWatch 的
get_metric_data批量查询多个指标 - 分页加载:Pod 列表、日志等数据支持分页
- 懒加载:前端路由和组件使用懒加载
8.3 告警策略
| 监控项 | 告警条件 | 通知方式 |
|---|---|---|
| RDS CPU | > 80% 持续 5 分钟 | 邮件 + 钉钉 |
| RDS 磁盘 | < 20% 剩余空间 | 邮件 + 钉钉 |
| Pod CrashLoop | 重启次数 > 5 | 邮件 + 音频告警 |
| 成本异常 | 日成本 > 预算 120% | 邮件 + 钉钉 |
九、写在最后的一些感想
这个项目是我利用工作之余独立完成的,受限于个人精力和能力,有很多地方做得不够好。但也正因为是一个人摸索,踩了不少坑,也学到了不少东西。
一个人做项目,好处是迭代快、什么都能接触到,从后端 API 到前端页面到 CI/CD 部署,每个环节都得自己上手,逼着自己成长。坏处也很明显:没有人帮你 Code Review,代码质量全靠自觉;缺少不同视角的反馈,容易钻牛角尖;测试覆盖基本为零,重构的时候心里没底;而且一旦自己不维护了,别人接手会很痛苦。
十、结语
"天下大势,分久必合。"监控领域也是如此。从最初的监控孤岛,到统一平台,再到未来可能演进为基于 Grafana 的混合架构 -- 这个过程本身就是技术演进的缩影。
CTMT 不是一个完美的系统,但它解决了实际问题:让非运维人员能自助查看资源状态,让成本数据透明可追溯,让多环境的 Kubernetes 管理不再依赖命令行。作为一个人的作品,我对它有感情,也清楚它的局限。
如果你也在考虑构建类似的监控平台,我的建议是:先评估 Grafana + Prometheus 能否满足 80% 的需求,只对剩下 20% 的定制化需求做自研;从第一天就考虑数据缓存和异步处理;写测试,哪怕只是核心逻辑的测试;记录文档,未来的你会感谢现在的你。
监控的终极目标不是收集更多的数据,而是在正确的时间把正确的信息传递给正确的人。这个目标,无论用什么技术栈,都值得追求。
📜 版权声明
本文作者:王梓 | 原文链接:https://www.bthlt.com/note/15142197-Teg从零构建企业级多云监控平台:架构设计与实战经验
出处:葫芦的运维日志 | 转载请注明出处并保留原文链接


📜 留言板
留言提交后需管理员审核通过才会显示