Kubernetes监控手册07-监控controller-manager

Kubernetes controller-manager 监控实操:如何验证 /metrics、配置 Prometheus agent 抓取、导入夜莺大盘,并理解 workqueue、leader election、PV/PVC 等关键指标。

作者 秦晓辉&孔飞@快猫星云

写在前面

controller-manager 是 Kubernetes 控制面的核心组件,负责持续监听对象状态,并把实际状态调谐到期望状态。它通常不太可能出问题,一般监控通用进程指标就能覆盖基础可用性;但 controller-manager 也暴露了很多 /metrics 白盒指标,能帮助我们判断各个 controller 的队列深度、任务耗时、重试次数和选主状态。

这篇文章重点回答 4 个问题:

  • controller-manager 的 /metrics 接口为什么直接访问会返回 403。
  • 如何复用前文创建的 Token,通过 Prometheus agent mode 采集 controller-manager 指标。
  • 采集规则为什么要匹配 kube-system;kube-controller-manager;https 这个 endpoint。
  • 哪些 controller-manager 指标适合用来判断调谐延迟、队列堆积和控制器自身运行状态。

黑盒测试

类似上一篇《Kubernetes监控手册06-监控APIServer》描述的方法,我们先从黑盒角度测试一下,看看 controller-manager 的 /metrics 接口是否直接可用。

[root@tt-fc-dev01.nj manifests]# ss -tlnp|grep controller
LISTEN 0      128                *:10257            *:*    users:(("kube-controller",pid=2782446,fd=7))

[root@tt-fc-dev01.nj manifests]# curl -s http://localhost:10257/metrics
Client sent an HTTP request to an HTTPS server.

[root@tt-fc-dev01.nj manifests]# curl -k -s https://localhost:10257/metrics
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {},
  "status": "Failure",
  "message": "forbidden: User \"system:anonymous\" cannot get path \"/metrics\"",
  "reason": "Forbidden",
  "details": {},
  "code": 403
}

看起来也是需要认证的,我们直接复用上一篇创建的 Token,看看能否拿到数据:

[root@tt-fc-dev01.nj yamls]# token=`kubectl get secret categraf-token-6whbs -n flashcat -o jsonpath={.data.token} | base64 -d`
[root@tt-fc-dev01.nj yamls]# curl -s -k -H "Authorization: Bearer $token" https://localhost:10257/metrics > cm.metrics
[root@tt-fc-dev01.nj yamls]# head -n 6 cm.metrics
# HELP apiserver_audit_event_total [ALPHA] Counter of audit events generated and sent to the audit backend.
# TYPE apiserver_audit_event_total counter
apiserver_audit_event_total 0
# HELP apiserver_audit_requests_rejected_total [ALPHA] Counter of apiserver requests rejected due to an error in audit logging backend.
# TYPE apiserver_audit_requests_rejected_total counter
apiserver_audit_requests_rejected_total 0
[root@tt-fc-dev01.nj yamls]# cat cm.metrics | wc -l
10070

妥了,可以复用之前的 Token。这里的关键结论是:controller-manager 暴露的是 HTTPS metrics 接口,而且默认拒绝匿名访问,所以采集器要带上 ServiceAccount token,并且要允许跳过本地证书校验。

配置采集

我们还是使用 Prometheus agent mode 来拉取数据,原汁原味的,只要把 controller-manager 部分也加上就行了。改造之后的 prometheus-agent-configmap.yaml 内容如下:

apiVersion: v1
kind: ConfigMap
metadata:
  name: prometheus-agent-conf
  labels:
    name: prometheus-agent-conf
  namespace: flashcat
data:
  prometheus.yml: |-
    global:
      scrape_interval: 15s
      evaluation_interval: 15s

    scrape_configs:
      - job_name: 'apiserver'
        kubernetes_sd_configs:
        - role: endpoints
        scheme: https
        tls_config:
          insecure_skip_verify: true
        authorization:
          credentials_file: /var/run/secrets/kubernetes.io/serviceaccount/token
        relabel_configs:
        - source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
          action: keep
          regex: default;kubernetes;https

      - job_name: 'controller-manager'
        kubernetes_sd_configs:
        - role: endpoints
        scheme: https
        tls_config:
          insecure_skip_verify: true
        authorization:
          credentials_file: /var/run/secrets/kubernetes.io/serviceaccount/token
        relabel_configs:
        - source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
          action: keep
          regex: kube-system;kube-controller-manager;https

    remote_write:
    - url: 'http://10.206.0.16:19000/prometheus/v1/write'    

这里我新增了一个 scrape job name:controller-manager,Kubernetes 服务发现仍然使用 endpoints,匹配规则有三点(通过 relabel_configskeep 实现):

  • __meta_kubernetes_namespace endpoint 的 namespace 要求是 kube-system
  • __meta_kubernetes_service_name service name 要求是 kube-controller-manager
  • __meta_kubernetes_endpoint_port_name endpoint 的 port_name 要求是叫 https

这三项分别对应“在哪个命名空间找”“找哪个 Service”“抓哪个端口”。只要其中任何一项和集群实际 endpoint 不一致,Prometheus agent 都不会产生抓取目标。

如果你没有采集成功,就要去看看有没有这个 endpoint:

[work@tt-fc-dev01.nj yamls]$ kubectl get endpoints -n kube-system
NAME                      ENDPOINTS                                                            AGE
etcd                      10.206.0.16:2381                                                     126d
etcd-service              10.206.0.16:2379                                                     75d
etcd-service2             10.206.10.16:2379                                                    75d
kube-controller-manager   10.206.0.16:10257                                                    74d
kube-dns                  172.16.0.85:53,172.16.1.4:53,172.16.0.85:53 + 3 more...              324d
kube-scheduler            10.206.0.16:10259                                                    131d
kube-state-metrics        172.16.3.198:8081,172.16.3.198:8080                                  75d
kubelet                   10.206.0.11:10250,10.206.0.16:10250,10.206.0.17:10250 + 15 more...   315d

[work@tt-fc-dev01.nj yamls]$ kubectl get endpoints -n kube-system kube-controller-manager -o yaml
apiVersion: v1
kind: Endpoints
metadata:
  annotations:
    endpoints.kubernetes.io/last-change-trigger-time: "2022-09-15T09:43:21Z"
  creationTimestamp: "2022-09-15T09:43:21Z"
  labels:
    k8s-app: kube-controller-manager
  name: kube-controller-manager
  namespace: kube-system
  resourceVersion: "112212043"
  uid: 52cfb383-6d2b-452e-9a1f-95c7a898a1b4
subsets:
- addresses:
  - ip: 10.206.0.16
    nodeName: 10.206.0.16
    targetRef:
      kind: Pod
      name: kube-controller-manager-10.206.0.16
      namespace: kube-system
      resourceVersion: "112211925"
      uid: d9515495-057c-4ea6-ad1f-28341498710f
  ports:
  - name: https
    port: 10257
    protocol: TCP

__meta_kubernetes_endpoint_port_name 就是上面的倒数第三行。这些信息我的环境里都是有的,如果你的环境没有对应的 endpoint,可以手工创建一个 service,孔飞老师之前给大家准备过一个 https://github.com/flashcatcloud/categraf/blob/main/k8s/controller-service.yaml,把这个 controller-service.yaml apply 一下就行了。另外,如果是用 kubeadm 安装的 controller-manager,还要记得修改 /etc/kubernetes/manifests/kube-controller-manager.yaml,调整 controller-manager 的启动参数:--bind-address=0.0.0.0

如果采集失败,可以按下面的顺序定位:

检查项 正常现象 常见问题
端口监听 10257 端口存在监听 controller-manager 未监听或只监听本地地址
认证访问 带 Bearer Token 请求 /metrics 能返回指标 ServiceAccount 权限不足或 token 未挂载
Endpoint kube-controller-manager endpoint 中有 https 端口 集群没有创建对应 Service/Endpoint
relabel 规则 regex 与 namespace、service、port name 完全匹配 端口名不是 https,导致目标被过滤
启动参数 kubeadm 场景下可按需调整 --bind-address=0.0.0.0 仅本机可访问,远端采集器连不上

监控大盘

controller-manager 的大盘已经准备好了,地址在 https://github.com/flashcatcloud/categraf/blob/main/k8s/cm-dash.json,可以直接导入夜莺使用。如果觉得大盘有需要改进的地方,欢迎PR。

监控指标

controller-manager 的关键指标分别是啥意思,孔飞老师之前整理过,我给搬过来了:

# HELP rest_client_request_duration_seconds [ALPHA] Request latency in seconds. Broken down by verb and URL.
# TYPE rest_client_request_duration_seconds histogram
请求apiserver的耗时分布按照url+verb统计

# HELP cronjob_controller_cronjob_job_creation_skew_duration_seconds [ALPHA] Time between when a cronjob is scheduled to be run, and when the corresponding job is created
# TYPE cronjob_controller_cronjob_job_creation_skew_duration_seconds histogram
cronjob 创建到运行的时间分布

# HELP leader_election_master_status [ALPHA] Gauge of if the reporting system is master of the relevant lease, 0 indicates backup, 1 indicates master. 'name' is the string used to identify the lease. Please make sure to group by name.
# TYPE leader_election_master_status gauge
控制器的选举状态0表示backup 1表示master

# HELP node_collector_zone_health [ALPHA] Gauge measuring percentage of healthy nodes per zone.
# TYPE node_collector_zone_health gauge
每个zone的健康node占比

# HELP node_collector_zone_size [ALPHA] Gauge measuring number of registered Nodes per zones.
# TYPE node_collector_zone_size gauge
每个zone的node数

# HELP process_cpu_seconds_total Total user and system CPU time spent in seconds.
# TYPE process_cpu_seconds_total counter
cpu使用量也可以理解为cpu使用率

# HELP process_open_fds Number of open file descriptors.
# TYPE process_open_fds gauge
控制器打开的fd数

# HELP pv_collector_bound_pv_count [ALPHA] Gauge measuring number of persistent volume currently bound
# TYPE pv_collector_bound_pv_count gauge
当前绑定的pv数量

# HELP pv_collector_unbound_pvc_count [ALPHA] Gauge measuring number of persistent volume claim currently unbound
# TYPE pv_collector_unbound_pvc_count gauge
当前没有绑定的pvc数量


# HELP pv_collector_bound_pvc_count [ALPHA] Gauge measuring number of persistent volume claim currently bound
# TYPE pv_collector_bound_pvc_count gauge
当前绑定的pvc数量

# HELP pv_collector_total_pv_count [ALPHA] Gauge measuring total number of persistent volumes
# TYPE pv_collector_total_pv_count gauge
pv总数量


# HELP workqueue_adds_total [ALPHA] Total number of adds handled by workqueue
# TYPE workqueue_adds_total counter
各个controller已接受的任务总数
与apiserver的workqueue_adds_total指标类似

# HELP workqueue_depth [ALPHA] Current depth of workqueue
# TYPE workqueue_depth gauge
各个controller队列深度表示一个controller中的任务的数量
与apiserver的workqueue_depth类似这个是指各个controller中队列的深度数值越小越好

# HELP workqueue_queue_duration_seconds [ALPHA] How long in seconds an item stays in workqueue before being requested.
# TYPE workqueue_queue_duration_seconds histogram
任务在队列中的等待耗时,按照控制器分别统计

# HELP workqueue_work_duration_seconds [ALPHA] How long in seconds processing an item from workqueue takes.
# TYPE workqueue_work_duration_seconds histogram
任务出队到被处理完成的时间按照控制分别统计

# HELP workqueue_retries_total [ALPHA] Total number of retries handled by workqueue
# TYPE workqueue_retries_total counter
任务进入队列重试的次数

# HELP workqueue_longest_running_processor_seconds [ALPHA] How many seconds has the longest running processor for workqueue been running.
# TYPE workqueue_longest_running_processor_seconds gauge
正在处理的任务中最长耗时任务的处理时间

# HELP endpoint_slice_controller_syncs [ALPHA] Number of EndpointSlice syncs
# TYPE endpoint_slice_controller_syncs counter
endpoint_slice 同步的数量(1.20以上)

# HELP get_token_fail_count [ALPHA] Counter of failed Token() requests to the alternate token source
# TYPE get_token_fail_count counter
获取token失败的次数

# HELP go_memstats_gc_cpu_fraction The fraction of this program's available CPU time used by the GC since the program started.
# TYPE go_memstats_gc_cpu_fraction gauge
controller gc的cpu使用率

从排障角度看,可以把这些指标分成 4 类:

指标类型 代表指标 主要用于判断
调用 APIServer rest_client_request_duration_seconds controller-manager 访问 APIServer 是否变慢
控制器队列 workqueue_depthworkqueue_queue_duration_secondsworkqueue_retries_total 是否出现任务堆积、等待时间变长或频繁重试
资源对象状态 pv_collector_*node_collector_* PV/PVC、Node zone 等对象统计是否异常
进程与选主 leader_election_master_statusprocess_cpu_seconds_totalprocess_open_fds 当前实例是否为 leader,以及进程资源是否异常

常见问题

Q1:controller-manager 只监控进程指标够不够? A:基础可用性可以先看进程、CPU、FD 和存活状态;如果要判断控制器调谐是否变慢,就需要补充 workqueue_*rest_client_* 这类白盒指标。

Q2:为什么能复用 APIServer 那篇文章里的 Token? A:本文示例中的 ServiceAccount 已经具备访问控制面组件 metrics 路径的权限,所以 controller-manager 也可以使用同一个 Bearer Token。不同集群的 RBAC 配置可能不同,采集失败时优先检查权限。

Q3:workqueue_depth 越大一定代表故障吗? A:不一定。它表示队列里待处理任务数量,短时升高可能只是对象变更集中发生;如果队列深度、等待耗时和重试次数同时持续升高,就更值得排查 controller 处理能力或 APIServer 访问延迟。

相关文章

关于作者

本文作者秦晓辉,Flashcat合伙人,文章内容是Flashcat技术团队共同沉淀的结晶,作者做了编辑整理,我们会持续输出监控、稳定性保障相关的技术文章,文章可转载,转载请注明出处,尊重技术人员的成果。

联系我们交流

延伸路径

继续看解决方案和产品对比

如果你正在做监控、可观测性或故障定位相关选型,建议从解决方案和产品对比继续往下看。

快猫星云 联系方式 快猫星云 联系方式
快猫星云 联系方式
快猫星云 联系方式
快猫星云 联系方式
快猫星云