使用 Prometheus 和 Grafana#

本节将介绍如何在 Kubernetes 中使用 Prometheus 和 Grafana 监控 Ray 集群。

如果您没有在 Kubernetes 上使用 Prometheus 和 Grafana 的经验,请观看此 YouTube 播放列表

准备工作#

克隆 KubeRay 仓库 并切换到 master 分支。本教程需要仓库中的一些文件。

步骤 1:使用 Kind 创建 Kubernetes 集群#

kind create cluster

步骤 2:通过 Helm chart 安装 Kubernetes Prometheus Stack#

# Path: kuberay/
./install/prometheus/install.sh --auto-load-dashboard true

# Check the installation
kubectl get all -n prometheus-system

# (part of the output)
# NAME                                                  READY   UP-TO-DATE   AVAILABLE   AGE
# deployment.apps/prometheus-grafana                    1/1     1            1           46s
# deployment.apps/prometheus-kube-prometheus-operator   1/1     1            1           46s
# deployment.apps/prometheus-kube-state-metrics         1/1     1            1           46s
  • KubeRay 提供了一个 install.sh 脚本,用于

  • 我们对 kube-prometheus-stack chart 中原始的 values.yaml 进行了一些修改,以允许将 Grafana 面板嵌入 Ray Dashboard。有关更多详细信息,请参阅 overrides.yaml

    grafana:
      grafana.ini:
        security:
          allow_embedding: true
        auth.anonymous:
          enabled: true
          org_role: Viewer
    

步骤 3:安装 KubeRay operator#

  • 按照 本指南 通过 Helm 仓库安装最新的稳定版 KubeRay Operator。

  • 在使用 Helm 安装 KubeRay operator 时,设置 metrics.serviceMonitor.enabled=true 以创建 ServiceMonitor,该 ServiceMonitor 用于抓取 KubeRay operator 服务的指标。

    # Enable the ServiceMonitor and set the label `release: prometheus` to the ServiceMonitor so that Prometheus can discover it
    helm install kuberay-operator kuberay/kuberay-operator --version 1.5.1 \
      --set metrics.serviceMonitor.enabled=true \ 
      --set metrics.serviceMonitor.selector.release=prometheus 
    

    您可以通过以下方式验证 ServiceMonitor 的创建:

    kubectl get servicemonitor
    # NAME               AGE
    # kuberay-operator   11s
    

步骤 4:安装 RayCluster#

# path: ray-operator/config/samples/
kubectl apply -f ray-cluster.embed-grafana.yaml

# Check there's a Service that specifies port 8080 for the metrics endpoint.
# There may be a slight delay between RayCluster and Service creation.
kubectl get service -l ray.io/cluster=raycluster-embed-grafana

# NAME                                TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                                                    AGE
# raycluster-embed-grafana-head-svc   ClusterIP   None            <none>        44217/TCP,10001/TCP,44227/TCP,8265/TCP,6379/TCP,8080/TCP   13m

# Wait until all Ray Pods are ready.
kubectl wait pods -l ray.io/cluster=raycluster-embed-grafana --timeout 2m --for condition=Ready

# pod/raycluster-embed-grafana-head-2jk7c condition met
# pod/raycluster-embed-grafana-small-group-worker-8g2vv condition met

# Forward the port of the Prometheus metrics endpoint.
kubectl port-forward service/raycluster-embed-grafana-head-svc metrics

# Check metrics in a new terminal.
curl localhost:8080

# Example output (Prometheus metrics format):
# # HELP ray_spill_manager_request_total Number of {spill, restore} requests.
# # TYPE ray_spill_manager_request_total gauge
# ray_spill_manager_request_total{Component="raylet", NodeAddress="10.244.0.13", SessionName="session_2025-01-02_07-58-21_419367_11", Type="FailedDeletion", Version="2.9.0", container="ray-head", endpoint="metrics", instance="10.244.0.13:8080", job="prometheus-system/ray-head-monitor", namespace="default", pod="raycluster-embed-grafana-head-98fqt", ray_io_cluster="raycluster-embed-grafana"} 0
  • KubeRay 默认通过内置的 exporter 在端口 **8080** 上公开 Prometheus metrics endpoint。因此,我们不需要安装任何外部 exporter。

  • 如果您想将 metrics endpoint 配置到不同的端口,请参阅 kuberay/#954 获取更多详细信息。

  • Prometheus metrics format

    • # HELP: 描述此指标的含义。

    • # TYPE: 有关更多详细信息,请参阅 本文档

  • ray-cluster.embed-grafana.yaml 中定义了三个必需的环境变量。有关这些环境变量的更多信息,请参阅 配置和管理 Ray Dashboard

    env:
      - name: RAY_GRAFANA_IFRAME_HOST
        value: http://127.0.0.1:3000
      - name: RAY_GRAFANA_HOST
        value: http://prometheus-grafana.prometheus-system.svc:80
      - name: RAY_PROMETHEUS_HOST
        value: http://prometheus-kube-prometheus-prometheus.prometheus-system.svc:9090
    
    • 请注意,我们不在 head Pod 中部署 Grafana,因此我们需要同时设置 RAY_GRAFANA_IFRAME_HOSTRAY_GRAFANA_HOSTRAY_GRAFANA_HOST 由 head Pod 用于向后端 Grafana 发送健康检查请求。 RAY_GRAFANA_IFRAME_HOST 由您的浏览器用于从 Grafana 服务器而不是 head Pod 获取 Grafana 面板。由于在此示例中我们将 Grafana 的端口转发到 127.0.0.1:3000,因此我们将 RAY_GRAFANA_IFRAME_HOST 设置为 http://127.0.0.1:3000

    • http:// 是必需的。

步骤 5:使用 PodMonitor 收集 Head Node 指标#

RayService 为 head Pod 创建了两个 Kubernetes 服务;一个由 RayService 管理,另一个由底层的 RayCluster 管理。因此,建议使用 PodMonitor 来监控 head Pod 的指标,以避免在使用 ServiceMonitor 时因配置错误导致重复计算相同指标。

apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
  labels:
    # `release: $HELM_RELEASE`: Prometheus can only detect PodMonitor with this label.
    release: prometheus
  name: ray-head-monitor
  namespace: prometheus-system
spec:
  jobLabel: ray-head
  # Only select Kubernetes Pods in the "default" namespace.
  namespaceSelector:
    matchNames:
      - default
  # Only select Kubernetes Pods with "matchLabels".
  selector:
    matchLabels:
      ray.io/node-type: head
  # A list of endpoints allowed as part of this PodMonitor.
  podMetricsEndpoints:
    - port: metrics
      relabelings:
        - action: replace
          sourceLabels:
            - __meta_kubernetes_pod_label_ray_io_cluster
          targetLabel: ray_io_cluster
    - port: as-metrics # autoscaler metrics
      relabelings:
        - action: replace
          sourceLabels:
            - __meta_kubernetes_pod_label_ray_io_cluster
          targetLabel: ray_io_cluster
    - port: dash-metrics # dashboard metrics
      relabelings:
        - action: replace
          sourceLabels:
            - __meta_kubernetes_pod_label_ray_io_cluster
          targetLabel: ray_io_cluster
  • install.sh 脚本会创建上述 YAML 示例 podMonitor.yaml,因此您无需创建任何内容。

  • 有关配置的更多详细信息,请参阅官方 PodMonitor 文档

  • release: $HELM_RELEASE: Prometheus 只能检测带有此标签的 PodMonitor。有关更多详细信息,请参阅 此处

helm ls -n prometheus-system
# ($HELM_RELEASE is "prometheus".)
# NAME            NAMESPACE               REVISION        UPDATED                                 STATUS          CHART                           APP VERSION
# prometheus      prometheus-system       1               2023-02-06 06:27:05.530950815 +0000 UTC deployed        kube-prometheus-stack-44.3.1    v0.62.0

kubectl get prometheuses.monitoring.coreos.com -n prometheus-system -oyaml
# podMonitorSelector:
#   matchLabels:
#     release: prometheus
# ruleSelector:
#   matchLabels:
#     release: prometheus
  • Prometheus 使用 namespaceSelectorselector 来选择 Kubernetes Pod。

    kubectl get pod -n default -l ray.io/node-type=head
    # NAME                                  READY   STATUS    RESTARTS   AGE
    # raycluster-embed-grafana-head-khfs4   1/1     Running   0          4m38s
    
  • relabelings: 此配置将抓取指标中的 __meta_kubernetes_pod_label_ray_io_cluster 标签重命名为 ray_io_cluster。它确保每个指标都包含 Pod 所属的 RayCluster 的名称。此配置在部署多个 RayCluster 时区分指标特别有用。例如,带有 ray_io_cluster 标签的指标可能如下所示:

    ray_node_cpu_count{SessionName="session_2025-01-02_07-58-21_419367_11", container="ray-head", endpoint="metrics", instance="10.244.0.13:8080", ip="10.244.0.13", job="raycluster-embed-grafana-head-svc", namespace="default", pod="raycluster-embed-grafana-head-98fqt", ray_io_cluster="raycluster-embed-grafana", service="raycluster-embed-grafana-head-svc"}
    

    在此示例中,raycluster-embed-grafana 是 RayCluster 的名称。

步骤 6:使用 PodMonitors 收集 Worker Node 指标#

与 head Pod 类似,本教程也使用 PodMonitor 来收集 worker Pod 的指标。为 head Pod 和 worker Pod 使用不同的 PodMonitor 的原因在于,head Pod 暴露多个指标端点,而 worker Pod 只暴露一个。

注意:您可以创建一个 Kubernetes 服务,其选择器是我们的 worker Pod 的通用标签子集,但是,此配置并不理想,因为 worker 之间是独立的,也就是说,它们不是由 replicaset controller 生成的副本集合。由于这种行为,应避免使用 Kubernetes 服务将它们分组在一起。

apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
  name: ray-workers-monitor
  namespace: prometheus-system
  labels:
    # `release: $HELM_RELEASE`: Prometheus can only detect PodMonitor with this label.
    release: prometheus
spec:
  jobLabel: ray-workers
  # Only select Kubernetes Pods in the "default" namespace.
  namespaceSelector:
    matchNames:
      - default
  # Only select Kubernetes Pods with "matchLabels".
  selector:
    matchLabels:
      ray.io/node-type: worker
  # A list of endpoints allowed as part of this PodMonitor.
  podMetricsEndpoints:
  - port: metrics
    relabelings:
    - sourceLabels: [__meta_kubernetes_pod_label_ray_io_cluster]
      targetLabel: ray_io_cluster
  • PodMonitor 中的 namespaceSelectorselector 用于选择 Kubernetes Pod。

    kubectl get pod -n default -l ray.io/node-type=worker
    # NAME                                          READY   STATUS    RESTARTS   AGE
    # raycluster-kuberay-worker-workergroup-5stpm   1/1     Running   0          3h16m
    

步骤 7:使用 ServiceMonitor 抓取 KubeRay 指标#

  • 有关配置的更多详细信息,请参阅官方 ServiceMonitor 文档

  • KubeRay operator 为 RayCluster、RayService 和 RayJob 提供指标。有关更多详细信息,请参阅 KubeRay metrics references

  • Prometheus 使用 namespaceSelectorselector 来选择 Kubernetes 服务。

kubectl get service -n default -l app.kubernetes.io/name=kuberay-operator 
NAME               TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
kuberay-operator   ClusterIP   10.96.205.229   <none>        8080/TCP   53m

步骤 8:使用 recording rules 收集自定义指标#

Recording Rules 允许 KubeRay 预先计算常用或计算量大的 PromQL 表达式,并将其结果保存为自定义指标。请注意,此行为与 Custom application-level metrics 不同,后者用于 Ray 应用程序的可视化。

apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: ray-cluster-gcs-rules
  namespace: prometheus-system
  labels:
    # `release: $HELM_RELEASE`: Prometheus can only detect Recording Rules with this label.
    release: prometheus
spec:
  groups:
- #  Rules within a group are run periodically with the same evaluation interval(30s in this example).
    name: ray-cluster-main-staging-gcs.rules
    # How often rules in the group are evaluated.
    interval: 30s
    rules:
    - # The name of the custom metric.
      # Also see best practices for naming metrics created by recording rules:
      # https://prometheus.ac.cn/docs/practices/rules/#recording-rules
      record: ray_gcs_availability_30d
      # PromQL expression.
      expr: |
      (
        100 * (
          sum(rate(ray_gcs_update_resource_usage_time_bucket{container="ray-head", le="20.0"}[30d]))
          /
          sum(rate(ray_gcs_update_resource_usage_time_count{container="ray-head"}[30d]))
        )
      )
  • 上面的 PromQL 表达式是:$\(\frac{过去 30 天内 RTT 小于 20 毫秒的更新资源使用 RPC 数量}{过去 30 天内更新资源使用 RPC 的总数} \times 100 \)$

  • 上面的 recording rule 是 prometheusRules.yaml 中定义的规则之一,并且是由 **install.sh** 创建的。因此,无需在此创建任何内容。

  • 有关配置的更多详细信息,请参阅官方 PrometheusRule 文档

  • release: $HELM_RELEASE: Prometheus 只能检测带有此标签的 PrometheusRule。有关更多详细信息,请参阅 此处

  • PrometheusRule 可以在运行时重新加载。如果需要,请使用 kubectl apply {modified prometheusRules.yaml} 来重新配置规则。

步骤 9:使用 alerting rules 定义警报条件 (可选)#

Alerting rules 允许我们基于 PromQL 表达式定义警报条件,并将触发的警报发送到 Alertmanager,Alertmanager 在简单的警报定义之上增加了摘要、通知速率限制、静默和警报依赖项。

apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: ray-cluster-gcs-rules
  namespace: prometheus-system
  labels:
    # `release: $HELM_RELEASE`: Prometheus can only detect Alerting Rules with this label.
    release: prometheus
spec:
  groups:
  - name: ray-cluster-main-staging-gcs.rules
    # How often rules in the group are evaluated.
    interval: 30s
    rules:
    - alert: MissingMetricRayGlobalControlStore
      # A set of informational labels. Annotations can be used to store longer additional information compared to rules.0.labels.
      annotations:
        description: Ray GCS is not emitting any metrics for Resource Update requests
        summary: Ray GCS is not emitting metrics anymore
      # PromQL expression.
      expr: |
                      (
                       absent(ray_gcs_update_resource_usage_time_bucket) == 1
                      )
      # Time that Prometheus will wait and check if the alert continues to be active during each evaluation before firing the alert.
      # firing alerts may be due to false positives or noise if the setting value is too small.
      # On the other hand, if the value is too big, the alerts may not be handled in time.
      for: 5m
      # A set of additional labels to be attached to the alert.
      # It is possible to overwrite the labels in metadata.labels, so make sure one of the labels match the label in ruleSelector.matchLabels.
      labels:
        severity: critical
  • 上面的 PromQL 表达式检查是否存在 ray_gcs_update_resource_usage_time_bucket 指标的时间序列。有关更多详细信息,请参阅 absent()

  • 上面的 alerting rule 是 prometheusRules.yaml 中定义的规则之一,并且是由 **install.sh** 创建的。因此,无需在此创建任何内容。

  • Alerting rules 的配置方式与 recording rules 相同。

步骤 10:访问 Prometheus Web UI#

# Forward the port of Prometheus Web UI in the Prometheus server Pod.
kubectl port-forward -n prometheus-system service/prometheus-kube-prometheus-prometheus http-web
  • 访问 ${YOUR_IP}:9090/targets(例如 127.0.0.1:9090/targets)。您应该能看到

    • podMonitor/prometheus-system/ray-workers-monitor/0 (1/1 up)

    • serviceMonitor/prometheus-system/ray-head-monitor/0 (1/1 up)

Prometheus Web UI

  • 访问 ${YOUR_IP}:9090/graph。您应该能够查询

  • 访问 ${YOUR_IP}:9090/alerts。您应该能看到

    • Alerting Rules(例如 MissingMetricRayGlobalControlStore)。

步骤 11:访问 Grafana#

# Forward the Grafana port
kubectl port-forward -n prometheus-system service/prometheus-grafana 3000:http-web
# Note: You need to update `RAY_GRAFANA_IFRAME_HOST` if you expose Grafana to a different port.

# Check ${YOUR_IP}:3000/login for the Grafana login page (e.g. 127.0.0.1:3000/login).
# The default username is "admin" and the password is "prom-operator".

注意: kubectl port-forward 不推荐用于生产环境。有关将 Grafana 暴露在反向代理后的信息,请参阅 此 Grafana 文档

  • 默认密码由 kube-prometheus-stack chart 的 values.yaml 中的 grafana.adminPassword 定义。

步骤 12:手动导入 Grafana dashboards (可选)#

如果在运行 install.sh 时设置了 --auto-load-dashboard true,则可以跳过此步骤。

  • 手动导入 Grafana dashboards

    • 点击左侧面板中的“Dashboards”图标。

    • 点击“New”。

    • 点击“Import”。

    • 点击“Upload JSON file”。

    • 选择一个 JSON 文件。

      • 情况 1:如果您使用的是 Ray 2.41.0,可以使用 GitHub 仓库中的示例配置文件。文件名模式为 xxx_grafana_dashboard.json

      • 情况 2:否则,从 head Pod 的 /tmp/ray/session_latest/metrics/grafana/dashboards/ 目录中导入 JSON 文件。您可以使用 kubectl cp 将文件从 head Pod 复制到本地机器。 kubectl cp $(kubectl get pods --selector ray.io/node-type=head,ray.io/cluster=raycluster-embed-grafana -o jsonpath={..metadata.name}):/tmp/ray/session_latest/metrics/grafana/dashboards/ /tmp/

    • 点击“Import”。

步骤 13:查看来自不同 RayCluster CR 的指标#

一旦 Ray Dashboard 导入到 Grafana 中,您就可以使用 Cluster 变量来过滤指标。当您使用提供的 PodMonitor 配置时,Ray Dashboard 会自动应用此变量。您无需进行任何额外的设置即可进行此标记。

如果您有多个 RayCluster 自定义资源,Cluster 变量允许您过滤特定集群的指标。此功能可确保您轻松监控或调试单个 RayCluster 实例,而不会被所有集群的数据淹没。

例如,在下面的图中,一个选择了来自 RayCluster raycluster-embed-grafana 的指标,另一个选择了来自 RayCluster raycluster-embed-grafana-2 的指标。

Grafana Ray Dashboard

Grafana Ray Dashboard2

步骤 14:查看 KubeRay operator dashboard#

将 KubeRay operator dashboard 导入 Grafana 后,您可以监控来自 KubeRay operator 的指标。该 dashboard 包含一个下拉菜单,允许您过滤并查看特定 Ray 自定义资源 CR 的 controller runtime 指标:RayClusterRayJobRayService

KubeRay operator dashboard 应如下所示: Grafana KubeRay operator Controller Runtime dashboard

步骤 15:将 Grafana 面板嵌入 Ray dashboard (可选)#

kubectl port-forward service/raycluster-embed-grafana-head-svc dashboard
# Visit http://127.0.0.1:8265/#/metrics in your browser.

Ray Dashboard with Grafana panels