Docker镜像与容器基础操作

镜像和容器,是Docker世界里最核心的两个概念。我经常跟团队新同学说:镜像就是一份“可执行的打包文件”,容器则是这份文件“跑起来以后的进程实例”。你想想看,就像ISO镜像和虚拟机的关系——镜像是一张光盘,容器是光驱里正在读盘的那个运行环境。

我这个做生物信息学管线的,最怕环境不一致。QC工具换个版本就跑不通?以前全靠conda硬扛,直到用上Docker镜像,才真正告别“在我机器上能跑”这种尴尬。

关键认知:镜像只读不可写,容器在镜像层之上挂载可写层。所有对容器的修改,不提交新镜像的话,一删就丢。

2.1 镜像拉取 —— 从仓库拿“货”

你手上如果连镜像都没有,Docker也跑不出容器。第一步就是拉取镜像。命令很简洁:

docker pull [选项] 仓库地址:标签

举个例子,我常用ubuntu:22.04作为基础镜像:

docker pull ubuntu:22.04

默认从Docker Hub拉,速度在国内不太稳定。我建议配置国内镜像加速器,比如阿里云或腾讯云的。配置文件在/etc/docker/daemon.json:

{
  "registry-mirrors": ["https://your-mirror.mirror.aliyuncs.com"]
}

拉取时可以设置平台,比如在x86机器上拉arm镜像(用于交叉测试):

docker pull --platform linux/amd64 ubuntu:22.04
小技巧:拉取大镜像时加-q参数可以静默拉取,只显示镜像ID,适合脚本里用。

2.2 容器运行 —— 让镜像“活”起来

镜像拿到以后,用docker run启动容器。这是使用频率最高的命令。

docker run [选项] 镜像 [命令] [参数]

最基本的用法:

docker run --rm ubuntu:22.04 echo "Hello, Docker"

--rm参数表示容器退出后自动删除,临时测试时很有用。我当年不知道这个参数,测试完留下一堆已退出的容器,还要手动清理,特别烦。

下面是你需要掌握的常用docker run选项:

参数 作用 示例
-d 后台运行(detach) docker run -d nginx
-it 交互式终端(前台运行) docker run -it ubuntu bash
-p 端口映射(宿主机:容器) -p 8080:80
-v 挂载卷(宿主机目录:容器目录) -v /data:/data
--name 给容器命名 --name myapp
--restart 重启策略(always/unless-stopped等) --restart always
注意:用-v挂载宿主机目录时,容器内对该目录的修改会直接反映到宿主机。我曾经不小心把宿主机的/etc挂进去,容器内误操作导致宿主机系统文件被改——嗯,那次教训很深刻。建议只挂载数据目录,不要挂载系统目录。

2.3 常用命令速查

除了run和pull,日常操作还离不开下面这几条命令。

2.3.1 镜像管理

# 列出本地所有镜像
docker images

# 删除镜像(需要先删除依赖的容器)
docker rmi 镜像名:标签

# 给镜像打标签
docker tag 原镜像 新仓库/新镜像:新标签

# 从Dockerfile构建镜像
docker build -t 镜像名:标签 路径

避坑指南:我曾经docker images看到一堆“”镜像——这些都是 dangling 镜像,占空间。定期清理一下:

docker image prune -a -f

不过要小心,-a会删除所有未被任何容器引用的镜像,如果构建中途有缓存镜像也会被删。我一般只在CI流水线结束后跑一次。

2.3.2 容器管理

# 查看运行中的容器
docker ps

# 查看所有容器(包括已停止的)
docker ps -a

# 启动、停止、重启容器
docker start 容器ID或名字
docker stop 容器ID或名字
docker restart 容器ID或名字

# 强制删除容器
docker rm -f 容器ID或名字

# 查看容器日志(实时跟踪)
docker logs -f 容器ID或名字

# 进入运行中的容器(交互式shell)
docker exec -it 容器ID或名字 bash

docker exec非常实用。比如你有个跑生物信息管线的容器在后台跑,想进去看看中间结果:

docker exec -it my-qc-pipeline bash
推荐做法:启动容器时加--name起个好记的名字,后续操作直接用名字,不用记那一长串哈希ID。我习惯用项目名+功能命名,比如rnaseq-qc。

2.4 数据持久化与端口映射

容器默认是隔离的,数据随容器删除而丢失。要让数据持久化,有两条路:绑定挂载和数据卷。

绑定挂载:宿主机目录直接映射到容器目录,适合开发测试:

docker run -v /home/user/data:/data ubuntu ls /data

数据卷:由Docker管理,不依赖宿主机路径,适合生产:

docker volume create qc_data
docker run -v qc_data:/output ubuntu touch /output/result.txt

端口映射通过-p实现,格式是宿主机端口:容器端口。如果你跑一个Web服务(比如FastQC的HTML报告),可以映射出来:

docker run -d -p 8888:80 nginx

然后浏览器访问http://localhost:8888就能看到nginx默认页面。

2.5 本章知识体系

下面这张图帮你快速理清镜像与容器操作的全貌。

Docker镜像与容器基础操作流程 1. 获取镜像 2. 构建镜像(docker build) 3. 管理镜像(images / rmi / tag) A. 运行容器(docker run) B. 管理容器(ps / start / stop / rm) C. 查看日志与进入容器(logs / exec) 数据卷 / 端口映射(-v -p) 提交新镜像(docker commit) 镜像→容器:docker run 容器→新镜像:docker commit 镜像仓库:docker pull / push
一句话总结:镜像像“模板”,容器像“实例”。拉取镜像、构建镜像、管理镜像是一组操作;运行容器、管理容器、查看日志是另一组操作。两者通过run和commit互相转换。

掌握了上面这些命令,你已经可以应付90%的Docker日常工作了。接下来在实战中我会带你把质控管线封装进镜像,到时候这些命令你会用得更熟练。