持久化 KubeRay 自定义资源日志#
日志(系统日志和应用日志)对于排查 Ray 应用和集群问题非常有帮助。例如,当节点意外终止时,您可能需要访问系统日志。
与 Kubernetes 类似,Ray 并不提供原生的日志数据存储解决方案。用户需要自行管理日志的生命周期。本文档将指导您如何在 Kubernetes 上收集正在运行的 Ray 集群的日志。
Ray 日志目录#
默认情况下,Ray 会将日志写入每个 Ray Pod 文件系统中的目录 /tmp/ray/session_*/logs,包括应用日志和系统日志。在开始收集日志之前,请详细了解 日志目录和日志文件 以及 日志轮转配置。
日志处理工具#
Kubernetes 生态系统中提供了许多开源日志处理工具。本文档将展示如何使用 Fluent Bit 提取 Ray 日志。其他流行的工具包括 Vector、Fluentd、Filebeat 和 Promtail。
日志收集策略#
要将收集到的日志写入 Pod 的文件系统,请使用以下两种日志记录策略之一:**sidecar 容器** 或 **daemonset**。请参阅 Kubernetes 文档 了解这些日志模式的更多信息。
Sidecar 容器#
本指南提供了一个关于 sidecar 策略的 示例。您可以为每个 Ray Pod 配置一个日志处理 sidecar 来处理日志。Ray 容器应配置为通过卷挂载与日志 sidecar 共享 /tmp/ray 目录。
您可以将 sidecar 配置为执行以下任一操作:
将 Ray 日志流式传输到 sidecar 的 stdout。
将日志导出到外部服务。
Daemonset#
或者,也可以在 Kubernetes 节点级别收集日志。为此,需要将日志处理 daemonset 部署到 Kubernetes 集群的节点上。采用此策略时,关键是将 Ray 容器的 /tmp/ray 目录挂载到相关的 hostPath。
使用 Fluent Bit 设置日志 sidecar#
在本节中,我们将提供一个示例,说明如何为 Ray Pod 设置日志输出 Fluent Bit sidecar,以将日志发送到 Grafana Loki,从而实现集中的日志管理和查询。
在此处查看带有日志 sidecar 的单 Pod RayCluster 的完整配置:链接。现在,我们将讨论此配置并展示如何部署它。
部署 Loki 单体模式#
请按照 部署 Loki 单体模式 的说明,以单体模式部署 Grafana Loki。
部署 Grafana#
请按照 部署 Grafana 的说明,设置 Grafana Loki 数据源并部署 Grafana。
配置日志处理#
第一步是创建一个包含 Fluent Bit 配置的 ConfigMap。
下面的 ConfigMap 示例配置了一个 Fluent Bit sidecar,用于:
跟踪 Ray 日志。
将日志发送到 Grafana Loki 端点。
向日志添加元数据,以便按标签进行过滤,例如
RayCluster。
apiVersion: v1
kind: ConfigMap
metadata:
name: fluentbit-config
data:
fluent-bit.conf: |
[INPUT]
Name tail
Path /tmp/ray/session_latest/logs/*
Tag ray
Path_Key true
Refresh_Interval 5
[FILTER]
Name modify
Match ray
Add POD_LABELS ${POD_LABELS}
[OUTPUT]
Name loki
Match *
Host loki-gateway
Port 80
Labels RayCluster=${POD_LABELS}
tenant_id test
关于上述配置的一些说明:
上面的
Path_Key true行确保文件名包含在 Fluent Bit 发出的日志记录中。上面的
Refresh_Interval 5行指示 Fluent Bit 每 5 秒刷新一次日志目录中的文件列表,而不是默认的 60 秒。原因是目录/tmp/ray/session_latest/logs/最初不存在(Ray 必须先创建它)。将Refresh_Interval设置得低一些,可以让我们更快地在 Fluent Bit 容器的 stdout 中看到日志。Kubernetes वापरा Downward API 将
POD_LABELS变量填充到FILTER部分。它从 Pod 的元数据标签ray.io/cluster中拉取标签,该标签在 Fluent Bit sidecar 容器的环境中定义。字段
tenant_id允许您将日志分配给不同的租户。在此示例中,Fluent Bit sidecar 将日志发送到test租户。您可以调整此配置以匹配您的 Grafana Loki 实例中设置的租户 ID,从而启用 Grafana 中的多租户支持。字段
Host指定 Loki 网关的端点。如果 Loki 和 RayCluster 位于不同的命名空间中,则需要将.namespace追加到主机名,例如loki-gateway.monitoring(将monitoring替换为 Loki 所在的命名空间)。
向 RayCluster 自定义资源 (CR) 添加日志 sidecar#
添加日志和配置卷#
对于 RayCluster CR 中的每个 Pod 模板,我们需要添加两个卷:一个用于 Ray 日志,另一个用于存储上面应用的 ConfigMap 中的 Fluent Bit 配置。
volumes:
- name: ray-logs
emptyDir: {}
- name: fluentbit-config
configMap:
name: fluentbit-config
挂载 Ray 日志目录#
将以下卷挂载添加到 Ray 容器的配置中。
volumeMounts:
- mountPath: /tmp/ray
name: ray-logs
添加 Fluent Bit sidecar#
最后,将 Fluent Bit sidecar 容器添加到 RayCluster CR 中每个 Ray Pod 的配置中。
- name: fluentbit
image: fluent/fluent-bit:3.2.2
# Get Kubernetes metadata via downward API
env:
- name: POD_LABELS
valueFrom:
fieldRef:
fieldPath: metadata.labels['ray.io/cluster']
# These resource requests for Fluent Bit should be sufficient in production.
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 100m
memory: 128Mi
volumeMounts:
- mountPath: /tmp/ray
name: ray-logs
- mountPath: /fluent-bit/etc/fluent-bit.conf
subPath: fluent-bit.conf
name: fluentbit-config
挂载 ray-logs 卷可使 sidecar 容器访问 Ray 的日志。而fluentbit-config
整合所有内容#
将以上所有元素整合在一起,我们得到以下 YAML 配置,适用于带有日志处理 sidecar 的单 Pod RayCluster。
# Fluent Bit ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: fluentbit-config
data:
fluent-bit.conf: |
[INPUT]
Name tail
Path /tmp/ray/session_latest/logs/*
Tag ray
Path_Key true
Refresh_Interval 5
[FILTER]
Name modify
Match ray
Add POD_LABELS ${POD_LABELS}
[OUTPUT]
Name loki
Match *
Host loki-gateway
Port 80
Labels RayCluster=${POD_LABELS}
tenant_id test
---
# RayCluster CR with a FluentBit sidecar
apiVersion: ray.io/v1
kind: RayCluster
metadata:
name: raycluster-fluentbit-sidecar-logs
spec:
rayVersion: '2.46.0'
headGroupSpec:
template:
spec:
containers:
- name: ray-head
image: rayproject/ray:2.46.0
# This config is meant for demonstration purposes only.
# Use larger Ray containers in production!
resources:
limits:
cpu: 1
memory: 2Gi
requests:
cpu: 500m
memory: 1Gi
# Share logs with Fluent Bit
volumeMounts:
- mountPath: /tmp/ray
name: ray-logs
# Fluent Bit sidecar
- name: fluentbit
image: fluent/fluent-bit:3.2.2
# Get Kubernetes metadata via downward API
env:
- name: POD_LABELS
valueFrom:
fieldRef:
fieldPath: metadata.labels['ray.io/cluster']
# These resource requests for Fluent Bit should be sufficient in production.
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 100m
memory: 128Mi
volumeMounts:
- mountPath: /tmp/ray
name: ray-logs
- mountPath: /fluent-bit/etc/fluent-bit.conf
subPath: fluent-bit.conf
name: fluentbit-config
# Log and config volumes
volumes:
- name: ray-logs
emptyDir: {}
- name: fluentbit-config
configMap:
name: fluentbit-config
部署带有日志 sidecar 的 RayCluster#
要部署上述配置,请先安装 KubeRay Operator(如果尚未安装):请参考 入门指南 获取相关说明。
现在,运行以下命令来部署 Fluent Bit ConfigMap 和带有 Fluent Bit sidecar 的单 Pod RayCluster。
kubectl apply -f https://raw.githubusercontent.com/ray-project/kuberay/refs/heads/master/ray-operator/config/samples/ray-cluster.fluentbit.yaml
要从本地机器访问 Grafana,请通过运行以下命令设置端口转发:
export POD_NAME=$(kubectl get pods --namespace default -l "app.kubernetes.io/name=grafana,app.kubernetes.io/instance=grafana" -o jsonpath="{.items[0].metadata.name}")
kubectl --namespace default port-forward $POD_NAME 3000
此命令使 Grafana 在本地可用,地址为 https://:3000。
用户名:“admin”
密码:使用以下命令获取密码
kubectl get secret --namespace default grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo
最后,使用 LogQL 查询来查看特定 RayCluster 或 RayJob 的日志,并按照本示例中 FluentBit ConfigMap OUTPUT 配置中所设置的 RayCluster 进行过滤。
{RayCluster="raycluster-fluentbit-sidecar-logs"}

将 Ray 日志重定向到 stderr#
默认情况下,Ray 会将日志写入 /tmp/ray/session_*/logs 目录中的文件。如果您的日志处理工具能够捕获写入 stderr 的日志记录,您可以通过在所有 Ray 节点上设置环境变量 RAY_LOG_TO_STDERR=1 将 Ray 日志重定向到 Ray 容器的 stderr 流。
警告:不推荐此做法。
如果设置了 RAY_LOG_TO_STDERR=1,Ray 将不会将日志写入文件。因此,此行为可能导致一些依赖日志文件的 Ray 功能出现故障。例如,如果您将 Ray 日志重定向到 stderr,则 将 worker 日志重定向到 driver 将无法正常工作。如果您需要这些功能,请考虑使用上面提到的 Fluent Bit 解决方案。对于虚拟机上的集群,请勿将日志重定向到 stderr。而是遵循 此指南 来持久化日志。
将日志重定向到 stderr 还会为每个日志记录消息添加一个 ({component}) 前缀,例如 (raylet)。
[2022-01-24 19:42:02,978 I 1829336 1829336] (gcs_server) grpc_server.cc:103: GcsServer server started, listening on port 50009.
[2022-01-24 19:42:06,696 I 1829415 1829415] (raylet) grpc_server.cc:103: ObjectManager server started, listening on port 40545.
2022-01-24 19:42:05,087 INFO (dashboard) dashboard.py:95 -- Setup static dir for dashboard: /mnt/data/workspace/ray/python/ray/dashboard/client/build
2022-01-24 19:42:07,500 INFO (dashboard_agent) agent.py:105 -- Dashboard agent grpc address: 0.0.0.0:49228
这些前缀允许您按感兴趣的组件过滤日志的 stderr 流。但请注意,多行日志记录在每一行的开头 **不会** 有此组件标记。
请按照以下步骤在所有 Ray 节点上设置环境变量 RAY_LOG_TO_STDERR=1:
使用 CLI 显式启动集群
env RAY_LOG_TO_STDERR=1 ray start
使用 ray.init 隐式启动集群
os.environ["RAY_LOG_TO_STDERR"] = "1"
ray.init()
在每个 Ray Pod 的 Ray 容器中,将 RAY_LOG_TO_STDERR 环境变量设置为 1。使用此 示例 YAML 文件 作为参考。