跳转至

Env Deps

Abstract

Ray 应用经常依赖于 Ray 脚本之外的内容,比如:

  • 依赖或导入某些 Python 包
  • 需要设置特定的环境变量
  • 需要访问脚本之外的其他文件

Reference: Environment Dependencies

在集群上运行任务时,需要注意:Ray 要求所有依赖项在每一个 Ray 节点上都可用。如果缺失,会出现诸如 ModuleNotFoundErrorFileNotFoundError 等错误。

解决方式主要有两种:

  1. 预先准备依赖 利用 Ray Cluster Launcher(集群启动器),提前将所有必须的依赖项准备好,比如通过定制容器镜像进行统一分发。
  2. 动态安装依赖 借助 Ray 的 Runtime Environments(运行时环境),在作业提交运行时自动按需安装依赖项。

建议

  • 生产环境依赖固定时,推荐将依赖项写入容器镜像中,并结合 Cluster Launcher 指定启动镜像,保证环境一致性和可复现性。
  • 开发或实验阶段,推荐使用 Ray 的 Runtime Environments 进行灵活、动态的依赖管理。

核心概念

  • Ray 应用程序(Ray Application):包含了 ray.init() 并使用 Ray Task 或 Actor 的 Python 脚本。
  • 依赖项 / 环境(Dependencies / Environment):指一切 Ray 脚本以外、程序运行时所需的内容,比如:外部代码文件、第三方库、数据、环境变量等。
  • 文件(Files):应用所需的代码文件、数据文件等。
  • 软件包(Packages):通过 pip、conda 等方式安装的第三方库或可执行文件。
  • 本地机器 & 集群(Local machine & Cluster):本地机器用于开发和提交作业,集群节点实际执行 Ray 任务(如通过 Ray Job 或 ray attach 提交/连接)。
  • 作业(Job):指同一个脚本下的一组 Ray 任务、对象和执行器的集合,是一个独立的 Ray 应用实例。

Cluster Launcher 预设环境

Ray 环境依赖预设的主要方式,是在启动 Ray 前为集群节点准备好所需的统一环境,常用手段包括:

  • 容器镜像:把代码、依赖库等全部打包进一个镜像中(如 Docker),在集群 YAML 配置的 docker.image 字段指定该镜像,实现环境完全一致。
  • setup_commands:在集群 YAML 的 setup_commands 配置项里加入安装依赖的软件包命令,这些命令将在每个新加入的节点初始化时自动执行。
  • 文件同步:用 ray rsync_up 命令,将本地代码或数据文件同步到集群各节点指定目录,保证文件在分布式环境下一致可用。

注意

生产环境建议将必要的软件包直接构建到容器镜像中,setup_commands 适用于补充小量依赖或调试。


Runtime environments

注意

需要通过 pip install "ray[default]" 完整安装 Ray 后使用本功能。Ray 1.4.0 起支持(macOS、Linux 可用,Windows 处于 Beta)。

Ray 的 运行时环境(Runtime Environment) 功能支持在任务或作业运行时,动态安装和分发所需的依赖,包括: - Python 包(第三方库) - 文件 - 环境变量等

Ray 会在作业提交时,将指定的依赖自动同步、安装到相关的集群节点,每项依赖只会被安装一次,并自动做本地缓存。

运行时环境非常适合和 Ray Cluster Launcher(基础环境预设)结合使用。例如:在镜像中预装常用依赖,实验性包通过运行时环境进行增量补充。

注意

运行时环境只对 Ray TaskActorJob 生效,不会影响节点的全局 Python 环境,如 shell 或交互式 Python 终端下无法直接 import 这些包。

你可以指定运行时环境的两个主要作用域:

  • 针对每个 Job
  • 针对 Job 内每个 Task 或 Actor

Ray 支持按 Task、Actor 和 Job 级别灵活配置依赖隔离,满足多样化协作和复杂项目的需求。

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"}
)

为每个 Job 指定运行时环境

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

选项 1:启动单节点本地集群或连接到现有本地集群

ray.init(runtime_env=runtime_env)

选项 2:使用 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,
)

选项 3:使用 Ray Jobs API (CLI)

注意:可以使用 --runtime-env 传递 YAML 文件,而不是行内 JSON 字符串。

ray job submit --address="http://<head-node-ip>:8265" \
    --runtime-env-json='{"working_dir": "/data/my_files", "pip": ["emoji"]}' \
    -- python my_ray_script.py

选项 4:使用 KubeRay RayJob

你可以在 RayJob YAML 清单中指定运行时环境:

# [...]
spec:
  runtimeEnvYAML: |
    pip:
      - requests==2.26.0
      - pendulum==2.1.2
    env_vars:
      KEY: "VALUE"


为每个 Task 或 Actor 指定运行时环境

你可以使用 .options() 方法或 @ray.remote 装饰器,为每个 Actor 或每个 Task 指定不同的运行时环境:

提示

.options() 的优先级最高,它会直接覆盖而非融合 @ray.remote 中的设置,你可以将装饰器配置视为“默认值”,而将 .options() 视为“运行时动态覆盖”。

# 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

这允许你的 Actor 和 Task 运行在各自独立的环境中,而不受周围环境的影响(周围环境可以是 Job 的运行时环境,也可以是集群的系统环境)。

注意

Ray 不保证具有冲突 runtime environments 的 Tasks 和 Actors 之间的兼容性。

例如,如果一个 runtime environment 中包含某个 pip 包的 Actor 尝试与另一个拥有该包不同版本的 Actor 进行通信,可能会导致不可预知的行为,例如 unpickling errors(反序列化错误)。


常见使用场景

本节介绍一些 runtime environments 的常见使用场景。这些场景并非互斥;下文描述的所有选项都可以在单个 runtime environment 中组合使用。


使用本地文件

你的 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://<head-ip>:10001", runtime_env=...)ray.init(address="auto", runtime_env=...))。

调用 ray.init() 并指定本地目录后,Ray 会自动将目录内容同步到集群各节点。

你还可以直接使用远程云存储(如 S3、GCS 等)的 URI;详情见官方文档的 Remote URIs 部分。

指定 working_dir 时,Ray 会优先创建和分发该目录,并将其路径写入环境变量 ${RAY_RUNTIME_ENV_CREATE_WORKING_DIR},方便 pipconda 等依赖工具在 requirements.txt、environment.yml 等文件中引用本地内容。


使用 condapip 软件包

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

通常情况下,Ray 期望所有导入的包都已预先安装在 Cluster 的每个节点上;具体来说,这些包不会自动从你的本地机器传输到 Cluster,也不会自动从任何仓库下载。

然而,通过使用 runtime environments,你可以动态指定要在虚拟环境中为你的 Ray Job、特定的 Ray Tasks 或 Actors 自动下载并安装的软件包。

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

runtime_env 作用范围

runtime_env 中指定的依赖包只会安装到 Ray worker 节点,不会安装到运行 driver 脚本的本机环境。若在脚本顶层(ray.init() 调用之前)直接 import 某个包,该包仍需在本地预先安装;否则脚本会在启动时就抛出 ModuleNotFoundError。推荐将只在远程任务中使用的包的 import 语句放在函数体内部,避免产生混淆。

你可以通过 Python 列表或本地的 requirements.txt 文件来指定 pip 依赖项。当你的 pip install 命令需要 --extra-index-url--find-links 等选项时,请考虑指定 requirements.txt 文件。此外,你也可以通过 Python 字典或本地的 environment.yml 文件来指定 conda 环境。这个 conda 环境可以包含 pip 包。

注意

由于 runtime_env 中的软件包是在运行时安装的,在指定那些涉及从源码构建(build from source)的 condapip 包时请务必小心,因为这可能会非常缓慢。

虚拟环境差异

pip 字段是在集群原有环境的基础上叠加安装新包,而 conda 字段会创建一个完全隔离的新环境,这两种方式不能混用,需要二选一。

  • 使用 pip 字段时:指定的包会借助 virtualenv 安装在原有环境“之上”,因此集群节点上原有的包依然可以被导入使用。
  • 使用 conda 字段时:Ray Tasks 和 Actors 会运行在一个完全隔离的新环境中,原有环境的包不会被继承。

⚠️ 注意:不能在同一个 runtime_env 字典的顶层同时指定 condapip 字段,否则会报错。

ray[default] 包本身会自动安装在环境

仅针对 conda 字段:如果你正在使用任何其他 Ray 库(例如 Ray Serve),则需要在 runtime_env 中显式指定该库。

runtime_env = {
    "conda": {
        "dependencies": [
            "pytorch",
            "pip",
            {"pip": ["requests", "ray[serve]"]}
        ]
    }
}

Python 版本一致性

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


使用 uv 进行包管理

推荐使用 uv 进行依赖管理,结合 runtime_envuv run 来启动任务。这一方式具有以下优势:

  • 依赖一致性:Driver 与 Ray Worker 节点会严格按照同一套锁定的依赖(pyproject.toml + uv.lock)环境运行,避免版本不一致问题。
  • 现代依赖生态:原生支持 pyproject.toml 配置(包括 editable 模式),满足主流 Python 项目需求。
  • 高效可复现:通过 uv lock 可以生成锁文件,保证环境的可复现与确定性。
使用步骤举例(同样支持 editable 包的使用)
  1. 在项目根目录新建 pyproject.toml

    [project]
    
    name = "test"
    
    version = "0.1"
    
    dependencies = [
    "emoji",
    "ray",
    ]
    
  2. 创建一个 test.py 脚本:

    import emoji
    import ray
    
    @ray.remote
    def f():
        return emoji.emojize('Python is :thumbs_up:')
    
    # Execute 1000 copies of f across a cluster.
    print(ray.get([f.remote() for _ in range(1000)]))
    
  3. 使用 uv run test.py 运行 Driver 脚本。这将在 Ray Cluster 的多个 Python Worker 进程中运行 1000 个 f 函数。此时,emoji 依赖不仅对主脚本可用,对所有 Worker 进程也同样可用。同时,当前工作目录下的源码也会同步到所有 Workers。

支持可编辑包

此工作流同样支持可编辑包,例如你可以使用 uv add --editable ./path/to/package(该路径必须在当前工作目录内)。

在 Ray Job 中使用 uv:使用上述举例中的两个文件,你可以通过以下命令提交 Ray Job:

ray job submit --working-dir . -- uv run test.py

该命令确保 Job 的 Driver 和 Workers 都运行在 pyproject.toml 指定的 uv 环境中。

在 Ray Serve 中使用 uv:配合相应的 pyproject.tomlapp.py 文件,你可以通过 uv run serve run app:main 运行 Ray Serve 应用程序。

最佳实践

  • 版本匹配:在 Ray Cluster 上运行时,uv 环境中的 Ray 和 Python 版本必须与集群保持一致,否则会触发版本不匹配异常。解决方式有以下几种:
    • 如果使用的是临时(ephemeral)Ray 集群,在具有正确版本的集群上运行应用。
    • 如果需要在版本不同的集群上运行,可以通过修改 pyproject.toml 来调整 uv 环境的版本,或在 uv run 时添加 --active 标志(即 uv run --active main.py)。
  • 锁定依赖:使用 uv lock 生成锁文件,冻结所有依赖版本,防止包的新版本发布后引发不可控的变化。
  • requirements.txt 迁移:如果你有 requirements.txt 文件,可以使用 uv add -r requirements.txt 将依赖添加到 pyproject.toml,再配合 uv run 使用。
  • 子目录中的 pyproject.toml:如果 pyproject.toml 位于某个子目录中,可以使用 uv run --project 从该目录加载配置。
  • 工作目录控制:如果使用 uv run 时需要将工作目录重置为当前目录以外的路径,使用 --directory 标志。Ray 的 uv 集成会自动将 working_dir 设置为对应路径。

高级操作 —— 灵活使用 py_executable

在底层实现中,uv run 的支持是通过一个底层的 runtime environment 插件 py_executable 实现的。它允许你指定 Ray Worker 启动时使用的 Python 可执行程序(包括参数)。

在使用 uv 的情况下,py_executable 会被设置为 uv run,并且使用与启动 driver 时相同的参数。同时,Ray 会使用 working_dir runtime environment 将 driver 的工作目录(包括 pyproject.toml) 传递到 worker 上。这样,uv 就能够为 worker 设置正确的依赖和运行环境。

在某些高级场景中,你可能希望在程序中直接使用 py_executable 机制:

  1. 具有异构依赖的应用:Ray 支持为不同的 Task 或 Actor 使用不同的 runtime environment。

    这对于以下场景非常有用:

    • 在 Ray Serve 的不同部署中运行不同的推理引擎、模型或微服务
    • 在 Ray Data 中构建具有不同依赖的异构数据处理流水线

    实现方式包括:

    • 为每个 runtime environment 指定不同的 py_executable,并使用带有不同 --project 参数的 uv run
    • 为每个环境指定不同的 working_dir
  2. 自定义 Worker 运行命令:在 worker 上,你可能希望对 uv 运行方式进行额外定制。 例如:

    • uv 添加 driver 没有使用的特殊参数
    • 使用 poetry run
    • 通过构建系统(例如 Bazel)运行
    • 在 profiler(性能分析工具) 或 debugger(调试器) 中运行进程

    在这些情况下,你可以通过 py_executable 显式指定 worker 使用的可执行命令。这个可执行程序甚至可以是一个存储在 working_dir 中的 shell 脚本,如果你需要以更复杂的方式封装或协调多个进程。

Note

uv 环境会被所有子 Tasks 和 Actors 继承。如果你想混合使用环境(例如在 uv run 中嵌套使用 pip 类型的 runtime environments),你需要将 Python 可执行文件重置为非隔离环境下的路径:

import ray

@ray.remote(runtime_env={"pip": ["wikipedia"], "py_executable": "python"})
def f():
    import wikipedia
    return wikipedia.summary("Wikipedia")

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

print(ray.get(f.remote()))
print(ray.get(g.remote()))
[project]

name = "test"

version = "0.1"

dependencies = [
"emoji",
"ray",
"pip",
"virtualenv",
]

在这个例子中:

  • f 任务通过 runtime_env={"pip": ["wikipedia"], "py_executable": "python"} 使用 pip runtime environment,并将 Python 可执行程序设置为普通的 python,从而避免继承 uv 环境。
  • g 任务则继续使用当前 uv 环境中的依赖(如 emoji)。

虽然这种模式对于 兼容旧应用(legacy applications) 很有用,但 Ray 团队仍然推荐使用 uv 来管理嵌套环境。 实现方式是:为嵌套环境创建一个单独的 pyproject.toml,在其中声明该环境所需的依赖,然后通过 uv 来管理这些依赖关系。


库开发 (Library Development)

假设你正在 Ray 上开发一个名为 my_module 的库。一个典型的开发迭代周期通常包括:

  1. my_module 的源代码进行修改。
  2. 运行一个 Ray 脚本来测试这些修改(可能是在一个分布式 Cluster 上)。

为了确保你的本地修改能够同步到所有 Ray Workers 并被正确导入,请使用 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(test_my_module.remote())

自动重载

这种方式非常适合“热开发”。当你修改了本地代码并重新启动 Job 时,Ray 会重新打包最新版本的 my_module 并分发,避免了手动在集群每个节点上安装库的麻烦。

py_modules vs working_dir

  • working_dir 会上传整个目录并将其设为当前路径。
  • py_modules 更加精准,它专门用于同步 Python 模块或包。Ray 会自动找到该模块的本地路径,将其打包并分发到所有 Workers 的 PYTHONPATH 中。

API Reference

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

working_dir (str):指定 Workers 的工作目录。
  • 要求
    • 本地现有目录(总大小不超过 500 MiB);
    • 本地现有的 zip 文件(解压后不超过 500 MiB,注意 excludes 对其无效);
    • 远程存储的 zip 文件 URI(Ray 不限制文件大小)。
  • 行为:指定目录将下载到 Cluster 的每个节点,Workers 将在各自节点的该目录副本中启动。
  • 注意:目前不支持为单个 Task 或 Actor 设置本地目录,只能在 ray.init() 中为整个 Job 设置。
  • 忽略规则
    • 默认遵循 .gitignore.rayignore。可设置环境变量 RAY_RUNTIME_ENV_IGNORE_GITIGNORE=1 来禁用 .gitignore 文件。
    • 默认自动排除一些常见目录,如 .git.pytest_cache.venv__pycache__ 等。可设置环境变量 RAY_OVERRIDE_RUNTIME_ENV_DEFAULT_EXCLUDES 来覆盖默认排除规则。
  • 符号链接:如果本地目录包含符号链接,Ray 会跟随这些链接并上传它们指向的文件到集群。
py_executable (str):指定 Ray Worker 使用的 Python 可执行文件(可附带参数)
  • 你可以通过 py_executable 字段,设置 Worker 启动时用哪个 Python 执行文件,支持传递参数(如 python -O)。
  • 常见使用场景:
    • 希望 Worker 进程运行在 特定调试器、分析器 下(如 cProfile、Pyflame);
    • 需要让 Worker 用包管理器(如 uvconda run python)准备好的自定义 Python 环境执行。
  • 可执行文件可打包在 working_dir 指定的目录下,无需全局可见。
  • 注意:当前该功能为实验特性。
excludes (List[str]):指定需要排除的文件或路径列表
  • 当与 working_dirpy_modules 一起使用时,指定要排除在上传之外的文件或路径列表。
  • 使用与 .gitignore 相同的模式匹配语法
  • 路径解释规则:若模式开头或中间含有 /,则该模式相对于 working_dir 解析:
    • 不要使用绝对路径(如 /Users/my_working_dir/subdir/
    • 应使用相对路径(如 /subdir/,前导 / 表示仅匹配顶层的 subdir 目录,而非所有层级中同名目录)

示例:

{
    "working_dir": "/Users/my_working_dir/",
    "excludes": ["my_file.txt", "/subdir/", "path/to/dir", "*.log"]
}
pip (dict | List[str] | str):指定要安装的 pip 依赖

支持以下三种形式:

  • 列表:直接列出 pip requirements specifier,遵循 PEP 508 语法。
  • 字符串:本地 requirements.txt 文件的路径。
  • 字典:精细控制安装行为,包含以下字段:
字段 类型 必填 说明
packages List[str] pip 包列表
pip_check bool 安装完成后是否执行 pip check,默认 False
pip_version str 指定 pip 自身的版本,Ray 会拼成 pip<pip_version> 作为依赖项
pip_install_options List[str] 传给 pip install 的额外选项,默认 ["--disable-pip-version-check", "--no-cache-dir"]

示例:

# 列表形式
["requests==1.0.0", "aiohttp", "ray[serve]"]

# requirements.txt 路径
"./requirements.txt"

# 字典形式
{"packages": ["tensorflow", "requests"], "pip_check": False, "pip_version": "==22.0.2;python_version=='3.8.11'"}

注意事项

  • 安装在 Ray Workers 运行时,集群预装环境中的包仍然可用
  • 如需使用 Ray Serve / Ray Tune 等库,需显式指定,如 "ray[serve]",且版本必须与集群一致。
  • 指定 requirements.txt 路径时,该文件须存在于本地机器,且路径为本地绝对路径或相对于本地当前工作目录的相对路径,而非相对于 runtime_envworking_dir 的路径。
  • requirements.txt 中不支持直接引用本地文件(如 -r ./my-laptop/more-requirements.txt./my-pkg.whl)。如需引用,请使用环境变量 ${RAY_RUNTIME_ENV_CREATE_WORKING_DIR},并确保对应文件已包含在 working_dir 中:
    -r ${RAY_RUNTIME_ENV_CREATE_WORKING_DIR}/my-laptop/more-requirements.txt
    ${RAY_RUNTIME_ENV_CREATE_WORKING_DIR}/my-pkg.whl
    
uv (dict | List[str] | str):使用 uv 安装 pip 兼容依赖

功能说明(Alpha 版本)

这是 pip 插件的 uv 版本,用于以 uv pip install 方式安装包。若需要 uv run + pyproject.toml + uv.lock 的完整支持,请 使用 uv 进行包管理(即 py_executable 方案),而非本字段。

支持以下三种形式:

  • 列表:直接列出 requirements specifier(语法与 pip 相同)。
  • 字符串:本地 requirements.txt 文件的路径。
  • 字典:精细控制安装行为,包含以下字段:
字段 类型 必填 说明
packages List[str] uv 包列表
uv_version str 指定 uv 自身的版本,Ray 会拼成 uv<uv_version> 作为依赖项
uv_check bool 安装完成后是否执行 pip check,默认 False
uv_pip_install_options List[str] 传给 uv pip install 的额外选项,默认 ["--no-cache"];传入空列表 [] 可不附带任何选项

示例:

# 列表形式
["requests==1.0.0", "aiohttp", "ray[serve]"]

# requirements.txt 路径
"./requirements.txt"

# 字典形式
{"packages": ["tensorflow", "requests"], "uv_version": "==0.4.0;python_version=='3.8.11'"}

注意事项

  • 安装在 Ray Workers 运行时,集群预装环境中的包仍然可用
  • 如需使用 Ray Serve / Ray Tune 等库,需显式指定,如 "ray[serve]",且版本必须与集群一致。
  • 指定 requirements.txt 路径时,同 pip 字段,路径须为本地路径,而非相对于 working_dir 的路径。
  • requirements.txt 中不支持直接引用本地文件,如需引用,请使用 ${RAY_RUNTIME_ENV_CREATE_WORKING_DIR} 环境变量,并确保对应文件已包含在 working_dir 中:
    -r ${RAY_RUNTIME_ENV_CREATE_WORKING_DIR}/my-laptop/more-requirements.txt
    ${RAY_RUNTIME_ENV_CREATE_WORKING_DIR}/my-pkg.whl
    
conda (dict | str):指定 conda 环境

支持以下四种形式:

  • 字典:直接提供 conda 环境的 YAML 内容。
  • 字符串(文件路径):本地 environment.yml 文件的路径。
  • 字符串(环境名):集群每个节点上已安装的 conda 环境名称(如 "pytorch_p36")。
  • 字符串(绝对路径):conda 环境的绝对路径(如 "/home/youruser/anaconda3/envs/pytorch_p36")。

示例:

# 字典形式(内联 YAML)
{"dependencies": ["pytorch", "torchvision", "pip", {"pip": ["pendulum"]}]}

# environment.yml 文件路径
"./environment.yml"

# 已安装的 conda 环境名
"pytorch_p36"

# conda 环境绝对路径
"/home/youruser/anaconda3/envs/pytorch_p36"

注意事项

  • 使用字典或文件路径形式时,Ray 会自动向环境中注入所需的 Ray 和 Python 依赖以保证兼容性,无需手动指定。Python 和 Ray 版本须与集群一致。
  • condapip 字段不能同时使用。若需在 conda 环境中添加 pip 包,请在 environment.yml 或字典的 "pip" 字段中声明,例如:
    {"dependencies": ["pytorch", "pip", {"pip": ["pendulum"]}]}
    
  • 指定 environment.yml 路径时,该文件须存在于本地机器,路径为本地绝对路径或相对于本地当前工作目录的相对路径,而非相对于 runtime_envworking_dir 的路径。
  • environment.yml 中不支持直接引用本地文件(如 -r ./my-laptop/more-requirements.txt)。如需引用,请使用 ${RAY_RUNTIME_ENV_CREATE_WORKING_DIR} 环境变量,并确保对应文件已包含在 working_dir 中:
    -r ${RAY_RUNTIME_ENV_CREATE_WORKING_DIR}/my-laptop/more-requirements.txt
    
env_vars (Dict[str, str]):设置环境变量
  • 以键值对形式指定要在 Ray Workers 中设置的环境变量。
  • 集群上已有的环境变量仍然可见,无需通过 os.environ 重新传入。
  • 默认行为:若同名环境变量在集群上已存在,本字段的值会覆盖它。
  • 追加行为:可使用 ${ENV_VAR} 语法引用已有变量,实现追加而非覆盖。若引用的变量不存在,则视为空字符串 ""

示例:

# 直接设置
{"OMP_NUM_THREADS": "32", "TF_WARNINGS": "none"}

# 追加到已有变量
{"LD_LIBRARY_PATH": "${LD_LIBRARY_PATH}:/home/admin/my_lib"}

# 引用不存在的变量(结果为 ":/home/admin/my_lib")
{"ENV_VAR_NOT_EXIST": "${ENV_VAR_NOT_EXIST}:/home/admin/my_lib"}
nsight (str | Dict[str, str]):配置 Nsight System Profiler
  • "default":使用默认配置启动 Nsight 分析器。
  • 字典:自定义 Nsight System Profiler 选项及其值。

示例:

# 默认配置
"default"

# 自定义选项
{"stop-on-exit": "true", "t": "cuda,cublas,cudnn", "ftrace": ""}
image_uri (str):指定 Docker 镜像(实验特性)
  • 要求 Worker 进程运行在指定的容器镜像中。
  • 注意:该功能目前为实验特性。

示例:

"anyscale/ray:2.53.0-py310-cpu"
config (dict | RuntimeEnvConfig):运行时环境的配置项

可以是 Python 字典或 RuntimeEnvConfig 实例,支持以下字段:

字段 类型 说明
setup_timeout_seconds int 运行时环境创建的超时时间(秒)
eager_install bool 是否在 ray.init() 时提前安装运行时环境,默认 True;设为 False 时推迟到首次 Task/Actor 调用时再安装

注意

eager_install 目前不支持在单个 Task 或 Actor 级别单独指定,仅可在 Job 级别配置。

示例:

# 字典形式
{"setup_timeout_seconds": 10}
{"eager_install": False}

# RuntimeEnvConfig 形式
RuntimeEnvConfig(setup_timeout_seconds=10)
RuntimeEnvConfig(eager_install=False)

缓存与垃圾回收

每个节点上的运行时环境资源(如 conda 环境、pip 包、已下载的 working_dirpy_modules 目录)会被缓存在集群上,以便在同一 Job 内的不同运行时环境之间快速复用。

每个字段(working_dirpy_modules 等)都有独立的缓存空间,默认上限为 10 GB。如需修改默认值,可在启动 Ray 前在集群的每个节点上设置环境变量:

export RAY_RUNTIME_ENV_WORKING_DIR_CACHE_SIZE_GB=1.5

通用格式为 RAY_RUNTIME_ENV_<FIELD>_CACHE_SIZE_GB,将 <FIELD> 替换为对应字段名的大写形式(如 WORKING_DIRPY_MODULES 等)。

当缓存超出上限时,所有当前未被任何 Actor、Task 或 Job 使用的资源将被自动删除。


运行时环境冲突与合并

运行入口脚本时,运行时环境可以通过以下两种方式指定:

  • ray job submit --runtime-env=...:运行时环境同时作用于 Driver 脚本本身以及它创建的所有 Task 和 Actor。
  • ray.init(runtime_env=...):运行时环境只作用于 Task 和 Actor,不作用于 Driver 脚本本身。

ray job submitray.init 同时指定 runtime_env 时的合并与冲突

当你通过 ray job submit 提交作业时,Driver 代码里通常也会调用 ray.init(runtime_env=...)。这种情况下,Ray 会尝试对这两处配置的运行时环境(runtime_env)进行合并

  • Driver 脚本本身使用 ray job submit 命令指定的运行时环境。
  • 所有 Task 和 Actor 使用合并后的运行时环境。
  • 如果两处配置存在冲突,Ray 会抛出异常(如同名 key,但值不同的情况)。

合并规则

  • env_vars 字段:逐个 key 合并;若同名 key 冲突则抛出异常。
  • 其他所有字段:整体合并;若同名 key 冲突则抛出异常。
# `ray job submit --runtime_env=...`
{"pip": ["requests", "chess"], "env_vars": {"A": "a", "B": "b"}}

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

# Driver 实际使用的 runtime_env(合并结果)
{"pip": ["requests", "chess"], "env_vars": {"A": "a", "B": "b", "C": "c"}}
# 示例 1:env_vars 冲突
# `ray job submit --runtime_env=...`
{"pip": ["requests", "chess"], "env_vars": {"C": "a", "B": "b"}}

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

# Ray 因 "C" 冲突而抛出异常

# 示例 2:其他字段(如 pip)冲突
# `ray job submit --runtime_env=...`
{"pip": ["requests", "chess"]}

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

# Ray 因 "pip" 冲突而抛出异常

跳过冲突检测

可设置环境变量 RAY_OVERRIDE_JOB_RUNTIME_ENV=1 来避免冲突时抛出异常。此时合并行为改为继承模式:ray job submit 作为父级,ray.init 作为子级,规则见下节"继承"。


继承

运行时环境具有可继承性:一旦在 Job、Task 或 Actor 上设置,除非被显式覆盖,否则会自动传递给所有子 Task 和 Actor。

当 Actor 或 Task 指定了新的 runtime_env 时,它会覆盖父级的 runtime_env(父级可以是父 Actor/Task,或 Job 级别的 runtime_env),覆盖规则如下:

  • env_vars 字段:与父级的 env_vars 合并,子级新增或修改的变量会覆盖同名父级变量,未涉及的父级变量仍会保留。
  • 其他所有字段:子级的值直接替换父级,不进行合并。例如 py_modules 指定后会完全替换父级的 py_modules
# 父级 runtime_env
{"pip": ["requests", "chess"],
"env_vars": {"A": "a", "B": "b"}}

# 子级指定的 runtime_env
{"pip": ["torch", "ray[serve]"],
"env_vars": {"B": "new", "C": "c"}}

# 子级实际使用的 runtime_env(继承合并后)
{"pip": ["torch", "ray[serve]"],
"env_vars": {"A": "a", "B": "new", "C": "c"}}

FAQ

运行时环境会安装到每个节点吗?

如果通过 ray.init(runtime_env=...) 指定运行时环境,则它会安装到集群的每个节点上。

默认情况下,运行时环境会在集群启动时提前(eagerly)安装到所有节点。如需改为按需懒加载,可将 eager_install 设为 False

ray.init(runtime_env={..., "config": {"eager_install": False}})
运行时环境何时开始安装?
  • Per-Job:在调用 ray.init() 时安装(除非设置了 "eager_install": False)。
  • Per-Task / Per-Actor:在调用 my_task.remote()my_actor.remote() 时,即 Task 被调度或 Actor 被实例化时安装。
运行时环境缓存在哪里?

环境下载的本地文件缓存在:

/tmp/ray/session_latest/runtime_resources
安装或从缓存加载需要多长时间?

首次安装时,耗时主要取决于所使用的 runtime_env 选项:

  • pip:运行 pip install 的时间
  • conda:运行 conda create / conda activate 的时间
  • working_dir:上传或下载目录的时间

通常在数秒到数分钟不等。

从缓存加载时,速度接近普通 Ray worker 的启动时间,通常在数秒内完成。每个需要新运行时环境的 Task 或 Actor 都会启动一个新的 Ray worker 进程。

conda 缓存加载

即使是从缓存加载,conda 环境仍可能较慢,因为 conda activate 命令本身有时需要几秒钟。

防止安装挂起

可通过 setup_timeout_seconds 设置超时时间。若安装未在规定时间内完成,对应的 Task 或 Actor 将启动失败。

ray.init(runtime_env={..., "config": {"setup_timeout_seconds": 60}})
运行时环境与 Docker 是什么关系?

两者可以独立使用,也可以结合使用

  • Docker 容器镜像:适合大型或静态依赖,通过 Cluster Launcher 在集群级别指定。
  • 运行时环境:适合动态场景,可按 Job、Task 或 Actor 粒度指定。

运行时环境会继承容器镜像中的包、文件和环境变量,在此基础上叠加增量依赖。

runtime_env 已安装,但登录节点后无法 import 包?

这是正常现象。运行时环境只对 Ray worker 进程生效,不会将包安装到节点的全局 Python 环境中。因此在 shell 或交互式终端中无法直接 import 这些包。


Remote URIs

runtime_env 中的 working_dirpy_modules 字段既可以指定本地路径,也可以指定远程 URI

  • 本地路径:必须是目录路径,目录内容将直接作为 working_dirpy_module 使用。
  • 远程 URI:必须直接指向一个 zip 文件(py_modules 还额外支持 wheel 文件)。zip 文件内必须只有一个顶级目录,该目录的内容将作为 working_dirpy_module 使用。

本地路径示例

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

制作 zip 文件

若需将本地目录托管到远端,需先将其压缩为 zip 文件。必须从目标目录的父目录执行,以保证 zip 内只有一个顶级目录:

cd /some_path
zip -r zip_file_name.zip example_dir

可用以下命令验证 zip 结构是否正确(顶级应只有一个目录):

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

注意隐藏文件和元数据目录

某些压缩方式会在 zip 顶层产生隐藏文件或元数据目录。若 Ray 检测到顶层存在多个目录,会使用整个 zip 文件而非顶级目录,可能导致非预期行为。

建议始终使用 zip -r 命令,从父目录对目标目录直接压缩,避免此类问题。

远程 URI 示例

将压缩好的 zip 文件上传到远端后,在 runtime_env 中直接指定远程 URI:

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

支持的远程 URI 类型

目前支持以下四种远程 URI:

HTTPS

https:// 开头的 URL,适合直接使用远程 Git 仓库(GitHub、GitLab、Bitbucket 等)提供的归档下载链接,方便版本管理。

依赖:需预先安装 smart_open

pip install smart_open

示例

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

S3

s3:// 开头的 URI,指向存储在 AWS S3 中的压缩包。Ray 不会显式传入凭据,认证由 boto3 负责(读取环境变量、共享凭证文件或 AWS 配置文件)。

依赖:需预先安装 smart_openboto3

pip install smart_open boto3

示例

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

GCS(Google Cloud Storage)

gs:// 开头的 URI,指向存储在 Google Cloud Storage 中的压缩包。Ray 不会显式传入凭据,认证使用本地服务账号密钥和环境变量,参考 GCS 身份验证文档 进行配置。

依赖:需预先安装 smart_opengoogle-cloud-storage

pip install smart_open google-cloud-storage

示例

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

Azure Blob Storage

azure:// 开头的 URI,指向存储在 Azure Blob Storage 中的压缩包。支持两种认证方式:

  • Connection String:设置环境变量 AZURE_STORAGE_CONNECTION_STRING
  • Managed Identity:设置环境变量 AZURE_STORAGE_ACCOUNT(存储账户名),将使用 Azure 托管标识进行认证。

依赖:需预先安装以下包:

pip install smart_open[azure] azure-storage-blob azure-identity

示例

runtime_env = {"working_dir": "azure://container-name/example_file.zip"}

依赖包必须预装在集群节点上

smart_openboto3google-cloud-storageazure-storage-blobazure-identity 等包默认未安装,且在 runtime_envpip 字段中指定它们是无效的。这些包必须在 Ray 启动前已预装到集群的所有节点上。


在远程 Git 托管平台上发布依赖

你可以将依赖存储在 GitHub、Bitbucket、GitLab 等 Git 托管平台的仓库中,并通过定期推送来更新。本节以 GitHub 为例,说明如何将依赖托管到远端并在 runtime_env 中使用。

适用于其他平台

本节以 GitHub 为例,其他大型 Git 托管平台(Bitbucket、GitLab 等)同理。

准备工作:在 GitHub 上创建一个仓库,将 working_dir 内容或 py_module 依赖上传进去。GitHub 在下载仓库 zip 时,默认会在 zip 内生成一个包含仓库内容的顶级目录,符合 Ray 对 zip 文件结构的要求,可以直接使用。

上传完成后,你需要获取仓库 zip 文件的 HTTPS URL,填入 runtime_env 字典中。获取方式有以下两种:


方式一:Download ZIP(快速,不推荐用于生产环境)

在 GitHub 仓库页面选择目标分支,点击绿色 Code 下拉按钮,右键点击 Download ZIP,选择"复制链接地址",即可获得 HTTPS 链接。

一致性风险

该链接始终指向所选分支的最新提交。如果你的 Ray 集群在多个节点拉取依赖包的过程中,你向仓库推送了新的提交,不同节点可能拉取到不同版本的包,造成环境不一致。

生产环境建议使用方式二,通过固定 commit hash 来保证所有节点使用完全相同的版本。


方式二:手动构造 URL(推荐用于生产环境)

通过在 URL 模板中填入具体参数,可以精确控制使用的分支和 commit,避免一致性问题。

以下是常用 URL 模板,将 [username][repository][commit hash] 等替换为实际值:

从公开 GitHub 仓库的指定 commit 获取

runtime_env = {"working_dir": ("https://github.com"
                               "/[username]/[repository]/archive/[commit hash].zip")}

从私有 GitHub 仓库获取(使用 Personal Access Token,适用于开发阶段)

runtime_env = {"working_dir": ("https://[username]:[personal access token]@github.com"
                               "/[username]/[private repository]/archive/[commit hash].zip")}

从公开 GitHub 仓库的最新 commit 获取

runtime_env = {"working_dir": ("https://github.com"
                               "/[username]/[repository]/archive/HEAD.zip")}

从公开 Bitbucket 仓库的指定 commit 获取

runtime_env = {"working_dir": ("https://bitbucket.org"
                               "/[owner]/[repository]/get/[commit hash].tar.gz")}

最佳实践

推荐指定具体的 commit hash 而非 HEAD,可避免多节点集群上的版本不一致问题。


获取 URL 后,将其填入 runtime_env 字典,传入 ray.init().options() 即可完成远程依赖的配置。


调试

当运行时环境无法正常创建时(如网络故障、下载失败等),Ray 会拒绝调度依赖该环境的 Task 或 Actor。调用 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

日志文件

运行时环境的完整安装日志始终写入以下日志文件:

场景 日志文件
Per-Actor / Per-Task / Per-Job 环境 runtime_env_setup-[job_id].log
使用 Ray Client 的 Per-Job 环境 runtime_env_setup-ray_client_server_[port].log

实时日志流到 Driver

在启动 Ray 前,在集群每个节点上设置以下环境变量,可将完整的运行时环境安装日志实时打印到 Driver(即调用 ray.init() 的脚本):

export RAY_RUNTIME_ENV_LOG_TO_DRIVER_ENABLED=1

可通过 Ray Cluster 配置文件中的 setup_commands 批量设置。启用后的日志输出示例:

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