4. Docker 容器基本操作:运行、停止、删除

容器跑起来,才算真正用上 Docker。这一章咱们就聊最核心的三个动作:运行、停止、删除。操作本身不复杂,但坑不少。我最早学 Docker 时,光一个 docker run 就踩了好几回雷,比如容器启动后根本没跑到我想要的版本、端口忘映射、容器删不掉…嗯,这些我都会在下面拆开讲。

容器生命周期核心流程 Image 镜像 Running 运行 Stopped 停止 Removed 删除 docker run docker stop docker rm -f docker rm 已停止容器 占用磁盘空间

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,后者可以分两步做,适合需要先配置再启动的场景。

曾经踩过的坑: 运行容器时忘了绑定端口。比如运行一个 Web 服务:
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,它只会删除停止的容器,运行中的不会动。这个命令执行前会问你是否确认,挺人性化。

小技巧: 如果你发现删不掉容器,提示 "Error response from daemon: unable to remove filesystem",多半是存储驱动问题或容器还在跑。先 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 看看环境再操作,别手一滑把正在用的容器干掉了。我当年就这么干过,一分钟前还在跑的任务被自己停了,气得想砸键盘。