第2章 环境搭建:安装Cromwell、MiniWDL以及配置运行环境

说实话,开始用WDL之前,最烦的就是环境配置。你想想看,工具链没搭好,连个“Hello World”都跑不起来,多打击信心。我刚开始接触时也栽过坑——Java版本不对、Python包冲突、配置文件写错……后来总结了一套步骤,按顺序来,基本十分钟就能搞定。

这一章我们搞定三样东西:Cromwell(工业级执行引擎)、MiniWDL(轻量级调试工具),以及本地运行环境的配置。我会把踩过的坑和习惯做法都告诉你。

2.1 安装Cromwell

Cromwell 是 Broad Institute 开发的 WDL 执行引擎,支持本地、集群、云等多种后端。我一般用它的 JAR 包,简单直接,不需要装乱七八糟的依赖。

依赖要求:Java 11 或更高版本。先确认下你有 Java 没:

java -version

如果版本低于11,去 https://adoptium.net 下载一个。我个人习惯用 AdoptOpenJDK 的 LTS 版本,稳定。

然后下载 Cromwell JAR:

wget https://github.com/broadinstitute/cromwell/releases/download/87/cromwell-87.jar
建议建个专用目录,比如 ~/tools/cromwell,把 JAR 放进去。后面运行命令也方便。

验证安装:

java -jar ~/tools/cromwell/cromwell-87.jar --version

如果看到版本号,就成功了。我在项目中遇到过因为 JDK 版本太高(比如 17 以上)导致某些老版 Cromwell 崩溃的情况,所以建议用 11 或 17,别追最新。

2.2 安装 MiniWDL

MiniWDL 是我个人最喜欢的调试工具。它是个 Python 库,轻量、单机执行,适合写 WDL 时快速验证逻辑。你想想看,如果每次调试都要整个 Cromwell 跑一遍,光启动时间就够喝杯咖啡了。

安装命令(建议在虚拟环境里装):

pip install miniwdl

如果遇到底层依赖问题(比如 lark-parser 版本冲突),加个 --upgrade 重装一遍就好。我之前在一台老 Ubuntu 机器上装的时候,报过 “Failed building wheel for lark-parser”,后来发现是 Python 3.6 太老了,升级到 3.8 就好了。

MiniWDL 目前只支持 WDL 1.0 和部分 1.1 特性。如果你的 WDL 用了 draft-2 或很新版本的结构化任务,得用 Cromwell 跑。

验证安装:

miniwdl --version

正常输出类似 miniwdl 1.9.1。

2.3 配置运行环境

环境不止是装两个工具,还要约定工作目录和输入输出路径。我通常用这样的目录结构:

my_pipeline/
├── workflows/       # 存放 .wdl 文件
├── inputs/          # 存放 .json 输入配置
├── outputs/         # 运行时生成的结果
└── configs/         # Cromwell 后端配置(如果用到)

Cromwell 默认的输出路径是当前目录下的 cromwell-executions,可以通过 -Dconfig.file 参数指定自定义配置文件来修改。MiniWDL 则默认在当前目录下生成 miniwdl_run/ 目录。

对于 Cromwell,我建议手写一个简单的配置文件 cromwell.conf,指定本地后端和输出目录:

include required(classpath("application"))

webservice {
  port = 8000
}

backend {
  default = "Local"
  providers {
    Local {
      actor-factory = "cromwell.backend.impl.sfs.config.ConfigBackendLifecycleActorFactory"
      config {
        root = "outputs"
        filesystems {
          local {
            localization = "copy-local"
          }
        }
      }
    }
  }
}

这样跑 Cromwell 时加上 -Dconfig.file=configs/cromwell.conf 就能用自定义输出目录了。

2.4 验证环境:跑个 Hello World

光装完还不够,得跑一个最简单的 WDL 来验证三条链路:编写 → 校验 → 执行。

先写一个 hello.wdl:

version 1.0

workflow hello_workflow {
  String name = "WDL"

  call hello {
    input:
      name = name
  }
}

task hello {
  input {
    String name
  }
  command {
    echo "Hello, ~{name}!"
  }
  output {
    String greeting = read_string(stdout())
  }
}

再用 MiniWDL 快速验证语法和逻辑:

miniwdl run hello.wdl

应该看到类似输出:

Running workflow hello_workflow...
All outputs: ["Hello, WDL!"]
注意看输出的字符串里有没有正确的名字。如果没输出,检查下 WDL 版本声明和 task 引用语法。

再用 Cromwell 跑一遍:

java -jar ~/tools/cromwell/cromwell-87.jar run hello.wdl

启动后它会打开一个 Web 服务(默认端口 8000),同时在本机执行任务。看到 “Run ID: xxxx” 就算成功。如果你嫌它开 Web 服务麻烦,加个参数 --no-curl 可以关掉。

2.5 工具对比与选型建议

我把两个工具的核心差异整理成了一张表,方便你根据场景选择:

特性 Cromwell MiniWDL
运行模式 服务模式 + 命令行 纯命令行,单次运行
后端支持 本地、SLURM、AWS、GCP、PBS 等 仅本地(Docker 可选)
WDL 版本支持 draft-2 / 1.0 / 1.1 1.0(部分 1.1)
启动速度 较慢(依赖 Java 虚拟机启动) 几乎瞬间
适用阶段 生产、大规模并行、集群运行 开发调试、本地原型验证
调试体验 有 Web UI 和 API,日志详细 命令行输出,轻量直接
我的原则是:写 WDL 时先用 MiniWDL 快速迭代,确认逻辑无误后再用 Cromwell 跑全量。两套工具互补,不是二选一。

2.6 整体环境关系图

下面这张图展示了我们在本章搭建的三大组件以及它们之间的关系。看不清?点图放大?不不,咱们直接看内嵌 SVG——

WDL 执行环境组件关系图 WDL 源文件 输入 JSON 配置 Cromwell Java JAR / Web 服务 MiniWDL Python CLI / 单机 本地文件系统 / Shell Docker(可选) 输出结果 / 日志 可根据场景灵活选择执行器

从上图可以看到,你的 WDL 源文件和输入配置可以同时交给两个引擎。Cromwell 偏向生产环境,MiniWDL 适合调试。两者都能调用本地 Shell 或 Docker 来实际执行命令,最后产出结果和日志。

2.7 常见问题与避坑指南

  • Java 版本不对:Cromwell 启动时报 “UnsupportedClassVersionError”。我曾经被这个问题卡了半小时,后来发现用的 OpenJDK 8。换 JDK 11 就好了。
  • MiniWDL 找不到命令:如果你把它装在虚拟环境里,记得先 source venv/bin/activate 再跑。
  • Cromwell 输出路径全是数字目录:那是因为没配 cromwell.conf,用默认的执行 ID 作为目录名。按我上面的配置文件改一下,输出结构就清爽了。
  • WDL 语法校验不通过:先跑 miniwdl validate hello.wdl 看看具体报错。MiniWDL 的错误信息比 Cromwell 更友好。
千万别在生产环境直接用 MiniWDL 跑大规模并行任务——它不支持并发调度,也没有失败重试机制。MiniWDL 是用来“试”代码的,不是用来“跑”生产的。