第四章

容器生命周期:生老病死与日志

第三层 · 生命周期/日志 容器说没就没,日志去哪了

一、容器的一生:从出生到死亡

"小陈,容器也有'一生'。搞懂它,你才能不慌。"老周画:

容器的生命周期:
  创建(create)→ 启动(start)→ 运行(running)
                                  │
                            ┌─────┴─────┐
                            │ 正常运行    │ ← 主进程活着
                            │ 主进程退出  │
                            └─────┬─────┘
                                  ▼
                            停止(stopped)
                                  │
                            删除(rm)→ 彻底消失(数据没了!)

"关键概念:容器的'生死'跟它的主进程绑定。 容器里那个 CMD 命令的进程一退出,容器就停了。比如 CMD ["python", "app.py"]——python 进程挂了,容器就停止。容器不是一个'系统',是一个'进程'的隔离环境。"

# 生命周期相关命令
docker create --name web01 nginx    # 创建(不启动)
docker start web01                  # 启动
docker stop web01                   # 优雅停止(发 SIGTERM,等一会再 SIGKILL)
docker kill web01                   # 强制杀死(直接 SIGKILL)
docker restart web01                # 重启
docker rm web01                     # 删除(容器没了)
docker rm -f web01                  # 强制删除(运行中也删)

"stopkill 的区别要记住:stop 是'请优雅退出'(给应用时间保存数据),kill 是'直接砍死'。 生产环境优先 stop。"


二、前台 vs 后台:为什么 docker run nginx 会"卡住"

小陈第一次跑 nginx 容器,发现终端"卡住"了,没反应。

老周:"你卡住的其实是 nginx 的前台日志。容器有两种运行方式:"

前台运行(默认):
  docker run nginx
  → 容器的输出直接打到你的终端(适合调试、看日志)
  → Ctrl+C 退出 = 容器停止

后台运行(生产常用):
  docker run -d --name web01 nginx
  → 容器在后台跑,终端不占用(-d = detached)
  → 日志不显示,用 docker logs 查看

交互式运行(进容器操作):
  docker run -it ubuntu bash
  → -i 保持标准输入打开,-t 分配终端
  → 像 ssh 进了一台机器(其实进了容器)

"生产环境用 -d 后台跑,调试用前台或 -it 进容器。 这是最基本的习惯。"


三、进入容器:exec 与 attach

"容器跑起来之后,想进去看看?用 exec:"老周说:

# 进入正在运行的容器(开一个 bash)
docker exec -it web01 bash

# 在容器里执行单条命令(不进交互)
docker exec web01 ls /etc/nginx

# 看容器的"主进程"日志(attach 到主进程输出)
docker attach web01
exec vs attach:
  exec   :在容器里"新开一个进程"(常用,如开 bash 排查)
  attach :"连到容器主进程的输出"(相当于看前台日志)
  调试首选 exec -it bash

"exec 是你排查容器问题的最常用武器——进不去容器,你都不知道里面发生了什么。"


四、日志:容器说没就没,日志去哪了

"容器最大的坑之一:它死了,日志也跟着没了(如果没配置)。"老周说,"所以要从一开始就把日志管好:"

# 查看容器日志
docker logs web01              # 看全部日志
docker logs -f web01           # 实时跟踪(-f = follow)
docker logs --tail 100 web01   # 只看最后 100 行
docker logs --since 1h web01   # 看最近 1 小时的

# 日志的坑:默认日志都写在容器的可写层
# 容器删除 → 日志消失!
# 生产环境必须配"日志驱动"或把日志写到数据卷/外部收集
docker run -d --name web01 \
  --log-driver json-file \     # 默认就是这个
  --log-opt max-size=10m \     # 每个日志文件最大 10MB(防爆盘)
  --log-opt max-file=3 \       # 最多 3 个文件(循环)
  nginx

"日志管理三原则:容器内别写日志文件(写 stdout)、日志要限制大小(防爆盘)、日志要能持久化(配数据卷/收集到 ELK)。 后面第五章讲数据卷,第八章讲镜像仓库时都会碰到日志。"


五、容器挂了怎么办:重启策略

"容器里的应用崩了,容器就停了。谁来把它拉起来?"老周说,"靠重启策略(Restart Policy):"

# 重启策略(--restart)
docker run -d --name web01 \
  --restart=always \      # 挂了自动重启(常用)
  nginx

# 四种策略:
no              # 不自动重启(默认)
on-failure[:N]  # 非正常退出才重启,最多 N 次
always          # 无论什么原因退出都重启(docker stop 除外)
unless-stopped  # 总是重启,除非手动 stop

"生产容器几乎都用 --restart=always(或 unless-stopped)——让 Docker 引擎当'保姆',容器挂了自动拉起来。这是最简单的一层'自愈'。"


六、资源限制:防止一个容器吃垮整台机器

"还记得第一章说的'容器共享内核,隔离弱'吗?"老周说,"所以必须用 Cgroup 给容器上'紧箍咒':"

# 资源限制(第一章提过,这里完整版)
docker run -d --name ai01 \
  --cpus=2 \              # 最多 2 核
  --memory=1g \           # 最多 1GB 内存
  --memory-swap=1g \      # 内存+swap 总共 1G(禁止 swap 溢出)
  --pids-limit=100 \      # 最多 100 个进程(防 fork 炸弹)
  --restart=always \
  yunjian/ai-recommend:v1

# 查看容器的资源使用
docker stats               # 实时看所有容器的 CPU/内存

"不设资源限制的容器 = 定时炸弹——一个内存泄漏的容器能把整台服务器拖垮。上线前必配:--cpus + --memory + --restart。 这是容器运维的'安全三件套'。"


七、章末:老周的第三层总结

第三层:容器生命周期
├── 生命周期:create → start → run → stop → rm
│   容器生死 = 主进程生死(容器是"进程隔离",不是"系统")
├── 运行方式:前台(调试)/ -d 后台(生产)/ -it 交互
├── exec:进容器排查(-it bash);attach:看主进程输出
├── 日志:写 stdout、限制大小(max-size)、要持久化
├── 重启策略:--restart=always(容器挂了自动拉起)
└── 资源限制:--cpus/--memory/--pids-limit(安全三件套)

"小陈,现在你有个很扎心的问题要回答我:如果 web01 容器挂了,我们把它删了、重新 run 一个——容器里写的数据(比如用户上传的图片、数据库文件)还在吗?"

小陈想了想:"……好像不在了?容器删了不就全没了?"

"对!这是容器最大的'骗局'——容器内的文件系统是临时的! 下一章,我们解决这个问题:数据卷(Volume)。学会它,你的容器才能'删了又起,数据不丢'。"

✌ 语言