3. Docker 基础概念:镜像、容器、仓库、Docker 架构

你们好,这一章我们来聊聊 Docker 最核心的几个概念。说实话,当年我刚接触 Docker 的时候,也被镜像、容器、仓库这几个词绕得有点晕。后来在实验室折腾过几次才彻底搞明白——说白了,它们就是 Docker 世界的三块积木,理解透了,后面批量处理质谱数据才会顺手。

3.1 镜像:一个只读的“样板间”

先说说镜像。您可以把它理解成一个只读的模板——里面装了操作系统基础层、运行时环境、依赖库,还有您要跑的应用程序。镜像是分层构建的,每一层都可以重复利用,这一点在做质谱数据处理时特别实用。

您思考过没有?为什么大家总说 Docker 镜像“小”?

因为镜像文件里只存了“增量变化”。比如您拉一个 Ubuntu 镜像,里面只装了最精简的 coreutils 和 glibc,没有桌面环境,没有多余驱动。对比一下完整虚拟机动辄几个 GB,Docker 镜像往往只有几百 MB。我在项目中遇到过团队把每个质谱分析工具都单独做成镜像,结果拉取时间极短,磁盘占用也很少。

镜像构建小提示:
推荐用 Dockerfile 定义镜像,每一条指令都会产生一个新层。写 Dockerfile 时尽量合并 RUN 命令,减少层数。

3.2 容器:镜像的“运行态”

容器是基于镜像启动的一个独立进程。它有自己的文件系统、网络和进程空间,但共享宿主机的内核。您可以把容器看成镜像的“实例”。

我曾犯过一个错误:以为容器里面能装很多进程持久运行。其实 Docker 容器最佳实践是“一个容器一个进程”。质谱数据处理的时候,我习惯一个个容器跑完就销毁,这样每次处理都是一个干净环境——不会因为前一个样本的残留库污染下一个样本的结果。

核心区别:

特性 镜像 容器
读写状态 只读 可读写(上层)
生命周期 持久存在 创建 → 运行 → 停止 → 删除
启动方式 无 docker run
典型用途 分发、版本控制 单次或批量执行任务

3.3 仓库:镜像的“代码仓库”

仓库就是存放和分发镜像的地方。用的最多的是 Docker Hub 和 Harbor。仓库分公共和私有两种——质谱实验数据往往涉及项目保密,我建议您搭建私有仓库,比如用 Harbor 自托一个。

为什么要有仓库?您想想看,如果没有仓库,每次换台机器都要重新 build 一次镜像——不仅耗时,而且容易因环境差异导致构建失败。把镜像推到仓库,开发机、服务器甚至集群都能直接拉取同一个版本,这才是“一次构建,到处运行”。

常用命令一览:

docker pull ubuntu:22.04          # 从仓库拉取镜像
docker push mylab/ms-tool:1.0    # 推送镜像到仓库
docker search mzkit              # 在仓库中搜索镜像
避坑提醒:
我曾经在公共仓库里放过一个包含内网 IP 的配置文件的镜像——结果被外网直接拉走了,那叫一个尴尬。敏感信息千万不能打包进镜像,用环境变量或卷挂载来传参更安全。

3.4 Docker 架构:Client-Server 的协作方式

整个 Docker 采用的是 C/S(客户端/服务端)架构。您平时在终端里敲的 docker build、docker run 都是客户端行为,所有的实际工作都交给后台的 Docker 守护进程(dockerd)去完成。

我用一张 SVG 图把这套架构的关系画了出来——

Docker 架构关系图 Docker Client docker build / run / push Docker Daemon dockerd 后台进程 Registry Docker Hub / Harbor REST API pull / push 镜像 Image 容器 Container docker run 镜像层结构 Ubuntu 层 + 依赖库层 + 质谱工具层 (只读叠加) 容器运行时 读写层(临时) + 只读镜像层 进程隔离 独立网络

3.5 结合质谱数据分析场景

这套架构在批量处理质谱样本时怎么用?我举个例子:

  1. 构建镜像:把质谱数据处理软件(比如 OpenMS、mzQC 库)和依赖的 Python/R 环境打包成镜像,Dockerfile 里做好多阶段构建,减少体积。
  2. 推送仓库:镜像 push 到公司私有 Harbor,团队成员都能拉。
  3. 容器批量运行:写一个 shell 脚本,遍历一批 .mzML 文件,每条命令都 docker run --rm -v $(pwd)/input:/data mylab/ms-tool:1.0 启动一个新容器处理一个文件。
  4. 清理:每次处理完加上 --rm,容器自动删除,不给宿主机留垃圾。
一句话总结: 镜像 = 配方,容器 = 按配方现做的一顿饭,仓库 = 存配方的公共厨房。Docker Client 就是您点菜下单的手机 App,Daemon 是后厨的大师傅。

我个人的习惯是每新接一批质谱样本数据,都会先更新镜像版本号,打上标签如 ms-tool:v2.3.0,再 push 到仓库,然后集群节点自动拉取新版本批量运行。这样所有样本的处理环境完全一致,实验结果可复现。嗯,您也可以试试。如果您还没搭建私有仓库,强烈建议从 Harbor 开始,部署起来比想象中简单。