常用监控对象的指标采集

对于集群的监控一般我们需要考虑以下几个方面:

  • 内部系统组件的状态:比如 kube-apiserver、kube-scheduler、kube-controller-manager、kubedns/coredns 等组件的详细运行状态
  • Kubernetes 节点的监控:比如节点的 cpu、load、disk、memory 等指标
  • 业务容器指标的监控(容器CPU、内存、磁盘等)
  • 编排级的 metrics:比如 Deployment 的状态、资源请求、调度和 API 延迟等数据指标

    监控配置

    监控coreDNS,修改target配置:

    ```yaml apiVersion: v1 kind: ConfigMap metadata: name: prometheus-config namespace: monitor data: prometheus.yml: | global:
    1. scrape_interval: 15s
    2. scrape_timeout: 15s
    scrape_configs:
    • job_name: ‘prometheus’ static_configs:
      • targets: [‘localhost:9090’]
    • job_name: ‘coredns’ static_configs:
      • targets: [‘10.96.0.10:9153’]

$ kubectl apply -f prometheus-configmap.yaml

重建pod生效

$ kubectl -n monitor delete po prometheus-dcb499cbf-fxttx

  1. <a name="K82pr"></a>
  2. ### 监控kube-apiserver
  3. apiserver自身也提供了/metrics 的api来提供监控数据,可以通过手动配置如下job来试下对apiserver服务的监控
  4. ```yaml
  5. ...
  6. - job_name: 'kubernetes-apiserver'
  7. static_configs:
  8. - targets: ['10.96.0.1']
  9. scheme: https
  10. tls_config:
  11. ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
  12. insecure_skip_verify: true
  13. bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token

监控节点主机 node_exporter https://github.com/prometheus/node_exporter

分析:

  • 每个节点都需要监控,因此可以使用DaemonSet类型来管理node_exporter
  • 添加节点的容忍配置
  • 挂载宿主机中的系统文件信息

    创建node-exporter服务

    1. apiVersion: apps/v1
    2. kind: DaemonSet
    3. metadata:
    4. name: node-exporter
    5. namespace: monitor
    6. labels:
    7. app: node-exporter
    8. spec:
    9. selector:
    10. matchLabels:
    11. app: node-exporter
    12. template:
    13. metadata:
    14. labels:
    15. app: node-exporter
    16. spec:
    17. hostPID: true
    18. hostIPC: true
    19. hostNetwork: true
    20. nodeSelector:
    21. kubernetes.io/os: linux
    22. containers:
    23. - name: node-exporter
    24. image: prom/node-exporter:v1.0.1
    25. args:
    26. - --web.listen-address=$(HOSTIP):9100
    27. - --path.procfs=/host/proc
    28. - --path.sysfs=/host/sys
    29. - --path.rootfs=/host/root
    30. - --collector.filesystem.ignored-mount-points=^/(dev|proc|sys|var/lib/docker/.+)($|/)
    31. - --collector.filesystem.ignored-fs-types=^(autofs|binfmt_misc|cgroup|configfs|debugfs|devpts|devtmpfs|fusectl|hugetlbfs|mqueue|overlay|proc|procfs|pstore|rpc_pipefs|securityfs|sysfs|tracefs)$
    32. ports:
    33. - containerPort: 9100
    34. env:
    35. - name: HOSTIP
    36. valueFrom:
    37. fieldRef:
    38. fieldPath: status.hostIP
    39. resources:
    40. requests:
    41. cpu: 150m
    42. memory: 180Mi
    43. limits:
    44. cpu: 150m
    45. memory: 180Mi
    46. securityContext:
    47. runAsNonRoot: true
    48. runAsUser: 65534
    49. volumeMounts:
    50. - name: proc
    51. mountPath: /host/proc
    52. - name: sys
    53. mountPath: /host/sys
    54. - name: root
    55. mountPath: /host/root
    56. mountPropagation: HostToContainer
    57. readOnly: true
    58. tolerations:
    59. - operator: "Exists"
    60. volumes:
    61. - name: proc
    62. hostPath:
    63. path: /proc
    64. - name: dev
    65. hostPath:
    66. path: /dev
    67. - name: sys
    68. hostPath:
    69. path: /sys
    70. - name: root
    71. hostPath:
    72. path: /

    部署

    1. $ kubectl create -f node-exporter.yaml
    2. $ kubectl -n monitor get po

    如何添加到Prometheus的target中?

  • 配置一个Service,后端挂载node-exporter的服务,把Service的地址配置到target中

    • 带来新的问题,target中无法直观的看到各节点node-exporter的状态
  • 把每个node-exporter的服务都添加到target列表中

    • 带来新的问题,集群节点的增删,都需要手动维护列表
    • target列表维护量随着集群规模增加

      Prometheus的服务发现与Relabeling

      之前已经给Prometheus配置了RBAC,有读取node的权限,因此Prometheus可以去调用Kubernetes API获取node信息,所以Prometheus通过与 Kubernetes API 集成,提供了内置的服务发现分别是:Node、Service、Pod、Endpoints、Ingress

      配置job,添加node-exporter到target中

      1. ...
      2. - job_name: 'kubernetes-sd-node-exporter'
      3. kubernetes_sd_configs:
      4. - role: node

      重建查看效果:

      1. $ kubectl apply -f prometheus-configmap.yaml
      2. $ kubectl -n monitor delete po prometheus-dcb499cbf-6cwlg
      Prometheus监控k8s集群 - 图1
      默认访问的地址是http://node-ip/10250/metrics,10250是kubelet API的服务端口,说明Prometheus的node类型的服务发现模式,默认是和kubelet的10250绑定的,而我们是期望使用node-exporter作为采集的指标来源,因此需要把访问的endpoint替换成http://node-ip:9100/metrics。
      Prometheus监控k8s集群 - 图2

      在真正抓取数据前,Prometheus提供了relabeling的能力。怎么理解?

      查看Target的Label列,可以发现,每个target对应会有很多Before Relabeling的标签,这些__开头的label是系统内部使用,不会存储到样本的数据里,但是,我们在查看数据的时候,可以发现,每个数据都有两个默认的label,即:
      1. prometheus_notifications_dropped_total{instance="localhost:9090",job="prometheus"}
      instance的值其实则取自于address
      这种发生在采集样本数据之前,对Target实例的标签进行重写的机制在Prometheus被称为Relabeling。
      因此,利用relabeling的能力,只需要将address替换成node_exporter的服务地址即可。
      1. ...
      2. - job_name: 'kubernetes-sd-node-exporter'
      3. kubernetes_sd_configs:
      4. - role: node
      5. relabel_configs:
      6. - source_labels: [__address__]
      7. regex: '(.*):10250'
      8. replacement: '${1}:9100'
      9. target_label: __address__
      10. action: replace
      再次更新Prometheus服务后,查看targets列表及node-exporter提供的指标,node_load1

      cadvisor监控指标的采集

      cAdvisor 的指标访问路径为#IP为api-server的serviceIP
      1. https://10.96.0.1/api/v1/nodes/<node_name>/proxy/metrics
      2. https://10.96.0.1/api/v1/nodes/k8s-master/proxy/metrics
      3. https://10.96.0.1/api/v1/nodes/k8s-slave1/proxy/metrics
      4. https://10.96.0.1/api/v1/nodes/k8s-slave2/proxy/metrics
      分析:
  • 每个节点都需要做替换,可以利用Prometheus服务发现中 node这种role

    1. - job_name: 'kubernetes-sd-cadvisor'
    2. kubernetes_sd_configs:
    3. - role: node

    默认添加的target列表为:address metrics_path
    http://192.168.136.10:10250/metrics
    http://192.168.136.11:10250/metrics
    http://192.168.136.12:10250/metrics
    抓取的地址是相同的,可以用10.96.0.1做固定值进行替换address

    1. - job_name: 'kubernetes-sd-cadvisor'
    2. kubernetes_sd_configs:
    3. - role: node
    4. relabel_configs:
    5. - target_label: __address__
    6. replacement: 10.96.0.1
    7. action: replace

    目前为止,替换后的样子:
    http://10.96.0.1/metrics
    http://10.96.0.1/metrics
    http://10.96.0.1/metrics
    需要把找到node-name,来做动态替换metrics_path

    1. - job_name: 'kubernetes-sd-cadvisor'
    2. kubernetes_sd_configs:
    3. - role: node
    4. relabel_configs:
    5. - target_label: __address__
    6. replacement: 10.96.0.1
    7. action: replace
    8. - source_labels: [__meta_kubernetes_node_name]
    9. regex: (.+)
    10. target_label: __metrics_path__
    11. replacement: /api/v1/nodes/${1}/proxy/metrics/cadvisor

    目前为止,替换后的样子:
    http://10.96.0.1/api/v1/nodes/k8s-master/proxy/metrics
    http://10.96.0.1/api/v1/nodes/k8s-slave1/proxy/metrics
    http://10.96.0.1/api/v1/nodes/k8s-slave2/proxy/metrics
    加上api-server的认证信息

    1. - job_name: 'kubernetes-sd-cadvisor'
    2. kubernetes_sd_configs:
    3. - role: node
    4. scheme: https
    5. tls_config:
    6. ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
    7. insecure_skip_verify: true
    8. bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
    9. relabel_configs:
    10. - target_label: __address__
    11. replacement: 10.96.0.1
    12. - source_labels: [__meta_kubernetes_node_name]
    13. regex: (.+)
    14. target_label: __metrics_path__
    15. replacement: /api/v1/nodes/${1}/proxy/metrics/cadvisor

    重新应用配置,然后重建Prometheus的pod。查看targets列表,查看cadvisor指标,比如container_cpu_system_seconds_total
    综上,利用node类型,可以实现对daemonset类型服务的目标自动发现以及监控数据抓取。

集群Service服务的监控指标采集

比如集群中存在100个业务应用,每个业务应用都需要被Prometheus监控。
每个服务是不是都需要手动添加配置?有没有更好的方式?

  1. - job_name: 'kubernetes-sd-endpoints'
  2. kubernetes_sd_configs:
  3. - role: endpoints

添加到Prometheus配置中进行测试:

  1. $ kubectl apply -f prometheus-configmap.yaml
  2. $ kubectl -n monitor delete po prometheus-dcb499cbf-4h9qj

此使的Target列表中,kubernetes-sd-endpoints下出现了N多条数据,
Prometheus监控k8s集群 - 图3
可以发现,实际上endpoint这个类型,目标是去抓取整个集群中所有的命名空间的Endpoint列表,然后使用默认的/metrics进行数据抓取,我们可以通过查看集群中的所有ep列表来做对比:

  1. $ kubectl get endpoints --all-namespaces

但是实际上并不是每个服务都已经实现了/metrics监控的,也不是每个实现了/metrics接口的服务都需要注册到Prometheus中,因此,我们需要一种方式对需要采集的服务实现自主可控。这就需要利用relabeling中的keep功能。
Prometheus监控k8s集群 - 图4
我们知道,relabel的作用对象是target的Before Relabling标签,比如说,假如通过如下定义:

  1. - job_name: 'kubernetes-sd-endpoints'
  2. kubernetes_sd_configs:
  3. - role: endpoints
  4. relabel_configs:
  5. - source_labels: [__keep_this_service__]
  6. action: keep
  7. regex: true

那么就可以实现target的Before Relabling中若存在keep_this_service,且值为true的话,则会加入到kubernetes-endpoints这个target中,否则就会被删除。
因此可以为我们期望被采集的服务,加上对应的Prometheus的label即可。

问题来了,怎么加?
查看coredns的metrics类型Before Relabling中的值,可以发现,存在如下类型的Prometheus的标签:
meta_kubernetes_service_annotation_prometheus_io_scrape=”true”
meta_kubernetes_service_annotation_prometheus_io_port=”9153”
这些内容是如何生成的呢,查看coredns对应的服务属性:

  1. $ kubectl -n kube-system get service kube-dns -o yaml
  2. apiVersion: v1
  3. kind: Service
  4. metadata:
  5. annotations:
  6. prometheus.io/port: "9153"
  7. prometheus.io/scrape: "true"
  8. creationTimestamp: "2020-06-28T17:05:35Z"
  9. labels:
  10. k8s-app: kube-dns
  11. kubernetes.io/cluster-service: "true"
  12. kubernetes.io/name: KubeDNS
  13. name: kube-dns
  14. namespace: kube-system
  15. ...

发现存在annotations声明,因此,可以联想到二者存在对应关系,Service的定义中的annotations里的特殊字符会被转换成Prometheus中的label中的下划线。
我们即可以使用如下配置,来定义服务是否要被抓取监控数据。

  1. - job_name: 'kubernetes-sd-endpoints'
  2. kubernetes_sd_configs:
  3. - role: endpoints
  4. relabel_configs:
  5. - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape]
  6. action: keep
  7. regex: true

这样的话,我们只需要为服务定义上如下的声明,即可实现Prometheus自动采集数据

  1. annotations:
  2. prometheus.io/scrape: "true"

有些时候,我们业务应用提供监控数据的path地址并不一定是/metrics,如何实现兼容?
同样的思路,我们知道,Prometheus会默认使用Before Relabling中的__metrics_path作为采集路径,因此,我们再自定义一个annotation,prometheus.io/path

  1. annotations:
  2. prometheus.io/scrape: "true"
  3. prometheus.io/path: "/path/to/metrics"

这样,Prometheus端会自动生成如下标签:

  1. __meta_kubernetes_service_annotation_prometheus_io_path="/path/to/metrics"

我们只需要在relabelconfigs中用该标签的值,去重写_metrics_path的值即可。因此:

  1. - job_name: 'kubernetes-sd-endpoints'
  2. kubernetes_sd_configs:
  3. - role: endpoints
  4. relabel_configs:
  5. - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape]
  6. action: keep
  7. regex: true
  8. - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path]
  9. action: replace
  10. target_label: __metrics_path__
  11. regex: (.+)

有些时候,业务服务的metrics是独立的端口,比如coredns,业务端口是53,监控指标采集端口是9153,这种情况,如何处理?
很自然的,我们会想到通过自定义annotation来处理,

  1. annotations:
  2. prometheus.io/scrape: "true"
  3. prometheus.io/path: "/path/to/metrics"
  4. prometheus.io/port: "9153"

如何去替换?
我们知道Prometheus默认使用Before Relabeling中的address进行作为服务指标采集的地址,但是该地址的格式通常是这样的
address=”10.244.0.20:53”
address=”10.244.0.21”
我们的目标是将如下两部分拼接在一起:

  • 10.244.0.20
  • prometheus.io/port定义的值,即__meta_kubernetes_service_annotation_prometheus_io_port的值

因此,需要使用正则规则取出上述两部分:

  1. - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port]
  2. action: replace
  3. target_label: __address__
  4. regex: ([^:]+)(?::\d+)?;(\d+)
  5. replacement: $1:$2

需要注意的几点:

  • address中的:53有可能不存在,因此,使用()?的匹配方式进行
  • 表达式中,三段()我们只需要第一和第三段,不需要中间括号部分的内容,因此使用?:的方式来做非获取匹配,即可以匹配内容,但是不会被记录到$1,$2这种变量中
  • 多个source_labels中间默认使用;号分割,因此匹配的时候需要注意添加;号

此外,还可以将before relabeling 中的更多常用的字段取出来添加到目标的label中,比如:

  1. - source_labels: [__meta_kubernetes_namespace]
  2. action: replace
  3. target_label: kubernetes_namespace
  4. - source_labels: [__meta_kubernetes_service_name]
  5. action: replace
  6. target_label: kubernetes_name
  7. - source_labels: [__meta_kubernetes_pod_name]
  8. action: replace
  9. target_label: kubernetes_pod_name

因此,目前的relabel的配置如下:

  1. - job_name: 'kubernetes-sd-endpoints'
  2. kubernetes_sd_configs:
  3. - role: endpoints
  4. relabel_configs:
  5. - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape]
  6. action: keep
  7. regex: true
  8. - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path]
  9. action: replace
  10. target_label: __metrics_path__
  11. regex: (.+)
  12. - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port]
  13. action: replace
  14. target_label: __address__
  15. regex: ([^:]+)(?::\d+)?;(\d+)
  16. replacement: $1:$2
  17. - source_labels: [__meta_kubernetes_namespace]
  18. action: replace
  19. target_label: kubernetes_namespace
  20. - source_labels: [__meta_kubernetes_service_name]
  21. action: replace
  22. target_label: kubernetes_name
  23. - source_labels: [__meta_kubernetes_pod_name]
  24. action: replace
  25. target_label: kubernetes_pod_name

验证一下:
更新configmap并重启Prometheus服务,查看target列表。

kube-state-metrics监控

已经有了cadvisor,容器运行的指标已经可以获取到,但是下面这种情况却无能为力:
我调度了多少个replicas?现在可用的有几个?
多少个Pod是running/stopped/terminated状态?
Pod重启了多少次?
而这些则是kube-state-metrics提供的内容,它基于client-go开发,轮询Kubernetes API,并将Kubernetes的结构化信息转换为metrics。因此,需要借助于kube-state-metrics来实现
指标类别包括:

  • CronJob Metrics
  • DaemonSet Metrics
  • Deployment Metrics
  • Job Metrics
  • LimitRange Metrics
  • Node Metrics
  • PersistentVolume Metrics
  • PersistentVolumeClaim Metrics
  • Pod Metrics
    • kube_pod_info
    • kube_pod_owner
    • kube_pod_status_phase
    • kube_pod_status_ready
    • kube_pod_status_scheduled
    • kube_pod_container_status_waiting
    • kube_pod_container_status_terminated_reason
  • Pod Disruption Budget Metrics
  • ReplicaSet Metrics
  • ReplicationController Metrics
  • ResourceQuota Metrics
  • Service Metrics
  • StatefulSet Metrics
  • Namespace Metrics
  • Horizontal Pod Autoscaler Metrics
  • Endpoint Metrics
  • Secret Metrics
  • ConfigMap Metrics

部署: https://github.com/kubernetes/kube-state-metrics#kubernetes-deployment

  1. $ wget https://github.com/kubernetes/kube-state-metrics/archive/v1.9.7.tar.gz
  2. $ tar zxf v1.9.7.tar.gz
  3. $ cp -r kube-state-metrics-1.9.7/examples/standard/ .
  4. $ ll standard/
  5. total 20
  6. -rw-r--r-- 1 root root 377 Jul 24 06:12 cluster-role-binding.yaml
  7. -rw-r--r-- 1 root root 1651 Jul 24 06:12 cluster-role.yaml
  8. -rw-r--r-- 1 root root 1069 Jul 24 06:12 deployment.yaml
  9. -rw-r--r-- 1 root root 193 Jul 24 06:12 service-account.yaml
  10. -rw-r--r-- 1 root root 406 Jul 24 06:12 service.yaml
  11. # 替换namespace为monitor
  12. $ sed -i 's/namespace: kube-system/namespace: monitor/g' standard/*
  13. $ kubectl create -f standard/
  14. clusterrolebinding.rbac.authorization.k8s.io/kube-state-metrics created
  15. clusterrole.rbac.authorization.k8s.io/kube-state-metrics created
  16. deployment.apps/kube-state-metrics created
  17. serviceaccount/kube-state-metrics created
  18. service/kube-state-metrics created

如何添加到Prometheus监控target中?

  1. apiVersion: v1
  2. kind: Service
  3. metadata:
  4. annotations:
  5. prometheus.io/scrape: "true"
  6. prometheus.io/port: "8080"
  7. labels:
  8. app.kubernetes.io/name: kube-state-metrics
  9. app.kubernetes.io/version: v1.9.7
  10. name: kube-state-metrics
  11. namespace: monitor
  12. spec:
  13. clusterIP: None
  14. ports:
  15. - name: http-metrics
  16. port: 8080
  17. targetPort: http-metrics
  18. - name: telemetry
  19. port: 8081
  20. targetPort: telemetry
  21. selector:
  22. app.kubernetes.io/name: kube-state-metrics
  1. $ kubectl apply -f standard/service.yaml