第二讲:环境搭建准备——本地与云端的前置条件
说实话,Cromwell 的坑,有一半都埋在环境里。我见过不少人,工作流写得很漂亮,结果一跑就崩。最后发现,要么 Java 版本不对,要么 Docker 没装好,要么云 SDK 认证失败。所以这一章,咱们把地基打牢。
我把环境准备拆成三块:Java、Docker、云 SDK。每一块都有我踩过的坑,咱们直接说怎么装、怎么避坑。
2.1 整体环境概览
先给个全景图。Cromwell 服务端运行在 Java 虚拟机上,任务执行依赖 Docker 容器,跟云端通信靠云 SDK。这三者必须同时工作,缺一不可。
核心原则:Java 8 以上是刚需;Docker 必须支持 API 1.40+;云 SDK 版本要跟 Cromwell 后端配置对齐。
| 组件 | 最低版本 | 推荐版本 | 备注 |
|---|---|---|---|
| Java (JDK) | 1.8 | 11 / 17 | CentOS 7 自带 OpenJDK 11 |
| Docker | 19.03 | 24.0+ | 需要 containerd 和 runc |
| gcloud CLI | — | 最新 LTS | 必须配置 application-default 凭据 |
| Cromwell | — | 86+ | 建议 JAR 模式部署 |
下面这张图,展示各组件之间的调用关系。我个人习惯把它贴在工作站上,出问题先看一眼,定位很快。
2.2 Java 环境:版本决定成败
Cromwell 是用 Scala 写的,跑在 JVM 上。我记得第一次部署时用的是 Java 8,跑一个稍大的 WDL 就 OOM。后来换成 Java 11,堆外内存管理好很多。
安装命令(以 CentOS 为例)
# 安装 OpenJDK 11
yum install -y java-11-openjdk-devel
# 验证版本
java -version
# 输出应包含 "openjdk version "11.0.x""
经验谈:我个人强烈建议用 JDK 11 或 17。JDK 8 虽然也能跑,但 Cromwell 从 86 版本开始,已经不再对 JDK 8 做完整测试。你想想看,要是跑一半崩了,日志里报个 UnsupportedClassVersionError,那得多浪费时间。
常见安装失败与解决
- 问题:java: command not found
原因:没装 JDK,或者 PATH 没配。我曾经遇到有人只装了 JRE,Cromwell 跑不起来,因为 JRE 没有 javac。
解决:用yum list installed | grep java确认是否装了 JDK,而不是 JRE。 - 问题:Error: A JNI error has occurred
原因:Java 版本太老,或者 32 位/64 位不匹配。
解决:用uname -m确认架构,装对应架构的 JDK。 - 问题:PermGen / Metaspace 溢出
原因:Java 8 的永久代默认太小。Cromwell 启动时如果加载大量数据库驱动就容易炸。
解决:加 JVM 参数:-XX:MaxMetaspaceSize=256m
避坑实操:我曾经在升级 Cromwell 版本后,Java 11 报错 java.lang.reflect.InaccessibleObjectException。这是因为 Java 模块化限制了反射访问。解决方法是在启动脚本加 --add-opens java.base/java.lang=ALL-UNNAMED。这个问题很隐蔽,不熟悉 Java 模块化的朋友容易折腾半天。
2.3 Docker 环境:容器化的基础
Cromwell 的工作流任务,默认用 Docker 容器执行。它通过 Docker 的 API 来拉取镜像、运行容器、获取日志。所以 Docker 引擎必须稳定。
安装命令
# 推荐使用官方脚本
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh
# 启动并验证
systemctl start docker
docker info | grep "Server Version"
个人习惯:我会检查 Docker 的 API 版本。Cromwell 要求 1.40+。用 docker version 看 Client 和 Server 的 API 版本,必须都 >= 1.40。否则 Cromwell 会报 "Not supported" 错误。
常见安装失败与解决
- 问题:Cannot connect to the Docker daemon
原因:没启动 Docker 服务,或者当前用户不在 docker 组。
解决:systemctl start docker;然后usermod -aG docker $USER,退出重新登录。 - 问题:Error response from daemon: OCI runtime create failed
原因:容器运行时(runc)版本太低,或者 overlay2 文件系统有问题。
解决:升级 Docker 到 24.0+,检查df -hT /var/lib/docker确认文件系统类型。 - 问题:docker: 'compose' is not a docker command
原因:Docker Compose v2 还需要手动安装?其实 Docker 24+ 已经内置了。
解决:用docker compose version确认;没有的话装docker-compose-plugin包。
避坑实操:嗯,这里要注意。我曾经在一个 CentOS 7 的机器上装 Docker,系统内核是 3.10,结果 overlay2 驱动有 bug,导致容器跑着跑着就卡死。后来把内核升级到 4.18,问题才解决。所以你看,Docker 对内核也有要求。用 uname -r 检查,低于 4.x 的建议升级。
2.4 云 SDK 环境:打通混合云的关键
Cromwell 要跟云端通信,必须通过云 SDK 来做认证和 API 调用。以 Google Cloud 为例,常用的是 gcloud CLI 和它的应用默认凭据。
安装与初始化
# 安装 gcloud CLI
curl https://sdk.cloud.google.com | bash
exec -l $SHELL
gcloud init
# 配置应用默认凭据
gcloud auth application-default login
经验谈:我个人习惯把认证信息放到环境变量,而不是靠 gcloud 默认路径。因为 Cromwell 在某些执行后端(比如 PAPI v2)会直接读取环境变量。用 export GOOGLE_APPLICATION_CREDENTIALS=/path/to/your-key.json 更稳妥。
常见安装失败与解决
- 问题:ERROR: (gcloud.auth.login) Could not reach the login server
原因:网络代理没配。很多公司内网需要 HTTP 代理才能访问外网。
解决:export HTTPS_PROXY=http://proxy.example.com:8080 - 问题:Permission denied: compute.instances.create
原因:服务账号权限不够。Cromwell 需要新建虚拟机,所以要有 compute.admin 这类权限。
解决:给服务账号加 IAM 角色。我建议用自定义角色,只给最小权限,安全又省心。 - 问题:Quota exceeded: 'IN_USE_ADDRESSES'
原因:项目 IP 配额用完了。Cromwell 每启动一个任务就会创建一个临时外部 IP。
解决:在 GCP Console 里申请提升配额,或者在 Cromwell 配置里禁用外部 IP:noAddress: true
小结:环境安装看似琐碎,但每一步都直接影响 Cromwell 的稳定性。Java 版本要选对,Docker 引擎要稳,云 SDK 凭据要配准。这三样都就绪了,Cromwell 就能顺畅跑起来。
下面给一份完整的快速检查清单,装完环境后直接跑一遍,心里就有底了。
# 检查 Java
java -version && javac -version
# 检查 Docker
docker version --format '{{.Server.APIVersion}}'
docker run hello-world
# 检查 gcloud 认证
gcloud auth application-default print-access-token
# 如果有输出 Token,说明认证成功
要是哪一步报错,别慌。回到对应的小节,看看是不是版本不对、权限不足,或者内核太老。这些东西我基本都踩过一遍,照着上面的坑来排查,很快就能过。