第06章:Docker 容器生命周期

第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 创建容器

bash 复制代码
# 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 运行容器

bash 复制代码
# 常用的 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 参数详解

bash 复制代码
# 完整的 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 停止容器

bash 复制代码
# 优雅停止(先发 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 删除容器

bash 复制代码
# 删除已停止的容器
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 清理策略

bash 复制代码
# 一键清理所有停止的容器、无用网络、悬空镜像和构建缓存
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 进入运行中的容器

bash 复制代码
# 方式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 查看容器日志

bash 复制代码
# 查看容器日志
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 容器进程查看

bash 复制代码
# 查看容器内运行的进程
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 限制

bash 复制代码
# 限制 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 内存限制

bash 复制代码
# 限制内存
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 限制

bash 复制代码
# 限制读写速率
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 查看容器资源使用

bash 复制代码
# 查看所有运行容器的资源使用
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 中定义

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 中定义

bash 复制代码
# 运行时添加健康检查
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 查看健康状态

bash 复制代码
# 查看容器健康状态
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 容器的重启策略

bash 复制代码
# 设置重启策略
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 容器的复制文件

bash 复制代码
# 从容器复制文件到主机
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 导出容器文件系统

bash 复制代码
# 导出容器的文件系统为 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:容器生命周期完整体验

bash 复制代码
# 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:资源限制测试

bash 复制代码
# 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:健康检查测试

bash 复制代码
# 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 课后练习

  1. 基础题:创建一个 Nginx 容器,体验从创建到删除的完整生命周期。
  2. 进阶题:为 Nginx 容器配置 CPU 和内存限制,使用压测工具验证限制效果。
  3. 实践题:为 MySQL 容器配置健康检查,观察健康状态的变化。

📖 下一章:Docker 网络模型 ------ 深入理解容器间通信机制