CMDB导入CMS 2.0 最佳实践

更新时间:
复制为 MD 格式

本文以 VeOps CMDB 为例,提供完整的数据导入方案。采用 API 调用的方式,用同步工具 API 将数据同步到 CMS 2.0 中。

示例场景

本示例 Mock 了一套典型企业的 CMDB 数据,用于演示完整的导入流程。数据规模:

  • 服务树三级组织结构:3 个事业部 → 8 个产品线 → 20 个应用

  • 基础设施资源:30 台物理机、50 台虚拟机、40 个 Docker 容器

  • 硬件组件:49 块网卡、89 块硬盘、171 条内存

  • 关系网络:通过 contains(包含)和 deploys_on(部署)两种关系类型,构建约 377 条关系

涵盖 9 种 CI 类型、460 个实例、377 条关系的完整 CMDB 资产图谱。

本地部署

Docker 本地一键部署, 更多部署命令参考:部署文档

# 前提步骤: 安装 Docker 环境和 Docker Compose(v2)
# 拷贝项目代码
git clone https://github.com/veops/cmdb.git

# 进入主目录并启动
docker compose up -d

服务树结构

服务树

实体拓扑关系

实体拓扑关系映射

实施步骤

步骤一:模型映射

理解 CMDB 与 UModel 之间的概念对应关系,为后续配置生成和数据同步奠定基础。

核心概念映射

CMDB 概念

UModel 概念

说明

配置项(CI)

Entity(实体)

CMDB 中的基本管理单元,如服务器、应用、数据库等

配置项类型(CI Type)

EntitySet(实体集)

定义一类实体的模型,包含字段定义、主键、生命周期等

CI Type 关系

EntitySetLink(实体集关联)

定义不同实体类型之间的关系类型(如包含、部署、依赖)

CI 实例关系

Topo(拓扑关系)

具体实体实例之间的关联关系

属性定义

Field(字段)

实体的属性字段,包含类型、约束、是否必填等

核心转换原则

  • 模型定义层:CI Type → EntitySet

  • 实例数据层:CI 实例 → Entity

  • 关系定义层:CI Type 关系 → EntitySetLink

  • 关系实例层:CI 实例关系 → Topo

实体类型映射表

基于示例场景,9 种 CI Type 映射到 UModel 的具体规则如下:

CMDB CI Type

UModel EntitySet

主键字段

显示字段

关系类型

事业部

business_unit

cmdb.business_unit

bu_name

bu_name

contains → Product

产品线

product

cmdb.product

product_name

product_name

contains → Application

应用

application

cmdb.application

app_name, product_name

app_name

deploys_on → Server/VServer/Docker

物理机

server

cmdb.server

hostname

hostname, private_ip

contains → VServer/NIC/HardDisk/RAM

虚拟机

vserver

cmdb.vserver

hostname

hostname, private_ip

-

Docker容器

docker

cmdb.docker

instance_id

instance_id, image

-

网卡

nic

cmdb.nic

mac_address

mac_address, model

-

硬盘

harddisk

cmdb.harddisk

serial_number

serial_number, capacity

-

内存

ram

cmdb.ram

serial_number

serial_number, capacity

-

步骤二:生成 UModel 配置

UModel 关于EntitySet/EntitySetLink配置文件既可以通过配置文件静态配置,也可以基于 CMDB 定义中的 Schema 去动态生成,混合使用是最佳实践方式, 如果静态文件存在,则以静态文件为主,这样做的好处在于集成了两者的优势。

以 VeOps 为例,实体有唯一标识,也有显式字段,唯一标识字段可以作为 EntitySet 的 primary_keys,而显示字段则可以作为 name_files,由于 VeOps 不支持 Schema 查询API,目前采用了静态配置的方法去生成 EntitySet 和 EntitySetLink 配置文件。

image.png

2.1 配置映射规则

编辑 config.yaml,配置 CI Type 到 EntitySet 的映射:

ci_type_mapping:
  business_unit:
    entity_set: "cmdb.business_unit"
    domain: "cmdb"
    primary_keys: ["bu_name"]
    name_fields: ["bu_name"]
    
  product:
    entity_set: "cmdb.product"
    domain: "cmdb"
    primary_keys: ["product_name"]
    name_fields: ["product_name"]
    
  application:
    entity_set: "cmdb.application"
    domain: "cmdb"
    primary_keys: ["project_name"]
    name_fields: ["project_name"]
    
  server:
    entity_set: "cmdb.server"
    domain: "cmdb"
    primary_keys: ["server_name"]
    name_fields: ["server_name", "private_ip"]

配置说明:

  • entity_set:UModel 实体集名称

  • primary_keys:唯一标识实体的字段

  • name_fields:用于显示的字段

2.2 运行生成工具

python3 generate_umodel_config.py

步骤三:应用 UModel 配置

将生成的 UModel 配置文件上传到 CMS 2.0 控制台,完成实体和关系的定义。

  1. 登录云监控2.0控制台

  2. 进入目标工作空间,在左侧导航栏选择UModel探索

  3. UModel 探索页面,单击页面右上角image,在弹出框中单击上传 UModel YAML /JSON

  4. 批量上传 UModel的弹窗中,单击image选择文件,或将文件拖拽到上传框中:上传 umodel_config/ 目录下的所有 YAML 文件。

    选择配置文件

  5. 文件上传后,单击立即导入

  6. 导入成功后,单击页面右上角提交

  7. 在提交预览页面,检查内容无误后,单击确认内容符合预期,执行变更。在变更情况弹框中,单击确定

  8. 结果验证:在实体集列表中应该看到 9 个新增的 cmdb.* 实体集。

    上传成功

步骤四:同步实体和关系数据

实体和关系数据通过 CMDB API 获取 CI 实例和关系数据,转换为 UModel 实体/关系格式并写入 SLS。

实体数据格式转换

VeOps API 通过 /api/v0.1/ci获取所有实体数据格式:

GET /api/v0.1/ci?ci_type=server&page=1&count=100

返回数据示例:

{
    "_id": 1234,
    "ci_id": "272",
    "ci_type_id": "4",
    "bu": "云计算",
    "buy_date": "2023-01-08",
    "ci_type": "server",
    "ci_type_alias": "物理机",
    "cmc_ip": "28.191.122.80",
    "cnc_ip": "224.127.127.194",
    "cpu": "AMD EPYC 7542",
    "cpu_count": "2",
    "ctc_ip": "75.76.9.36",
    "device_spec": "Huawei RH2288H V5",
    "env": "test",
    "idc": "阿里云-河源",
    "ilo_ip": "10.161.85.215",
    "ilo_mac": "05:0f:a9:63:91:ad",
    "kernel_version": "3.10.0-1160.el7.x86_64",
    "logic_cpu_count": "40",
    "manufacturer": "Dell",
    "oneagent_id": "XD1VLEEIR15O",
    "op_duty": "[\"张丽华\"]",
    "os_version": "CentOS 7.9",
    "perm": "{\"execute\": false, \"groups\": [\"viewers\", \"admins\", \"guests\"], \"owner\": \"张志强\", \"read\": true, \"write\": true}",
    "private_ip": "10.122.144.73",
    "rack": "59",
    "raid": "RAID 10",
    "ram": "64GB DDR4",
    "ram_size": "64",
    "rd_duty": "[\"齐晶\"]",
    "server_name": "phy-server-011",
    "server_room": "阿里云-河源机房",
    "sn": "C2LVEAZRIVH1",
    "ssh_port": "22",
    "status": "在线",
    "unique": "sn",
    "unique_alias": "服务器序列号",
    "vnc_port": "5910",
    "__pack_meta__": "0|MTc2MjgzMzA5NTg5OTYzMjg1OQ==|32|3",
    "__topic__": "",
    "__source__": "30.221.145.27",
    "__tag__:__receive_time__": "1763629311",
    "__time__": "1763629311",
    "__time_ns_part__": "127734016"
}

转换格式后写入 ${workspace}__entity ,系统字段映射如下:

UModel 字段

示例

说明

__domain__

cmdb

实体归属的域

__entity_type__

cmdb.server

实体集名称,对应 CI Type

__entity_id__

b4da1c11d1a62257087aab071d27c1bc

全局唯一ID

__first_observed_time__

1700000000

首次观测时间,秒级时间戳

__keep_alive_seconds__

3600

存活时间,秒为单位,一般设置为同步周期的 2-3 倍

__last_observed_time__

1700000000

首次观测时间,秒级时间戳

其他字段

hostname, private_ip...

保留所有原始字段

完整示例:

{
    "__domain__": "cmdb",
    "__entity_type__": "cmdb.server",
    "__entity_id__": "b4da1c11d1a62257087aab071d27c1bc",
    "__method__": "Update",
    "__last_observed_time__": "1763629311",
    "__keep_alive_seconds__": "3600",
    "ci_id": "272",
    "ci_type_id": "4",
    "bu": "云计算",
    "buy_date": "2023-01-08",
    "ci_type": "server",
    "ci_type_alias": "物理机",
    "cmc_ip": "28.191.122.80",
    "cnc_ip": "224.127.127.194",
    "cpu": "AMD EPYC 7542",
    "cpu_count": "2",
    "ctc_ip": "75.76.9.36",
    "device_spec": "Huawei RH2288H V5",
    "env": "test",
    "idc": "阿里云-河源",
    "ilo_ip": "10.161.85.215",
    "ilo_mac": "05:0f:a9:63:91:ad",
    "kernel_version": "3.10.0-1160.el7.x86_64",
    "logic_cpu_count": "40",
    "manufacturer": "Dell",
    "oneagent_id": "XD1VLEEIR15O",
    "op_duty": "[\"张丽华\"]",
    "os_version": "CentOS 7.9",
    "perm": "{\"execute\": false, \"groups\": [\"viewers\", \"admins\", \"guests\"], \"owner\": \"张志强\", \"read\": true, \"write\": true}",
    "private_ip": "10.122.144.73",
    "rack": "59",
    "raid": "RAID 10",
    "ram": "64GB DDR4",
    "ram_size": "64",
    "rd_duty": "[\"齐晶\"]",
    "server_name": "phy-server-011",
    "server_room": "阿里云-河源机房",
    "sn": "C2LVEAZRIVH1",
    "ssh_port": "22",
    "status": "在线",
    "unique": "sn",
    "unique_alias": "服务器序列号",
    "vnc_port": "5910",
    "__pack_meta__": "0|MTc2MjgzMzA5NTg5OTYzMjg1OQ==|32|3",
    "__topic__": "",
    "__source__": "30.221.145.27",
    "__tag__:__receive_time__": "1763629311",
    "__time__": "1763629311",
    "__time_ns_part__": "127734016"
}

关系数据格式转换

VeOps 通过/api/v0.1/relation_ci获取 CI 关系数据。API 调用:

GET /api/v0.1/relation_ci?parent_type=product&child_type=application&level=1

返回数据示例:

{
  "parent_id": 100,
  "child_id": 200,
  "relation_type": "contains"
}
UModel Topo 数据格式

转换后写入 ${workspace}__topo 的数据格式及系统字段映射:

UModel 字段

示例

说明

__src_entity_type__

cmdb.server

__src_domain__

cmdb

__src_entity_id__

cb18feff0a2faa1b007000773c717942

源实体全局唯一ID

__dest_domain__

cmdb.ram

__dest_entity_type__

cmdb

__dest_entity_id__

b4da1c11d1a62257087aab071d27c1bc

目标实体全局唯一ID

__relation_type__

contains

标准化关系类型

__first_observed_time__

1700000000

首次观测时间,秒级时间戳

__keep_alive_seconds__

3600

存活时间,秒为单位,一般设置为同步周期的 2-3 倍

__last_observed_time__

1700000000

首次观测时间,秒级时间戳

完整示例:

{
    "__src_domain__": "cmdb",
    "__src_entity_type__": "cmdb.server",
    "__src_entity_id__": "cb18feff0a2faa1b007000773c717942",
    "__dest_domain__": "cmdb",
    "__dest_entity_type__": "cmdb.ram",
    "__dest_entity_id__": "b4da1c11d1a62257087aab071d27c1bc",
    "__relation_type__": "contains",
    "__method__": "Update",
    "__last_observed_time__": "1763703248"
}

2.1 配置同步连接

编辑 config.yaml,配置 CMDB 和 SLS 连接信息:

# CMDB 配置
cmdb:
  endpoint: "http://cmdb.example.com"
  api_key: "your-api-key"
  secret: "your-api-secret"

# SLS 配置
sls:
  endpoint: "cn-hangzhou.log.aliyuncs.com"
  access_key_id: "YOUR_ACCESS_KEY_ID"
  access_key_secret: "YOUR_ACCESS_KEY_SECRET"
  project: "cms-workspace-project"
  entity_logstore: "workspace__entity"
  topo_logstore: "workspace__topo"

2.2 执行一键同步

执行全量同步命令,同步所有实体和关系数据:

python3 main.py --mode full --all

2.3 设置定期同步

UModel 实体需要定期更新 last_observed_time 字段来维持存活状态(KeepAlive 机制)。实际部署建议采用全量同步 + 增量同步相结合的方式:

全量同步

  • 扫描 CMDB 中所有 CI 实例和关系,重新写入 EntityStore 中。

  • 确保数据完整性,修复增量同步可能遗漏的数据。

  • 适用于:首次导入、数据修复、定期数据校验(如每天凌晨执行)。

增量同步

  • 仅同步自上次同步后发生变更的数据(依赖 CMDB 的 updated_at 字段)。

  • 同步速度快、资源消耗低,适合高频执行。

  • 适用于:日常持续同步(如每 5-15 分钟执行一次)。

本示例采用 crontab 定时任务实现全量同步:

# 编辑 crontab
crontab -e

# 添加定时任务(每小时执行一次)
0 * * * * cd /path/to/cmdb_sync && python3 main.py --mode full --all >> logs/cron.log 2>&1

接入完成后的效果

完成数据导入后,可以在 CMS 2.0 控制台查看和操作 CMDB 数据。

1. 实体列表

查看所有从 CMDB 同步的实体。

实体列表

2. 实体关系拓扑

可视化展示实体间的完整关系网络。

实体关系拓扑

3. 单个实体拓扑

查看特定实体的关联关系。

单个实体拓扑

查询

链路数据查询

.topo | graph-call cypher(`
        MATCH (src {__entity_type__:"cmdb.business_unit"})-[e1]-(n1)-[e2]-(n2)
        RETURN src, e1, n1, e2, n2
      `)

image

多级跳

.topo | graph-call cypher(`
          MATCH (src {__entity_type__:"cmdb.business_unit"})-[e*3..4]->(dest)
          WHERE dest.__domain__ = 'cmdb'
          RETURN src, dest, dest.__entity_type__
      `)

image.png

获取单个实体可操作的方法

.entity_set with(domain='cmdb', name='cmdb.business_unit', ids=['cc723a11313b5b16a20806a64b89a212'])  | entity-call __list_method__()

image.png

获取邻居节点

.entity_set with(domain='cmdb', name='cmdb.business_unit', ids=['cc723a11313b5b16a20806a64b89a212'])  | entity-call get_neighbor_entities()

image.png

结合高阶算子完成高级能力

当实体接入其他可观测数据后,可结合高阶 SPL 算子完成高级能力,以下示例针对应用的请求延迟指标进行异常检测:

.entity_set with(domain='apm', name='apm.service', ids=['e22adf09a11550f4d7eae98d8a11a1e9']) 
| entity-call get_metric('apm', 'apm.metric.apm.service', 'avg_request_latency_seconds', aggregate=false) 
| extend r = series_decompose_anomalies(__value__) 
| extend anomaly_b =r.anomalies_score_series , anomaly_type = r.anomalies_type_series , __anomaly_msg__ = r.error_msg  
| extend x = zip(anomaly_b, __ts__, anomaly_type, __value__) 
| extend __anomaly_rst__ = filter(x, x-> x.field0 > 0) 
| project __entity_id__, __labels__, __anomaly_rst__, __anomaly_msg__

__anomaly_rst__中返回异常时间点,异常类型,以及当时的值

image.png