4. Docker 容器基本操作:运行、停止、删除
容器跑起来,才算真正用上 Docker。这一章咱们就聊最核心的三个动作:运行、停止、删除。操作本身不复杂,但坑不少。我最早学 Docker 时,光一个 docker run 就踩了好几回雷,比如容器启动后根本没跑到我想要的版本、端口忘映射、容器删不掉…嗯,这些我都会在下面拆开讲。
4.1 运行容器 —— 先让它活起来
最基础的命令就是 docker run。它从镜像创建一个新容器并启动。举个实际例子——我们在后面做质控管线时会用到的 FastQC 镜像:
docker run --rm -it biocontainers/fastqc fastqc --help
这条命令里:
--rm——容器退出后自动删除。我个人的习惯:调试阶段不加--rm,这样容器停了还能用docker start重新进去看日志;确定没问题了再补上--rm。-it——交互式,让你能实时看输出。biocontainers/fastqc——镜像名,后面跟的是容器内要执行的命令。
你想想看,docker run 背后其实做了三件事:下载镜像(如果本地没有)、创建容器、启动它。但注意,docker run 不等于 docker create + docker start,后者可以分两步做,适合需要先配置再启动的场景。
docker run -d nginx跑是跑起来了,但本机根本访问不到。必须加上
-p 8080:80 才能把宿主机的 8080 端口映射到容器内的 80 端口。我当初调试 NGS 质控报告 Web 界面时就栽过这个跟头。
常用的 docker run 参数我给你整理了一个速查表:
| 参数 | 作用 | 举例 |
|---|---|---|
-d |
后台运行(detached) | docker run -d nginx |
--name |
给容器起个名字,方便管理 | docker run --name myweb -d nginx |
-p |
端口映射 宿主机:容器 | docker run -p 8080:80 nginx |
-v |
挂载卷(宿主机目录:容器目录) | docker run -v /data:/app/data nginx |
--rm |
退出后自动删除容器 | docker run --rm alpine echo hello |
docker run 的最后一个参数可以是命令,也可以是 sh 进入容器 Shell。例如 docker run -it alpine sh,调试镜像内部环境时非常方便。
4.2 停止容器 —— 优雅还是暴力?
停止容器有两种方式:优雅停 docker stop 和暴力停 docker kill。区别在于:
docker stop先发 SIGTERM 信号,给进程 10 秒(默认)做清理工作,然后发 SIGKILL。docker kill直接发 SIGKILL,不给任何机会。
我建议在日常操作中用 docker stop,除非容器卡死无响应才用 docker kill。例子:
# 优雅停止名为 my_fastqc 的容器
docker stop my_fastqc
# 查看所有容器(包括已停止的)
docker ps -a
# 如果容器没反应,强制杀死
docker kill my_fastqc
为什么要区分?我记得有一次跑批量质控脚本,容器里正在写中间文件,用 kill 直接杀掉,结果输出文件损坏,又得重跑。从那以后我基本只用 stop,除非确认进程不关心数据一致。
4.3 删除容器 —— 清理战场
容器停止后并不会消失,只是状态变成 Exited。它们仍然占用磁盘空间。我自己的习惯是每周末清一次没用的容器。
# 删除一个停止的容器
docker rm my_fastqc
# 强制删除运行中的容器(相当于 stop + rm)
docker rm -f my_fastqc
# 删除所有已停止的容器
docker container prune
怎么查看有哪些容器可以删?用 docker ps -a,看 STATUS 是 "Exited" 的。如果容器很多,可以配合 grep:
docker ps -a | grep Exited | awk '{print $1}' | xargs docker rm
当然,更安全的是用 docker container prune,它只会删除停止的容器,运行中的不会动。这个命令执行前会问你是否确认,挺人性化。
docker stop 再 docker rm,或者直接用 docker rm -f。我遇到过因为 overlay2 驱动 bug 导致删不掉的,重启 Docker daemon 就好了。
4.4 容器的四种状态与操作对照
为了让你对整体流程更清楚,我画了个状态对照表:
| 当前状态 | 可用操作 | 结果 |
|---|---|---|
| Created(创建未启动) | docker start |
→ Running |
| Running(运行中) | docker stop |
→ Exited(退出码0) |
| Running(运行中) | docker kill |
→ Exited(退出码137) |
| Exited(已停止) | docker start |
→ Running |
| Exited(已停止) | docker rm |
→ 删除(不再存在) |
-v 挂载卷或者使用 named volume。我在给实验室搭建质控平台时,忘了挂载输出目录,跑完一上午的数据全没了,差点被老板骂死。
4.5 实战演练:从运行到删除的完整流程
拿我们后面的质控工具 FastQC 举例,你可以在终端里敲一下这段:
# 1. 查看本地是否有 fastqc 镜像
docker images | grep fastqc
# 2. 运行容器,后台执行 fastqc 分析
docker run -d --name fastqc_test \
-v /data/fastq:/input \
biocontainers/fastqc \
fastqc /input/sample1.fastq
# 3. 查看容器日志
docker logs fastqc_test
# 4. 等分析完成后,停止容器
docker stop fastqc_test
# 5. 删除容器(释放磁盘)
docker rm fastqc_test
如果想一步到位:docker run --rm ...,分析完容器就自动删除,省去第4、5步。不过调试时我建议还是分开,方便出问题时进容器 h 面看看。
4.6 避坑总结
- 容器名重复: 第二次用相同
--name会报错,先docker rm旧的。 - 端口冲突:
-p 8080:80如果 8080 已被占用,换个端口或先docker stop占用容器。 - 卷权限问题: 容器内程序可能以非 root 用户运行,挂载卷的目录权限要对。我经常先
chmod 777临时解决,但在生产环境别这么干。 - 不要随便
docker rm -f运行中的数据库容器: 除非你明确知道数据已持久化到卷,否则可能会丢数据。
好了,容器的运行、停止、删除就这么几个命令,但每个背后都有细节。多练几次,养成习惯——先 docker ps -a 看看环境再操作,别手一滑把正在用的容器干掉了。我当年就这么干过,一分钟前还在跑的任务被自己停了,气得想砸键盘。