1. Docker基础:为什么需要Docker、Docker与虚拟机的区别、Docker核心概念

1.1 为什么需要Docker?

说实话,我第一次接触Docker,完全是被环境逼的。那时候我要复现一个批次质控流程——就是把不同实验室、不同时间跑出来的质控样本重新处理一遍,保证结果一致。听起来简单?做起来简直噩梦。因为每个人的系统不一样,有的用CentOS,有的用Ubuntu,有的还装了不同版本的Python和R包。

环境不一致是质控复现最大的坑。我在项目里至少见过三次这种情况:

  • A实验室的脚本在本地跑得顺,到B实验室就抛异常
  • 某个依赖库小版本更新,结果差异肉眼可见
  • 服务器重装系统后,之前的流程彻底废了

嗯,后来我意识到,问题的根源在于环境依赖没有被固化。而Docker正好解决这个痛点——它把应用和它的运行环境(包括操作系统、库、配置、脚本)打包成一个独立单元,保证一次构建,到处运行。

说白了,Docker就是给你的质控流程拍一张“环境快照”,以后不管在谁的机器上,只要拉起这个快照,结果就是一样的。我习惯管这叫“环境冷冻术”。

1.2 Docker与虚拟机的区别

不少人刚接触时会把Docker和虚拟机混在一起。其实两者差得挺远。我画个对比表,你一看就明白了:

特性虚拟机(VM)Docker容器
虚拟化层级硬件级虚拟化(模拟整台物理机)操作系统级虚拟化(共享宿主机内核)
启动时间分钟级(需要加载完整Guest OS)秒级(直接利用宿主机内核启动进程)
资源占用重,每个VM包含完整OS(几GB起步)轻,容器镜像通常MB~GB级
隔离级别强,硬件级隔离进程级隔离(通过Linux Namespace + Cgroups)
适用场景需要完整OS环境、不同内核需求微服务、CI/CD、批量任务、同内核环境复现

举个例子:如果你要在同一台服务器上同时跑CentOS和Ubuntu的流程,那就得用虚拟机。但做质控复现,大部分流程跑在同一个Linux内核上(比如都是x86_64的Linux),这时候用Docker就够了——轻量、快速、容易管理。

我记得有个项目,服务器资源很紧张,原本用VM部署4个节点就跑满了。改成Docker容器后,同样的硬件跑了12个节点,还留有余量。

我的习惯:如果流程依赖特定的内核版本或硬件驱动(比如GPU),我会先用uname -r确认宿主机内核,再考虑是否用Docker。大部分时候,Docker的进程隔离已经足够安全。

1.3 Docker核心概念

要把Docker用溜,三个概念必须吃透:镜像(Image)、容器(Container)、仓库(Registry)。我习惯把它们类比成「程序安装包」、「运行中的程序」和「App Store」。

镜像(Image)

镜像是只读的模板,里面打包了应用、系统库、依赖、配置、脚本等所有东西。你想想看,质控流程需要的Python环境、R包、分析脚本、甚至特定版本的BioConda channel,都可以写进一个Dockerfile里。然后通过docker build生成镜像。

# 一个简单的质控流程镜像示例
FROM ubuntu:20.04
RUN apt-get update && apt-get install -y python3 python3-pip r-base
COPY requirements.txt /tmp/
RUN pip3 install -r /tmp/requirements.txt

镜像可以分层存储。每次修改只产生新的一层,复用已有层,节省空间。我经常用docker history看一个镜像的“成分”——哪一层装了啥,都清清楚楚。

容器(Container)

容器是镜像的运行实例。镜像文件系统是只读的,容器启动时会在上层加一个可写层,所有运行时产生的文件都写在这里。比如质控日志、中间结果,都可以放在容器内,也可以挂载到宿主机目录。

# 启动一个质控流程容器
docker run --rm \
  -v /data/input:/input \
  -v /data/output:/output \
  my-qc-image:latest \
  python run_qc.py --input /input/样本1.txt --output /output/结果1.csv

容器启动是秒级的,用完就销毁(--rm),不占空间。我曾在同一台8核机器上同时启动30个批次质控容器,每个负责一个样本,并行处理,几个小时内完成了原来要跑两天的分析。

曾经踩过的坑:有一次我忘了挂载持久化存储,容器跑完结果全部丢失,重新跑了一整天。后来我写了个启动脚本,强制检查-v挂载参数,再也不敢偷懒。

仓库(Registry)

仓库用来存放和分发镜像。大家最熟悉的是Docker Hub——官方的公共仓库。企业内部也可以搭私有仓库,比如Harbor、Nexus。质控流程标准化后,我把构建好的镜像推送到内部仓库,团队成员直接docker pull就能拿到一模一样的环境,再也不用发愁“你那边为什么跑不出来”。

# 推送镜像到私有仓库
docker tag my-qc-image:latest registry.mycompany.com/qc/my-qc-image:v1.0
docker push registry.mycompany.com/qc/my-qc-image:v1.0

# 队友拉取
docker pull registry.mycompany.com/qc/my-qc-image:v1.0

仓库还支持版本标签(tag),我习惯给每个批次流程打一个版本号,比如v1.0、v2.0-beta。这样哪天发现新版本有问题,直接回滚到旧版本,几秒钟的事。


下面这张图梳理了Docker的核心要素和它们之间的关系:

Docker 核心概念关系图 Registry(仓库) 存储与分发镜像 Image(镜像) 只读模板,包含环境 Container(容器) 镜像的运行实例 Docker Engine 容器运行时调度 Host OS(宿主机) docker pull docker push docker run 调度 & 隔离 共享内核 核心流程: 镜像从仓库拉取 → 通过引擎运行成容器 → 容器完成质控任务 → 新镜像可推送回仓库。

总结一下:镜像好比一个“标准化环境模板”,容器是模板跑起来后的“工作现场”,仓库就是存放模板的“中央货架”。三者配合,才能真正实现批次质控流程的一次构建、处处复现。