Env Deps
Abstract
Ray 应用经常依赖于 Ray 脚本之外的内容,比如:
- 依赖或导入某些 Python 包
- 需要设置特定的环境变量
- 需要访问脚本之外的其他文件
Reference: Environment Dependencies
在集群上运行任务时,需要注意:Ray 要求所有依赖项在每一个 Ray 节点上都可用。如果缺失,会出现诸如 ModuleNotFoundError、FileNotFoundError 等错误。
解决方式主要有两种:
- 预先准备依赖 利用 Ray Cluster Launcher(集群启动器),提前将所有必须的依赖项准备好,比如通过定制容器镜像进行统一分发。
- 动态安装依赖 借助 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 Task、Actor、Job 生效,不会影响节点的全局 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},方便 pip 或 conda 等依赖工具在 requirements.txt、environment.yml 等文件中引用本地内容。
使用 conda 或 pip 软件包
你的 Ray 应用程序可能通过 import 语句依赖某些 Python 软件包(例如 pendulum 或 requests)。
通常情况下,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)的 conda 或 pip 包时请务必小心,因为这可能会非常缓慢。
虚拟环境差异
pip 字段是在集群原有环境的基础上叠加安装新包,而 conda 字段会创建一个完全隔离的新环境,这两种方式不能混用,需要二选一。
- 使用
pip字段时:指定的包会借助virtualenv安装在原有环境“之上”,因此集群节点上原有的包依然可以被导入使用。 - 使用
conda字段时:Ray Tasks 和 Actors 会运行在一个完全隔离的新环境中,原有环境的包不会被继承。
⚠️ 注意:不能在同一个 runtime_env 字典的顶层同时指定 conda 和 pip 字段,否则会报错。
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_env 的 uv run 来启动任务。这一方式具有以下优势:
- 依赖一致性:Driver 与 Ray Worker 节点会严格按照同一套锁定的依赖(
pyproject.toml+uv.lock)环境运行,避免版本不一致问题。 - 现代依赖生态:原生支持
pyproject.toml配置(包括 editable 模式),满足主流 Python 项目需求。 - 高效可复现:通过
uv lock可以生成锁文件,保证环境的可复现与确定性。
使用步骤举例(同样支持 editable 包的使用)
-
在项目根目录新建
pyproject.toml:[project] name = "test" version = "0.1" dependencies = [ "emoji", "ray", ] -
创建一个
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)])) -
使用
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.toml 和 app.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 机制:
-
具有异构依赖的应用:Ray 支持为不同的 Task 或 Actor 使用不同的 runtime environment。
这对于以下场景非常有用:
- 在 Ray Serve 的不同部署中运行不同的推理引擎、模型或微服务
- 在 Ray Data 中构建具有不同依赖的异构数据处理流水线
实现方式包括:
- 为每个 runtime environment 指定不同的
py_executable,并使用带有不同--project参数的uv run - 为每个环境指定不同的
working_dir
-
自定义 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"}使用pipruntime environment,并将 Python 可执行程序设置为普通的 python,从而避免继承 uv 环境。g任务则继续使用当前 uv 环境中的依赖(如emoji)。
虽然这种模式对于 兼容旧应用(legacy applications) 很有用,但 Ray 团队仍然推荐使用 uv 来管理嵌套环境。
实现方式是:为嵌套环境创建一个单独的 pyproject.toml,在其中声明该环境所需的依赖,然后通过 uv 来管理这些依赖关系。
库开发 (Library Development)
假设你正在 Ray 上开发一个名为 my_module 的库。一个典型的开发迭代周期通常包括:
- 对
my_module的源代码进行修改。 - 运行一个 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 用包管理器(如
uv、conda run python)准备好的自定义 Python 环境执行。
- 可执行文件可打包在
working_dir指定的目录下,无需全局可见。 - 注意:当前该功能为实验特性。
excludes (List[str]):指定需要排除的文件或路径列表
- 当与
working_dir或py_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_env中working_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 版本须与集群一致。
conda和pip字段不能同时使用。若需在 conda 环境中添加 pip 包,请在environment.yml或字典的"pip"字段中声明,例如:{"dependencies": ["pytorch", "pip", {"pip": ["pendulum"]}]}- 指定
environment.yml路径时,该文件须存在于本地机器,路径为本地绝对路径或相对于本地当前工作目录的相对路径,而非相对于runtime_env中working_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_dir 或 py_modules 目录)会被缓存在集群上,以便在同一 Job 内的不同运行时环境之间快速复用。
每个字段(working_dir、py_modules 等)都有独立的缓存空间,默认上限为 10 GB。如需修改默认值,可在启动 Ray 前在集群的每个节点上设置环境变量:
export RAY_RUNTIME_ENV_WORKING_DIR_CACHE_SIZE_GB=1.5
通用格式为 RAY_RUNTIME_ENV_<FIELD>_CACHE_SIZE_GB,将 <FIELD> 替换为对应字段名的大写形式(如 WORKING_DIR、PY_MODULES 等)。
当缓存超出上限时,所有当前未被任何 Actor、Task 或 Job 使用的资源将被自动删除。
运行时环境冲突与合并
运行入口脚本时,运行时环境可以通过以下两种方式指定:
ray job submit --runtime-env=...:运行时环境同时作用于 Driver 脚本本身以及它创建的所有 Task 和 Actor。ray.init(runtime_env=...):运行时环境只作用于 Task 和 Actor,不作用于 Driver 脚本本身。
ray job submit 和 ray.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_dir 和 py_modules 字段既可以指定本地路径,也可以指定远程 URI。
- 本地路径:必须是目录路径,目录内容将直接作为
working_dir或py_module使用。 - 远程 URI:必须直接指向一个 zip 文件(
py_modules还额外支持 wheel 文件)。zip 文件内必须只有一个顶级目录,该目录的内容将作为working_dir或py_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_open 和 boto3:
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_open 和 google-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_open、boto3、google-cloud-storage、azure-storage-blob、azure-identity 等包默认未安装,且在 runtime_env 的 pip 字段中指定它们是无效的。这些包必须在 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