技术博客

Docker 容器生命周期管理:run/exec/logs/inspect/cp 命令详解

系统讲解 Docker 容器的完整生命周期:docker run 常用参数(-d/-p/-v/-e/--name/--restart)、容器状态机(created/running/paused/stopped/dead)、docker exec 进入容器调试、docker logs 日志查看与跟踪、docker inspect 容器信息提取、docker cp 文件传输,以及容器的优雅停止与强制删除。

Docker容器runexeclogsinspect生命周期入门

容器生命周期管理是 Docker 日常运维中最频繁的操作。本文以“一个容器从创建到删除”的完整流程为主线,系统讲解所有相关命令,重点覆盖生产环境中最常见的参数和使用场景。

容器状态机

Docker 容器有几种状态,理解状态转换对排障很重要:

       docker create

        Created(已创建,未运行)
           ↓ docker start
        Running(运行中) ←──────── docker unpause
         ↓      ↓
  docker pause  docker stop/kill
         ↓      ↓
       Paused  Stopped(已停止,进程退出)
                ↓ docker start
              Running
                ↓ docker rm
             Deleted(已删除,不可恢复)

特殊状态:
  Restarting:正在重启(restart policy 触发)
  Dead:容器进程崩溃且无法恢复
  OOMKilled:被内核 OOM Killer 杀死

一、docker run — 启动容器

docker run 是最核心的命令,等于 docker create + docker start

基础参数

# 前台运行(看到输出,Ctrl+C 退出并停止容器)
docker run nginx

# 后台运行(-d/--detach,最常用)
docker run -d nginx

# 交互模式(-it,进入容器 shell)
docker run -it ubuntu:22.04 bash
# -i: 保持 stdin 打开
# -t: 分配 TTY 终端(使 shell 可以正常交互)

端口映射 (-p)

# 格式:-p 宿主机端口:容器端口
docker run -d -p 8080:80 nginx        # 宿主机 8080 → 容器 80
docker run -d -p 443:443 -p 80:80 nginx  # 多端口映射

# 绑定特定 IP(限制访问来源)
docker run -d -p 127.0.0.1:8080:80 nginx  # 只允许本机访问

# 随机端口(宿主机随机分配)
docker run -d -p 80 nginx
docker port <container>  # 查看分配的端口

环境变量 (-e)

# 传入单个环境变量
docker run -d \
    -e MYSQL_ROOT_PASSWORD=secret123 \
    -e MYSQL_DATABASE=myapp \
    mysql:8.0

# 从文件读取(每行 KEY=VALUE)
cat > .env << 'EOF'
MYSQL_ROOT_PASSWORD=secret123
MYSQL_DATABASE=myapp
MYSQL_USER=appuser
MYSQL_PASSWORD=apppass123
EOF
docker run -d --env-file .env mysql:8.0

# 传递宿主机的环境变量
docker run -d -e JAVA_OPTS=$JAVA_OPTS myapp:v1

数据卷挂载 (-v)

# Bind mount(挂载宿主机目录)
docker run -d \
    -v /data/nginx/html:/usr/share/nginx/html \
    -v /data/nginx/conf/nginx.conf:/etc/nginx/nginx.conf:ro \
    nginx
# :ro 表示容器内只读

# Named volume(Docker 管理的卷)
docker run -d \
    -v mysql_data:/var/lib/mysql \
    mysql:8.0

# --mount 语法(更清晰,推荐)
docker run -d \
    --mount type=bind,source=/data/app,target=/app \
    --mount type=volume,source=mysql_data,target=/var/lib/mysql \
    myapp:v1

容器命名和重启策略

# 命名容器(--name)
docker run -d --name mysql-prod mysql:8.0
docker run -d --name nginx-prod nginx

# 重启策略(--restart)
docker run -d --restart=always nginx          # 总是重启(系统重启后也会启动)
docker run -d --restart=unless-stopped nginx  # 手动 stop 不重启,其他情况重启
docker run -d --restart=on-failure:3 nginx    # 失败时重启,最多 3 次
docker run -d --restart=no nginx              # 不自动重启(默认)

# 生产建议:使用 unless-stopped 或 always

资源限制

# CPU 限制
docker run -d --cpus=1.5 nginx        # 最多使用 1.5 个 CPU 核
docker run -d --cpu-shares=512 nginx  # 相对权重(默认 1024)

# 内存限制
docker run -d --memory=512m nginx         # 内存上限 512MB(超出被 OOM Kill)
docker run -d --memory=512m --memory-swap=1g nginx  # 内存+Swap 共 1GB

# 同时设置(生产推荐)
docker run -d \
    --cpus=2 \
    --memory=1g \
    --memory-swap=1g \  # 禁止使用 swap(swap=memory 时)
    --name myapp \
    myapp:v1

其他常用参数

# 删除容器时自动清理(--rm,适合临时任务)
docker run --rm ubuntu echo "hello world"

# 设置主机名
docker run -d --hostname myapp-01 myapp:v1

# 设置 DNS
docker run -d --dns=114.114.114.114 myapp:v1

# 连接到已有网络
docker run -d --network=mynet myapp:v1

# 容器间共享网络(--network=container:)
docker run -d --network=container:nginx-prod myapp-sidecar

# 特权模式(尽量避免)
docker run -d --privileged myapp:v1  # 危险!容器有完整宿主机权限

二、容器状态查看

# 查看运行中的容器
docker ps

# 输出示例:
# CONTAINER ID  IMAGE   COMMAND             CREATED       STATUS       PORTS                  NAMES
# a1b2c3d4e5f6  nginx   "/docker-entrypoint…" 2 hours ago  Up 2 hours  0.0.0.0:8080->80/tcp   nginx-prod

# 查看所有容器(包括已停止的)
docker ps -a

# 只显示容器 ID(用于脚本)
docker ps -q           # 运行中
docker ps -aq          # 所有

# 格式化输出
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"

# 过滤
docker ps --filter "name=nginx"         # 按名称过滤
docker ps --filter "status=exited"      # 查找已停止的容器
docker ps --filter "ancestor=nginx:1.25"  # 按基础镜像过滤

# 查看容器统计(CPU/内存实时)
docker stats           # 所有容器
docker stats nginx-prod redis-prod  # 指定容器
docker stats --no-stream  # 只输出一次,不刷新

三、docker exec — 进入容器

# 进入运行中容器的 bash(最常用)
docker exec -it nginx-prod bash

# 如果容器没有 bash,用 sh
docker exec -it alpine-prod sh

# 执行单条命令(不进入交互)
docker exec nginx-prod nginx -t        # 检查 nginx 配置
docker exec mysql-prod mysqladmin ping  # 检查 MySQL 是否运行

# 以指定用户执行
docker exec -it -u root nginx-prod bash   # root 用户
docker exec -it -u 1000 myapp bash        # UID 1000

# 设置环境变量
docker exec -e DEBUG=true myapp python debug.py

# 在指定目录执行
docker exec -w /tmp myapp ls -la

exec vs attach 的区别:

# docker attach:连接到容器的主进程 stdin/stdout
docker attach nginx-prod
# 危险:Ctrl+C 会停止容器!只在需要查看主进程输出时使用

# docker exec:在容器内创建新进程
docker exec -it nginx-prod bash
# 安全:exit 退出但容器继续运行

四、docker logs — 查看容器日志

# 查看全部日志
docker logs nginx-prod

# 跟踪日志(-f,类似 tail -f)
docker logs -f nginx-prod

# 最近 N 行
docker logs --tail=100 nginx-prod

# 跟踪最近 50 行
docker logs -f --tail=50 nginx-prod

# 按时间过滤
docker logs --since="2026-06-10T10:00:00" nginx-prod
docker logs --since=2h nginx-prod      # 最近 2 小时
docker logs --until=1h nginx-prod      # 1 小时前之前的

# 显示时间戳
docker logs -t nginx-prod

# 综合用法(生产排障最常用)
docker logs -f --tail=100 -t nginx-prod

# 保存日志到文件
docker logs nginx-prod > nginx.log 2>&1

日志驱动配置:

# 查看容器使用的日志驱动
docker inspect nginx-prod --format '{{.HostConfig.LogConfig}}'

# daemon.json 全局配置(推荐)
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m", 单个日志文件最大 100MB
    "max-file": "3" 保留 3 个日志文件(滚动)
  }
}

# 单容器指定(覆盖全局配置)
docker run -d \
    --log-driver=json-file \
    --log-opt max-size=50m \
    --log-opt max-file=5 \
    nginx-prod

五、docker inspect — 查看容器详情

# 完整 JSON 信息
docker inspect nginx-prod

# 常用字段提取
# IP 地址
docker inspect nginx-prod --format '{{.NetworkSettings.IPAddress}}'

# 挂载卷
docker inspect nginx-prod --format '{{json .Mounts}}' | jq .

# 环境变量
docker inspect nginx-prod --format '{{json .Config.Env}}' | jq .

# 启动命令
docker inspect nginx-prod --format '{{json .Config.Cmd}}'

# 容器状态(ExitCode、OOMKilled 等)
docker inspect nginx-prod --format '{{json .State}}' | jq .

# 资源限制
docker inspect nginx-prod --format \
    'Memory: {{.HostConfig.Memory}} CPUs: {{.HostConfig.NanoCpus}}'

# 查看容器的完整网络信息
docker inspect nginx-prod --format '{{json .NetworkSettings.Networks}}' | jq .

六、docker cp — 容器与宿主机文件传输

# 从容器复制到宿主机
docker cp nginx-prod:/etc/nginx/nginx.conf ./nginx.conf
docker cp nginx-prod:/var/log/nginx/ ./nginx-logs/

# 从宿主机复制到容器
docker cp ./nginx.conf nginx-prod:/etc/nginx/nginx.conf
docker cp ./myapp.jar myapp-prod:/opt/app/myapp.jar

# 使用场景:
# 1. 临时修改容器内配置(测试用,生产应重新构建镜像)
docker cp nginx.conf nginx-prod:/etc/nginx/nginx.conf
docker exec nginx-prod nginx -s reload

# 2. 从容器拿出日志/数据
docker cp nginx-prod:/var/log/nginx/error.log ./

# 3. 不进入容器直接查看文件
docker cp nginx-prod:/etc/nginx/nginx.conf -  # 输出到 stdout

七、容器停止与删除

# 优雅停止(发送 SIGTERM,等待进程自行退出)
docker stop nginx-prod          # 默认等待 10 秒
docker stop -t 30 nginx-prod   # 等待 30 秒后强制 SIGKILL

# 强制停止(立即发送 SIGKILL)
docker kill nginx-prod
docker kill --signal=SIGUSR1 nginx-prod  # 发送指定信号

# 重启
docker restart nginx-prod
docker restart -t 5 nginx-prod  # 等 5 秒再重启

# 删除停止的容器
docker rm nginx-prod

# 删除运行中的容器(强制)
docker rm -f nginx-prod  # 慎用

# 批量删除所有已停止的容器
docker container prune

# 删除所有容器(包括运行中的)
docker rm -f $(docker ps -aq)  # 危险!生产禁用

容器操作速查

# 创建但不启动
docker create --name myapp myapp:v1

# 启动已存在的容器
docker start myapp

# 暂停/恢复(冻结进程,适合快照前)
docker pause myapp
docker unpause myapp

# 查看容器进程
docker top myapp

# 查看容器的端口映射
docker port myapp

# 等待容器退出
docker wait myapp
echo "Container exited with: $?"

# 查看容器变更(相对于镜像)
docker diff myapp
# C /var/log/nginx       ← C = Changed
# A /var/log/nginx/access.log  ← A = Added

小结

容器生命周期管理的核心:

docker run -d 启动容器(后台模式),-p 映射端口,-v 挂载数据,-e 传环境变量,--restart=unless-stopped 设置重启策略。

日常运维最常用的组合:

docker logs -f --tail=100 <container>  # 看日志
docker exec -it <container> bash       # 进入排查
docker stats <container>               # 看资源使用
docker inspect <container>             # 看配置详情

下一篇讲 Dockerfile:如何通过写 Dockerfile 把自己的应用打包成镜像。