第06章:Docker 容器生命周期
本章目标:掌握容器从创建到销毁的完整生命周期,学会容器的资源管理、健康检查和日志管理。
6.1 容器的状态机
6.1.1 容器的五种状态
┌─────────────────────────────────────────────────────┐
│ Docker 容器状态机 │
│ │
│ ┌──────────┐ │
│ │ Created │ ← docker create / docker run │
│ └────┬─────┘ │
│ │ docker start │
│ ▼ │
│ ┌──────────┐ │
│ │ Running │ ← 容器正在运行 │
│ └──┬───┬───┘ │
│ │ │ │
│ │ │ docker pause / unpause │
│ │ ▼ │
│ │ ┌──────────┐ │
│ │ │ Paused │ ← 进程被 SIGSTOP 挂起 │
│ │ └────┬─────┘ │
│ │ │ docker unpause │
│ │ └──→ Running │
│ │ │
│ │ docker stop (SIGTERM → SIGKILL) │
│ ▼ │
│ ┌──────────┐ │
│ │ Stopped │ ← 容器已停止(可重启) │
│ │ (Exited) │ │
│ └────┬─────┘ │
│ │ docker rm │
│ ▼ │
│ ┌──────────┐ │
│ │ Deleted │ ← 容器已删除(不可恢复) │
│ └──────────┘ │
└─────────────────────────────────────────────────────┘
6.1.2 状态转换命令
| 当前状态 |
操作 |
目标状态 |
命令 |
| --- |
创建 |
Created |
docker create |
| --- |
创建并启动 |
Running |
docker run |
| Created |
启动 |
Running |
docker start |
| Running |
暂停 |
Paused |
docker pause |
| Paused |
恢复 |
Running |
docker unpause |
| Running |
停止 |
Stopped |
docker stop |
| Running |
强制停止 |
Stopped |
docker kill |
| Stopped |
启动 |
Running |
docker start |
| Stopped |
删除 |
Deleted |
docker rm |
| 任意 |
强制删除 |
Deleted |
docker rm -f |
6.2 容器的基本操作
6.2.1 创建容器
# docker create 只创建不启动
docker create --name my-nginx -p 8080:80 nginx:latest
# 输出容器 ID:a1b2c3d4e5f6...
# 查看创建的容器(状态为 Created)
docker ps -a | grep my-nginx
# CONTAINER ID IMAGE STATUS NAMES
# a1b2c3d4e5f6 nginx:latest Created my-nginx
# 启动容器
docker start my-nginx
6.2.2 运行容器
# 常用的 docker run 参数
# 基本运行
docker run nginx
# 后台运行(detach 模式)
docker run -d nginx
# 交互式运行
docker run -it ubuntu:22.04 /bin/bash
# 命名容器
docker run -d --name web-server nginx
# 端口映射
docker run -d -p 8080:80 nginx # 主机端口:容器端口
docker run -d -p 127.0.0.1:8080:80 nginx # 仅本地访问
docker run -d -p 8080:80/tcp nginx # 指定协议
docker run -d -P nginx # 随机映射 EXPOSE 的端口
# 环境变量
docker run -d -e DB_HOST=mysql -e DB_PORT=3306 myapp
# 挂载卷
docker run -d -v /host/path:/container/path nginx
docker run -d --mount type=bind,source=/host,target=/container nginx
# 限制资源
docker run -d --cpus="1.5" --memory="512m" nginx
# 自动重启策略
docker run -d --restart=always nginx
docker run -d --restart=unless-stopped nginx
# 设置网络
docker run -d --network host nginx
docker run -d --network my-network nginx
# 读写模式
docker run -d --read-only nginx # 只读文件系统
docker run -d --tmpfs /tmp nginx # 临时文件系统
# 删除退出的容器
docker run --rm nginx # 容器退出后自动删除
6.2.3 docker run 参数详解
# 完整的 docker run 示例
docker run -d \
--name production-app \
--hostname app-server \
--network my-network \
--publish 8080:80 \
--env APP_ENV=production \
--env DB_HOST=mysql \
--volume /data/app:/app/data \
--mount type=bind,source=/config,target=/app/config,readonly \
--cpus="2" \
--memory="1g" \
--memory-swap="1g" \
--restart unless-stopped \
--health-cmd "curl -f http://localhost/health || exit 1" \
--health-interval 30s \
--health-timeout 5s \
--health-retries 3 \
--read-only \
--tmpfs /tmp \
myapp:latest
6.3 容器的停止与删除
6.3.1 停止容器
# 优雅停止(先发 SIGTERM,等待后发 SIGKILL)
docker stop <container> # 默认等待 10 秒
docker stop -t 30 <container> # 等待 30 秒后强杀
# 停止所有运行中的容器
docker stop $(docker ps -q)
# 强制停止(直接发 SIGKILL)
docker kill <container>
# 发送自定义信号
docker kill --signal=SIGHUP <container> # 重载配置
docker kill --signal=SIGUSR1 <container> # 自定义信号
6.3.2 删除容器
# 删除已停止的容器
docker rm <container>
docker container rm <container>
# 强制删除运行中的容器
docker rm -f <container>
# 删除所有已停止的容器
docker container prune
# 删除所有容器(包括运行中的)
docker rm -f $(docker ps -aq)
# 删除容器时同时删除关联的卷
docker rm -v <container>
6.3.3 清理策略
# 一键清理所有停止的容器、无用网络、悬空镜像和构建缓存
docker system prune
# 更彻底的清理
docker system prune -a --volumes
# 清理特定类型的资源
docker container prune -f # 停止的容器
docker volume prune -f # 无主的卷
docker network prune -f # 无用的网络
docker image prune -a -f # 未使用的镜像
6.4 容器的交互与调试
6.4.1 进入运行中的容器
# 方式1:docker exec(推荐)
docker exec -it <container> /bin/bash
docker exec -it <container> /bin/sh # Alpine 等没有 bash 的镜像
# 以特定用户执行
docker exec -it --user root <container> /bin/bash
# 设置环境变量
docker exec -it -e MY_VAR=value <container> /bin/bash
# 方式2:docker attach(不推荐)
docker attach <container>
# ⚠️ attach 进入的是容器的主进程,按 Ctrl+P, Ctrl+Q 可以安全退出
# ⚠️ 如果直接退出(Ctrl+C),容器会停止
6.4.2 查看容器日志
# 查看容器日志
docker logs <container>
# 实时跟踪日志
docker logs -f <container> # 类似 tail -f
docker logs --follow <container>
# 查看最后 N 行
docker logs --tail 100 <container>
# 查看特定时间之后的日志
docker logs --since "2024-01-01T10:00:00" <container>
docker logs --since 30m <container> # 最近30分钟
# 查看特定时间之前的日志
docker logs --until "2024-01-01T12:00:00" <container>
# 带时间戳
docker logs -t <container>
# 查看容器详情(包含日志路径)
docker inspect <container> --format='{{.LogPath}}'
# /var/lib/docker/containers/<id>/<id>-json.log
6.4.3 容器进程查看
# 查看容器内运行的进程
docker top <container>
# 查看容器资源使用(实时更新)
docker stats
docker stats <container>
# 查看容器资源使用(一次性)
docker stats --no-stream <container>
# 输出示例:
# CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O
# a1b2c3d4e5f6 web-server 0.05% 12.5MiB / 512MiB 2.44% 1.2kB / 0B 8.19kB / 0B
6.5 容器资源限制
6.5.1 CPU 限制
# 限制 CPU 核数
docker run -d --cpus="1.5" nginx # 最多使用 1.5 个 CPU 核心
docker run -d --cpus="2" nginx # 最多使用 2 个 CPU 核心
# 限制 CPU 份额(相对权重)
docker run -d --cpu-shares=512 nginx # 默认 1024
docker run -d --cpu-shares=1024 nginx # 与默认相同
docker run -d --cpu-shares=2048 nginx # 两倍权重
# 绑定到特定 CPU 核心
docker run -d --cpuset-cpus="0,1" nginx # 只使用 CPU 0 和 1
docker run -d --cpuset-cpus="0-3" nginx # 使用 CPU 0 到 3
# 查看容器 CPU 使用
docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}" <container>
6.5.2 内存限制
# 限制内存
docker run -d --memory="512m" nginx # 最大 512MB
docker run -d --memory="1g" nginx # 最大 1GB
docker run -d --memory="1g" --memory-swap="2g" nginx # 内存 1GB + swap 1GB
# 禁用 OOM Killer(谨慎使用)
docker run -d --memory="512m" --oom-kill-disable nginx
# 设置内存软限制
docker run -d --memory="512m" --memory-reservation="256m" nginx
# 查看容器内存使用
docker stats --no-stream --format "table {{.Name}}\t{{.MemUsage}}" <container>
6.5.3 磁盘 I/O 限制
# 限制读写速率
docker run -d --device-read-bps /dev/sda:10mb nginx # 读速率 10MB/s
docker run -d --device-write-bps /dev/sda:10mb nginx # 写速率 10MB/s
# 限制读写 IOPS
docker run -d --device-read-iops /dev/sda:1000 nginx # 读 IOPS 1000
docker run -d --device-write-iops /dev/sda:1000 nginx # 写 IOPS 1000
6.5.4 查看容器资源使用
# 查看所有运行容器的资源使用
docker stats
# 实时更新(类似 top)
docker stats
# 单次查询
docker stats --no-stream
# 自定义输出格式
docker stats --no-stream --format \
"table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}\t{{.BlockIO}}"
6.6 容器健康检查
6.6.1 在 Dockerfile 中定义
# 健康检查指令
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD curl -f http://localhost:8080/health || exit 1
# 不同应用的健康检查示例:
# Web 应用(HTTP 检查)
HEALTHCHECK CMD curl -f http://localhost/ || exit 1
# MySQL 数据库
HEALTHCHECK CMD mysqladmin ping -h localhost || exit 1
# Redis
HEALTHCHECK CMD redis-cli ping || exit 1
# PostgreSQL
HEALTHCHECK CMD pg_isready -U postgres || exit 1
# 禁用健康检查
HEALTHCHECK NONE
6.6.2 在 docker run 中定义
# 运行时添加健康检查
docker run -d \
--health-cmd "curl -f http://localhost/ || exit 1" \
--health-interval 30s \
--health-timeout 5s \
--health-start-period 10s \
--health-retries 3 \
nginx
6.6.3 查看健康状态
# 查看容器健康状态
docker inspect --format='{{.State.Health.Status}}' <container>
# healthy / unhealthy / starting
# 查看健康检查日志
docker inspect --format='{{json .State.Health}}' <container> | python3 -m json.tool
# 查看所有容器的健康状态
docker ps --format "table {{.Names}}\t{{.Status}}"
# NAMES STATUS
# web-server Up 5 minutes (healthy)
# database Up 10 minutes (healthy)
# cache Up 10 minutes (unhealthy)
6.7 容器的重启策略
# 设置重启策略
docker run -d --restart=no nginx # 默认,不自动重启
docker run -d --restart=always nginx # 始终重启
docker run -d --restart=unless-stopped nginx # 除非手动停止,否则重启
docker run -d --restart=on-failure:5 nginx # 失败时重启,最多5次
# 重启策略说明
# no 不自动重启(默认)
# always 始终重启(包括 Docker 守护进程启动时)
# unless-stopped 类似 always,但手动停止的容器不会自动重启
# on-failure[:max] 仅在非零退出码退出时重启,可选最大重试次数
6.8 容器的复制文件
# 从容器复制文件到主机
docker cp <container>:/app/logs/app.log ./logs/
docker cp a1b2c3d4e5f6:/app/config.json ./config.json
# 从主机复制文件到容器
docker cp ./data.csv <container>:/app/data/
docker cp ./config.json web-server:/etc/nginx/conf.d/
# 复制目录
docker cp <container>:/app/logs/ ./logs/
docker cp ./static/ <container>:/app/static/
# 注意:
# 1. 容器可以是运行中或已停止状态
# 2. 目标路径不存在时会自动创建
# 3. 复制的是文件内容,不保留权限和时间戳
6.9 容器的导出与快照
6.9.1 导出容器文件系统
# 导出容器的文件系统为 tar 文件
docker export <container> > container-backup.tar
docker export -o container-backup.tar <container>
# 通过管道导入为镜像
docker export <container> | docker import - my-snapshot:v1.0
# 导出并压缩
docker export <container> | gzip > container-backup.tar.gz
gunzip -c container-backup.tar.gz | docker import - my-snapshot:v1.0
6.9.2 docker commit vs docker export
| 操作 |
docker commit |
docker export |
| 输入 |
运行中的容器 |
运行或停止的容器 |
| 输出 |
新镜像(保留层和元数据) |
tar 文件(单层,丢失元数据) |
| 用途 |
基于容器创建镜像 |
备份容器文件系统 |
| 数据保留 |
保留所有层 |
只保留最终状态 |
6.10 动手实验
实验 6.1:容器生命周期完整体验
# 1. 创建容器(不启动)
docker create --name lifecycle-test ubuntu:22.04 sleep 3600
# 2. 查看状态
docker ps -a | grep lifecycle-test
# 状态:Created
# 3. 启动容器
docker start lifecycle-test
docker ps | grep lifecycle-test
# 状态:Up ... (running)
# 4. 暂停容器
docker pause lifecycle-test
docker ps | grep lifecycle-test
# 状态:Up ... (Paused)
# 5. 恢复容器
docker unpause lifecycle-test
docker ps | grep lifecycle-test
# 状态:Up ... (running)
# 6. 停止容器
docker stop lifecycle-test
docker ps -a | grep lifecycle-test
# 状态:Exited (0) ...
# 7. 重新启动
docker start lifecycle-test
docker ps | grep lifecycle-test
# 状态:Up ... (running)
# 8. 强制停止并删除
docker rm -f lifecycle-test
docker ps -a | grep lifecycle-test
# 无输出(已删除)
实验 6.2:资源限制测试
# 1. 启动一个限制资源的容器
docker run -d --name resource-test \
--cpus="0.5" \
--memory="256m" \
nginx:latest
# 2. 查看资源限制
docker inspect resource-test --format='{{.HostConfig.CpuQuota}}'
docker inspect resource-test --format='{{.HostConfig.Memory}}'
# 3. 监控资源使用
docker stats resource-test
# 4. 在容器内进行压力测试
docker exec -it resource-test bash
# 安装压测工具
apt-get update && apt-get install -y stress
# 创建 CPU 压力(单核)
stress --cpu 1 --timeout 30s
# 5. 观察 CPU 使用率被限制在 50%
# 6. 清理
docker rm -f resource-test
实验 6.3:健康检查测试
# 1. 启动一个带健康检查的容器
docker run -d --name health-test \
--health-cmd "curl -f http://localhost/ || exit 1" \
--health-interval 5s \
--health-timeout 3s \
--health-retries 3 \
nginx:latest
# 2. 观察健康状态变化
docker ps
# 初始状态:health: starting
# 几秒后: health: healthy
# 3. 模拟不健康状态
docker exec -it health-test bash -c "echo 'server { }' > /etc/nginx/conf.d/default.conf && nginx -s reload"
sleep 10
docker ps
# 状态:health: unhealthy
# 4. 清理
docker rm -f health-test
6.11 本章小结
| 操作 |
命令 |
说明 |
| 创建 |
docker create |
创建容器但不启动 |
| 运行 |
docker run |
创建并启动容器 |
| 启动 |
docker start |
启动已停止的容器 |
| 暂停 |
docker pause |
挂起容器进程 |
| 恢复 |
docker unpause |
恢复暂停的容器 |
| 停止 |
docker stop |
优雅停止容器 |
| 强杀 |
docker kill |
强制停止容器 |
| 重启 |
docker restart |
重启容器 |
| 删除 |
docker rm |
删除容器 |
| 进入 |
docker exec -it |
进入运行中的容器 |
| 日志 |
docker logs |
查看容器日志 |
| 统计 |
docker stats |
查看资源使用 |
| 复制 |
docker cp |
在容器和主机间复制文件 |
6.12 课后练习
- 基础题:创建一个 Nginx 容器,体验从创建到删除的完整生命周期。
- 进阶题:为 Nginx 容器配置 CPU 和内存限制,使用压测工具验证限制效果。
- 实践题:为 MySQL 容器配置健康检查,观察健康状态的变化。
📖 下一章:Docker 网络模型 ------ 深入理解容器间通信机制