2. Nextflow运行环境搭建

Nextflow 本身是一个基于 JVM 的工作流引擎,它的运行依赖 Java 运行时环境,同时它又通过“自举”方式把自身封装成一个可执行脚本。理解这一层依赖关系,是搭建稳定运行环境的前提。本节从 Java 环境准备开始,逐步完成 Nextflow 安装、版本锁定、配置文件编写,最后跑通一个 hello 流程,形成一条可复现的环境搭建闭环。

Java 环境:Nextflow 的运行底座

Nextflow 官方要求 Java 17 或更高版本(较新的 Nextflow 版本已不再支持 Java 8/11)。在开始安装 Nextflow 之前,先确认系统里已有的 Java 版本:

java -version
# 期望输出示例:
# openjdk version "17.0.10" 2024-01-16
# OpenJDK Runtime Environment (build 17.0.10+7)
# OpenJDK 64-Bit Server VM (build 17.0.10+7, mixed mode)

如果版本低于 17,或者系统根本没有 Java,推荐使用 Conda/Mamba 安装,这样可以把 Java 与 Nextflow 一起纳入同一个环境管理,避免污染系统级 JDK:

mamba create -n nf -c conda-forge openjdk=17 nextflow
mamba activate nf
java -version
nextflow -version

这里有一个容易被忽略的细节:Nextflow 的启动脚本会读取 JAVA_HOME 或直接调用 java。如果机器上同时存在多个 JDK,务必确认当前 shell 中 which java 指向的是 17 及以上版本,否则会出现 Unsupported class file major version 之类的启动错误。

Nextflow 安装与自举机制

Nextflow 的安装方式很特别:官方提供的 nextflow 文件本身是一个启动器脚本,首次运行时会根据内部记录的版本号,从 GitHub 拉取对应的 nextflow-<version>-all 自举包并缓存到 ~/.nextflow/ 下。因此安装过程实际上分两步:放置启动器 + 首次运行触发下载。

# 方式一:官方脚本安装(推荐)
curl -s https://get.nextflow.io | bash
chmod +x nextflow
sudo mv nextflow /usr/local/bin/

# 方式二:Conda 安装(与 Java 同环境)
mamba install -c bioconda nextflow

# 验证
nextflow info

nextflow info 会输出当前版本、运行平台、Java 版本以及缓存目录。如果网络受限,可以设置代理或使用 NXF_OPTS 指定镜像;企业内网环境也可以预先下载 all 包并放到 ~/.nextflow/ 下,避免每次启动都访问外网。

版本管理:让流程可复现

Nextflow 迭代很快,不同版本在 DSL2 语法、插件机制、容器支持上可能有差异。生产流程必须锁定版本,否则“昨天能跑、今天报错”会非常常见。锁定方式有三种,按推荐程度排列:

  • 环境文件锁定:在 Conda 的 environment.yml 中写死 nextflow=24.04.2,随环境一起分发。
  • 启动器锁定:保留一份指定版本的 nextflow 启动器,配合 NXF_VER 环境变量控制。
  • 容器镜像锁定:把 Nextflow 与 Java 一起打进 Docker/Singularity 镜像,用镜像 tag 固定版本。
# 临时切换版本(会触发对应版本自举包下载)
NXF_VER=24.04.2 nextflow -version

# 在 nextflow.config 中声明最低版本要求
nextflowVersion = '>=24.04.0'

在 nextflow.config 里写 nextflowVersion 是一个好习惯:当别人用旧版本运行时,Nextflow 会直接给出明确报错,而不是在流程中途出现难以定位的语法问题。

配置文件:nextflow.config 的基本结构

nextflow.config 是 Nextflow 的核心配置入口,它决定了流程在哪里跑、用什么执行器、资源如何分配、容器如何启用。一个最小可用的配置如下:

nextflowVersion = '>=24.04.0'

params {
    input  = "${projectDir}/data/samples.tsv"
    outdir = "${projectDir}/results"
}

process {
    executor = 'local'
    cpus     = 2
    memory   = '4 GB'
    time     = '1h'
    errorStrategy = 'retry'
    maxRetries    = 2
}

docker {
    enabled = false
}

report {
    enabled = true
    file    = "${params.outdir}/pipeline_report.html"
}

几个关键点:params 块定义默认参数,命令行 --input 会覆盖它;process 块中的资源设置是全局默认值,单个 process 可以再覆盖;executor 决定任务提交方式,本地调试用 local,集群上换成 slurm、pbs 等;report 会生成 HTML 执行报告,便于排查资源与耗时。

第一个 hello 流程

下面写一个最小 DSL2 流程,包含一个参数、一个 process 和一个输出通道。保存为 hello.nf:

#!/usr/bin/env nextflow

nextflow.enable.dsl = 2

params.greeting = 'Hello'
params.name     = 'Nextflow'

process sayHello {
    tag "$name"
    publishDir "${params.outdir}/hello", mode: 'copy'

    input:
    val name

    output:
    path 'greeting.txt'

    script:
    """
    echo "${params.greeting}, ${name}!" > greeting.txt
    """
}

workflow {
    Channel.of(params.name)
        | sayHello
}

运行命令:

nextflow run hello.nf --name Bioinfo --outdir results

执行后,终端会输出任务哈希、process 名称、状态和耗时;results/hello/greeting.txt 中会写入 Hello, Bioinfo!。同时 results/pipeline_report.html 会记录本次运行的资源使用情况。如果看到 Completed successfully,说明 Java、Nextflow、配置文件和流程本身都已正确串联。

首次运行 nextflow run 时,Nextflow 会在当前目录生成 .nextflow/ 缓存和 work/ 工作目录。调试阶段可以保留 work/ 以便查看中间文件;正式运行时可用 nextflow clean -f 清理,避免磁盘被历史任务占满。

环境搭建的完整关系

把上面的步骤串起来看,Java 提供运行时,Nextflow 启动器负责自举与调度,配置文件决定执行策略,流程脚本描述计算逻辑,四者缺一不可。下图展示了它们之间的依赖与数据流向,以及版本锁定在其中的位置。

Nextflow 运行环境依赖与数据流 Java 运行时 OpenJDK 17+ JAVA_HOME / PATH Nextflow 启动器 自举包缓存 ~/.nextflow NXF_VER 版本控制 nextflow.config params / process / executor nextflowVersion 约束 提供 JVM 注入配置 hello.nf DSL2 workflow process sayHello 解析执行 执行器 Executor local / slurm / pbs cpus / memory / time 提交任务 输出与报告 results/hello/greeting.txt pipeline_report.html publishDir 运行命令 nextflow run hello.nf --name Bioinfo --outdir results 版本锁定:environment.yml 固定 nextflow=24.04.2 | nextflowVersion 声明最低版本 | 容器镜像 tag 固化