Kubernetes监控手册08-监控scheduler

Kubernetes scheduler 监控实操:验证 /metrics 认证、用 Prometheus agent 抓取 kube-scheduler,并理解调度队列、调度耗时、抢占和 leader election 等关键指标。

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

写在前面

scheduler 是 Kubernetes 的控制面组件,负责把 Pod 调度到合适的 Node 上。调度过程会经过队列、过滤、打分、绑定等环节,因此 scheduler 监控不能只看进程是否存活,还要关注待调度 Pod 数量、调度尝试次数、调度耗时、抢占次数和插件执行耗时。

本文围绕 scheduler 监控的 4 个关键点展开:

  • 如何确认 kube-scheduler 的 /metrics 接口需要 HTTPS 和 Token 认证。
  • 如何复用前文 ServiceAccount,通过 Prometheus agent mode 抓取 scheduler 指标。
  • 为什么 scrape 规则要匹配 kube-system;kube-scheduler;https
  • 哪些指标能反映调度堆积、不可调度、内部错误和调度延迟。

黑盒测试

[root@tt-fc-dev01.nj ~]# ss -tlnp|grep kube-sche
LISTEN 0      128                *:10259            *:*    users:(("kube-scheduler",pid=2782518,fd=7))

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

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

ss -tlnp|grep kube-sche 可以看出来,kube-scheduler 监听在 10259 端口,直接请求,提示这是一个 https server,那我们就请求 https 地址,返回 403,说明也是需要 token 认证的。

我们复用《Kubernetes监控手册06-监控APIServer》一文中创建的 Token,看看能否通过认证:

[root@tt-fc-dev01.nj qinxiaohui]# token=`kubectl get secret categraf-token-6whbs -n flashcat -o jsonpath={.data.token} | base64 -d`

[root@tt-fc-dev01.nj qinxiaohui]# curl -s -k -H "Authorization: Bearer $token" https://localhost:10259/metrics > scheduler.metrics

[root@tt-fc-dev01.nj qinxiaohui]# head -n 6 scheduler.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

通过了认证,说明之前创建的 ServiceAccount 可以直接用,权限是够的。这个验证动作很重要:如果手工 curl 都拿不到指标,后续 Prometheus agent 的采集配置即使写对,也不会有有效数据。

采集配置

接下来就是采集数据了,我们还是使用 prometheus agent mode 来拉取数据,原汁原味的,只要在上一篇文章提供的 configmap 中增加 scheduler 相关的配置即可,改造之后的 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

      - job_name: 'scheduler'
        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-scheduler;https
    remote_write:
    - url: 'http://10.206.0.16:19000/prometheus/v1/write'    

scrape 配置中增加了 scheduler 这个 job,Kubernetes 服务发现仍然使用 endpoints,匹配规则有三点(通过 relabel_configskeep 实现):

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

这类规则的本质是从 Kubernetes 自动发现出来的一批 endpoint 中,只保留 kube-scheduler 的 HTTPS metrics 端口。排查采集问题时,不要只看 Service 名称,也要确认 endpoint 的 port name 是否真叫 https

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

[root@tt-fc-dev01.nj qinxiaohui]# kubectl get endpoints -n kube-system | grep sche
kube-scheduler            10.206.0.16:10259                                                    134d

[root@tt-fc-dev01.nj qinxiaohui]# kubectl get endpoints -n kube-system kube-scheduler -o yaml
apiVersion: v1
kind: Endpoints
metadata:
  annotations:
    control-plane.alpha.kubernetes.io/leader: '{"holderIdentity":"tt-fc-dev01.nj_859c205c-0bf9-4f3e-a41e-6da8dcb90308","leaseDurationSeconds":15,"acquireTime":"2022-10-27T06:53:19Z","renewTime":"2022-12-02T06:24:16Z","leaderTransitions":9}'
    endpoints.kubernetes.io/last-change-trigger-time: "2022-07-20T10:25:10Z"
  creationTimestamp: "2022-07-20T10:24:54Z"
  labels:
    k8s-app: kube-scheduler
    service.kubernetes.io/headless: ""
  name: kube-scheduler
  namespace: kube-system
  resourceVersion: "129050770"
  uid: a963d2bd-6ef3-4e93-b4dc-4b95d2aea890
subsets:
- addresses:
  - ip: 10.206.0.16
    nodeName: 10.206.0.16
    targetRef:
      kind: Pod
      name: kube-scheduler-10.206.0.16
      namespace: kube-system
      resourceVersion: "112211935"
      uid: 6a6c699e-008d-41b6-9480-7eed7f18ae2d
  ports:
  - name: https
    port: 10259
    protocol: TCP

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

采集失败时,可以按这个顺序检查:

检查项 正常现象 失败时优先看什么
本地端口 kube-scheduler 监听 10259 组件是否启动、端口是否变更
认证访问 带 Token 请求 /metrics 能返回指标 RBAC、ServiceAccount、token 挂载
Endpoint kube-scheduler endpoint 有 https 端口 Service/Endpoint 是否存在,端口名是否匹配
抓取协议 scrape 使用 scheme: https 误用 http 会返回 HTTPS server 提示
kubeadm 参数 必要时调整 --bind-address=0.0.0.0 远端采集器无法访问本地监听

监控大盘

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

监控指标

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

# 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的延迟分布

# HELP rest_client_requests_total [ALPHA] Number of HTTP requests, partitioned by status code, method, and host.
# TYPE rest_client_requests_total counter
请求apiserver的总数 ,按照host code method 统计

# 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 scheduler_queue_incoming_pods_total [STABLE] Number of pods added to scheduling queues by event and queue type.
# TYPE scheduler_queue_incoming_pods_total counter
进入调度队列的pod数

# HELP scheduler_preemption_attempts_total [STABLE] Total preemption attempts in the cluster till now
# TYPE scheduler_preemption_attempts_total counter
调度器驱逐容器的次数

# HELP scheduler_scheduler_cache_size [ALPHA] Number of nodes, pods, and assumed (bound) pods in the scheduler cache.
# TYPE scheduler_scheduler_cache_size gauge
调度器cache中node pod和绑定pod的数目

# HELP scheduler_pending_pods [STABLE] Number of pending pods, by the queue type. 'active' means number of pods in activeQ; 'backoff' means number of pods in backoffQ; 'unschedulable' means number of pods in unschedulableQ.
# TYPE scheduler_pending_pods gauge
调度pending的pod数量按照queue type分别统计

# HELP scheduler_plugin_execution_duration_seconds [ALPHA] Duration for running a plugin at a specific extension point.
# TYPE scheduler_plugin_execution_duration_seconds histogram
调度插件在每个扩展点的执行时间按照extension_point+plugin+status 分别统计

# HELP scheduler_e2e_scheduling_duration_seconds [ALPHA] (Deprecated since 1.23.0) E2e scheduling latency in seconds (scheduling algorithm + binding). This metric is replaced by scheduling_attempt_duration_seconds.
# TYPE scheduler_e2e_scheduling_duration_seconds histogram
调度延迟分布1.23.0 以后会被scheduling_attempt_duration_seconds替代

# HELP scheduler_framework_extension_point_duration_seconds [STABLE] Latency for running all plugins of a specific extension point.
# TYPE scheduler_framework_extension_point_duration_seconds histogram
调度框架的扩展点延迟分布,按extension_point(扩展点Bind Filter Permit PreBind/PostBind PreFilter/PostFilter Reseve)
+profile调度器+ status(调度成功) 统计

# HELP scheduler_pod_scheduling_attempts [STABLE] Number of attempts to successfully schedule a pod.
# TYPE scheduler_pod_scheduling_attempts histogram
pod调度成功前调度重试的次数分布

# HELP scheduler_schedule_attempts_total [STABLE] Number of attempts to schedule pods, by the result. 'unschedulable' means a pod could not be scheduled, while 'error' means an internal scheduler problem.
# TYPE scheduler_schedule_attempts_total counter
按照调度结果统计的调度重试次数 "unschedulable" 表示无法调度"error"表示调度器内部错误

# HELP scheduler_scheduler_goroutines [ALPHA] Number of running goroutines split by the work they do such as binding.
# TYPE scheduler_scheduler_goroutines gauge
按照功能(binding filter之类)统计的goroutine数量

# HELP scheduler_scheduling_algorithm_duration_seconds [ALPHA] Scheduling algorithm latency in seconds
# TYPE scheduler_scheduling_algorithm_duration_seconds histogram
调度算法的耗时分布

# HELP scheduler_scheduling_attempt_duration_seconds [STABLE] Scheduling attempt latency in seconds (scheduling algorithm + binding)
# TYPE scheduler_scheduling_attempt_duration_seconds histogram
调度算法+binding的耗时分布

# HELP scheduler_scheduler_goroutines [ALPHA] Number of running goroutines split by the work they do such as binding.
# TYPE scheduler_scheduler_goroutines gauge
调度器的goroutines数目

这些指标可以按排障目标归类:

排障目标 优先观察的指标 判断方向
是否有调度积压 scheduler_pending_podsscheduler_queue_incoming_pods_total pending 数量是否持续增加,队列流入是否异常
调度为什么慢 scheduler_scheduling_attempt_duration_secondsscheduler_plugin_execution_duration_seconds 调度整体耗时和插件执行耗时是否升高
是否不可调度 scheduler_schedule_attempts_total unschedulableerror 结果是否异常增加
是否发生抢占 scheduler_preemption_attempts_total 抢占次数是否与资源紧张、优先级配置相关
scheduler 自身状态 leader_election_master_statusscheduler_scheduler_goroutines leader 是否稳定,goroutine 数是否异常

常见问题

Q1:scheduler 监控最应该先看哪个指标? A:如果目标是发现调度问题,先看 scheduler_pending_podsscheduler_schedule_attempts_total;如果目标是定位调度慢,再看调度耗时和插件耗时相关的 histogram。

Q2:unschedulable 一定是 scheduler 故障吗? A:不一定。unschedulable 表示 Pod 当前无法调度,常见原因包括资源不足、亲和/反亲和规则、污点容忍、节点选择器等。它更像是调度结果信号,不等同于 scheduler 进程故障。

Q3:为什么这里仍然用 endpoints 做服务发现? A:控制面组件的 metrics 端口通常已经通过 kube-system 下的 endpoint 暴露出来,用 endpoints 发现可以和前文 APIServer、controller-manager 的采集方式保持一致。

相关文章

关于作者

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

联系我们交流

延伸路径

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

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

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