(高级) 不使用 KubeRay 部署静态 Ray 集群#
Ray 的这种部署方法不再需要使用自定义资源定义 (CRDs)。相比之下,CRDs 是使用 KubeRay 的先决条件。KubeRay 的关键组件之一 KubeRay Operator 通过监听 Kubernetes 事件(创建/删除/更新)来管理 Ray 集群资源。尽管 KubeRay Operator 可以在单个命名空间内运行,但使用 CRDs 具有集群范围的作用域。如果部署 KubeRay 不具备必要的 Kubernetes 管理权限,本文档介绍了一种在不使用 KubeRay 的情况下将静态 Ray 集群部署到 Kubernetes 的方法。但是,需要注意的是,这种部署方法缺乏 KubeRay 提供的内置自动扩缩容功能。
准备工作#
安装最新的 Ray 版本#
使用Ray 作业提交与远程集群交互时需要此步骤。
! pip install -U "ray[default]"
有关更多详细信息,请参阅安装 Ray。
安装 kubectl#
要与 Kubernetes 交互,我们将使用 kubectl。安装说明可在Kubernetes 文档中找到。
访问 Kubernetes 集群#
我们需要访问 Kubernetes 集群。有两种选择
! kind create cluster
要执行本指南中的示例,请确保您的 Kubernetes 集群(或本地 Kind 集群)可以处理 3 个 CPU 和 3Gi 内存的额外资源请求。另外,请确保您的 Kubernetes 集群和 Kubectl 版本均不低于 1.19。
部署 Redis 实现故障容错#
请注意,Kubernetes 部署配置文件中包含一个用于将 Redis 部署到 Kubernetes 的部分,以便 Ray 头节点可以通过它写入 GCS 元数据。如果 Redis 已经在 Kubernetes 上部署,则可以省略此部分。
部署静态 Ray 集群#
在本节中,我们将在不使用 KubeRay 的情况下将静态 Ray 集群部署到default
命名空间。要使用其他命名空间,请在 kubectl 命令中指定该命名空间
kubectl -n <您的命名空间> ...
# Deploy a sample Ray Cluster from the Ray repo:
! kubectl apply -f https://raw.githubusercontent.com/ray-project/ray/master/doc/source/cluster/kubernetes/configs/static-ray-cluster.with-fault-tolerance.yaml
# Note that the Ray cluster has fault tolerance enabled by default using the external Redis.
# Please set the Redis IP address in the config.
# The password is currently set as '' for the external Redis.
# Please download the config file and substitute the real password for the empty string if the external Redis has a password.
Ray 集群部署完成后,您可以运行以下命令查看头节点和工作节点的 Pods
! kubectl get pods
# NAME READY STATUS RESTARTS AGE
# deployment-ray-head-xxxxx 1/1 Running 0 XXs
# deployment-ray-worker-xxxxx 1/1 Running 0 XXs
# deployment-ray-worker-xxxxx 1/1 Running 0 XXs
等待 Pods 达到 Running
状态。这可能需要几分钟时间——大部分时间用于下载 Ray 镜像。在另一个 shell 中,您可以使用以下命令实时观察 Pods 的状态
# If you're on MacOS, first `brew install watch`.
# Run in a separate shell:
! watch -n 1 kubectl get pod
如果您的 Pods 卡在 Pending
状态,您可以通过 kubectl describe pod deployment-ray-head-xxxx-xxxxx
查看错误,并确保您的 Docker 资源限制设置得足够高。
请注意,在生产环境中,您会希望使用更大的 Ray Pods。实际上,将每个 Ray Pod 设置为占用整个 Kubernetes 节点是有利的。有关更多详细信息,请参阅配置指南。
为静态 Ray 集群部署网络策略#
如果您的 Kubernetes 对 Pods 有默认的拒绝网络策略,则需要手动创建一个网络策略,以允许 Ray 集群中头节点和工作节点之间的双向通信,如端口配置文档中所述。
# Create a sample network policy for the static Ray cluster from the Ray repo:
! kubectl apply -f https://raw.githubusercontent.com/ray-project/ray/master/doc/source/cluster/kubernetes/configs/static-ray-cluster-networkpolicy.yaml
网络策略部署完成后,您可以运行以下命令查看静态 Ray 集群的网络策略
! kubectl get networkpolicies
# NAME POD-SELECTOR AGE
# ray-head-egress app=ray-cluster-head XXs
# ray-head-ingress app=ray-cluster-head XXs
# ray-worker-egress app=ray-cluster-worker XXs
# ray-worker-ingress app=ray-cluster-worker XXs
外部 Redis 集成实现故障容错#
Ray 默认使用一个内部键值存储,称为全局控制存储 (GCS)。GCS 运行在头节点上并存储集群元数据。这种方法的一个缺点是,如果头节点崩溃,它会丢失元数据。Ray 还可以将此元数据写入外部 Redis 以实现可靠性和高可用性。通过此设置,静态 Ray 集群可以从头节点崩溃中恢复,并容忍 GCS 故障而不会丢失与工作节点的连接。
要使用此功能,我们需要在Kubernetes 部署配置文件的 Ray 头节点部分传入 RAY_REDIS_ADDRESS
环境变量和 --redis-password
。
在静态 Ray 集群上运行应用程序#
在本节中,我们将与刚刚部署的静态 Ray 集群进行交互。
使用 kubectl exec 访问集群#
与使用 KubeRay 部署的 Ray 集群一样,我们可以直接 exec 进入头 Pod 并运行 Ray 程序。
首先,运行以下命令获取头 Pod
! kubectl get pods --selector=app=ray-cluster-head
# NAME READY STATUS RESTARTS AGE
# deployment-ray-head-xxxxx 1/1 Running 0 XXs
现在我们可以在之前确定的头 Pod 上执行 Ray 程序。以下命令连接到 Ray 集群,然后终止 Ray 程序。
# Substitute your output from the last cell in place of "deployment-ray-head-xxxxx"
! kubectl exec deployment-ray-head-xxxxx -it -c ray-head -- python -c "import ray; ray.init('auto')"
# 2022-08-10 11:23:17,093 INFO worker.py:1312 -- Connecting to existing Ray cluster at address: <IP address>:6380...
# 2022-08-10 11:23:17,097 INFO worker.py:1490 -- Connected to Ray cluster. View the dashboard at ...
尽管上面的单元格对于在 Ray 集群上临时执行很有用,但在 Ray 集群上运行应用程序的推荐方法是使用Ray 作业。
Ray 作业提交#
要为 Ray 作业提交设置 Ray 集群,需要确保 Ray Jobs 端口可供客户端访问。Ray 通过头节点上的 Dashboard 服务器接收作业请求。
首先,我们需要识别 Ray 头节点。静态 Ray 集群配置文件设置了一个针对 Ray 头 Pod 的Kubernetes Service。此 Service 允许我们与 Ray 集群交互,而无需直接在 Ray 容器中执行命令。要识别示例集群的 Ray 头 Service,请运行
! kubectl get service service-ray-cluster
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# service-ray-cluster ClusterIP 10.92.118.20 <none> 6380/TCP,8265/TCP,10001/TCP... XXs
现在我们有了 Service 的名称,可以使用端口转发来访问 Ray Dashboard 端口(默认为 8265)。
# Execute this in a separate shell.
# Substitute the service name in place of service-ray-cluster
! kubectl port-forward service/service-ray-cluster 8265:8265
现在我们已经可以访问 Dashboard 端口,可以提交作业到 Ray 集群执行
! ray job submit --address http://localhost:8265 -- python -c "import ray; ray.init(); print(ray.cluster_resources())"
清理#
删除 Ray 集群#
删除静态 Ray 集群的 Service 和 Deployment
! kubectl delete -f https://raw.githubusercontent.com/ray-project/ray/master/doc/source/cluster/kubernetes/configs/static-ray-cluster.with-fault-tolerance.yaml
删除静态 Ray 集群的网络策略
! kubectl delete -f https://raw.githubusercontent.com/ray-project/ray/master/doc/source/cluster/kubernetes/configs/static-ray-cluster-networkpolicy.yaml