Jenkins 和 CMDB竟然着了DNS的道
点击上方蓝字关注我们
读完需 5 分钟
速读需 2 分钟
简述
CMDB在按业务、集群、模块、IP 纳管了基础设施资源后,如何为上层应用提供数据支撑,我想到的场景如下:
监控平台资产按业务/集群/模块/IP 进行管理,告警内容可以帮助我们快速定位故障;
堡垒机资产按业务/集群/模块/IP 进行管理,资产授权可以按不同粒度进行权限分配;
防火墙权限策略按模块区分,避免重复的权限分配及配置混乱;
为CI/CD构建按模块名提供动态化IP参数,有效避免IP的静态分配;
从以上几个场景可以看出,CMDB给我们提供了解决问题的基本思路。
本章我们就从为CI/CD构建提供动态化参数的实际案例来介绍下。
需求
在CI/CD中构建一项job需要目标主机的IP,我们可以通过以下几种方式获得:
构建参数中手动指定
ssh publisher 或其他ssh 插件中提前定义
在配置job过程中直接指定
以上几种方式都需要提前知道目标主机的IP,对执行构建人员来说很不友好。那么我们能不能参照DNS的套路,通过特定的名称查询CMDB来获取IP呢? 因此,jenkins从CMDB中根据模块名,动态获取模块对应IP的解决方案就有了。
通常情况下,较大的企业都会基于CMDB配套企业服务总线(ESB),来给各个平台提供服务。显然,我们的小企业是不具备这种能力的。因此我们需要借助CMDB API,自行将其封装成标准格式,然后通过Jenkins 调用API 来提供动态化参数,实现参数化构建。
整理流程如下:
API封装
通常情况下CMDB 自带的API 返回的结果数据比较多,上层的应用调用需要进行层层过滤筛选才能获得最终的结果。
例如蓝鲸CMDB 根据模块查询IP 接口,获取的结果数据为:
# 请求cmdb api
curl http://paas.bk.net/api/c/compapi/v2/cc/search_host/ -d
{
"bk_app_code": "bk-test",
"bk_app_secret": "62bc9c22-334d-4fcd-9523-991662163b67",
"bk_username": "admin",
"condition": [
{
"bk_obj_id": "biz",
"fields": [],
"condition": [
{
"field": "bk_biz_name",
"operator": "$in",
"value": ["生产环境"]
}
]
},
{
"bk_obj_id":"module",
"fields":[""],
"condition":[
{
"field": "bk_module_name",
"operator": "$in",
"value": ["test"]
}
]
}
],
"page": {
"start": 0,
"limit": 1,
"sort": "bk_host_id"
},
"pattern": ""
}
# 返回数据
{
"message": "success",
"code": 0,
"data": {
"count": 2,
"info": [
{
"host": {
"bk_cpu": null,
"bk_isp_name": null,
"host_host_manageip": "",
"bk_os_name": "",
"bk_province_name": null,
"bk_host_id": 1861,
"import_from": "3",
"bk_os_version": "",
"bk_disk": null,
"operator": null,
"create_time": "2019-12-08T14:24:04.924+08:00",
"bk_mem": null,
"bk_host_name": "",
"bk_host_innerip": "10.168.202.58",
"bk_host_type": "2",
"bk_comment": "",
"bk_host_jiwei": "",
"bk_host_band": "",
"bk_os_bit": "",
"bk_outer_mac": "",
"bk_host_jigui": "",
"bk_asset_id": "",
"bk_service_term": null,
"bk_cloud_id": [
{
"bk_obj_name": "",
"id": "0",
"bk_obj_id": "plat",
"bk_obj_icon": "",
"bk_inst_id": 0,
"bk_inst_name": "default area"
}
],
"bk_sla": null,
"bk_cpu_mhz": null,
"bk_service_limit": null,
"bk_host_outerip": "",
"bk_state_name": null,
"bk_os_type": null,
"bk_host_stat": "1",
"bk_mac": "",
"bk_bak_operator": null,
"bk_supplier_account": "0",
"bk_host_model": "",
"bk_sn": "",
"bk_cpu_module": ""
},
"set": [],
"biz": [
{
"bk_biz_id": 3,
"language": "1",
"life_cycle": "2",
"bk_biz_developer": "",
"bk_biz_maintainer": "admin",
"bk_biz_tester": "",
"time_zone": "Asia/Shanghai",
"default": 0,
"create_time": "2020-12-09T11:12:04.449+08:00",
"bk_biz_productor": "",
"bk_supplier_account": "0",
"operator": "admin",
"bk_biz_name": "生产环境",
"last_time": "2021-11-29T09:17:09.837+08:00",
"bk_supplier_id": 0
}
],
"module": [
{
"default": 0,
"TopModuleName": "生产环境",
"bk_module_id": 1358
}
]
}
]
},
"result": true,
"request_id": "02ed84f480e0412980923cb1959973ba"
}
其中从请求的json数据可以得出查询条件:
业务名:生产环境
模块名:test
返回的结果包含了很多信息,但是我们只想要test模块所部署的IP:10.168.202.58
,其他信息可以忽略。如果直接使用原生API ,我们要花费很大的精力在解析json数据上。因此我们需要单独封装一个API,功能需求不变,即根据业务、模块查询IP。
# 请求封装后的api
curl http://10.168.209.88:8080/cmdb/getHost/?module=test&env=pro
{"status": 200, "module": "test", "env": "pro", "hosts": ["10.168.202.58"]}
通过简单的参数查询,即可得到我们想要的结果,后面只需愉快的接入了。
Jenkins接入
Jenkins我们以管理应用的job为例,功能为启动、停止、重启指定应用。
在参数化构建过程中,我们只需输入应用名,就可以获得该应用名所对应的部署IP,后面的一系列操作就可以基于此IP按需实现。
1.参数化构建
其中:
APP_NAME: 对应CMDB中的模块名
ACTION: 启动、停止、重启操作
HOST: 模块名对应的IP,调用api后结果以单选框的形式展现。
2.Active Choices Reactive Parameter
由于Jenkins 是基于grovvy开发,因此我们需要在Groovy Script
处调用封装的API ,实现根据模块名动态获取IP的功能
,得到的结果以Single Select
即单选框的形式展现。
另外,Referenced parameters 是将实际输入的APP_NAME参数指,传递到Groovy Script中,实现按需调用。
3.构建结果
总结
通过CMDB给Jenkins提供动态参数,使CMDB成为数据孤岛的可能性进一步降低,同时也给Jenkins带来了另一种最佳实践。这种方式类似于DNS,我们不需要知道IP地址,只需知道应用名就可以快速获取IP进行操作了。