Docker基础操作:从拉取到清理,一套完整的容器生命周期

对 Docker 来说,容器就像一个个轻量级的虚拟机。但它的生命周期管理,说白了就六个动作:拉取、运行、看日志、进入、停止、删除。这六个动作我每天都在用,几乎成了肌肉记忆。

我记得刚开始带团队时,有个小伙子上线前忘了删临时测试容器,结果生产环境磁盘被打满…… 从那以后,我特别强调“操作闭环”的概念。你创建了什么,用完就要清理什么。咱们从拉取走起。

本章核心:掌握容器从生到死的完整操作链。
重点不在于记住所有参数,而在于形成一套标准的处理习惯。

拉取镜像:你总得先有“模子”

拉取镜像是所有操作的前提。没有镜像,你拿什么运行容器?

我个人习惯用 docker pull 来获取镜像。命令很简单:

docker pull nginx:latest
docker pull ubuntu:22.04
docker pull python:3.11-slim

这里我踩过一个坑:标签问题。我曾经在项目中直接用 nginx:latest,结果一个月后重新拉取,配置全变了。因为 latest 只是个指针,指向最新版本。你想想看,如果依赖 latest,哪天上游更新了,你的环境可能就炸了。

所以我现在有个习惯——拉取时指定具体版本:

docker pull nginx:1.25
docker pull postgres:16-alpine

这样做的好处是“可复现”。不管什么时候拉,内容都一样。

小技巧:平时可以用 docker images 查看本地仓库里已有的镜像。
docker images
# 或者
docker image ls
这两个命令效果一样,我更喜欢 docker images,敲起来顺手。

运行容器:从镜像到实例的临门一脚

镜像拉好后,下一步就是运行容器。命令是 docker run。但这家伙参数多,新手容易懵。

我通常把 docker run 拆成几个基本参数来记:

docker run -d --name my-nginx -p 8080:80 nginx:1.25
参数含义我的备注
-d后台运行(detach)不加这个,终端就被“粘住”了
--name给容器起名字不指定的话 Docker 会随机生成一个,不好记
-p端口映射宿主机端口:容器端口
-i -t交互式终端调试时常用,可合并为 -it

举个例子,我想跑一个 Ubuntu 容器进去玩玩:

docker run -it --name debug-ubuntu ubuntu:22.04 bash

-it 加上 bash,容器启动后会直接进入 shell。嗯,这里要注意:容器里默认是终端环境,没有中文支持,也没有你习惯的工具链。我第一次用 ubuntu 镜像时,进去发现连 ping 都没有…… 需要自己 apt update && apt install。

避坑提醒:docker run 每次都会创建一个新容器。如果你只是想让已经停止的容器重新跑起来,用 docker start 容器名 而非 docker run。

查看容器日志:排查问题的第一件事

容器跑起来后,你总会好奇它里面发生了什么。日志就是你的探针。

docker logs my-nginx

这条命令会打印容器标准输出(stdout)的所有内容。我常用的几个变体:

  • docker logs -f my-nginx —— 持续跟踪日志输出,像 tail -f 一样
  • docker logs --tail 50 my-nginx —— 只看最后50行
  • docker logs --since 5m my-nginx —— 只看最近5分钟的日志

我记得有一次排查生产故障,容器不断重启。我用 docker logs --tail 20 my-app 看到了错误信息——数据库连接超时。没有日志的话,你就像盲人摸象。

进入容器:在“内部”做诊断

光看日志还不够,有时你得直接进容器里看一眼。这里有两个命令:docker attach 和 docker exec。我推荐用后者。

docker exec 是在运行中的容器里启动一个新进程。用法:

docker exec -it my-nginx bash

这样就进入了 nginx 容器的 bash 终端。你可以查看文件、修改配置、检查进程。我经常进去看 /etc/nginx/nginx.conf 是不是我部署的那份。

为什么呢? 有的基础镜像(比如 alpine)默认没有 bash,只有 sh。这时候可以这样:
docker exec -it my-alpine-container sh
或者安装 bash 后再进入。我个人习惯先装 bash,毕竟用得顺手。

还有一点:docker exec 创建的进程退出后,容器仍在运行。而 docker attach 会直接连接到主进程,退出时容器也会停止。所以除非你特别清楚自己在做什么,否则别用 attach。

停止与删除:记得“关水龙头”

容器用完了,就得停掉、删掉。不养成这个习惯,你的服务器上会堆满废弃容器。

停止一个容器:

docker stop my-nginx

如果你停不下来(某些容器里进程没响应 SIGTERM),可以强制杀死:

docker kill my-nginx

停止后容器还在,可以用 docker ps -a 看到它。要彻底删除:

docker rm my-nginx

你也可以一步到位——停止并删除:

docker rm -f my-nginx

这里有个细节:用 -f 时,Docker 会先发 SIGKILL 强制终止进程,再删除。我一般不推荐频繁使用 kill 或 rm -f,因为很多应用需要优雅关机。但紧急情况下,该用还得用。

实际案例:我曾经在测试环境忘了清理一个占用 2GB 内存的容器,跑了三天才发现。白白浪费了一大批资源。所以我建议定期执行:
docker container prune
这条命令会删除所有已停止的容器。别怕,仍在运行的容器不会受影响。

完整的操作链:一张图说清楚

上面五个步骤是串起来的。我画了一张流程图来总结——你可以看到从头到尾的操作脉络:

Docker 容器生命周期操作链 docker pull docker run docker logs docker exec docker stop docker rm docker container prune 虚线 = 调试/运维可选路径 节点颜色对应 ■ 蓝色:获取(拉取) ■ 绿色:创建(启动) ■ 橙色:观察(日志) ■ 紫色:诊断(进入) ■ 红色:销毁(停止/删除)

你看,从左到右是“正向流”:拉取 -> 运行 -> 日志/进入(调试) -> 停止 -> 删除。虚线表示你可以在运行时随时停下来看日志或进入容器,修完了再决定是继续用还是删掉。

一些操作习惯总结

我罗列了几条我认为非常重要的习惯,全部来自真实项目中的教训:

  • 命名容器:不加 --name 的话,Docker 会生成类似 hungry_bhaskara 这种名字,你根本记不住。我习惯用 项目-功能-序号 的命名方式,比如 blog-web-01。
  • 及时清理:用完的容器如果不打算再用,立刻删掉。别让它们“停在那里”。docker container prune 是个好工具。
  • 区分 detach 与 attach:-d 用于长期运行的 daemon 容器;-it 用于需要交互的任务。这两个场景用的参数完全不同。
  • 日志是命脉:生产环境建议把日志挂载到宿主机上,或者使用外部日志收集。不然容器一删,日志就没了。
我的日常快速检查清单:
# 看正在跑的容器
docker ps
# 看所有容器(含停止的)
docker ps -a
# 看本地镜像列表
docker images
# 批量删掉所有停止的容器
docker container prune
# 批量删掉所有没被使用的镜像(慎用)
docker image prune
这些命令我每天至少用好几次,已经刻进肌肉记忆了。

嗯,这一套操作你反复练几遍,就会变成习惯。镜像拉取、容器运行、日志查看、进入调试、停止删除——每次折腾一个容器,就走过这个循环。不用想太多,敲就完了。