环境准备:本地Docker、Cromwell安装、虚拟机设置

说实话,很多混合云迁移项目最后栽在第一步——环境没搭利索。我见过团队花了两周调Cromwell,结果发现是Docker版本不兼容,一怒之下全重装了。咱们别走那个弯路。

这一章的目标很简单:在你的本地机器上搭出一个能跑Cromwell的最小环境。包括三块——Docker、Cromwell本体、还有必须的虚拟机/云主机连通配置。我会按我自己的安装流水线来讲,你跟着做就行。

基础设施概览

先看整体逻辑,心里有个谱:

环境准备核心组件 Docker引擎 Cromwell服务 目标主机(ES/云) 容器运行时 Docker CE 20.10+ 开启CPU/RAM限制 工作流调度器 Cromwell 87+ MySQL/PostgreSQL后端 执行节点 Ubuntu 20.04 / CentOS 7 SSH密钥认证 网络互通(VPC/SSH/端口放行)

关键链路:Docker 装在本地或跳板机上 → Cromwell 以 JAR 或容器方式运行 → 通过 SSH 或 HTTP 向远程虚拟机/云主机下发任务。三者网络必须打通,否则后面全是空转。

第一步:安装 Docker

Docker 这东西现在基本成了基础设施标配。但我建议你别图省事直接 apt install docker.io,那种版本经常落后一两个大版本。我习惯从官方仓库装,干净又可控。

Ubuntu 下标准操作:

sudo apt update
sudo apt install -y ca-certificates curl gnupg lsb-release
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

装完别忘了把当前用户加入 docker 组,省得每次 sudo:

sudo usermod -aG docker $USER
newgrp docker   # 或者重新登录一次

小技巧:检验是否成功,跑个 docker run hello-world。如果提示“permission denied”,那就是组没生效——我最开始也犯过这个错,后来学乖了,每次都先跑一遍这个测试。

第二步:安装 Cromwell

Cromwell 本质是个 Java 应用,一个 JAR 包搞定。我个人喜欢直接下载最新版,而不是用包管理器:

wget https://github.com/broadinstitute/cromwell/releases/download/87/cromwell-87.jar
mv cromwell-87.jar /opt/cromwell/

然后你需要一个配置文件。Cromwell 默认会连本地 H2 数据库,但混合云场景我强烈建议用 MySQL 或 PostgreSQL,后面任务多了 H2 扛不住。这是我的最小配置模板:

# cromwell.conf
include required(classpath("application"))

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

database {
  profile = "slick.jdbc.MySQLProfile$"
  db {
    driver = "com.mysql.cj.jdbc.Driver"
    url = "jdbc:mysql://localhost:3306/cromwell?useSSL=false&allowPublicKeyRetrieval=true"
    user = "cromwell"
    password = "your_password"
    connectionTimeout = 5000
  }
}

启动 Cromwell:

java -jar /opt/cromwell/cromwell-87.jar server --config /etc/cromwell/cromwell.conf

等几秒钟,看到日志输出 Server running at http://0.0.0.0:8000 就说明成功了。我记得有一次配置里漏写了数据库驱动,启动直接报错,查了半天才发现是 mysql-connector-java 没放到类路径里。所以如果你用 MySQL,记得额外下载 jar 放到 lib 目录:

wget https://repo1.maven.org/maven2/mysql/mysql-connector-java/8.0.33/mysql-connector-java-8.0.33.jar
java -cp "/opt/cromwell/cromwell-87.jar:/opt/cromwell/lib/*" cromwell.CromwellApp server --config /etc/cromwell/cromwell.conf

第三步:配置虚拟机 / 云主机

Cromwell 只负责调度,实际干活的是远程机器。我常用的模式是:在本地或跳板机跑 Cromwell,然后通过 SSH 把任务发到一台或多台 Ubuntu 22.04 云主机上。

你需要确保远程机器满足这些条件:

项目 最低要求 推荐配置
操作系统 Ubuntu 18.04 / CentOS 7 Ubuntu 22.04 LTS / Rocky Linux 9
CPU 2 核 8 核以上
内存 4 GB 16 GB + 交换空间
磁盘 40 GB(系统 + 临时数据) 200 GB SSD + 单独数据盘
网络 SSH 端口可达(默认 22) 内网 VPC + 安全组放行 22、8000
运行时 Docker CE 20.10+ Docker CE 24+

关键的 SSH 配置。我通常创建一个专用用户 cromwell 并配好密钥:

# 在远程机器上
sudo useradd -m -s /bin/bash cromwell
sudo mkdir -p ~cromwell/.ssh
echo "ssh-rsa AAA... your-public-key" | sudo tee ~cromwell/.ssh/authorized_keys
sudo chmod 600 ~cromwell/.ssh/authorized_keys
sudo chown -R cromwell:cromwell ~cromwell/.ssh

# 允许该用户执行 docker(重要)
sudo usermod -aG docker cromwell

然后在 Cromwell 的配置里加一个 SSH 后端。我给个简化示例:

# cromwell.conf 增加 backend provider
backend {
  default = "SshBackend"
  providers {
    SshBackend {
      actor-factory = "cromwell.backend.impl.sfs.config.SshBackendLifecycleActorFactory"
      config {
        root = "/home/cromwell/cromwell-root"
        filesystems {
          local {
            localization = "copy"
          }
        }
        connection {
          host = "10.0.1.100"
          user = "cromwell"
          key-file = "/home/youruser/.ssh/id_rsa"
          timeout = 30
        }
      }
    }
  }
}

注意:我曾经踩过一个大坑——远程机器上的 Docker daemon 没有设置数据目录权限,导致 Cromwell 下发的容器创建失败,但错误信息只显示“exit code 125”。排查了半天。所以装完 Docker 后一定要用 docker run --rm hello-world 在远程机器上验证一遍。

验证端到端连通性

环境都搭好了,咱们跑个最小的 WDL 测试一下:

# hello.wdl
workflow hello {
  call sayHello
}
task sayHello {
  command {
    echo "Hello from Cromwell!"
  }
  output {
    String out = read_string(stdout())
  }
  runtime {
    docker: "ubuntu:latest"
  }
}

提交任务:

curl -X POST http://localhost:8000/api/workflows/v1 \
  -F workflowSource=@hello.wdl \
  -F workflowInputs={}

如果一切顺利,你会得到类似这样的返回:

{
  "id": "a1b2c3d4-...",
  "status": "Submitted"
}

然后轮询状态:

curl -s http://localhost:8000/api/workflows/v1/a1b2c3d4-.../status

看到 "Succeeded" 的那一刻,环境准备就算彻底完成了。嗯,其实还有一种更快的验证方式——直接看日志里有没有明晃晃的 Backend initialization complete.。

常见问题速查

  1. Docker daemon 没启动 → 手动跑 sudo systemctl start docker && sudo systemctl enable docker
  2. Cromwell 启动报数据库连接失败 → 检查 MySQL 是否允许远程连接,以及 cromwell 用户是否有建表权限
  3. 任务卡在 Queued 状态 → 大概率 SSH 连不上远程主机,先手动 ssh cromwell@10.0.1.100 试试
  4. 容器退出的错误码 125/137 → 通常是资源限制导致 OOM,检查远程机器的 docker info 中内存限制是否打开

一句话总结:本地 Docker 装好 → Cromwell JAR 跑起来 → 远程虚拟机配好 SSH 密钥和 Docker → 用 hello.wdl 走通全流程。底层网络连通是地基,数据库持久化是长期跑的保障。做到这两点,后面的混合云迁移就有了一个稳当的起点。