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 图把这套架构的关系画了出来——
3.5 结合质谱数据分析场景
这套架构在批量处理质谱样本时怎么用?我举个例子:
- 构建镜像:把质谱数据处理软件(比如 OpenMS、mzQC 库)和依赖的 Python/R 环境打包成镜像,Dockerfile 里做好多阶段构建,减少体积。
- 推送仓库:镜像 push 到公司私有 Harbor,团队成员都能拉。
- 容器批量运行:写一个 shell 脚本,遍历一批 .mzML 文件,每条命令都
docker run --rm -v $(pwd)/input:/data mylab/ms-tool:1.0启动一个新容器处理一个文件。 - 清理:每次处理完加上
--rm,容器自动删除,不给宿主机留垃圾。
我个人的习惯是每新接一批质谱样本数据,都会先更新镜像版本号,打上标签如 ms-tool:v2.3.0,再 push 到仓库,然后集群节点自动拉取新版本批量运行。这样所有样本的处理环境完全一致,实验结果可复现。嗯,您也可以试试。如果您还没搭建私有仓库,强烈建议从 Harbor 开始,部署起来比想象中简单。