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 是不是我部署的那份。
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,因为很多应用需要优雅关机。但紧急情况下,该用还得用。
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
这些命令我每天至少用好几次,已经刻进肌肉记忆了。
嗯,这一套操作你反复练几遍,就会变成习惯。镜像拉取、容器运行、日志查看、进入调试、停止删除——每次折腾一个容器,就走过这个循环。不用想太多,敲就完了。