3. Docker 镜像管理:拉取、构建、标签与推送
镜像管理,说白了就是 Docker 使用者的基本功。你想想看,不管你的单细胞分析流程写得再漂亮,最后都得打包成镜像才能到处跑。这一章,我就带你把这四个核心操作——拉取、构建、标签、推送——彻底捋清楚。
3.1 镜像拉取:从 Registry 下载现成镜像
docker pull 是你最常用的命令。它的作用是从镜像仓库(比如 Docker Hub、GitHub Container Registry)把别人做好的镜像拉到本地。
我刚开始用 Docker 时犯过个错误:每次都 docker pull ubuntu:latest,后来发现这个 latest 标签在不同时间拉到的可能是不同版本,导致分析结果对不上。后来我学乖了——拉镜像时必须指定版本标签。
我的习惯做法:拉取镜像总带上具体版本号,除了初次测试时用 latest。
基本命令长这样:
# 拉取官方 Ubuntu 22.04
docker pull ubuntu:22.04
# 拉取带有 CUDA 的 R 基础镜像
docker pull rocker/tidyverse:4.3
# 拉取空间转录组分析常用工具
docker pull quay.io/biocontainers/seurat:4.4.0
拉取的镜像存放在本地,可以用 docker images 查看。如果你在墙内或者学校网络受限,记得配置镜像加速器。我曾经因为没配加速,pull 一个 2GB 的镜像等了三个小时才超时——太折磨了。
# 查看本地所有镜像
docker images
# 输出示例
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 22.04 a04f64a1d8a4 2 weeks ago 77.8MB
rocker/tidyverse 4.3 e3b0c44298fc 5 days ago 1.2GB
3.2 镜像构建:从 Dockerfile 生成镜像
拉取是拿别人的,构建才是做自己的。docker build 根据你写的 Dockerfile 来一步步生成镜像。这是整个封装过程中最核心的一步——你的单细胞分析环境好不好用,全看 Dockerfile 写得怎么样。
先看一个简单的 Dockerfile 示例:
FROM rocker/tidyverse:4.3
RUN apt-get update && apt-get install -y \
libhdf5-dev \
libxml2-dev \
libssl-dev
RUN R -e "install.packages('Seurat', repos='https://cloud.r-project.org')"
WORKDIR /workspace
COPY scripts/ /workspace/scripts/
CMD ["Rscript", "scripts/run_analysis.R"]
构建命令很简单:
# 在当前目录下找 Dockerfile 构建,-t 指定镜像名:标签
docker build -t spatial-analysis:v1 .
# 如果 Dockerfile 名字不一样,用 -f 指定
docker build -f Dockerfile.cpu -t spatial-analysis:cpu-v1 .
注意缓存问题:Docker 构建会缓存每一层。如果你改了 Dockerfile 的前几行,后面的层会用缓存,可能导致旧依赖混进来。我遇到过好几次——改了 Seurat 版本但忘记清理缓存,结果还是旧版。稳妥做法是用 --no-cache:
docker build --no-cache -t spatial-analysis:v2 .
为什么会这样?Docker 对每一条 RUN、COPY 指令都会生成一个层。只要指令文本没变,它就复用之前的缓存层。但你想想看,如果上游的基础镜像更新了,缓存层可能就不对了。所以定期用 docker build --pull 强制拉取最新的基础镜像是个好习惯。
3.3 镜像标签:给你的镜像起个靠谱的名字
docker tag 为镜像添加额外标签。标签就是镜像的别名,本身不复制数据。我见过很多新手直接 push 一个没有标签的镜像,最后仓库里一堆 latest,根本分不清哪个是哪个。
# 语法:docker tag 源镜像[:标签] 新镜像名[:新标签]
# 给本地镜像加标签
docker tag spatial-analysis:v1 docker.io/yourname/spatial-analysis:v1.0
# 加 latest 标签
docker tag spatial-analysis:v1 docker.io/yourname/spatial-analysis:latest
命名规范很重要。我个人习惯按这样的规则打标签:
| 字段 | 示例 | 说明 |
|---|---|---|
| 应用名 | spatial-single-cell | 表明用途,别起太通用 |
| 版本号 | v1.2.3 | 语义化版本,方便回溯 |
| 基础镜像 | r4.3-cuda12.0 | 标明底层环境,方便兼容性判断 |
| 日期 | 20250115 | 哪天构建的,排查问题时好用 |
一个完整的镜像名可以很长:
docker tag spatial-base:latest \
ghcr.io/your-lab/spatial-single-cell:r4.3-cuda12.0-v1.0.0-20250115
避坑指南:我曾有一次给镜像打错了 tag,结果 push 到了别人的仓库名下。你想想看,这后果多严重?所以推送前一定要用 docker images 确认镜像名和标签是否正确。
3.4 镜像推送:把镜像分享到仓库
构建好、打好标签,最后一步就是推送。推送前要先登录目标仓库:
# 登录 Docker Hub
docker login
# 登录 GitHub Container Registry
docker login ghcr.io -u your-github-username
# 登录私有仓库
docker login registry.yourlab.edu.cn
认证信息会被缓存,存在 ~/.docker/config.json。如果你用 CI/CD 自动推送,建议用 echo "PAT" | docker login ... --password-stdin 的方式,不要明文写密码。
推送命令:
# 推送已打好标签的镜像
docker push docker.io/yourname/spatial-analysis:v1.0
# 推送到 GitHub Container Registry
docker push ghcr.io/your-lab/spatial-single-cell:r4.3-cuda12.0-v1.0.0-20250115
# 推送多个标签
docker push yourname/spatial-analysis:latest
docker push yourname/spatial-analysis:v1.0
推送技巧:大镜像可以先试试 docker save 看看压缩后多大。超过 10GB 的镜像推送很容易超时。我一般会把基础依赖和数据分析工具分开成两个镜像,用 multi-stage build 或者共享 base 镜像来减小每次推送的负担。
镜像大小和推送时间的关系,我统计过一次:
| 镜像大小(压缩后) | 推送耗时(10Mbps 上行) | 建议策略 |
|---|---|---|
| < 500MB | 1-2 分钟 | 直接推送 |
| 500MB - 2GB | 5-15 分钟 | 分两次推送不同标签 |
| 2GB - 10GB | 20-90 分钟 | 用 base + app 拆分 |
| > 10GB | 可能超时失败 | 考虑用 .sif 或者压缩后手动传 |
嗯,这里要注意。推送大镜像时网络断了怎么办?Docker 支持断点续传——它会缓存已经推送的层。所以中断后重新 docker push 就好,不需要从头推。
3.5 全流程实战:从 Dockerfile 到仓库
把上面四个步骤串起来,一个典型的工作流是这样的:
# 1. 拉取基础镜像
docker pull rocker/tidyverse:4.3
# 2. 构建镜像(假设当前目录有 Dockerfile)
docker build -t spatial-seurat:dev .
# 3. 打标签
docker tag spatial-seurat:dev \
docker.io/wanglab/spatial-seurat:r4.3-v1.0.0
# 4. 登录仓库
echo "ghp_xxxxxx" | docker login ghcr.io -u wanglab --password-stdin
# 5. 推送
docker push docker.io/wanglab/spatial-seurat:r4.3-v1.0.0
# 6. 本地验证:删除后重新拉取
docker rmi docker.io/wanglab/spatial-seurat:r4.3-v1.0.0
docker pull docker.io/wanglab/spatial-seurat:r4.3-v1.0.0
最后一步的本地验证很重要。我吃过亏——push 上去的镜像因为 Dockerfile 里用了相对路径,COPY 指令没执行成功,结果在另一台机器上 pull 下来跑不了。所以推送完一定要在干净的本地重新拉取并测试一遍。
3.6 本章知识结构
下面这张图概括了镜像管理的完整流程和四个核心操作之间的关系: