环境依赖#

您的 Ray 应用程序可能有一些依赖项存在于您的 Ray 脚本之外。例如:

  • 您的 Ray 脚本可能会导入/依赖于某些 Python 包。

  • 您的 Ray 脚本可能正在寻找某些特定的环境变量以使其可用。

  • 您的 Ray 脚本可能会导入脚本之外的一些文件。

在集群上运行时经常遇到的一个问题是,Ray 期望这些“依赖项”存在于每个 Ray 节点上。如果这些依赖项不存在,您可能会遇到诸如 ModuleNotFoundErrorFileNotFoundError 等问题。

要解决这个问题,你可以 (1) 提前在集群上准备你的依赖项(例如使用容器镜像)使用 Ray 集群启动器,或者 (2) 使用 Ray 的 运行时环境 来即时安装它们。

对于生产使用或不变的环境,我们建议将依赖项安装到容器镜像中,并使用集群启动器指定镜像。对于动态环境(例如开发和实验),我们建议使用运行时环境。

概念#

  • Ray 应用程序。 一个包含 Ray 脚本的程序,该脚本调用了 ray.init() 并使用了 Ray 任务或角色。

  • 依赖项,或 环境。 任何在 Ray 脚本之外,您的应用程序运行所需的内容,包括文件、包和环境变量。

  • 文件。代码文件、数据文件或其他Ray应用程序运行所需的文件。

  • 。Ray 应用程序所需的第三方库或可执行文件,通常通过 pipconda 安装。

  • 本地机器集群。通常,您可能希望将 Ray 集群计算机器/Pod 与处理和提交应用程序的机器/Pod 分开。您可以通过 Ray 作业提交机制 提交 Ray 作业,或使用 ray attach 以交互方式连接到集群。我们称提交作业的机器为您的 本地机器

  • 任务。一个 Ray 任务 是一个单一的应用程序:它是由同一个脚本产生的 Ray 任务、对象和角色的集合。

使用 Ray 集群启动器准备环境#

设置依赖的第一种方法是,在启动 Ray 运行时之前,在整个集群中准备一个单一的环境。

  • 你可以将所有文件和依赖项构建到一个容器镜像中,并在你的 集群YAML配置 中指定这一点。

  • 你也可以在 Ray 集群配置文件中使用 setup_commands 来安装包(参考);这些命令将在每个节点加入集群时运行。注意,对于生产环境,建议将任何必要的包构建到容器镜像中。

  • 你可以使用 ray rsync_up 将本地文件推送到集群 (参考)。

运行时环境#

备注

此功能需要使用 pip install "ray[default]" 进行 Ray 的完整安装。此功能从 Ray 1.4.0 版本开始可用,目前支持 macOS 和 Linux,Windows 上提供 beta 支持。

第二种设置依赖项的方法是在 Ray 运行时动态安装它们。

运行时环境 描述了您的 Ray 应用程序运行所需的依赖项,包括 文件、包、环境变量等。它会在集群运行时动态安装,并缓存以供将来使用(有关生命周期的详细信息,请参阅 缓存和垃圾回收)。

如果使用了 Ray 集群启动器 ,可以在其准备的环境之上使用运行时环境。例如,您可以使用集群启动器安装一组基础包,然后使用运行时环境安装额外的包。与基础集群环境相比,运行时环境仅对 Ray 进程有效。(例如,如果使用指定 pipmy_pkg 的运行时环境,在 Ray 任务、角色或作业之外调用 import my_pkg 将会失败。)

运行时环境还允许您在长时间运行的 Ray 集群上为每个任务、每个执行者和每个作业设置依赖项。

import ray

runtime_env = {"pip": ["emoji"]}

ray.init(runtime_env=runtime_env)

@ray.remote
def f():
  import emoji
  return emoji.emojize('Python is :thumbs_up:')

print(ray.get(f.remote()))
Python is 👍

运行时环境可以用一个 Python dict 来描述:

runtime_env = {
    "pip": ["emoji"],
    "env_vars": {"TF_WARNINGS": "none"}
}

或者,你可以使用 ray.runtime_env.RuntimeEnv:

from ray.runtime_env import RuntimeEnv
runtime_env = RuntimeEnv(
    pip=["emoji"],
    env_vars={"TF_WARNINGS": "none"}
)

更多示例,请跳转到 API 参考

你可以指定运行时环境的两个主要范围:

为每个作业指定运行时环境#

你可以为整个作业指定一个运行时环境,无论是直接在集群上运行脚本,使用 Ray Jobs API,还是提交一个 KubeRay RayJob

# Option 1: Starting a single-node local Ray cluster or connecting to existing local cluster
ray.init(runtime_env=runtime_env)
# Option 2: Using Ray Jobs API (Python SDK)
from ray.job_submission import JobSubmissionClient

client = JobSubmissionClient("http://<head-node-ip>:8265")
job_id = client.submit_job(
    entrypoint="python my_ray_script.py",
    runtime_env=runtime_env,
)
# Option 3: Using Ray Jobs API (CLI). (Note: can use --runtime-env to pass a YAML file instead of an inline JSON string.)
$ ray job submit --address="http://<head-node-ip>:8265" --runtime-env-json='{"working_dir": "/data/my_files", "pip": ["emoji"]}' -- python my_ray_script.py
# Option 4: Using KubeRay RayJob. You can specify the runtime environment in the RayJob YAML manifest.
# [...]
spec:
  runtimeEnvYAML: |
    pip:
      - requests==2.26.0
      - pendulum==2.1.2
    env_vars:
      KEY: "VALUE"

警告

submit_jobray job submit 调用中指定 runtime_env 参数,确保在运行入口脚本之前,运行时环境已在集群上安装。

如果从 ray.init(runtime_env=...) 中指定了 runtime_env,运行时环境仅应用于所有子任务和参与者,而不应用于入口脚本(驱动程序)本身。

如果 runtime_env 同时由 ray job submitray.init 指定,运行时环境将被合并。更多详情请参见 作业和驱动程序同时指定的运行时环境

备注

关于何时安装运行时环境,有两种选择:

  1. 一旦作业开始(即,一旦调用 ray.init()),依赖项就会被立即下载并安装。

  2. 依赖项仅在调用任务或创建角色时安装。

默认选项是选项1。要更改为选项2的行为,请在 runtime_envconfig 中添加 "eager_install": False

为每个任务或每个角色指定运行时环境#

你可以使用 .options()@ray.remote 装饰器为每个actor或每个任务指定不同的运行时环境:

# Invoke a remote task that will run in a specified runtime environment.
f.options(runtime_env=runtime_env).remote()

# Instantiate an actor that will run in a specified runtime environment.
actor = SomeClass.options(runtime_env=runtime_env).remote()

# Specify a runtime environment in the task definition.  Future invocations via
# `g.remote()` will use this runtime environment unless overridden by using
# `.options()` as above.
@ray.remote(runtime_env=runtime_env)
def g():
    pass

# Specify a runtime environment in the actor definition.  Future instantiations
# via `MyClass.remote()` will use this runtime environment unless overridden by
# using `.options()` as above.
@ray.remote(runtime_env=runtime_env)
class MyClass:
    pass

这允许你在自己的环境中运行演员和任务,独立于周围的环境。(周围的环境可能是作业的运行时环境,或者是集群的系统环境。)

警告

Ray 不保证具有冲突运行时环境的任务和角色之间的兼容性。例如,如果一个运行时环境包含 pip 包的角色尝试与另一个具有该包不同版本的角色通信,可能会导致意外行为,如解封错误。

常见工作流程#

本节介绍了一些运行时环境的常见用例。这些用例并不互斥;下面描述的所有选项都可以在单个运行时环境中组合使用。

使用本地文件#

您的 Ray 应用程序可能依赖于源文件或数据文件。在开发工作流程中,这些文件可能位于您的本地机器上,但当需要大规模运行时,您需要将它们传输到远程集群。

以下简单示例解释了如何将本地文件上传到集群。

import os
import ray

os.makedirs("/tmp/runtime_env_working_dir", exist_ok=True)
with open("/tmp/runtime_env_working_dir/hello.txt", "w") as hello_file:
  hello_file.write("Hello World!")

# Specify a runtime environment for the entire Ray job
ray.init(runtime_env={"working_dir": "/tmp/runtime_env_working_dir"})

# Create a Ray task, which inherits the above runtime env.
@ray.remote
def f():
    # The function will have its working directory changed to its node's
    # local copy of /tmp/runtime_env_working_dir.
    return open("hello.txt").read()

print(ray.get(f.remote()))
Hello World!

备注

上面的示例是为在本地机器上运行而编写的,但对于所有这些示例,当指定一个要连接的 Ray 集群时,它也同样适用(例如,使用 ray.init("ray://123.456.7.89:10001", runtime_env=...)ray.init(address="auto", runtime_env=...))。

当调用 ray.init() 时,指定的本地目录将自动推送到集群节点。

您还可以通过远程云存储URI指定文件;详情请参阅 远程URI

如果你指定了一个 working_dir,Ray 总是会先准备好它,并且在创建其他运行时环境时,它存在于 ${RAY_RUNTIME_ENV_CREATE_WORKING_DIR} 环境变量中。这种顺序允许 pipconda 引用 working_dir 中的本地文件,如 requirements.txtenvironment.yml。更多详情请参见 API 参考 中的 pipconda 部分。

使用 condapip#

你的 Ray 应用程序可能通过 import 语句依赖于 Python 包(例如,pendulumrequests)。

Ray 通常期望所有导入的包在集群的每个节点上都是预先安装的;特别是,这些包不会自动从您的本地机器发送到集群或从任何仓库下载。

然而,通过使用运行时环境,您可以动态指定要自动下载并安装在 Ray 作业的虚拟环境中,或特定 Ray 任务或角色的软件包。

import ray
import requests

# This example runs on a local machine, but you can also do
# ray.init(address=..., runtime_env=...) to connect to a cluster.
ray.init(runtime_env={"pip": ["requests"]})

@ray.remote
def reqs():
    return requests.get("https://www.ray.io/").status_code

print(ray.get(reqs.remote()))
200

您还可以通过Python列表或本地``requirements.txt``文件指定``pip``依赖项。当您的``pip install``命令需要诸如``–extra-index-url``或``–find-links``等选项时,请考虑指定一个``requirements.txt``文件;详情请参见`<https://pip.pypa.io/en/stable/reference/requirements-file-format/#>`_。或者,您可以指定一个``conda``环境,无论是作为Python字典还是通过本地的``environment.yml``文件。此conda环境可以包含``pip``包。详情请参阅:ref:API参考 <runtime-environments-api-ref>

警告

由于 runtime_env 中的包是在运行时安装的,因此在指定需要从源代码构建安装的 condapip 包时要谨慎,因为这可能会很慢。

备注

当使用 "pip" 字段时,指定的包将使用 virtualenv 安装在基础环境之上,因此集群上现有的包仍然可以导入。相比之下,当使用 conda 字段时,您的 Ray 任务和角色将在隔离环境中运行。condapip 字段不能在单个 runtime_env 中同时使用。

备注

ray[default] 包本身将自动安装在环境中。对于 conda 字段,如果你使用了其他 Ray 库(例如,Ray Serve),那么你需要在运行时环境中指定该库(例如,runtime_env = {"conda": {"dependencies": ["pytorch", "pip", {"pip": ["requests", "ray[serve]"]}]}}。)

备注

conda 环境必须与 Ray 集群的 Python 版本相同。不要在 conda 依赖项中列出 ray ,因为它会自动安装。

库开发#

假设你正在Ray上开发一个名为 my_module 的库。

一个典型的迭代周期将涉及

  1. my_module 的源代码进行一些修改

  2. 运行一个Ray脚本来测试更改,可能在分布式集群上进行。

为了确保你的本地更改能在所有 Ray 工作节点上显示并能被正确导入,请使用 py_modules 字段。

import ray
import my_module

ray.init("ray://123.456.7.89:10001", runtime_env={"py_modules": [my_module]})

@ray.remote
def test_my_module():
    # No need to import my_module inside this function.
    my_module.test()

ray.get(f.remote())

注意:此功能目前仅限于那些作为包的模块,这些包包含一个包含 __init__.py 文件的单一目录。对于单文件模块,您可以使用 working_dir

API 参考#

runtime_env 是一个 Python 字典或一个 Python 类 ray.runtime_env.RuntimeEnv,包含以下一个或多个字段:

  • working_dir (str): 指定 Ray 工作者的工目录。这必须是以下之一:(1) 一个总大小最多为 100 MiB 的本地现有目录,(2) 一个总解压大小最多为 100 MiB 的本地现有压缩文件(注意:excludes 无效),或 (3) 一个包含作业工作目录的远程存储的压缩文件的 URI(Ray 不强制执行文件大小限制)。详情请参阅 远程URI。指定的目录将被下载到集群中的每个节点,Ray 工作者将在其节点副本的该目录中启动。

    • 示例

      • "."  # 当前工作目录

      • "/src/my_project"

      • "/src/my_project.zip"

      • "s3://path/to/my_dir.zip"

    注意:目前不支持为每个任务或每个执行者设置本地目录;它只能按作业设置(即在 ray.init() 中)。

    注意:如果本地目录包含一个 .gitignore 文件,其中指定的文件和路径不会上传到集群。你可以通过在执行上传的机器上设置环境变量 RAY_RUNTIME_ENV_IGNORE_GITIGNORE=1 来禁用此功能。

    注意:如果本地目录包含符号链接,Ray 会跟随这些链接,并且它们指向的文件会被上传到集群。

  • py_modules (List[str|module]): 指定在 Ray 工作进程中可导入的 Python 模块。(有关指定包的其他方式,请参阅下面的 pipconda 字段。)每个条目必须是以下之一:(1) 本地目录的路径,(2) 远程 zip 或 wheel 文件的 URI(详情请参阅 远程URI),(3) Python 模块对象,或 (4) 本地 .whl 文件的路径。

    • 列表中的条目示例:

      • "."

      • "/local_dependency/my_module"

      • "s3://bucket/my_module.zip"

      • my_module # 假设 my_module 已经被导入,例如通过 ‘import my_module’

      • my_module.whl

      • "s3://bucket/my_module.whl"

    模块将被下载到集群中的每个节点。

    注意:目前不支持按任务或按角色设置选项 (1)、(3) 和 (4),只能按作业设置(即在 ray.init() 中设置)。

    注意:对于选项(1),如果本地目录包含一个 .gitignore 文件,则其中指定的文件和路径不会上传到集群。您可以通过在执行上传的机器上设置环境变量 RAY_RUNTIME_ENV_IGNORE_GITIGNORE=1 来禁用此功能。

    注意:此功能目前仅限于那些作为包的模块,这些包包含一个包含 __init__.py 文件的单一目录。对于单文件模块,您可以使用 working_dir

  • excludes (List[str]): 当与 working_dirpy_modules 一起使用时,指定一个要从上传到集群中排除的文件或路径列表。此字段使用 .gitignore 文件的匹配语法:详见 https://git-scm.com/docs/gitignore。注意:根据 .gitignore 语法,如果模式的开头或中间(或两者)有分隔符(/),则该模式被解释为相对于 working_dir 的级别。特别是,你不应该在 excludes 中使用绝对路径(例如 /Users/my_working_dir/subdir/);相反,你应该使用相对路径 /subdir/`(此处使用前导 `/`` 来仅匹配顶层的 subdir 目录,而不是所有级别的名为 subdir 的目录。)

    • 示例: {"working_dir": "/Users/my_working_dir/", "excludes": ["my_file.txt", "/subdir/", "path/to/dir", "*.log"]}

  • pip (字典 | 列表[字符串] | 字符串): 可以是以下三种之一:(1) 包含 requirements specifiers 的 pip 列表,(2) 包含本地 pip “requirements.txt” 文件路径的字符串,或 (3) 包含三个字段的 Python 字典:(a) packages (必填, 列表[字符串]): pip 包的列表,(b) pip_check (可选, 布尔值): 是否在 pip 安装结束时启用 pip check,默认为 False。(c) pip_version (可选, 字符串): pip 的版本;Ray 会在 pip_version 前加上 “pip” 形成最终的要求字符串。要求说明符的语法在 PEP 508 中有详细定义。这将在 Ray 工作进程运行时安装。预安装在集群环境中的包仍然可用。要使用 Ray Serve 或 Ray Tune 等库,您需要在此处包含 "ray[serve]""ray[tune]"。Ray 版本必须与集群版本匹配。

    • 示例: ["requests==1.0.0", "aiohttp", "ray[serve]"]

    • 示例: "./requirements.txt"

    • 示例: {"packages":["tensorflow", "requests"], "pip_check": False, "pip_version": "==22.0.2;python_version=='3.8.11'"}

    当指定一个 requirements.txt 文件的路径时,该文件必须存在于您的本地机器上,并且它必须是一个有效的绝对路径或相对于您本地当前工作目录的相对文件路径,而不是相对于 runtime_env 中指定的 working_dir 的相对路径。此外,在 requirements.txt 文件中引用本地文件并不直接支持(例如,-r ./my-laptop/more-requirements.txt./my-pkg.whl)。相反,在创建过程中使用 ${RAY_RUNTIME_ENV_CREATE_WORKING_DIR} 环境变量。例如,使用 -r ${RAY_RUNTIME_ENV_CREATE_WORKING_DIR}/my-laptop/more-requirements.txt${RAY_RUNTIME_ENV_CREATE_WORKING_DIR}/my-pkg.whl 来引用本地文件,同时确保它们位于 working_dir 中。

  • conda (dict | str): 可以是以下三种之一:(1) 一个表示 conda 环境 YAML 的字典,(2) 一个包含本地 conda “environment.yml” 文件路径的字符串,或者 (3) 集群中每个节点上已安装的本地 conda 环境名称(例如,"pytorch_p36")或其绝对路径(例如,"/home/youruser/anaconda3/envs/pytorch_p36")。在前两种情况下,Ray 和 Python 依赖项将自动注入到环境中以确保兼容性,因此无需手动包含它们。Python 和 Ray 版本必须与集群的版本匹配,因此您可能不应该手动指定它们。请注意,runtime_envcondapip 键不能同时指定——要一起使用它们,请使用 conda 并在 conda 的 environment.yaml 中的 "pip" 字段添加您的 pip 依赖项。

    • 示例: {"dependencies": ["pytorch", "torchvision", "pip", {"pip": ["pendulum"]}]}

    • 示例: "./environment.yml"

    • 示例: "pytorch_p36"

    • 示例: "/home/youruser/anaconda3/envs/pytorch_p36"

    当指定一个 environment.yml 文件的路径时,该文件必须存在于您的本地机器上,并且它必须是一个有效的绝对路径或相对于您本地当前工作目录的相对路径,而不是相对于 runtime_env 中指定的 working_dir 的相对路径。此外,在 environment.yml 文件中引用本地文件并不直接支持(例如,-r ./my-laptop/more-requirements.txt./my-pkg.whl)。相反,在创建过程中使用 ${RAY_RUNTIME_ENV_CREATE_WORKING_DIR} 环境变量。例如,使用 -r ${RAY_RUNTIME_ENV_CREATE_WORKING_DIR}/my-laptop/more-requirements.txt${RAY_RUNTIME_ENV_CREATE_WORKING_DIR}/my-pkg.whl 来引用本地文件,同时确保它们在 working_dir 中。

  • env_vars (Dict[str, str]): 要设置的环境变量。已经在集群上设置的环境变量仍然对 Ray 工作进程可见;因此,不需要在 env_vars 字段中包含 os.environ 或类似内容。默认情况下,这些环境变量会覆盖集群上同名的环境变量。你也可以使用 ${ENV_VAR} 引用现有的环境变量来实现追加行为。如果环境变量不存在,它将变为空字符串 ""

    • 示例: {"OMP_NUM_THREADS": "32", "TF_WARNINGS": "none"}

    • 示例: {"LD_LIBRARY_PATH": "${LD_LIBRARY_PATH}:/home/admin/my_lib"}

    • 不存在的变量示例:{"ENV_VAR_NOT_EXIST": "${ENV_VAR_NOT_EXIST}:/home/admin/my_lib"} -> ENV_VAR_NOT_EXIST=":/home/admin/my_lib"

  • nsight (Union[str, Dict[str, str]]): 指定 Nsight System Profiler 的配置。值可以是 (1) “default”,它指的是 默认配置,或者 (2) 一个包含 Nsight System Profiler 选项及其值的字典。有关设置和使用的更多详细信息,请参阅 这里

    • 示例:"default"

    • 示例: {"stop-on-exit": "true", "t": "cuda,cublas,cudnn", "ftrace": ""}

  • container (dict): 需要一个给定的 (Docker) 镜像,工作进程将在使用此镜像的容器中运行。worker_path 是 default_worker.py 的路径。仅当容器中的 ray 安装目录与 raylet 主机不同时才需要此项。run_options 列表规范在 这里

    • 示例: {"image": "anyscale/ray:2.31.0-py39-cpu", "worker_path": "/root/python/ray/workers/default_worker.py", "run_options": ["--cap-drop SYS_ADMIN","--log-level=debug"]}

    注意:container 目前是实验性的。如果您有任何需求或遇到任何问题,请在 github 提出问题。

  • config (dict | ray.runtime_env.RuntimeEnvConfig): 运行时环境的配置。可以是字典或 RuntimeEnvConfig。字段:(1) setup_timeout_seconds,运行时环境创建的超时时间,超时时间以秒为单位。

    • 示例: {"setup_timeout_seconds": 10}

    • 示例: RuntimeEnvConfig(setup_timeout_seconds=10)

    (2) eager_install (bool): Indicates whether to install the runtime environment on the cluster at ray.init() time, before the workers are leased. This flag is set to True by default. If set to False, the runtime environment will be only installed when the first task is invoked or when the first actor is created. Currently, specifying this option per-actor or per-task is not supported.

    • 示例: {"eager_install": False}

    • 示例: RuntimeEnvConfig(eager_install=False)

缓存和垃圾回收#

每个节点上的运行时环境资源(如 conda 环境、pip 包或下载的 working_dirpy_modules 目录)将被缓存在集群中,以便在作业内的不同运行时环境中快速重用。每个字段(working_dirpy_modules 等)都有自己的缓存,其大小默认为 10 GB。要更改此默认值,您可以在集群中的每个节点上启动 Ray 之前设置环境变量 RAY_RUNTIME_ENV_<field>_CACHE_SIZE_GB,例如 export RAY_RUNTIME_ENV_WORKING_DIR_CACHE_SIZE_GB=1.5

当缓存大小限制被超过时,当前未被任何Actor、任务或作业使用的资源将被删除。

由作业和驱动程序指定的运行时环境#

当运行一个入口点脚本(Driver)时,可以通过 ray.init(runtime_env=...)ray job submit --runtime-env 来指定运行时环境(更多详情请参见 为每个作业指定运行时环境)。

  • 如果运行时环境由 ray job submit --runtime-env=... 指定,则运行时环境将应用于入口点脚本(驱动程序)以及由此创建的所有任务和参与者。

  • 如果运行时环境由 ray.init(runtime_env=...) 指定,运行时环境将应用于所有任务和角色,但不适用于入口脚本(驱动程序)本身。

由于 ray job submit 提交了一个调用 ray.init 的驱动程序,有时它们的运行时环境都会被指定。当 Ray Job 和驱动程序都指定了运行时环境时,如果没有冲突,它们的运行时环境会被合并。这意味着驱动程序脚本使用 ray job submit 指定的运行时环境,而所有任务和角色将使用合并后的运行时环境。如果运行时环境存在冲突,Ray 会抛出异常。

  • ray job submit --runtime-env=... 中的 runtime_env["env_vars"]ray.init(runtime_env=...) 中的 runtime_env["env_vars"] 合并。请注意,每个单独的 env_var 键都会被合并。如果环境变量冲突,Ray 会引发异常。

  • runtime_env 中的每个其他字段都将被合并。如果有任何键冲突,则会引发异常。

示例:

# `ray job submit --runtime_env=...`
{"pip": ["requests", "chess"],
"env_vars": {"A": "a", "B": "b"}}

# ray.init(runtime_env=...)
{"env_vars": {"C": "c"}}

# Driver's actual `runtime_env` (merged with Job's)
{"pip": ["requests", "chess"],
"env_vars": {"A": "a", "B": "b", "C": "c"}}

冲突示例:

# Example 1, env_vars conflicts
# `ray job submit --runtime_env=...`
{"pip": ["requests", "chess"],
"env_vars": {"C": "a", "B": "b"}}

# ray.init(runtime_env=...)
{"env_vars": {"C": "c"}}

# Ray raises an exception because the "C" env var conflicts.

# Example 2, other field (e.g., pip) conflicts
# `ray job submit --runtime_env=...`
{"pip": ["requests", "chess"]}

# ray.init(runtime_env=...)
{"pip": ["torch"]}

# Ray raises an exception because "pip" conflicts.

你可以设置环境变量 RAY_OVERRIDE_JOB_RUNTIME_ENV=1 以避免在冲突时引发异常。在这种情况下,运行时环境以与 驱动程序和任务和参与者都指定运行时环境 相同的方式继承,其中 ray job submit 是父级,ray.init 是子级。

继承#

运行时环境是可继承的,因此它适用于作业中的所有任务和角色,以及任务或角色设置后的所有子任务和角色,除非被覆盖。

如果一个 Actor 或 Task 指定了一个新的 runtime_env,它将覆盖父级的 runtime_env``(即父 Actor Task ``runtime_env,或者如果 Actor 或 Task 没有父级,则覆盖 Job 的 runtime_env),如下所示:

  • runtime_env["env_vars"] 字段将与父级的 runtime_env["env_vars"] 字段合并。这允许父级运行时环境中的环境变量自动传播到子级,即使子级的运行时环境中设置了新的环境变量。

  • runtime_env 中的每个其他字段都将被子对象 覆盖,而不是合并。例如,如果指定了 runtime_env["py_modules"],它将替换父对象的 runtime_env["py_modules"] 字段。

示例:

# Parent's `runtime_env`
{"pip": ["requests", "chess"],
"env_vars": {"A": "a", "B": "b"}}

# Child's specified `runtime_env`
{"pip": ["torch", "ray[serve]"],
"env_vars": {"B": "new", "C": "c"}}

# Child's actual `runtime_env` (merged with parent's)
{"pip": ["torch", "ray[serve]"],
"env_vars": {"A": "a", "B": "new", "C": "c"}}

常见问题#

环境是否安装在每个节点上?#

如果在 ray.init(runtime_env=...) 中指定了运行时环境,那么该环境将被安装在每个节点上。更多详情请参见 每个作业。(注意,默认情况下,运行时环境将急切地在集群中的每个节点上安装。如果希望按需延迟安装运行时环境,请将 eager_install 选项设置为 false: ray.init(runtime_env={..., "config": {"eager_install": False}})。)

环境何时安装?#

当按作业指定时,环境会在调用 ray.init() 时安装(除非设置了 "eager_install": False)。当按任务或按角色指定时,环境会在任务被调用或角色被实例化时安装(即当你调用 my_task.remote()my_actor.remote() 时。)更多详情请参见 按作业 按任务/角色,在作业内

环境缓存在哪里?#

环境下载的任何本地文件都缓存在 /tmp/ray/session_latest/runtime_resources

安装或从缓存加载需要多长时间?#

安装时间通常主要由运行 pip installconda create / conda activate 所需的时间,或者上传/下载 working_dir 所需的时间组成,具体取决于您使用的 runtime_env 选项。这可能需要几秒钟或几分钟。

另一方面,从缓存加载运行时环境的速度应该与普通 Ray 工作进程启动时间几乎一样快,大约几秒钟。每个需要新运行时环境的 Ray 角色或任务都会启动一个新的 Ray 工作进程。(请注意,加载缓存的 conda 环境可能仍然很慢,因为 conda activate 命令有时需要几秒钟。)

你可以设置 setup_timeout_seconds 配置以避免安装过程长时间挂起。如果安装在此时间内未完成,你的任务或角色将无法启动。

运行时环境和Docker之间的关系是什么?#

它们可以独立使用或一起使用。可以在 集群启动器 中指定容器镜像用于大型或静态依赖项,并且可以为每个作业或每个任务/角色指定运行时环境,以满足更动态的使用场景。运行时环境将从容器镜像继承包、文件和环境变量。

我的 runtime_env 已安装,但当我登录到节点时,无法导入包。#

运行时环境仅对 Ray 工作进程有效;它不会在节点上“全局”安装任何包。

远程URI#

runtime_env 字典中的 working_dirpy_modules 参数可以指定本地路径或远程URI。

本地路径必须是一个目录路径。该目录的内容将直接作为 working_dirpy_module 访问。远程URI必须是一个直接指向zip文件或wheel文件的链接(仅适用于 py_module)。zip文件必须只包含一个顶级目录。 该目录的内容将直接作为 working_dirpy_module 访问。

例如,假设您想使用本地 /some_path/example_dir 目录中的内容作为您的 working_dir。如果您想将此目录指定为本地路径,您的 runtime_env 字典应包含:

runtime_env = {..., "working_dir": "/some_path/example_dir", ...}

假设你希望将文件托管在远程的 /some_path/example_dir 目录中,并提供一个远程URI。你需要先将 example_dir 目录压缩成一个zip文件。

在zip文件的顶层不应该有其他文件或目录,除了 example_dir 。你可以在终端中使用以下命令来完成这个操作:

cd /some_path
zip -r zip_file_name.zip example_dir

请注意,此命令必须从所需的 working_dir父目录 运行,以确保生成的 zip 文件包含一个单一的顶级目录。通常,zip 文件的名称和顶级目录的名称可以是任何名称。顶级目录的内容将被用作 working_dir``(或 ``py_module)。

你可以在终端运行以下命令,检查zip文件是否包含一个单一的顶级目录:

zipinfo -1 zip_file_name.zip
# example_dir/
# example_dir/my_file_1.txt
# example_dir/subdir/my_file_2.txt

假设你将压缩的 example_dir 目录上传到 S3 URI 为 s3://example_bucket/example.zip 的 AWS S3。你的 runtime_env 字典应包含:

runtime_env = {..., "working_dir": "s3://example_bucket/example.zip", ...}

警告

检查压缩依赖中的隐藏文件和元数据目录。您可以通过在终端中运行 zipinfo -1 zip_file_name.zip 命令来检查zip文件的内容。某些压缩方法可能会导致隐藏文件或元数据目录出现在zip文件的顶层。为了避免这种情况,请直接从其父目录使用 zip -r 命令压缩您想要压缩的目录。例如,如果您有一个目录结构如:a/b,并且您想要压缩 b,请从目录 a 发出 zip -r b 命令。如果Ray检测到顶层有多个目录,它将使用整个zip文件而不是顶层目录,这可能会导致意外行为。

目前,支持三种类型的远程URI用于托管 working_dirpy_modules 包:

  • HTTPS: HTTPS 指的是以 https 开头的URL。这些URL特别有用,因为远程Git提供商(例如GitHub、Bitbucket、GitLab等)使用 https URL 作为仓库归档的下载链接。这使您能够将依赖项托管在远程Git提供商上,向其推送更新,并指定您的作业应使用的依赖项版本(即提交)。要通过 HTTPS URI 使用包,您必须拥有 smart_open 库(您可以使用 pip install smart_open 安装它)。

    • 示例:

      • runtime_env = {"working_dir": "https://github.com/example_username/example_respository/archive/HEAD.zip"}

  • S3: S3 指的是以 s3:// 开头的 URI,这些 URI 指向存储在 AWS S3 中的压缩包。要通过 S3 URI 使用包,您必须拥有 smart_openboto3 库(您可以使用 pip install smart_openpip install boto3 安装它们)。Ray 不会显式地将任何凭证传递给 boto3 进行身份验证。boto3 将使用您的环境变量、共享凭证文件和/或 AWS 配置文件来验证访问。请参阅 AWS boto3 文档 以了解如何配置这些内容。

    • 示例:

      • runtime_env = {"working_dir": "s3://example_bucket/example_file.zip"}

  • GS: GS 指的是以 gs:// 开头的 URI,这些 URI 指向存储在 Google Cloud Storage 中的压缩包。要通过 GS URI 使用包,您必须拥有 smart_opengoogle-cloud-storage 库(您可以使用 pip install smart_openpip install google-cloud-storage 安装它们)。Ray 不会显式地将任何凭据传递给 google-cloud-storageClient 对象。google-cloud-storage 将默认使用您的本地服务账户密钥和环境变量。请按照 Google Cloud Storage 的 Getting started with authentication 指南设置您的凭据,这将允许 Ray 访问您的远程包。

    • 示例:

      • runtime_env = {"working_dir": "gs://example_bucket/example_file.zip"}

请注意,smart_openboto3google-cloud-storage 包默认情况下不会安装,仅在 runtime_envpip 部分指定它们是不够的。相关包必须在 Ray 启动时已经安装在集群的所有节点上。

在远程Git提供商上托管依赖项:分步指南#

您可以将依赖项存储在远程Git提供商(例如GitHub、Bitbucket、GitLab等)的仓库中,并且可以定期推送更改以保持其更新。在本节中,您将学习如何在GitHub上存储依赖项并在您的运行时环境中使用它。

备注

如果你使用其他大型远程Git服务提供商(例如BitBucket、GitLab等),这些步骤也同样有用。为了简单起见,本节仅提及GitHub,但你可以在你的服务提供商上按照这些步骤操作。

首先,在 GitHub 上创建一个仓库来存储你的 working_dir 内容或你的 py_module 依赖项。默认情况下,当你下载仓库的 zip 文件时,zip 文件已经包含一个顶层目录来存放仓库内容,因此你可以直接将你的 working_dir 内容或你的 py_module 依赖项上传到 GitHub 仓库。

一旦你上传了你的 working_dir 内容或你的 py_module 依赖项,你需要仓库zip文件的HTTPS URL,这样你可以在你的 runtime_env 字典中指定它。

您有两种获取HTTPS URL的选项。

调试#

如果无法设置 runtime_env(例如,网络问题、下载失败等),Ray 将无法调度需要 runtime_env 的任务/角色。如果你调用 ray.get,它将引发 RuntimeEnvSetupError,并附带详细的错误信息。

import ray
import time

@ray.remote
def f():
    pass

@ray.remote
class A:
    def f(self):
        pass

start = time.time()
bad_env = {"conda": {"dependencies": ["this_doesnt_exist"]}}

# [Tasks] will raise `RuntimeEnvSetupError`.
try:
  ray.get(f.options(runtime_env=bad_env).remote())
except ray.exceptions.RuntimeEnvSetupError:
  print("Task fails with RuntimeEnvSetupError")

# [Actors] will raise `RuntimeEnvSetupError`.
a = A.options(runtime_env=bad_env).remote()
try:
  ray.get(a.f.remote())
except ray.exceptions.RuntimeEnvSetupError:
  print("Actor fails with RuntimeEnvSetupError")
Task fails with RuntimeEnvSetupError
Actor fails with RuntimeEnvSetupError

完整的日志始终可以在每个执行者、每个任务和每个作业环境的文件 runtime_env_setup-[job_id].log 中找到,或者在使用 Ray Client 时的每个作业环境的文件 runtime_env_setup-ray_client_server_[port].log 中找到。

你还可以通过在启动 Ray 之前在每个节点上设置环境变量 RAY_RUNTIME_ENV_LOG_TO_DRIVER_ENABLED=1 来启用 runtime_env 调试日志流,例如在 Ray 集群配置文件中使用 setup_commands``(:ref:`参考 <cluster-configuration-setup-commands>`)。这将把完整的 ``runtime_env 设置日志消息打印到驱动程序(调用 ray.init() 的脚本)。

示例日志输出:

ray.init(runtime_env={"pip": ["requests"]})
(pid=runtime_env) 2022-02-28 14:12:33,653       INFO pip.py:188 -- Creating virtualenv at /tmp/ray/session_2022-02-28_14-12-29_909064_87908/runtime_resources/pip/0cc818a054853c3841171109300436cad4dcf594/virtualenv, current python dir /Users/user/anaconda3/envs/ray-py38
(pid=runtime_env) 2022-02-28 14:12:33,653       INFO utils.py:76 -- Run cmd[1] ['/Users/user/anaconda3/envs/ray-py38/bin/python', '-m', 'virtualenv', '--app-data', '/tmp/ray/session_2022-02-28_14-12-29_909064_87908/runtime_resources/pip/0cc818a054853c3841171109300436cad4dcf594/virtualenv_app_data', '--reset-app-data', '--no-periodic-update', '--system-site-packages', '--no-download', '/tmp/ray/session_2022-02-28_14-12-29_909064_87908/runtime_resources/pip/0cc818a054853c3841171109300436cad4dcf594/virtualenv']
(pid=runtime_env) 2022-02-28 14:12:34,267       INFO utils.py:97 -- Output of cmd[1]: created virtual environment CPython3.8.11.final.0-64 in 473ms
(pid=runtime_env)   creator CPython3Posix(dest=/private/tmp/ray/session_2022-02-28_14-12-29_909064_87908/runtime_resources/pip/0cc818a054853c3841171109300436cad4dcf594/virtualenv, clear=False, no_vcs_ignore=False, global=True)
(pid=runtime_env)   seeder FromAppData(download=False, pip=bundle, setuptools=bundle, wheel=bundle, via=copy, app_data_dir=/private/tmp/ray/session_2022-02-28_14-12-29_909064_87908/runtime_resources/pip/0cc818a054853c3841171109300436cad4dcf594/virtualenv_app_data)
(pid=runtime_env)     added seed packages: pip==22.0.3, setuptools==60.6.0, wheel==0.37.1
(pid=runtime_env)   activators BashActivator,CShellActivator,FishActivator,NushellActivator,PowerShellActivator,PythonActivator
(pid=runtime_env)
(pid=runtime_env) 2022-02-28 14:12:34,268       INFO utils.py:76 -- Run cmd[2] ['/tmp/ray/session_2022-02-28_14-12-29_909064_87908/runtime_resources/pip/0cc818a054853c3841171109300436cad4dcf594/virtualenv/bin/python', '-c', 'import ray; print(ray.__version__, ray.__path__[0])']
(pid=runtime_env) 2022-02-28 14:12:35,118       INFO utils.py:97 -- Output of cmd[2]: 3.0.0.dev0 /Users/user/ray/python/ray
(pid=runtime_env)
(pid=runtime_env) 2022-02-28 14:12:35,120       INFO pip.py:236 -- Installing python requirements to /tmp/ray/session_2022-02-28_14-12-29_909064_87908/runtime_resources/pip/0cc818a054853c3841171109300436cad4dcf594/virtualenv
(pid=runtime_env) 2022-02-28 14:12:35,122       INFO utils.py:76 -- Run cmd[3] ['/tmp/ray/session_2022-02-28_14-12-29_909064_87908/runtime_resources/pip/0cc818a054853c3841171109300436cad4dcf594/virtualenv/bin/python', '-m', 'pip', 'install', '--disable-pip-version-check', '--no-cache-dir', '-r', '/tmp/ray/session_2022-02-28_14-12-29_909064_87908/runtime_resources/pip/0cc818a054853c3841171109300436cad4dcf594/requirements.txt']
(pid=runtime_env) 2022-02-28 14:12:38,000       INFO utils.py:97 -- Output of cmd[3]: Requirement already satisfied: requests in /Users/user/anaconda3/envs/ray-py38/lib/python3.8/site-packages (from -r /tmp/ray/session_2022-02-28_14-12-29_909064_87908/runtime_resources/pip/0cc818a054853c3841171109300436cad4dcf594/requirements.txt (line 1)) (2.26.0)
(pid=runtime_env) Requirement already satisfied: idna<4,>=2.5 in /Users/user/anaconda3/envs/ray-py38/lib/python3.8/site-packages (from requests->-r /tmp/ray/session_2022-02-28_14-12-29_909064_87908/runtime_resources/pip/0cc818a054853c3841171109300436cad4dcf594/requirements.txt (line 1)) (3.2)
(pid=runtime_env) Requirement already satisfied: certifi>=2017.4.17 in /Users/user/anaconda3/envs/ray-py38/lib/python3.8/site-packages (from requests->-r /tmp/ray/session_2022-02-28_14-12-29_909064_87908/runtime_resources/pip/0cc818a054853c3841171109300436cad4dcf594/requirements.txt (line 1)) (2021.10.8)
(pid=runtime_env) Requirement already satisfied: urllib3<1.27,>=1.21.1 in /Users/user/anaconda3/envs/ray-py38/lib/python3.8/site-packages (from requests->-r /tmp/ray/session_2022-02-28_14-12-29_909064_87908/runtime_resources/pip/0cc818a054853c3841171109300436cad4dcf594/requirements.txt (line 1)) (1.26.7)
(pid=runtime_env) Requirement already satisfied: charset-normalizer~=2.0.0 in /Users/user/anaconda3/envs/ray-py38/lib/python3.8/site-packages (from requests->-r /tmp/ray/session_2022-02-28_14-12-29_909064_87908/runtime_resources/pip/0cc818a054853c3841171109300436cad4dcf594/requirements.txt (line 1)) (2.0.6)
(pid=runtime_env)
(pid=runtime_env) 2022-02-28 14:12:38,001       INFO utils.py:76 -- Run cmd[4] ['/tmp/ray/session_2022-02-28_14-12-29_909064_87908/runtime_resources/pip/0cc818a054853c3841171109300436cad4dcf594/virtualenv/bin/python', '-c', 'import ray; print(ray.__version__, ray.__path__[0])']
(pid=runtime_env) 2022-02-28 14:12:38,804       INFO utils.py:97 -- Output of cmd[4]: 3.0.0.dev0 /Users/user/ray/python/ray

详情请参阅 日志目录结构