第3章:单机部署Cromwell(Linux环境)
先搞清楚Cromwell到底是什么
Cromwell是一个开源的工作流执行引擎。说白了,你写好一个WDL或者CWL脚本,它帮你把任务挨个跑完。我最初接触它时,觉得这个东西也没多厉害——不就是个任务调度器吗?真正用上之后才发现,它支持的并行任务调度、后端插件机制、日志聚合这些能力,远比我想的复杂。
| 特性 | 说明 |
|---|---|
| WDL/CWL支持 | 原生运行两种工作流定义语言 |
| 多后端扩展 | Local、HPC、云平台都能对接 |
| RESTful API | 提供HTTP接口进行任务控制 |
| Scala编写 | 运行需要JVM环境 |
环境准备——先把JDK和Docker安好
我个人习惯先在干净的Linux机器上部署。Cromwell跑在JVM上,所以JDK是第一件要装的东西。
1. 安装JDK 11以上版本
sudo apt update
sudo apt install openjdk-11-jdk -y
java -version
输出结果应该是这样的:
openjdk version "11.0.18" 2023-01-17
OpenJDK Runtime Environment (build 11.0.18+10-post-Ubuntu-0ubuntu122.04)
OpenJDK 64-Bit Server VM (build 11.0.18+10-post-Ubuntu-0ubuntu122.04, mixed mode, sharing)
2. 安装Docker引擎
虽然单机部署时Cromwell可以直接跑本地任务,但我建议还是装上Docker。为什么呢?因为在实际项目中,很多WDL任务依赖特定镜像环境。
sudo apt install docker.io -y
sudo systemctl start docker
sudo systemctl enable docker
sudo usermod -aG docker $USER
记得重启会话让组权限生效。我见过有人忘记加用户组,结果Docker命令全要加sudo,Cromwell调用容器时直接权限拒绝,跑了半天的任务全废掉。
下载Cromwell——两种方式选一种
方式一:通过GitHub release下载jar包
这是最简单的方式。去GitHub的broadinstitute/cromwell仓库,找到对应版本的jar。我个人习惯用最新稳定版。
wget https://github.com/broadinstitute/cromwell/releases/download/85/cromwell-85.jar
方式二:从源码编译
如果你的环境有网络限制,或者需要定制特定版本,那就自己编译。嗯,这里要注意编译过程非常吃内存,至少给sbt分配4GB以上。
git clone https://github.com/broadinstitute/cromwell.git
cd cromwell
sbt "project cromwell" "set cromwell/assembly / cromwell-assembly-*.jar" assembly
配置文件——cromwell.conf的写法
Cromwell启动时会读取配置文件。不提供配置文件的话,它会用默认值。但那样做在正式项目里是跑不通的。
下面是一个最基本的本地模式配置文件:
backend {
default = "Local"
providers {
Local {
actor-factory = "cromwell.backend.impl.sfs.config.ConfigBackendLifecycleActorFactory"
config {
root = "/data/cromwell-executions"
filesystems {
local {
localization = [
"hard-link", "soft-link", "copy"
]
}
}
}
}
}
}
database {
profile = "slick.jdbc.H2Profile$"
db {
driver = "org.h2.Driver"
url = "jdbc:h2:file:/data/cromwell-db/cromwell;MODE=MSSQLServer;"
user = "sa"
password = ""
connectionTimeout = 30000
}
}
各参数作用是什么?我列个表:
| 参数 | 含义 | 建议值 |
|---|---|---|
| backend.default | 默认使用的后端 | Local |
| root | 任务执行目录 | /data/cromwell-executions |
| database.db.url | 数据库连接地址 | H2文件路径或MySQL地址 |
| localization | 输入文件本地化方式 | hard-link, soft-link, copy |
启动Cromwell
配置写完,接下来就是启动了。
mkdir -p /data/cromwell-executions
mkdir -p /data/cromwell-db
java -jar cromwell-85.jar server --config cromwell.conf
启动日志会输出到控制台。看到类似下面这行,说明启动成功:
2025-03-20 10:15:32,231 cromwell-system-akka.actor.default-dispatcher-3 INFO -
Cromwell Service started on port 8000...
默认端口是8000。你可以通过浏览器访问:
http://your-server-ip:8000
会返回一个简单的JSON响应,表示Cromwell正在运行。
screen -S cromwell
java -jar cromwell-85.jar server --config cromwell.conf
# 按下 Ctrl+A, D 脱离会话
screen -r cromwell # 重新连接
提交一个简单的WDL任务验证安装
装好之后必须跑个任务看看。这里用最简单的hello world WDL:
先创建一个hello.wdl文件:
task hello {
command {
echo "Hello, Cromwell!"
}
output {
String greeting = read_string(stdout())
}
runtime {
docker: "ubuntu:latest"
}
}
workflow hello_workflow {
call hello
}
再创建输入JSON文件:
{}
然后通过RESTful API提交:
curl -X POST \
--header "Accept: application/json" \
-F "workflowSource=@hello.wdl" \
-F "workflowInputs=@inputs.json" \
http://localhost:8000/api/workflows/v1
提交后会返回一个workflow ID,表示任务已经被接收。接着用ID查询状态:
curl http://localhost:8000/api/workflows/v1/{workflow-id}/status
正常应该返回:
{"status": "Succeeded", "id": "xxxx-xxxx-xxxx-xxxx"}
避坑指南——我踩过的那些坑
- 文件权限问题:我曾经在NFS挂载的目录下运行Cromwell,结果Docker容器无法写入任务目录。原因是容器内用户ID与普通用户不同。解决方案是root目录用本地磁盘,或者设置合适的所有权。
- 端口冲突:Cromwell默认端口8000。如果你的机器上已经运行了其他服务,改端口就行:用java -jar cromwell-85.jar server --config cromwell.conf -Dwebservice.port=8080
- Docker拉取超时:Ubuntu镜像在国内有时候拉取超时。我的做法是提前在本地把镜像拉好:docker pull ubuntu:latest
- 内存设置不足:Cromwell本身启动大概需要2GB内存。如果机器内存太小,建议增加JVM堆内存:java -Xmx4g -jar cromwell-85.jar server --config cromwell.conf
知识体系概览——这张图帮你理清流程
下面这张SVG图展示了单机部署Cromwell后,一个WDL任务的完整执行流程。
单机部署的局限性——别等到生产环境才后悔
单机部署Cromwell跑小规模任务完全够用。但如果你要跑几百上千个并行任务,单机模式会暴露几个问题:
- 资源瓶颈:单机CPU和内存有限,并行任务多了就排队
- 磁盘压力:所有任务输入输出都挤在同一台机器的磁盘
- 单点故障:Cromwell进程挂了,所有正在运行的任务跟着完蛋
- 扩展困难:没法动态增加计算节点
不过这些问题是后续章节要解决的事。现阶段,单机部署是学习和调试的最佳起点。你想想看,如果连单机都跑不通,去搞混合云部署不是更痛苦吗?