Apache DolphinScheduler Jupyter 任务完整实战指南:基于 Papermill 的 Notebook 自动化执行与 Conda 环境管理
【免费下载链接】dolphinschedulerApache DolphinScheduler is the modern data orchestration platform. Agile to create high performance workflow with low-code项目地址: https://gitcode.com/GitHub_Trending/dol/dolphinscheduler
Jupyter 任务(Jupyter Task)是 Apache DolphinScheduler 内置的数据科学类任务插件,它让工作流能够以任务节点的形式直接驱动 Jupyter Notebook 的批量化执行。本指南围绕该插件的安装前提(Conda 配置)、三种 Python 依赖管理方式(预装环境 / Conda-Pack 打包环境 / requirements.txt 动态构建)、任务参数与创建流程展开,并结合仓库源码剖析其底层命令生成逻辑,帮助读者在 DolphinScheduler 中稳定、可复用地运行 Notebook 分析任务。
一、任务概述:Worker 如何执行 Jupyter Notebook
在 DolphinScheduler 中,Jupyter Task用于创建 jupyter 类型的任务节点并执行 Jupyter Notebook。当 Worker 执行该任务时,会调用 papermill 来"评估"(evaluate)Jupyter Notebook:papermill 接收一个输入 Notebook 模板,将参数化单元格中的变量注入后逐单元格执行,最终产出带结果的输出 Notebook 文件。
从源码看,Jupyter 任务被实现为一个标准插件,插件入口位于 JupyterTaskChannel.java,它负责把任务参数 JSON 反序列化为 JupyterParameters.java 并创建 JupyterTask.java 实例。任务运行时通过ShellCommandExecutor在 Worker 上执行一段拼接好的 shell 命令,命令的核心形态为:
papermill [OPTIONS] NOTEBOOK_PATH [OUTPUT_PATH]该命令的完整拼装逻辑见 JupyterTask.buildCommand(),下文会结合这段实现逐步讲解每个参数的去向。
二、前提配置:Conda 环境
Jupyter 任务插件依赖 conda 来管理和激活 Python 环境,因此必须先在 Worker 节点上正确配置conda.path:
在
common.properties中配置conda.path指向你的conda.sh脚本路径,该 conda 必须与你管理papermill和jupyter所用的 Python 环境是同一个 conda。conda.path的默认值为/opt/anaconda3/etc/profile.d/conda.sh。如果你不确定 conda 安装在哪里,可直接执行:conda info | grep -i 'base environment'输出的路径即为你需要填写的值。
仓库中的默认配置文件 dolphinscheduler-common/src/main/resources/common.properties 第 91 行正是:
# set path of conda.sh conda.path=/opt/anaconda3/etc/profile.d/conda.sh从源码实现看,插件在构建命令时通过PropertyUtils.getString(TaskConstants.CONDA_PATH)读取该配置(见 JupyterTask.readCondaPath()),其中CONDA_PATH常量定义在 TaskConstants.java:
public static final String CONDA_PATH = "conda.path";⚠️注意事项:
Jupyter Task Plugin使用source命令来激活 conda 环境。如果执行任务所用的租户(tenant)没有使用source的权限,Jupyter Task Plugin将无法正常工作。这一点在 JupyterConstants.java 中体现为CONDA_INIT = "source"、CONDA_ACTIVATE = "conda activate",即以source conda.sh初始化 shell 后再激活环境。
三、Python 依赖管理:三种方式任选
插件支持三种 Python 依赖管理方式,最终都会落到condaEnvName参数上;从源码看,插件正是通过判断condaEnvName的后缀(.tar.gz/.txt/ 其他)来决定走哪条执行路径(见 JupyterTask.buildCommand())。
3.1 方式一:使用预装的 Conda 环境
- 在目标 Worker 上手动或通过
shell task创建一个 conda 环境; - 在
jupyter task中把condaEnvName设置为该 conda 环境的名称。
此时插件生成的命令形如:
source /opt/anaconda3/etc/profile.d/conda.sh && conda activate jupyter-lab && papermill ...3.2 方式二:使用 Conda-Pack 打包的环境
- 使用 Conda-Pack 将你的 conda 环境打包成
tarball(通常为.tar.gz); - 将打包好的 conda 环境上传到资源中心(Resource Center);
- 在
jupyter task中把condaEnvName设置为打包环境的文件名,例如jupyter_env.tar.gz; - 在
jupyter task的resource中选择该打包环境文件,例如jupyter_env.tar.gz。
⚠️ 请严格按照 Conda-Pack 官方说明进行打包。解包后,打包环境的目录结构应当与下面一致:
. ├── bin ├── conda-meta ├── etc ├── include ├── lib ├── share └── ssl⚠️特别注意:请严格遵循上述
conda pack指令,不要修改bin/activate。Jupyter Task Plugin使用source命令激活打包的 conda 环境;如果你对使用source有顾虑,请选择其他方式来管理 Python 依赖。
源码中对应执行逻辑在 JupyterConstants.java,打包环境被解压到jupyter_env目录后直接激活:
mkdir jupyter_env && tar -xzf %s -C jupyter_env && source jupyter_env/bin/activate生成的完整命令类似:
source /opt/anaconda3/etc/profile.d/conda.sh && mkdir jupyter_env && tar -xzf jupyter.tar.gz -C jupyter_env && source jupyter_env/bin/activate && papermill ...3.3 方式三:从 requirements.txt 构建环境
- 在资源中心上传或创建一个包含 Python 依赖的
.txt文件; - 在
jupyter task中把condaEnvName设置为该 requirements 文件名,例如requirements.txt; - 在
jupyter task的resource中选择该文件,例如requirements.txt。
插件会自动据此构建 Python 依赖环境 → 运行你的 Python 代码 → 最终拆除(tear down)该环境。下面是文档给出的一份 requirements 示例文件(其中包含 papermill 及其 Notebook 运行所需的完整依赖链):
fastjsonschema==2.15.3 fonttools==4.33.3 geojson==2.5.0 identify==2.4.11 idna==3.3 importlib-metadata==4.11.3 importlib-resources==5.7.1 ipykernel==5.5.6 ipython==8.2.0 ipython-genutils==0.2.0 jedi==0.18.1 Jinja2==3.1.1 json5==0.9.6 jsonschema==4.4.0 jupyter-client==7.3.0 jupyter-core==4.10.0 jupyter-server==1.17.0 jupyterlab==3.3.4 jupyterlab-pygments==0.2.2 jupyterlab-server==2.13.0 kiwisolver==1.4.2 MarkupSafe==2.1.1 matplotlib==3.5.2 matplotlib-inline==0.1.3 mistune==0.8.4 nbclassic==0.3.7 nbclient==0.6.0 nbconvert==6.5.0 nbformat==5.3.0 nest-asyncio==1.5.5 notebook==6.4.11 notebook-shim==0.1.0 numpy==1.22.3 packaging==21.3 pandas==1.4.2 pandocfilters==1.5.0 papermill==2.3.4从源码看,当condaEnvName以.txt结尾时,插件先以set +e忽略错误继续执行(EXECUTION_FLAG),然后依次执行创建临时环境、激活、安装依赖、运行 papermill、最后拆除环境的命令(见 JupyterConstants.java):
conda create -n jupyter-tmp-env-<timestamp> -y && conda activate jupyter-tmp-env-<timestamp> && pip install -r requirements.txt # ... 执行 papermill ... conda deactivate && conda remove --name jupyter-tmp-env-<timestamp> --all -y其中<timestamp>由DateUtils.getTimestampString()生成,用于保证临时环境名的唯一性(见 JupyterTask.buildCommand())。
四、创建任务:在 DAG 中拖入 Jupyter 节点
- 进入
项目管理 → 项目名称 → 工作流定义,点击创建工作流按钮进入 DAG 编辑页面; - 从工具栏将 Jupyter 图标
拖拽到画布中。
拖入后即可在右侧面板填写任务参数,然后保存、上线并运行该工作流。关于任务创建、运行、停止、删除等通用操作,可参考任务参数附录 appendix.md 中Default Task Parameters一节(默认任务参数部分),本文不再赘述。
五、任务参数详解
Jupyter 任务的业务参数如下表所示:
| 参数 | 说明 |
|---|---|
| Conda Env Name | conda 环境名称,或打包的 conda 环境 tarball 文件名(.tar.gz),或 requirements 文件(.txt) |
| Input Note Path | 输入 Jupyter Notebook 模板的路径 |
| Out Note Path | 输出 Notebook 文件的路径 |
| Jupyter Parameters | JSON 格式的参数,用于对 Jupyter Notebook 做参数化(注入参数单元格) |
| Kernel | Jupyter Notebook 使用的 kernel |
| Engine | 用于评估 Jupyter Notebook 的执行引擎 |
| Jupyter Execution Timeout | 每个 Jupyter Notebook 单元格的执行超时时间 |
| Jupyter Start Timeout | Jupyter Notebook kernel 的启动超时时间 |
| Others | papermill 的其他命令行选项 |
这些参数在 JupyterParameters.java 中一一对应。其中有三个必填项——checkParameters()方法要求condaEnvName、inputNotePath、outputNotePath均非空(见 JupyterParameters.java),否则JupyterTask.init()会抛出 "jupyter task params is not valid" 异常。
参数如何映射为 papermill 命令
结合 JupyterTask.populateJupyterParameterization() 与 JupyterTask.populateJupyterOptions(),各参数与 papermill 命令行参数的对应关系如下:
- Jupyter Parameters:以 JSON 字符串形式传入(如
{"city": "Shanghai", "factor": "0.01"}),插件使用 JacksonObjectMapper解析为Map<String, String>后,逐个键值对拼成--parameters <key> <value>追加到命令中;JSON 解析失败会直接导致任务失败。 - Kernel:非空时追加
--kernel <kernel>(papermill 的--kernel指定运行内核); - Engine:非空时追加
--engine <engine>(指定执行引擎); - Jupyter Execution Timeout:非空时追加
--execution-timeout <seconds>,即每个单元格执行等待秒数,默认永久等待; - Jupyter Start Timeout:非空时追加
--start-timeout <seconds>,即 kernel 启动等待秒数; - Others:原样追加为 papermill 的额外命令行选项;
- 插件始终会追加两个固定选项:
--inject-paths(将输入/输出 Notebook 路径以PAPERMILL_INPUT_PATH/PAPERMILL_OUTPUT_PATH注入为 Notebook 参数)与--progress-bar(开启进度条)。
上述常量定义可参见 JupyterConstants.java。
六、任务示例与底层命令还原
下图展示了在 DAG 画布中配置一个 Jupyter 任务节点的效果:
要直观理解三种依赖管理方式最终会生成什么样的真实命令,最可靠的证据是插件自带的单元测试 JupyterTaskTest.java。它通过断言buildCommand()的输出来验证命令拼装逻辑:
- 本地 conda 环境(
condaEnvName=jupyter-lab):
source /opt/anaconda3/etc/profile.d/conda.sh && conda activate jupyter-lab && papermill /test/input_note.ipynb /test/output_note.ipynb --parameters city Shanghai --parameters factor 0.01 --kernel python3 --engine default_engine --execution-timeout 10 --start-timeout 3 --version --inject-paths --progress-bar- 打包 conda 环境(
condaEnvName=jupyter.tar.gz):
source /opt/anaconda3/etc/profile.d/conda.sh && mkdir jupyter_env && tar -xzf jupyter.tar.gz -C jupyter_env && source jupyter_env/bin/activate && papermill /test/input_note.ipynb /test/output_note.ipynb --parameters city Shanghai --parameters factor 0.01 --kernel python3 --engine default_engine --execution-timeout 10 --start-timeout 3 --version --inject-paths --progress-bar- requirements.txt 动态构建(
condaEnvName=requirements.txt,临时环境名被固定为123456789以便断言):
set +e source /opt/anaconda3/etc/profile.d/conda.sh && conda create -n jupyter-tmp-env-123456789 -y && conda activate jupyter-tmp-env-123456789 && pip install -r requirements.txt && papermill /test/input_note.ipynb /test/output_note.ipynb --parameters city Shanghai --parameters factor 0.01 --kernel python3 --engine default_engine --execution-timeout 10 --start-timeout 3 --version --inject-paths --progress-bar conda deactivate && conda remove --name jupyter-tmp-env-123456789 --all -y从这三组命令可以完整还原插件的执行链路:初始化 conda → 按依赖管理方式激活/构建环境 → 执行 papermill(参数注入、超时、kernel/engine、额外选项)→ 若是临时环境则自动拆除。这也解释了为什么文档要求 Worker 租户必须拥有source权限——命令的第一行就是对conda.sh执行source。
七、常见问题与排障建议
- 任务报 "jupyter task params is not valid":
condaEnvName、inputNotePath、outputNotePath三者任一为空都会触发该校验,请检查任务参数是否完整填写。 - 任务执行提示
source: command not found或权限不足:插件依赖source激活环境,请确认执行任务所使用的租户账号对该 Worker 拥有source权限。 - 找不到 conda 或环境激活失败:确认
common.properties中conda.path指向真实存在的conda.sh,且该 conda 与安装 papermill/jupyter 的环境一致;可执行conda info | grep -i 'base environment'核对路径。 - 打包环境无法激活:检查是否按 Conda-Pack 官方流程打包,且未改动
bin/activate;解包后的目录结构应与第三节所示一致。 - 临时环境残留:requirements 方式使用
jupyter-tmp-env-<timestamp>命名临时环境,任务结束后会自动conda remove;若任务中途被强杀导致残留,可在 Worker 上手动清理对应环境。
八、结语
Jupyter 任务把 DolphinScheduler 的工作流编排能力与 Jupyter Notebook 的交互式分析生态连接在一起:通过 papermill 实现 Notebook 参数化批量执行,通过三种 conda 依赖管理策略覆盖"复用预装环境 / 分发打包环境 / 按依赖清单动态构建"三类典型场景。结合本仓库源码中的 JupyterTask.java、JupyterConstants.java 与单元测试 JupyterTaskTest.java,你可以清晰地预见每一步配置在 Worker 上实际执行的命令,从而更从容地完成 Notebook 任务的调试、治理与运维。
【免费下载链接】dolphinschedulerApache DolphinScheduler is the modern data orchestration platform. Agile to create high performance workflow with low-code项目地址: https://gitcode.com/GitHub_Trending/dol/dolphinscheduler
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考