第二章 环境搭建:安装Cromwell、Java环境配置、本地运行第一个WDL工作流

说实话,环境搭建这事看着琐碎,但栽过跟头的人都知道——配好了后面全顺,配不对一步一个坑。我以前帮团队排查过一个问题,折腾了两天才发现是Java版本不对。所以这一章,咱们稳扎稳打。

2.1 Java环境配置

Cromwell 是 JVM 上的应用。运行时依赖 Java 8 或 11。我个人习惯用 Java 11,长支持版本,省心。

2.1.1 检查已有Java

你先打开终端,敲一句:

java -version

如果返回类似 openjdk version "11.0.18" 或 1.8.0_xxx,说明已经装了。如果提示找不到命令,那就去装一个。

2.1.2 安装Java(以Ubuntu为例)

sudo apt update
sudo apt install openjdk-11-jdk

装完再跑 java -version 确认。Windows 用户去 Adoptium 下载 msi 安装包,下一步到底就行。

2.1.3 设置JAVA_HOME(可选但推荐)

很多工具会读这个环境变量。我遇到过一次 Gradle 构建失败就是因为没配 JAVA_HOME。配一下不费事:

export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64
export PATH=$JAVA_HOME/bin:$PATH

想永久生效,就塞到 ~/.bashrc 或 ~/.zshrc 里。

注意:别用 Java 17 以上跑 Cromwell。早期版本直接不启动。曾经有个学员装了 Java 21,Cromwell 启动报 ClassNotFoundException……嗯,后来换了 Java 11 就好了。

2.2 下载与安装Cromwell

Cromwell 发布的是一个 fat jar。说白了就是一个大 JAR 包,包含所有依赖。下载步骤特别简单:

  1. 去 GitHub Releases 页面:https://github.com/broadinstitute/cromwell/releases
  2. 找到最新稳定版(比如 85),下载 cromwell-85.jar

或者直接用命令行:

wget https://github.com/broadinstitute/cromwell/releases/download/85/cromwell-85.jar

下载后我通常放 ~/tools/cromwell/ 里,好管理。

2.2.1 验证安装

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

如果输出类似 Cromwell 85-xxxxx,就成了。要是报错,八成是 Java 版本不对,回去检查 java -version。

小窍门:把 Cromwell jar 路径加到 alias 里,后面敲命令省事:alias cromwell='java -jar ~/tools/cromwell/cromwell-85.jar'。配好后 cromwell --version 直接跑。

2.3 理解Cromwell的运行模式

Cromwell 有两种启动模式:单机模式(Run)和服务器模式(Server)。我们第一章先用单机模式。服务器模式等到后面讲 REST API 时再涉及。

模式命令用途
Runjava -jar cromwell.jar run myworkflow.wdl直接执行一个 WDL,用完退出
Serverjava -jar cromwell.jar server启动常驻服务,通过HTTP提交任务

你想想看,刚学的时候用 Run 模式最直观。一次就跑一个工作流,日志全打在终端上,调试起来方便得很。

避坑指南:我第一次用 Run 模式时,忘了给 WDL 文件传输入参数。结果 Cromwell 报了个诡异的 NullPointerException。后来才发现,workflow {} 里声明了输入变量,但没给 JSON 输入文件。所以下面咱们写第一个工作流时,一定顺手把输入 JSON 也写了。

2.4 编写第一个WDL工作流

我们写一个最简工作流:接受一个名字,输出 "Hello {name}"。能跑通就是胜利。

2.4.1 WDL文件:hello.wdl

version 1.0

workflow hello_world {
  input {
    String name
  }
  call say_hello {
    input:
      name = name
  }
}

task say_hello {
  input {
    String name
  }
  command {
    echo "Hello ${name}"
  }
  output {
    String greeting = read_string(stdout())
  }
  runtime {
    docker: "ubuntu:latest"
  }
}

2.4.2 输入JSON文件:hello_inputs.json

{
  "hello_world.name": "Cromwell"
}

注意这个 key 的格式:{工作流名}.{输入变量名}。Cromwell 靠这个规则匹配输入。我刚开始经常写错——少了个下划线或多写了个点,跑起来就说 input not found。

2.4.3 执行命令

java -jar ~/tools/cromwell/cromwell-85.jar run hello.wdl -i hello_inputs.json

看到终端刷刷输出一堆日志,最后有这么一行,说明成功了:

[info] workflow output: {"hello_world.say_hello.greeting": "Hello Cromwell"}
经验之谈:初学时建议把 Cromwell 的日志级别调低,方便看清每一步在干什么:java -DLOG_LEVEL=DEBUG -jar cromwell.jar ...。但生产环境里别这么干,日志量太大会撑爆磁盘。

2.5 理解执行过程:一张图说清楚

这一节我用一张 SVG 把整套流程串起来。你注意看三个角色:你写的 WDL、Cromwell 引擎、以及底层的计算环境。执行时 Cromwell 会解析 WDL、载入输入、按依赖调度任务、最后收集输出。

Cromwell单机模式执行流程 WDL 工作流文件 输入 JSON 文件 Cromwell 引擎 解析·调度·执行 Docker 容器 输出结果文件 各环节说明 1. Cromwell 读取 WDL 文件定义的工作流结构和任务 2. 从 JSON 文件获取输入变量(如 name) 3. 按依赖顺序调度 task,在每个 task 内启动 Docker 执行命令 4. 收集 stdout 作为输出,写入到最终输出文件中

2.6 常见问题与排错

我帮你把新手最容易遇到的三类问题列出来,碰到了直接对照查:

症状原因解决
java.lang.UnsupportedClassVersionErrorJava版本太低或太高安装Java 11,重新设置JAVA_HOME
Input "hello_world.name" not foundJSON里的key写错了检查格式:{工作流名}.{变量名},注意大小写
Docker: Error response from daemonDocker没装或没运行装Docker Desktop并启动,确认 docker run hello-world 能用
警告:Cromwell 默认在本地跑 Docker 容器。如果你的机器没装 Docker,可以先把 WDL 里的 runtime { docker: ... } 一行删掉,Cromwell 就会直接用宿主机的 echo 命令。虽然不推荐,但至少能先跑通流程。

2.7 小结

到这一步,你已经在本地搭好了 Cromwell 环境,跑了第一个 WDL 工作流。别看只是输出了一个 "Hello Cromwell",背后的解析—调度—执行—输出流程,跟日后跑几百个任务的复杂工作流一模一样。把基础打牢,后面学起来才会顺手。

核心命令回顾:
java -jar cromwell.jar run workflow.wdl -i inputs.json
这是你之后最常用的命令。熟练了甚至可以写个脚本批量提交。