Skip to content

Docker 容器生命周期 · 启动与运行参数至停止、更新与清理 ​

返回分篇目录

先启动服务,再观察和排查,最后停止、更新和清理。

环境变量、标签与运行基线在创建时一并决定;历史 Go HTTP 构建例见完整练习。Dockerfile 指令解释与镜像仓库操作分别见 Dockerfile 和 镜像仓库。

Docker 容器生命周期 ​

先启动服务,再观察和排查,最后停止、更新和清理。

环境变量、标签与运行基线在创建时一并决定;历史 Go HTTP 构建例见完整练习。Dockerfile 指令解释与镜像仓库操作分别见 Dockerfile 和 镜像仓库。

启动与运行参数 ​

生命周期模型 ​

常见状态:

text
created -> running -> paused
                 \-> exited
                 \-> restarting
                 \-> dead

docker run 是 create 加 start 的便捷组合。容器是否运行取决于 PID 1;主进程退出,容器就退出。

bash
docker create --name demo alpine:3.23 sleep 300
docker start demo
docker stop demo
docker start demo
docker stop demo
docker rm demo

运行第一个服务 ​

bash
docker run -d \
  --name web \
  --restart unless-stopped \
  -p 127.0.0.1:8080:80 \
  nginx:alpine

参数含义:

  • -d:后台运行。
  • --name:稳定名称,便于日志和监控。
  • --restart unless-stopped:daemon 或宿主机重启后恢复,但人工停止后不自动恢复。
  • -p 127.0.0.1:8080:80:只在本机环回地址暴露。

验证:

bash
docker ps --filter name=web
curl -fsS http://127.0.0.1:8080/
docker logs --tail 50 web

前台、后台与交互 ​

bash
# 前台、交互终端、退出即删除
docker run --rm -it alpine:3.23 sh

# 后台
docker run -d --name sleeper alpine:3.23 sleep 1d

# 附着主进程
docker attach sleeper

attach 连接的是容器主进程。按 Ctrl+C 可能向主进程发送信号并停止容器;默认分离组合是 Ctrl+P、Ctrl+Q。日常排查更常用 exec。

环境变量 ​

bash
docker run --rm \
  -e APP_ENV=uat \
  --env-file ./app.env \
  alpine env

app.env:

dotenv
APP_PORT=8080
LOG_LEVEL=info

不要通过以下方式传敏感值:

  • Dockerfile ENV;
  • docker run -e SECRET=value 的命令行历史;
  • 提交到 Git 的 env 文件;
  • docker inspect 可见的容器环境变量。

使用专用 Secret 管理,并以文件或短期凭据注入。

标签与元数据 ​

bash
docker run -d \
  --name api \
  --label com.example.team=platform \
  --label com.example.service=api \
  --label com.example.release=2026.08.12 \
  team-api:2026.08.12

筛选:

bash
docker ps --filter label=com.example.team=platform
docker inspect api --format '{{json .Config.Labels}}'

容器运行基线 ​

生产运行至少考虑:

bash
docker run -d \
  --name api \
  --restart unless-stopped \
  --read-only \
  --tmpfs /tmp:rw,noexec,nosuid,size=64m \
  --cap-drop ALL \
  --security-opt no-new-privileges=true \
  --memory 512m \
  --cpus 1.0 \
  --pids-limit 256 \
  --health-cmd='curl -fsS http://127.0.0.1:8080/healthz || exit 1' \
  --health-interval 30s \
  --log-opt max-size=20m \
  --log-opt max-file=5 \
  -p 127.0.0.1:8080:8080 \
  team-api@sha256:REPLACE_ME

这是模板而非通用答案。应用需要写目录或特定 capability 时,应明确添加最小例外并测试。

观察与排查 ​

列表、过滤与格式化 ​

bash
docker ps
docker ps -a
docker ps --filter status=exited
docker ps --filter health=unhealthy
docker ps --filter label=com.example.team=platform
docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}'
docker ps -q

脚本中先检查结果非空,再把 ID 传给其他命令;不要直接把不受控的 docker ps -q 用于批量删除。

检查配置与状态 ​

bash
docker inspect web
docker inspect web --format '{{.State.Status}}'
docker inspect web --format '{{json .State.Health}}'
docker inspect web --format '{{json .Mounts}}'
docker inspect web --format '{{json .NetworkSettings.Networks}}'
docker inspect web --format '{{.HostConfig.RestartPolicy.Name}}'

查看主进程:

bash
docker top web
docker container stats --no-stream web

宿主机 PID:

bash
docker inspect web --format '{{.State.Pid}}'

日志 ​

bash
docker logs web
docker logs --follow web
docker logs --tail 100 web
docker logs --since 30m --timestamps web
docker logs --since '2026-08-12T09:00:00+08:00' web

应用应把结构化日志写到 stdout/stderr。不要默认写入容器可写层中的文件;这类日志难收集、难轮转,并会撑满存储。

进入容器 ​

bash
docker exec -it web sh
docker exec web nginx -T
docker exec -u 0 -it web sh
docker exec -w /etc/nginx web ls -la
docker exec -e DEBUG=1 web env

exec -u 0 是临时 root 调试,不能替代镜像中正确的用户和权限配置。极简/distroless 镜像可能没有 shell;此时使用:

  • docker inspect;
  • docker logs;
  • docker cp;
  • Docker Debug 或经过批准的临时调试容器;
  • 在测试环境构建带工具的 debug target。

复制文件 ​

bash
docker cp web:/etc/nginx/nginx.conf ./nginx.conf
docker cp ./nginx.conf web:/tmp/nginx.conf

注意:

  • docker cp 可能以 root 所有权写入容器。
  • 它不是配置发布流程;容器重建后手工修改消失。
  • 卷内数据应通过备份方案处理。
  • 不要从不可信容器向宿主机高权限路径复制文件。

容器差异与可写层 ​

bash
docker diff web

标记:

  • A:新增;
  • C:修改;
  • D:删除。

它适合发现应用是否把数据、缓存或日志误写进可写层。不能把结果当作完整安全审计。

健康检查 ​

运行时指定:

bash
docker run -d \
  --name api \
  --health-cmd='wget -qO- http://127.0.0.1:8080/healthz || exit 1' \
  --health-interval=30s \
  --health-timeout=3s \
  --health-retries=3 \
  --health-start-period=20s \
  team-api:2026.08.12

查看状态:

bash
docker inspect api --format '{{json .State.Health}}'
docker ps --filter health=unhealthy

健康检查应:

  • 快速、稳定、开销小;
  • 检查服务能否完成关键的最小工作;
  • 有合理超时;
  • 不产生副作用;
  • 不把所有下游短暂故障都放大为容器重启。

Engine 只记录 health 状态,不会因为 unhealthy 自动重启普通容器。

退出码 ​

bash
docker wait job
docker inspect job --format '{{.State.ExitCode}} {{.State.Error}} {{.State.OOMKilled}}'

常见含义:

  • 0:应用正常退出;
  • 125:Docker 自身未能启动容器;
  • 126:命令不可执行;
  • 127:命令不存在;
  • 128 + signal:因信号退出,如 137 常与 SIGKILL/OOM/强制停止相关,143 常为 SIGTERM。

退出码只能提供方向,必须结合 OOMKilled、daemon 日志和应用日志判断。

停止、更新与清理 ​

停止、终止与信号 ​

bash
docker stop --timeout 30 web
docker kill --signal SIGTERM web
docker kill --signal SIGQUIT web
docker restart --timeout 30 web

stop 先发送镜像/容器配置的停止信号,等待超时后再强制终止。kill 默认发送 SIGKILL,进程无法清理。

应用 PID 1 应:

  • 正确接收并处理 SIGTERM;
  • 停止接收新请求;
  • 等待在途请求或事务;
  • 在平台停止超时内退出;
  • 回收子进程,避免 zombie。

Shell form 容易让 shell 成为 PID 1 并影响信号转发:

dockerfile
# 不推荐
CMD my-server --port 8080

# 推荐 exec form
CMD ["my-server", "--port", "8080"]

重启策略 ​

策略行为
no默认,不自动重启
on-failure[:max-retries]非零退出时重启
always总是重启;人工停止后 daemon 再启动也会恢复
unless-stopped除非被人工停止,否则重启
bash
docker update --restart unless-stopped web
docker inspect web --format '{{json .HostConfig.RestartPolicy}}'

重启策略不是健康修复机制。进程未退出但已死锁时,需要 healthcheck、外部监控和编排系统处理。

暂停与恢复 ​

bash
docker pause web
docker unpause web

pause 通常通过 cgroup freezer 冻结进程。它不会优雅释放连接,长时间暂停可能触发上游超时,不适合常规发布。

重命名与更新 ​

bash
docker rename web web-old

docker update \
  --cpus 1.5 \
  --memory 768m \
  --memory-swap 1g \
  web-old

不是所有创建时配置都能原地更新。端口、挂载、部分网络或安全配置改变时通常需要重建容器。

自动删除 ​

一次性任务:

bash
docker run --rm alpine:3.23 echo ok

后台 --rm 容器停止后也会自动删除,不利于保留现场。生产批处理需要将日志和退出信息写入外部系统。

删除 ​

bash
docker stop web
docker rm web

强制删除:

bash
docker rm -f web

警告: 强制删除跳过应用的正常停止流程,可能造成事务或文件写入中断。仅在明确了解影响时使用。

删除容器并删除其匿名卷:

bash
docker rm -v stopped-container

危险: -v 会删除关联的匿名卷;命名卷通常不会由此删除,但仍应先用 docker inspect 核对挂载。

继续阅读