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个节点,还留有余量。
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的核心要素和它们之间的关系:
总结一下:镜像好比一个“标准化环境模板”,容器是模板跑起来后的“工作现场”,仓库就是存放模板的“中央货架”。三者配合,才能真正实现批次质控流程的一次构建、处处复现。