日志持久化#
日志(包括系统和应用程序日志)对于故障排除Ray应用程序和集群非常有用。例如,如果一个节点意外终止,您可能需要访问系统日志。
与Kubernetes类似,Ray不提供日志数据的本地存储解决方案。用户需要自行管理日志的生命周期。本页提供如何从运行在Kubernetes上的Ray集群收集日志的说明。
小技巧
跳转到 部署说明 以查看一个示例配置,展示如何从 Ray pod 中提取日志。
Ray 日志目录#
默认情况下,Ray 将日志写入每个 Ray pod 文件系统中的 /tmp/ray/session_*/logs
目录下的文件,包括应用程序和系统日志。在开始收集日志之前,请了解更多关于 日志目录和日志文件 以及 日志轮转配置 的信息。
日志处理工具#
在Kubernetes生态系统中,有许多开源的日志处理工具可用。本页展示了如何使用 [Fluent Bit][FluentBit] 提取Ray日志。其他流行的工具包括 [Vector][Vector]、[Fluentd][Fluentd]、[Filebeat][Filebeat] 和 [Promtail][Promtail]。
日志收集策略#
要将收集的日志写入Pod的文件系统,请使用以下两种日志记录策略之一:边车容器 或 守护进程集。在 [Kubernetes 文档][KubDoc] 中阅读有关这些日志记录模式的更多信息。
边车容器#
我们在本指南中提供了一个 示例 ,展示了边车策略。您可以通过为每个 Ray pod 配置一个日志处理边车来处理日志。Ray 容器应配置为通过卷挂载与日志边车共享 /tmp/ray
目录。
你可以配置边车执行以下任一操作:
将 Ray 日志流式传输到边车的标准输出。
将日志导出到外部服务。
Daemonset#
另外,也可以在 Kubernetes 节点级别收集日志。为此,需要在 Kubernetes 集群的节点上部署一个日志处理 daemonset。采用这种策略时,关键是要将 Ray 容器的 /tmp/ray
目录挂载到相关的 hostPath
。
使用 Fluent Bit 设置日志边车#
在本节中,我们提供了一个如何为 Ray pod 设置日志发送 [Fluent Bit][FluentBit] sidecar 的示例。
请参阅带有日志边车的单个pod RayCluster的完整配置 [此处][ConfigLink]。现在我们将讨论此配置并展示如何部署它。
配置日志处理#
第一步是创建一个包含 Fluent Bit 配置的 ConfigMap。
这是一个最小的 ConfigMap,它告诉 Fluent Bit 边车容器
Tail Ray 日志。
将日志输出到容器的标准输出。
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
[OUTPUT]
Name stdout
Match *
关于上述配置的一些说明:
除了将日志流式传输到标准输出外,您还可以使用 [OUTPUT] 子句将日志导出到 Fluent Bit 支持的任何 [存储后端][FluentBitStorage]。
上面的
Path_Key true
行确保文件名包含在 Fluent Bit 发出的日志记录中。Refresh_Interval 5
这一行要求 Fluent Bit 每 5 秒刷新一次日志目录中的文件列表,而不是默认的 60 秒。原因是目录/tmp/ray/session_latest/logs/
最初并不存在(Ray 必须先创建它)。设置Refresh_Interval
较低可以让我们更快地在 Fluent Bit 容器的 stdout 中看到日志。
将日志边车添加到 RayCluster 自定义资源 (CR)#
添加日志和配置卷#
对于 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 边车#
最后,将 Fluent Bit 边车容器添加到 RayCluster CR 中的每个 Ray pod 配置中。
- name: fluentbit
image: fluent/fluent-bit:1.9.6
# 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
卷使边车容器能够访问 Ray 的日志。fluentbit-config
将所有内容整合在一起#
将上述所有元素结合起来,我们为具有日志处理边车的单个Pod RayCluster 提供了以下yaml配置。
# 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
[OUTPUT]
Name stdout
Match *
---
# RayCluster CR with a FluentBit sidecar
apiVersion: ray.io/v1alpha1
kind: RayCluster
metadata:
labels:
controller-tools.k8s.io: "1.0"
name: raycluster-complete-logs
spec:
rayVersion: '2.3.0'
headGroupSpec:
rayStartParams:
dashboard-host: '0.0.0.0'
template:
spec:
containers:
- name: ray-head
image: rayproject/ray:2.3.0
lifecycle:
preStop:
exec:
command: ["/bin/sh","-c","ray stop"]
# This config is meant for demonstration purposes only.
# Use larger Ray containers in production!
resources:
limits:
cpu: "1"
memory: "1G"
requests:
cpu: "1"
memory: "1G"
# Share logs with Fluent Bit
volumeMounts:
- mountPath: /tmp/ray
name: ray-logs
# Fluent Bit sidecar
- name: fluentbit
image: fluent/fluent-bit:1.9.6
# 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
使用日志边车部署 RayCluster#
要部署上述配置,如果尚未部署 KubeRay Operator,请执行以下操作:参考 入门指南 获取此步骤的说明。
现在,运行以下命令来部署 Fluent Bit ConfigMap 和一个带有 Fluent Bit 边车的单节点 RayCluster。
kubectl apply -f https://raw.githubusercontent.com/ray-project/ray/releases/2.4.0/doc/source/cluster/kubernetes/configs/ray-cluster.log.yaml
确定 Ray pod 的名称
kubectl get pod | grep raycluster-complete-logs
检查 FluentBit 边车容器的 STDOUT 以查看 Ray 组件进程的日志。
# Substitute the name of your Ray pod.
kubectl logs raycluster-complete-logs-head-xxxxx -c fluentbit
在 DaemonSet 上使用 Fluent Bit 设置日志记录#
Fluent Bit 是一个轻量级代理,允许你从 Kubernetes 集群收集日志并发送到各种目的地,如 Elasticsearch、CloudWatch、S3 等。以下步骤将 [Fluent Bit][FluentBit] 设置为 DaemonSet 以将日志发送到 CloudWatch Logs。
AWS EKS 设置#
使用 eksctl
在 us-west-2
区域创建一个名为 fluent-bit-demo
的 Amazon EKS 集群,如 EKS 文档 所示。
eksctl create cluster --name fluent-bit-demo --region us-west-2
查看您的集群节点:
$ kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
ip-192-168-59-62.us-west-2.compute.internal Ready <none> 157m v1.27.5-eks-43840fb 192.168.59.62 54.190.144.241 Amazon Linux 2 5.10.192-183.736.amzn2.x86_64 containerd://1.6.19
ip-192-168-86-99.us-west-2.compute.internal Ready <none> 157m v1.27.5-eks-43840fb 192.168.86.99 34.219.16.107 Amazon Linux 2 5.10.192-183.736.amzn2.x86_64 containerd://1.6.19
EKS 集群节点需要能够访问 CloudWatch Logs 以便 Fluent Bit 使用。将 CloudWatchLogsFullAccess
策略附加到附加到集群节点的 IAM 角色上:
ROLE_NAME=$(eksctl get nodegroup --cluster fluent-bit-demo --region us-west-2 -o json | jq -r '.[].NodeInstanceRoleARN' | cut -f2 -d/)
aws iam attach-role-policy \
--role-name $ROLE_NAME \
--policy-arn arn:aws:iam::aws:policy/CloudWatchLogsFullAccess
部署 Fluent Bit DaemonSet#
如果你还没有一个名为 amazon-cloudwatch
的命名空间,可以通过输入以下命令来创建一个:
kubectl apply -f https://raw.githubusercontent.com/aws-samples/amazon-cloudwatch-container-insights/latest/k8s-deployment-manifest-templates/deployment-mode/daemonset/container-insights-monitoring/cloudwatch-namespace.yaml
运行以下命令以创建一个名为 cluster-info
的 ConfigMap,其中包含集群名称和发送日志的区域:
ClusterName=fluent-bit-demo
RegionName=us-west-2
FluentBitHttpPort='2020'
FluentBitReadFromHead='Off'
[[ ${FluentBitReadFromHead} = 'On' ]] && FluentBitReadFromTail='Off'|| FluentBitReadFromTail='On'
[[ -z ${FluentBitHttpPort} ]] && FluentBitHttpServer='Off' || FluentBitHttpServer='On'
kubectl create configmap fluent-bit-cluster-info \
--from-literal=cluster.name=${ClusterName} \
--from-literal=http.server=${FluentBitHttpServer} \
--from-literal=http.port=${FluentBitHttpPort} \
--from-literal=read.head=${FluentBitReadFromHead} \
--from-literal=read.tail=${FluentBitReadFromTail} \
--from-literal=logs.region=${RegionName} -n amazon-cloudwatch
通过运行以下命令将 Fluent Bit DaemonSet 部署到集群中:
kubectl apply -f https://raw.githubusercontent.com/aws-samples/amazon-cloudwatch-container-insights/latest/k8s-deployment-manifest-templates/deployment-mode/daemonset/container-insights-monitoring/fluent-bit/fluent-bit.yaml
通过输入以下命令验证您是否成功部署了 Fluent Bit:
kubectl -n amazon-cloudwatch logs ds/fluent-bit
验证命令是否创建了日志组:
...
[2023/10/10 06:13:55] [ info] [output:cloudwatch_logs:cloudwatch_logs.0] Created log group /aws/containerinsights/fluent-bit-demo/application
[2023/10/10 06:13:57] [ info] [output:cloudwatch_logs:cloudwatch_logs.2] Created log group /aws/containerinsights/fluent-bit-demo/host
[2023/10/10 06:13:57] [ info] [output:cloudwatch_logs:cloudwatch_logs.1] Created log group /aws/containerinsights/fluent-bit-demo/dataplane
...
查看 CloudWatch 仪表板#
最后,检查 CloudWatch 仪表板以查看日志。打开 CloudWatch 控制台,网址为 https://console.aws.amazon.com/cloudwatch/。
在搜索框中输入 /aws/containerinsights/fluent-bit-demo/
。
选择 /aws/containerinsights/fluent-bit-demo/application
。你应该能看到来自包括 Ray 在内的应用程序 pod 的日志。
在日志流下,点击任意日志流。你应该能看到来自pod的日志:
您可以根据pod名称、命名空间等指定过滤器。了解如何在此 过滤器模式语法文档 中编写过滤器。
将 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,将工作线程日志重定向到驱动程序 的功能将无法工作。如果你需要这些功能,可以考虑使用上面提到的 Fluent Bit 解决方案。对于 VM 上的集群,不要将日志重定向到 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 文件。