在 Kubernetes 中部署#

Mars 支持在 Kubernetes 管理的集群中执行。你可以使用 mars.deploy.kubernetes 模块配置一个 Mars 集群。

基本步骤#

Mars 默认会使用 marsproject/mars 中的镜像。自 v0.3.0 起,每个 Mars 的发布版本均会包含一个镜像,例如 v0.3.0 对应的镜像是 marsproject/mars:v0.3.0。如果你希望从源码制作一个镜像,可以使用下面的命令:

bin/kube-image-tool.sh build

一个使用当前版本号作为标签的 Docker 镜像将被制作出来。

接下来,你需要运行下面的命令来保证 Kubernetes 的客户端配置是正确的:

kubectl get nodes

如果上述命令报错,请参考 Kubernetes 相关文档或者咨询集群维护人员。

由于 Mars 使用 Python 操作 Kubernetes,你需要在本地使用 pip 或者 conda 安装 Python 上的 Kubernetes 客户端:

# install with pip
pip install kubernetes
# install with conda
conda install -c conda-forge python-kubernetes

在完成上述所有步骤后,我们可以创建一个拥有单一 Supervisor 和单一 Worker 的 Kubernetes 集群实例,并在上面执行一些作业:

from kubernetes import config
from mars.deploy.kubernetes import new_cluster
import mars.tensor as mt

cluster = new_cluster(config.new_client_from_config())

# new cluster will start a session and set it as default one
# execute will then run in the local cluster
a = mt.random.rand(10, 10)
a.dot(a.T).execute()

# after all jobs executed, you can turn off the cluster
cluster.stop()

如果你需要在其他地方使用刚创建的集群,你可以从 cluster 对象获取 namespaceendpoint 参数,此后创建另一个 KubernetesClusterClient

# obtain information from current cluster
namespace, endpoint = cluster.namespace, cluster.endpoint

# create a new cluster client
from kubernetes import config
from mars.deploy.kubernetes import KubernetesClusterClient

cluster = KubernetesClusterClient(
    config.new_client_from_config(), namespace, endpoint)

定制集群#

new_cluster 函数提供若干可用于定制集群的参数。你可以使用 image 参数定义所有 Pod 使用的镜像,timeout 参数定义创建集群的超时时间。同时,该函数还提供调整集群规模的功能。

Supervisor 相关参数:

参数

描述

supervisor_num

集群中 Supervisor 的数目,默认为 1

supervisor_cpu

每个 Supervisor 的 CPU 数目

supervisor_mem

每个 Supervisor 的内存大小,可使用字节数或带单位的大小,例如 1g

supervisor_extra_env

在 Supervisor 中额外增加的环境变量,以 dict 表示

Worker 相关参数:

参数

描述

worker_num

集群中 Worker 的数目,默认为 1

worker_cpu

每个 Worker 的 CPU 数目,此参数为必需

worker_mem

每个 Worker 的内存大小,可使用字节数或带单位的大小,例如 1g,此参数为必需

worker_spill_paths

在宿主机上用于 Worker spill 的路径列表

worker_cache_mem

Worker 中共享内存的大小或者占比。关于 Mars Worker 中的内存管理细节可以参考 内存调优 章节。

min_worker_num

new_cluster 结束执行时所需的最小可用 Worker 个数,默认为 worker_num

worker_extra_env

在 Worker 中额外增加的环境变量,以 dict 表示

例如,如果你需要创建一个包含单个 Supervisor 和 100 个 Worker 的 Mars 集群,每个 Worker 拥有 4 核 16GB 内存,当 95 个 Worker 可用时认为整个集群可用,你可以使用下面的代码:

from kubernetes import config
from mars.deploy.kubernetes import new_cluster

api_client = config.new_client_from_config()
cluster = new_cluster(api_client, supervisor_num=1, worker_num=100, worker_cpu=4,
                      worker_mem='16g', min_worker_num=95)

实现细节#

当调用 new_cluster 时,该方法会为此后使用的每个 Kubernetes 对象,包括 Pod、Role等创建一个单独的 名称空间 。当用户停止服务时,整个 Namespace 都会被删除。

Supervisor 和 Worker 使用 Deployment 创建。各种服务通过默认的 服务账户 使用 Kubernetes API 发现 Supervisor。Worker 读取 Pod 的地址和可用度来决定是否启动。与此同时,客户端通过读取所有 Pod 的可用度并确认所有 Supervisor 以及至少 min_worker_num 个 Worker 可用。

Mars 服务的可用度由 可用度检测器 确定,检测结果可从 Pod 状态中获取。对于 Supervisor 和 Worker 而言,当服务启动时,一个 ReadinessActor 将会在服务中被创建,检测器将检测该 Actor 是否存在。对于 Web 服务,检测器将直接检测 Web 端口是否被创建。

由于默认的服务账号不具备在 Kubernetes API 中读取 Pod 的权限,我们在创建集群 Replication Controller 前,在名称空间内使用 RBAC API 创建了一个具备读取和监视 Pod 状态的 角色 ,此后将其绑定到默认账户中。这使得 Mars 容器可以检测其他容器的状态。

Mars 使用 Kubernetes 服务 对外暴露服务,目前仅支持 NodePort 模式。在此模式下,Mars 将查找持有 Supervisor 的主机,并将其地址作为 Endpoint。LoadBalancer 模式尚未被支持。