第 3 章 容器生命周期
本章目标:掌握容器的创建、启动、停止、删除与日志查看,理解前台/后台/交互模式、端口映射、环境变量与重启策略。
1. 容器的生命周期状态
容器不是只有"运行/停止"两种状态,完整状态机如下:
text
docker create / run
┌──────────────┐
▼ │
created ──▶ running ──▶ exited(正常退出/被停止)
│ │ │ │
│ │ └─ paused │
│ ▼ ▼
└── dead(强制终止,一般少见)created:已创建(分配了文件系统与网络),尚未启动;running:进程正在运行;paused:进程挂起(CPU 冻结,内存保留),用docker pause/unpause切换;exited:已退出或停止,文件系统仍保留,可再次start重启;dead:无法正常停止的异常状态。
查看容器:
bash
docker ps # 只看运行中的容器
docker ps -a # 所有容器(含已退出)
docker ps -a --format 'table {{.Names}}\t{{.Status}}\t{{.Image}}' # 自定义列docker ps 默认看不到已退出的容器,很多"容器不见了"的困惑都源于此——用 -a。
2. 创建与启动:create 与 run
docker run 是 docker create + docker start 的合并,日常直接用它:
bash
docker create --name web nginx:alpine # 只创建
docker start web # 再启动
docker run --name web2 nginx:alpine # 一步创建并启动(前台)docker run 的常用选项:
| 选项 | 作用 |
|---|---|
-d, --detach | 后台运行,立即返回容器 ID |
-it | 交互模式(-i 保持 STDIN 打开,-t 分配伪终端),进 shell 用 |
--name <名字> | 指定容器名(不指定则随机取名) |
--rm | 容器退出时自动删除(适合一次性任务) |
--restart <策略> | 重启策略(见第 5 节) |
-p 宿主:容器 | 端口映射(见第 3 节) |
-e 键=值 | 设置环境变量(见第 3 节) |
bash
docker run -d --name web -p 8080:80 nginx:alpine # 后台运行 nginx
docker run --rm -it alpine sh # 起一个一次性交互 shell--rm 与 --restart 语义相反(一个退出即删、一个退出即重启),不要同时使用。
3. 访问容器:端口映射与环境变量
容器有自己的网络命名空间,宿主机默认访问不到容器内的端口,需要显式发布端口:
bash
docker run -d --name web -p 8080:80 nginx:alpine
curl http://localhost:8080 # 宿主机 8080 端口 → 容器内 80 端口-p 8080:80 表示"宿主机 8080 映射到容器 80"。省略宿主机端口(-p 80)会随机分配宿主机端口;-P 把容器声明的所有 EXPOSE 端口都随机映射。
端口冲突:
-p的宿主机端口必须唯一,被占用时会报port is already allocated,换个端口或先清理旧容器。
环境变量用于向容器传配置(数据库地址、密钥、运行参数),很多官方镜像都靠它定制行为:
bash
docker run -d --name db \
-e MYSQL_ROOT_PASSWORD=secret \
-e MYSQL_DATABASE=app \
mysql:8.0多个变量可以用 --env-file 从文件读取:
bash
# env.list
MYSQL_ROOT_PASSWORD=secret
MYSQL_DATABASE=app
docker run -d --env-file env.list mysql:8.04. 运行中的管理:日志、进入容器、停止与删除
bash
docker logs web # 查看日志(-f 跟随、--tail 只看末尾 N 行)
docker exec -it web sh # 进入运行中容器的 shell(nginx:alpine 里有 sh)
docker top web # 查看容器内进程
docker inspect web # 查看容器的详细配置(JSON)
docker stats # 实时查看所有容器的资源占用exec 是在运行中容器里执行命令;容器已退出时 exec 会失败,此时只能 docker start 或 docker logs 看历史输出。
停止与删除:
bash
docker stop web # 优雅停止(发 SIGTERM,宽限期后 SIGKILL)
docker kill web # 立即强杀(SIGKILL)
docker rm web # 删除已停止的容器
docker rm -f web # 删除运行中的容器(先强杀再删)
docker container prune # 批量清理所有已停止的容器要点:
stop与kill的区别:stop给应用留优雅退出时间(默认 10 秒),kill立即强杀;- 删除运行中的容器必须
-f; - 停止 ≠ 删除:
docker stop后容器还在(ps -a可见、可start重启),docker rm才真正释放。
5. 重启策略:容器挂了自己爬起来
--restart 由 docker 守护进程负责拉起退出或宕掉的容器,适合部署场景:
| 策略 | 行为 |
|---|---|
no(默认) | 不自动重启 |
on-failure[:N] | 非零退出码时重启,最多 N 次 |
unless-stopped | 退出即重启,除非管理员手动 stop |
always | 总是重启(包括 docker 重启后) |
bash
docker run -d --restart unless-stopped --name web -p 8080:80 nginx:alpine
docker restart web # 手动重启
docker update --restart no web # 修改已有容器的重启策略实践建议:开发调试用 --rm,部署用 --restart unless-stopped。
常见误区
- 误区:
docker ps看不到容器 = 容器没了。 正确:已退出的容器用docker ps -a看;停止 ≠ 删除。 - 误区:
docker run -d后想看输出就直接看。 正确:用docker logs;-d会把输出与终端分离。 - 误区:端口映射失败是容器问题。 正确:先检查宿主机端口是否被占用(
netstat -ano | findstr 8080)。 - 误区:
docker attach和docker exec一样。 正确:attach连的是容器主进程的 stdin/stdout(通常配合-it交互),exec是在容器里新起一个进程(如 shell),更常用。 - 误区:容器重启 = 数据还在。 正确:
restart保留文件系统;但docker rm重建容器会丢可写层数据——数据持久化要交给第 4 章的数据卷。
小结
- 状态流转:
created → running → exited,停止 ≠ 删除,ps -a看全部。 docker run= create + start;-d后台、-it交互、--name命名、--rm用完即删。- 容器内端口默认不对外,用
-p 宿主:容器发布;配置用-e/--env-file传入。 - 运维三件套:
logs(看输出)、exec(进容器)、inspect(看配置)。 - 开发用
--rm,部署用--restart unless-stopped。
练习
- 用
nginx:alpine起一个后台容器(-d -p 8081:80 --name web),curl http://localhost:8081确认返回页面,再用docker logs查看访问日志。 - 用
docker exec -it web sh进入容器,echo hello > /usr/share/nginx/html/test.txt,浏览器访问http://localhost:8081/test.txt验证容器内文件对外可见。 - 依次执行
docker stop web、docker ps -a(观察状态)、docker start web、docker rm -f web,记录容器状态变化。 - 分别用
--rm和--restart unless-stopped运行容器,比较两者在手动 stop 后的行为差异。
可运行示例见
examples/03-container-lifecycle/,按其中的 README 步骤执行。