可重复性实践:Docker与Nextflow结合 - 第1节

1. Docker 起源与核心概念

说起 Docker,我最早接触是在 2015 年。那时我在做一个生物信息学分析流程,环境依赖简直是个噩梦——Python 2.7 vs 3.5、R 版本冲突、某个 C 库非要特定的 glibc 版本。当时团队里有个同事神秘兮兮地说:「试试 Docker,装好一次,到处跑。」我半信半疑试了试,结果一发不可收拾。

Docker 这个项目最初是 dotCloud 公司(后来改名为 Docker Inc.)内部的一个小工具。2013 年开源,借助 Linux 内核的 cgroups 和 namespaces 技术,实现了轻量级的操作系统级虚拟化。说白了,它不像虚拟机那样需要模拟整个操作系统,而是直接共享宿主机的内核,只把进程、文件系统、网络等隔离起来。

为什么这很重要?因为它让「环境一致性」变得极其简单。你在笔记本上构建的容器,放到服务器、云端甚至同事的电脑上,行为完全一致。

核心洞察:容器不是微型虚拟机。它只是被隔离的一组进程,启动快(毫秒级)、资源开销低,非常适合微服务、持续集成和可重复性科研。

1.1 镜像、容器、仓库——三剑客

理解 Docker 要抓住三个核心概念:镜像(image)、容器(container)、仓库(registry)。

  • 镜像:一个只读的模板,包含操作系统文件、应用程序及其所有依赖。你可以把它想象成「软件安装包」的 snapshot。
  • 容器:从镜像启动的运行实例。它可在镜像上加一层可写层,所有修改都写在这一层,不影响原始镜像。
  • 仓库:存储和分发镜像的地方。最出名的是 Docker Hub,但你可以搭建私有仓库。

举个例子:我经常用 biocontainers 镜像跑 NGS 分析。拉取一次 quay.io/biocontainers/bwa:0.7.17,这个镜像就缓存在本地。每次启动一个容器,bwa 的环境是固定不变的。我的分析流程再也不会因为服务器升级而莫名报错。

个人习惯:我通常把基础镜像写成 Dockerfile 放在 Git 仓库里,配合 CI/CD 自动构建。这样环境变更都有历史可查,可复现性大大提高。

1.2 Docker 的应用场景

Docker 的应用场景比你想象的多。这里列几个我实际踩过坑的领域:

场景 为什么用 Docker 我的经历
科研可重复性 封装整个分析环境,包括工具、库、系统补丁 曾经审稿时作者提供了 Dockerfile,我直接拉取运行,结果完全一致。这种论文我打高分。
CI/CD 流水线 每个构建任务跑在干净容器里,避免环境污染 在 Jenkins 上用 Docker 做并行测试,速度提升 3 倍。
微服务架构 每个服务独立容器,独立扩展 公司从单体迁移到微服务,全靠 Docker Compose 做本地编排。
桌面开发环境 在 Mac/Windows 上模拟 Linux 环境 我开发 Nextflow 流程时,所有测试都在容器里运行,避免污染宿主系统。

嗯,你可能会问:「那 Docker 有没有缺点?」有的。比如需要 root 权限(现在有 rootless 模式了),磁盘占用可能膨胀,网络性能略低于原生。但总的来说,在可重复性实践中,它的利远大于弊。

2. 安装配置实战

下面说说在不同操作系统上安装 Docker。我按自己的实战经验讲,不列官方文档的废话。

2.1 Linux(Ubuntu 22.04 为例)

Linux 安装最顺畅,因为 Docker 本来就是 Linux 原生的。我建议用官方仓库,别用系统自带的过时版本。

# 卸载旧版本
sudo apt remove docker docker-engine docker.io containerd runc

# 安装依赖
sudo apt update
sudo apt install -y ca-certificates curl

# 添加 Docker 官方 GPG 密钥
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# 添加仓库
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] 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-buildx-plugin docker-compose-plugin

# 启动并设置开机自启
sudo systemctl enable docker --now

装完后验证:

sudo docker run hello-world

如果能打印出 Hello from Docker! 说明成功。注意:默认需要 sudo。我习惯把当前用户加入 docker 组,省得每次敲 sudo。

sudo usermod -aG docker $USER
newgrp docker
安全提示:加入 docker 组相当于获得了 root 权限,因为 docker 组用户可以通过挂载卷等方式操作宿主机。如果你在共享服务器上,最好限制 docker 组成员。

2.2 macOS

Mac 上需要安装 Docker Desktop,它是一个带 UI 的完整环境。我用的是 Intel Mac,但 Apple Silicon 用户要注意版本。

  1. 从 Docker官网 下载 Docker Desktop for Mac(根据芯片选择 ARM64 或 x86_64)
  2. 双击安装,把 Docker.app 拖到 Applications 文件夹
  3. 启动后在系统栏会出现鲸鱼图标,等它显示「Docker Desktop is running」
  4. 打开终端验证:docker version

我曾经踩过一个坑:在 Mac 上跑 Docker 默认使用 HyperKit 虚拟机,磁盘空间容易爆满。后来我改用新的 Apple Virtualization 框架(Docker Desktop 4.3+),才解决了这个问题。如果你用 M1/M2 芯片,记得勾选「Use VirtioFS」来提升文件共享性能。

2.3 Windows

Windows 安装推荐使用 WSL 2 后端。这是目前最丝滑的方式。

  1. 确保安装了 WSL 2(Windows 10 2004+ 或 Windows 11)
  2. 安装 Docker Desktop for Windows,安装时勾选「Use WSL 2 based engine」
  3. 重启后,在 Docker Desktop 设置中将默认 WSL 发行版设为 Ubuntu(或其他你常用的)
  4. 打开 PowerShell 运行 docker run hello-world

有个细节:Windows 上文件系统性能差异很大。把项目代码放在 WSL 的 Linux 文件系统下(比如 /home/yourname/project)比放在 /mnt/c/Users/... 快得多。我在做 NGS 流程测试时,这个改动让运行时间缩短了 40%。

避坑指南:我曾经在 Windows 上直接用 Docker Toolbox(旧版),后来发现它用的是 VirtualBox,磁盘 I/O 很慢。切换到 Docker Desktop + WSL 2 后问题迎刃而解。

3. 知识体系一览

下图概括了本章的核心逻辑——从容器原理解释到安装配置的整个脉络。

Docker 核心概念与安装流程 核心概念 镜像 (Image) 容器 (Container) 仓库 (Registry) 应用场景 科研可重复性 CI/CD 流水线 微服务架构 桌面环境模拟 安装配置 Ubuntu macOS Windows (WSL2) 驱动 落地 💡 可重复性实践基石 理解容器原理 → 选择适合的应用场景 → 正确安装配置 → 奠定可重复性基础设施