{"id":13842422,"url":"https://github.com/n9e/k8s-mon","last_synced_at":"2025-10-24T20:32:09.115Z","repository":{"id":57575813,"uuid":"329294537","full_name":"n9e/k8s-mon","owner":"n9e","description":"滴滴夜莺Kubernetes monitor","archived":false,"fork":false,"pushed_at":"2022-10-17T15:02:53.000Z","size":362,"stargazers_count":45,"open_issues_count":2,"forks_count":15,"subscribers_count":6,"default_branch":"main","last_synced_at":"2024-09-29T05:46:08.579Z","etag":null,"topics":["k8s","monitor","nightingale"],"latest_commit_sha":null,"homepage":"https://www.bilibili.com/video/BV1ZK4y1H7PT?t=279","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/n9e.png","metadata":{"files":{"readme":"readme.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-01-13T12:02:20.000Z","updated_at":"2024-03-08T06:02:30.000Z","dependencies_parsed_at":"2023-01-20T02:31:01.576Z","dependency_job_id":null,"html_url":"https://github.com/n9e/k8s-mon","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/n9e%2Fk8s-mon","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/n9e%2Fk8s-mon/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/n9e%2Fk8s-mon/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/n9e%2Fk8s-mon/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/n9e","download_url":"https://codeload.github.com/n9e/k8s-mon/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":219867829,"owners_count":16555886,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["k8s","monitor","nightingale"],"created_at":"2024-08-04T17:01:34.278Z","updated_at":"2025-10-24T20:32:07.240Z","avatar_url":"https://github.com/n9e.png","language":"Go","funding_links":[],"categories":["Go"],"sub_categories":[],"readme":"# 问题排查\n- 遇到问题请先看，[问题排查文档](./问题排查.md)  ，其中汇总了场景问题和排查思路。\n\n\n# 模式说明\n- 对应配置项为collect_mode `cadvisor_plugin | kubelet_agent | server_side` 三选一\n- 代码为同一套代码\n\n|  模式名称  |  部署运行方式 |  collect_mode配置   |  说明 | \n|  ----  | ----  | ---- |---| \n| 夜莺插件形式采集cadvisor raw api\t| 可执行的插件由夜莺agent调用|\tcadvisor_plugin | 文档在readme最下面 (原有cadvisor采集模式) |  \n| 容器基础资源指标采集\t|  k8s daemonset 部署在每一个node上|\tkubelet_agent | 统称为新模式  (kubelet地址由对应metrics port listen地址决定) |  \n| 集中采集k8s服务组件\t|k8s deployment 部署 |\tserver_side | 统称为新模式  |  \n\n# k8s-mon对比prometheus的优点\n- Histogram指标分位值预计算，节约存储、降低服务端压力(高基数指标往往来自histogram的海量bucket，同时除了算分位值以外的应用如分布情况又较少)\n- 基础资源指标预计算，counterTogauge 简化最终查看的表达式\n- 容器基础资源/k8s资源指标和夜莺树绑定\n\n\n# 新模式：部署在k8s中采集相关指标\n## 原理说明\n\n- 通过抓取各个组件的/metrics接口获得prometheus的数据，ETL后push到夜莺\n- 各个采集项目有metirc和tag的白名单过滤\n- `cadvisor`数据需要hold点做计算比率类指标，多用在百分比的情况，其余不需要\n- `counter`类型将有夜莺agent转换为`gauge`型，即数值已经转为`rate`了 ,**所有`counter`类型metric_name 加`_rate`后缀**\n- 指标说明在`metrics-detail`文件夹里\n- k8s yaml配置在 `k8s-config`中\n- 服务组件监控时多实例问题：用户无需关心，k8s-mon自动发现并采集 \n- 采集每node上的`kube-proxy` `kubelet-node`指标时支持并发数配置和静态分片\n- 服务组件采集时会添加`func_name`标签作为区分具体组件任务，类似`prometheus`的`job`标签 \n- 基础指标添加`node_ip` ,`node_name`作为宿主机标识标签\n- ksm指标没有nid的默认上报到服务节点`server_side_nid` ，例如`kube_node_status_allocatable_cpu_cores`这种共享指标\n- **服务组件采集预聚合了一些指标，包括 分位值、平均值、成功率**，对应文档在 `metrics-detail/preaggregation.md` \n- 服务组件采集了对应golang 进程的指标 包括 内存、goroutine等 ，对应文档在 `metrics-detail/process-resource.md`\n\n## 采集内容说明\n\n- 一般来说在k8s集群汇总我们关注一下4类指标 \n\n|  指标类型  |  采集源 |  应用举例  |  部署方式 | \n|  ----  | ----  | ---- |---| \n| 容器基础资源指标\t| kubelet 内置cadvisor |\t查看容器cpu、mem等 | k8s daemonset   |  \n| k8s资源指标\t| [kube-stats-metrics](https://github.com/kubernetes/kube-state-metrics) (简称ksm)|\t查看pod状态、查看deployment信息等 | k8s deployment (需要提前部署ksm)   |  \n| k8s服务组件指标\t|各个服务组件的metrics接口(多实例自动发现)\u003cbr\u003e apiserver \u003cbr\u003e kube-controller-manager \u003cbr\u003e kube-scheduler \u003cbr\u003e etcd \u003cbr\u003e coredns \u003cbr\u003e kube-proxy \u003cbr\u003e kubelet-node |\t查看请求延迟/QPS等 | 和ksm同一套代码，部署在  k8s deployment   |  \n| 业务指标(暂不支持)\t| pod暴露的metrics接口|\t- | -  |  \n\n## 采集地址配置/发现说明\n- 每种项目配置了相关配置段才会开启，如果不想采集某类指标可以去掉其配置\n- 每种项目由 `user_specified` 配置是否采用用户指定的地址，用来处理有些服务组件以裸进程形式部署无法从内部发现的case\n- 当`user_specified：true`时，对应的`addrs`为采集地址url列表\n- 当`user_specified：false`时，则认为由内置的代码来进行动态发现，需要配置好对应的`port` `schema` `metrics_path`等信息\n\n|  采集类型  |  采集地址说明 |  配置/发现说明  | \n|  ----  | ----  | ---- |\n| 容器基础资源指标 kubelet-cadvisor\t| kubelet 在node上listen分两种情况:\u003cbr\u003e  listen 0.0.0.0 \u003cbr\u003e listen机器内网ip |\t默认为`k8s-mon`自动根据配置的`port`找到对应的地址 |\n| k8s资源指标\tkube-stats-metrics| 默认为通过coredns 访问service `http://kube-state-metrics.kube-system:8080/metrics` | 同时支持指定  |\n| k8s服务组件指标(master侧) \u003cbr\u003e apiserver \u003cbr\u003e kube-controller-manager \u003cbr\u003e kube-scheduler \u003cbr\u003e etcd \u003cbr\u003e coredns   \u003cbr\u003e| 需要注意这些组件的部署方式 : \u003cbr\u003e 部署在pod 中 \u003cbr\u003e 以裸进程部署 |\t`k8s-mon`默认认这些组件部署在pod中，通过**getpod**获取地址列表  |  \n| k8s服务组件指标(每node部署) kube-proxy \u003cbr\u003e kubelet-node | 需要注意这些组件的部署方式 : \u003cbr\u003e 部署在pod 中 \u003cbr\u003e 以裸进程部署 |\t`k8s-mon`默认认这些组件在每个node都可以以`ip:port/metrics`访问到，通过**getnode**获取internal ip ，对应的服务需要listen 内网ip或`0.0.0.0`|  \n| 业务指标(暂不支持)\t| pod暴露的metrics接口|\t- | -  |\n\n\n# 使用指南\n# 3、安装步骤\n\n## setup01 准备工作\n\n\u003e 准备k8s环境 ，确保每个node节点部署夜莺agent `n9e-agent`\n\n```shell script\n# 创建namespace kube-admin\nkubectl create ns kube-admin\n# 创建访问etcd所需secret，在master上执行（不采集etcd则不需要）\n# 注意如果 不采集etcd，没有创建对应的证书(如k8s使用公有云托管的)，默认 deployment中挂载证书那几行是注释掉的，开启etcd采集再打开\n# etcd证书信息依据自己环境替换即可\nkubectl create secret generic etcd-certs --from-file=/etc/kubernetes/pki/etcd/healthcheck-client.crt --from-file=/etc/kubernetes/pki/etcd/healthcheck-client.key --from-file=/etc/kubernetes/pki/etcd/ca.crt -n kube-admin\n\n```\n\n\u003e 直接使用公共源的镜像\n```shell script\n# 公共源使用阿里云的\n# registry.cn-beijing.aliyuncs.com/n9e/k8s-mon:v1\n```\n\n\n\u003e 或者自己下载代码，打镜像\n\n```shell script\nmkdir -pv $GOPATH/github.com/n9e \ncd $GOPATH/github.com/n9e \ngit clone https://github.com/n9e/k8s-mon \n\n# 使用docker 命令，或者ci工具,将镜像同步到仓库中 \n# 如需修改镜像名字，需要同步修改daemonset 和deployment yaml文件中的image字段\n# 镜像需要同步到所有node，最好上传到仓库中\ncd k8s-mon  \u0026\u0026 docker build -t k8s-mon:v1 . \n\n```\n\n\n## setup02 必须修改的配置\n\u003e 修改对接夜莺nid标签的名字\n- 对应配置为配置文件中的`n9e_nid_label_name`\n- 默认为:`N9E_NID`，与之前k8s-mon采集cadvisor指标要求容器环境变量名一致\n- 如需修改则需要改 `k8s-config/configMap_deployment.yaml` 和 `k8s-config/configMap_daemonset.yaml` 中的 `n9e_nid_label_name`字段 \n\n\u003e pod yaml文件中传入上述 nid标签，例如：`N9E_NID`  \n\n- 举例：deployment中定义pod的 `N9E_NID`  label，假设test-server01这个模块对应的服务树节点nid为5\n- 后续该pod的容器的基础指标出现在nid=5的节点下: 如 cpu.user \n- 后续该pod的k8s的基础指标出现在nid=5的节点下: 如 kube_deployment_status_replicas_available\n- 其余自定义标签不采集,如：`region: A` `cluster: B`\n                     \n```yaml\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: test-server01-deployment\n  labels:\n    app: test-server01\n    # 这里表示此deployment的nid为5\n    N9E_NID: \"5\"\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: test-server01\n  template:\n    metadata:\n      labels:\n        app: test-server01\n        region: A\n        cluster: B\n        # 这里表示此deployment启动的容器nid为5\n        N9E_NID: \"5\"\n```\n\n\u003e 服务组件监控需要指定server_side_nid\n-  修改  `k8s-config/configMap_deployment.yaml` 将 server_side_nid: 字段改为指定的服务组件监控叶子节点的nid\n- 举例：server_side_nid: \"6\"：代表6为k8s集群的服务树叶子节点，k8s控制平面的指标都会上报到这里\n\n\u003e k8s服务组件指标(master侧) 如果不是部署在pod中，需要指定采集地址\n- apiserver 、kube-scheduler、coredns、etcd等\n- `k8s-mon`默认认这些组件部署在pod中，通过**getpod**获取地址列表\n- 如果不是部署在pod中，需要指定采集地址(将user_specified设置为true，并指定addr，其余配置保持不变即可)，举例如下\n```yaml\napiserver:\n  user_specified: true\n  addrs:\n    - \"https://1.1.1.1:6443/metrics\"\n    - \"https://2.2.2.2:6443/metrics\"\n```\n\n\n## setup03 可以调整的配置(维持默认值时可跳过此段配置)\n\u003e 如果不想采集某类指标可以去掉其配置\n- 举例：不想采集`apiserver`的指标\n- 则去掉/注释掉 `k8s-config/configMap_deployment.yaml`中 `apiserver`段即可\n- deployment中需要采集每node的`kube-proxy` 和`kubelet` (node量大的时候)不需要可以去掉\n\n\u003e 每node的`kube-proxy` 和`kubelet`静态分片采集\n- 默认采集所有node的指标，在node数量大时会导致性能问题，则需要开启分片采集\n- 举例有1万个node需要采集kube-proxy，则部署3个k8s-mon，配置值开启kube-proxy段\n- 其中`hash_mod_num`代表总分片数量 `hash_mod_shard`代表本实例取模后的index(取值范围是0 ~ hash_mod_num-1)\n- 那么这三个实例则会将1万个node分片采集\n\n```yaml\n# 实例1\nkube_proxy:\n  hash_mod_num: 3\n  hash_mod_shard: 0\n```\n\n```yaml\n# 实例2\nkube_proxy:\n  hash_mod_num: 3\n  hash_mod_shard: 1\n```\n\n```yaml\n# 实例3\nkube_proxy:\n  hash_mod_num: 3\n  hash_mod_shard: 2\n```\n\n\n\u003e 想给某个采集项指定采集地址\n- 举例：想设置kube-scheduler的采集地址为 `https://1.1.1.1:1234/metrics` 和 `https://2.2.2.2:1234/metrics` \n- 则修改`k8s-config/configMap_deployment.yaml`中 `user_specified` 和`addrs`即可\n```yaml\nkube_scheduler:\n  user_specified: true\n  addrs:\n    - \"https://1.1.1.1:1234/metrics\"\n    - \"https://2.2.2.2:1234/metrics\"\n```\n\n\n\n\u003e 如需给采集的指标添加自定义tag \n- 则修改 `k8s-config/configMap_deployment.yaml` `k8s-config/configMap_daemonset.yaml`中的`append_tags`字段即可\n```yaml\nappend_tags:\n  key1: value1\n  key2: value2\n```\n\n\u003e 如需修改采集间隔\n- 修改`k8s-config/configMap_deployment.yaml` `k8s-config/configMap_daemonset.yaml`中的 `collect_step` 字段\n\n\u003e 如需修改某个项目的采集并发\n- 修改`k8s-config/configMap_deployment.yaml` 中的指定项目的 `concurrency_limit` 字段，默认10\n\n\n\u003e 如需服务组件采集多实例时的特征标签\n- 修改`k8s-config/configMap_deployment.yaml` 中的 `multi_server_instance_unique_label` 字段\n\n\u003e 调整日志级别\n- 修改`k8s-config/deployment.yaml` 中的 spec.containers.command 加上`--log.level=debug`即可看到debug日志，日志样例如下\n- 单项数据处理耗时\n```shell script\nlevel=debug ts=2021-02-24T15:47:31.810+08:00 caller=kube_controller_manager.go:180 msg=DoCollectSuccessfullyReadyToPush funcName=kube-controller-manager metrics_num=621 time_took_seconds=0.307592776\n```\n- 单项推送耗时\n```shell script\nlevel=debug ts=2021-02-24T15:47:31.863+08:00 caller=push.go:25 msg=PushWorkSuccess funcName=kube-controller-manager url=http://localhost:2080/api/collector/push metricsNum=621 time_took_seconds=0.053355322\n```\n- 获取pod耗时\n```shell script\nlevel=debug ts=2021-02-24T15:50:01.523+08:00 caller=get_pod.go:99 msg=server_pod_ips_result num_kubeSchedulerIps=1 num_kubeControllerIps=1 num_apiServerIps=1 num_coreDnsIps=2 num_kubeProxyIps=2 num_etcdIps=1 time_took_seconds=0.020384107\n``` \n\n## setup04 启动服务 \n\n\u003e 启动ksm服务(部署在kube-system namespace中 ，需要采集才启动)\n```shell script\nkubectl apply -f k8s-config/kube-stats-metrics\n```\n\u003e 启动k8s-mon daemonset 和deployment (部署在kube-admin namespace中，按需启动daemonset 和deployment)\n```shell script\nkubectl apply -f k8s-config\n```\n\n## setup05 观察日志，查看指标\n\u003e 查看日志 \n```shell script\nkubectl logs -l app=k8s-mon-deployment  -n kube-admin  -f\nkubectl logs -l app=k8s-mon-daemonset  -n kube-admin  -f\n``` \n\n## setup06 查看指标，导入大盘图\n\u003e 即时看图查看指标 \n```shell script\n# 浏览器访问及时看图path： http://\u003cn9e_addr\u003e/mon/dashboard?nid=\u003cnid\u003e\n \n``` \n\u003e 导入大盘图 \n```shell script\n# 大盘图在 metrics-detail/夜莺大盘-xxxjson中\n# 将三个大盘json文件放到夜莺服务端机器 \u003cn9e_home\u003e/etc/screen 下 \n# 或者 克隆夜莺3.5+代码，内置大盘图json在 etc/screen 下 \n# 刷新页面，在对应的节点选择导入内置大盘即可\n``` \n\n\n## 注意事项\n### 采集间隔\n- kubelet 内置了cadvisor作为容器采集 ，具体文档可以看这里 [cadvisor housekeeping配置](https://github.com/google/cadvisor/blob/master/docs/runtime_options.md#housekeeping)\n- 同时kubelet 命令行透传了[相关配置](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/)\n- ```--housekeeping-interval duration     Default: `10s` ``` 模式采集是10秒，所以在`默认配置`下无论prometheus还是k8s-mon采集间隔不应低于10s\n- **cpu 和mem指标需要pod设置limit，如果没有limit则某些指标会缺失**\n\n### 白名单问题\n- 建议保持默认的metrics名单，metrics_white_list为空则全采集\n- tag白名单可按需配置\n\n### histogram数据问题\n- 提供基于 histogram的分位值，所有的_bucket指标已经被过滤掉了，提供分位值`quantile`  50 90 95 99\n- 线性插值法计算，和prometheus大致相同 :prometheus先算rate再算sum，k8s-mon是先算sum再算rate\n- 举例 `coredns_dns_request_duration_seconds_bucket --\u003e coredns_dns_request_duration_seconds_quantile ` 代表coredns 解析平均延迟分位值\n- 同时提供平均值 举例 `coredns_dns_request_duration_seconds_bucket --\u003ecoredns_dns_request_duration_seconds_avg `\n\n\n# 原有cadvisor采集模式，即配置文件中collect_mode : cadvisor_plugin\n\u003e 作为Nightingale的插件，用于收集docker容器的监控指标\n\n## 快速构建 \n```\n    $ mkdir -p $GOPATH/src/github.com/n9e\n    $ cd $GOPATH/src/github.com/n9e\n    $ git clone https://github.com/n9e/k8s-mon.git\n    $ cd k8s-mon\n    $ make\n    $ ./k8s-mon\n```\n\n## 前置依赖\n1. docker容器所在宿主机已安装并启动了cadvisor\n2. docker容器的环境变量中包含 N9E_NID ，N9E_NID 的内容为夜莺服务树节点id，如果设置 N9E_NID = 1，则到节点id为1的节点下，就可以容器的监控指标\n\n## 使用方式\n1. 将 k8s-mon、k8s-mon.yml 分发到容器所在的宿主机上\n2. 到宿主机所属节点配置插件采集\n\n![k8s-mon](https://s3-gz01.didistatic.com/n9e-pub/image/docker.png)\n\n3. 配置完之后，到即时看图，选择对应的节点，再选择设备无关，即可查看采集到的容器监控指标\n![docker-metric](https://s3-gz01.didistatic.com/n9e-pub/image/docker_metric.png)\n\n## 视频教程\n[观看地址](https://s3-gz01.didistatic.com/n9e-pub/video/n9e-docker-mon.mp4)\n\n## 指标列表\n\n- CPU    \ncpu.user    \ncpu.sys    \ncpu.idle    \ncpu.util    \ncpu.periods    \ncpu.throttled_periods    \ncpu.throttled_time    \n\n- 内存    \nmem.bytes.total    \nmem.bytes.used    \nmem.bytes.used.percent    \nmem.bytes.cached    \nmem.bytes.rss    \nmem.bytes.swap    \n\n- 磁盘    \ndisk.io.read.bytes    \ndisk.io.write.bytes\t    \ndisk.bytes.total    \ndisk.bytes.used    \ndisk.bytes.used.percent    \n\n- 网络    \nnet.sockets.tcp.timewait    \nnet.in.bits    \nnet.in.pps    \nnet.in.errs    \nnet.in.dropped    \nnet.out.bits    \nnet.out.pps    \nnet.out.errs    \nnet.out.dropped    \nnet.tcp.established    \n\n- 系统    \nsys.ps.process.used    \nsys.ps.thread.used    \nsys.fd.count.used    \nsys.socket.count.used    \nsys.restart.count    \n\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fn9e%2Fk8s-mon","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fn9e%2Fk8s-mon","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fn9e%2Fk8s-mon/lists"}