(高级) 在没有 KubeRay 的情况下部署一个静态 Ray 集群#

这种 Ray 的部署方法不再需要使用自定义资源定义(CRD)。相比之下,CRD 是使用 KubeRay 的前提条件。其关键组件之一,KubeRay 操作员,通过监视 Kubernetes 事件(创建/删除/更新)来管理 Ray 集群资源。虽然 KubeRay 操作员可以在单个命名空间内运行,但 CRD 的使用具有集群范围的影响。如果部署 KubeRay 所需的 Kubernetes 管理员权限不可用,本文档介绍了一种在不使用 KubeRay 的情况下将静态 Ray 集群部署到 Kubernetes 的方法。但需要注意的是,这种部署方法缺乏 KubeRay 提供的内置自动扩展功能。

准备#

安装最新的 Ray 版本#

此步骤对于使用 Ray 作业提交 与远程集群交互是必要的。

! pip install -U "ray[default]"

更多详情请参见 安装

安装 kubectl#

要与 Kubernetes 交互,我们将使用 kubectl。安装说明可以在 Kubernetes 文档 中找到。

访问 Kubernetes 集群#

我们将需要访问一个 Kubernetes 集群。有两种选择:

  1. 配置对远程 Kubernetes 集群的访问

  2. 通过安装 kind 在本地运行示例。通过运行以下命令启动您的 kind 集群:

! kind create cluster

要执行本指南中的示例,请确保您的 Kubernetes 集群(或本地 Kind 集群)能够处理额外的 3 个 CPU 和 3Gi 内存的资源请求。此外,请确保您的 Kubernetes 集群和 Kubectl 至少是 1.19 版本。

部署一个用于容错的 Redis#

请注意,Kubernetes 部署配置文件 中有一个部分用于在 Kubernetes 上部署 Redis,以便 Ray 头节点可以通过 GCS 元数据进行写入。如果 Redis 已经在 Kubernetes 上部署,则可以省略此部分。

部署一个静态 Ray 集群#

在本节中,我们将在 default 命名空间中部署一个静态 Ray 集群,而不使用 KubeRay。要使用另一个命名空间,请在您的 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集群部署完成,您可以通过运行命令来查看头节点和工作节点的pod。

! 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

等待 pod 达到 Running 状态。这可能需要几分钟 – 大部分时间用于下载 Ray 镜像。在另一个 shell 中,您可能希望使用以下命令实时观察 pod 的状态:

# If you're on MacOS, first `brew install watch`.
# Run in a separate shell:

! watch -n 1 kubectl get pod

如果你的 Pod 卡在 Pending 状态,你可以通过 kubectl describe pod deployment-ray-head-xxxx-xxxxx 检查错误,并确保你的 Docker 资源限制设置得足够高。

请注意,在生产环境中,您可能希望使用更大的 Ray pod。实际上,将每个 Ray pod 的大小调整为占用整个 Kubernetes 节点是有优势的。有关更多详细信息,请参阅 配置指南

为静态 Ray 集群部署网络策略#

如果你的 Kubernetes 对 pod 有默认拒绝的网络策略,你需要手动创建一个网络策略,以允许 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 集群相同,我们可以直接进入头节点并运行 Ray 程序。

首先,运行以下命令以获取头部Pod:

! kubectl get pods --selector=app=ray-cluster-head

# NAME                                             READY   STATUS    RESTARTS   AGE
# deployment-ray-head-xxxxx                        1/1     Running   0          XXs

我们现在可以在之前识别的头节点上执行一个 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 Jobs

Ray 作业提交#

要为 Ray 作业提交设置 Ray 集群,必须确保 Ray 作业端口对客户端是可访问的。Ray 通过头节点上的 Dashboard 服务器接收作业请求。

首先,我们需要识别 Ray 头节点。静态 Ray 集群配置文件设置了一个 Kubernetes 服务,该服务指向 Ray 头 pod。此服务使我们能够与 Ray 集群交互,而无需直接在 Ray 容器中执行命令。要识别示例集群的 Ray 头服务,请运行:

! 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

既然我们已经有了服务的名称,我们可以使用端口转发来访问 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

现在我们已经可以访问仪表板端口,我们可以将作业提交到 Ray 集群进行执行:

! ray job submit --address http://localhost:8265 -- python -c "import ray; ray.init(); print(ray.cluster_resources())"

清理#

删除一个 Ray 集群#

删除静态 Ray 集群服务和部署

! 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