创建、启动、结束与退出码
本实验在真正的 VM 中运行
这个环境不是 Pod,而是由 KubeVirt 启动的虚拟机。Linux 内核独立运行,systemd 真正管理服务,docker 也不是模拟工具,而是真正的 Docker 引擎。通过 docker run 启动的容器会成为实际进程,docker exec 和 docker logs 也都能照常工作。
过去,这个实验在 Pod 中运行。由于该环境放弃了所有内核权限,启动容器的步骤无法进行,因此只能学习直接解开镜像归档的变通方法。现在不再需要绕路了。
有两点需要了解。
- **首次启动大约需要 1 分钟。**因为 VM 需要启动并安装 Docker,比 Pod 实验(通常 40 秒)更慢。
- **没有浏览器预览。**进入 VM 的连接只开放评分端口。如果启动了 Web 服务器,请在 VM 内使用
curl检查。
目标
亲手触发容器的状态转换,并有意重现退出码 143、137 和 42,切身体会它们各自的含义。
为什么重要
运维中最常收到的反馈是“容器挂了”。但容器至少有三种死亡方式,每一种的处理方法都完全不同。如果应用自行结束,就需要检查代码;如果收到 SIGTERM 后结束,则是正常部署;如果被 SIGKILL 杀死,应用日志中什么也不会留下。退出码是区分这三种情况成本最低的信号。只要知道大于 128 的值遵循 128 + 신호번호 这一规则,就能立即读出 143 = 128+15 = SIGTERM,137 = 128+9 = SIGKILL。
步骤
- 创建
/root/dk2,使用alpine:3.20仅创建一个名为dk-life的容器。命令为sleep 600。 - 启动
dk-life,使其进入 running 状态。 - 使用
alpine:3.20在后台运行dk-trap,使它在收到 SIGTERM 时输出caught-term,并以退出码 143结束。然后正常停止它。 - 使用
alpine:3.20在后台运行dk-notrap(命令为sleep 600),只给它 2 秒宽限时间后停止。退出码必须为 137。 - 使用
alpine:3.20运行dk-fail,使其以退出码 42结束,并将该值仅以数字形式写入/root/dk2/exit42.txt。 - 启动
dk-restart容器,并将重启策略设为 on-failure,最多 3 次。 - 在容器内导出进程列表并保存到
/root/dk2/pid1.txt。必须同时显示 PID 列。 **这个实验环境本身就是容器。**在这里运行ps -e -o pid,ppid,comm,既可以确认 PID 1 是该容器的主命令,也可以看到可见进程屈指可数。 - 在
/root/dk2/lifecycle.md中逐行写下dk-trap、dk-notrap、dk-fail三个容器的名称和退出码。
参考
- 可以使用
docker stop -t <초>调整宽限时间。 - Shell 信号处理程序以
trap '명령' TERM的形式注册。 - 使用
docker inspect <이름> | jq -r '.[0].State.ExitCode'读取退出码。 - 常见错误 1:在第 3 步中,如果先执行
sleep,之后才注册处理程序,就无法收到信号。请构造一个反复执行短时间 sleep 的循环。 - 常见错误 2:如果在主机上执行第 7 步,会看到几十个进程。在容器内应该只有屈指可数的几个。
只创建而不运行
创建 /root/dk2,使用 alpine:3.20 仅创建一个名为 dk-life 的容器。命令为 sleep 600。
run 会创建容器并立即启动。另有一个只负责创建的子命令。处于此状态时还没有进程。
启动已创建的容器
启动 dk-life,使其进入 running 状态。
想一想为什么创建和启动是分开的。启动后,State.Pid 中会出现实际的进程号。
接收 SIGTERM 并正常退出
使用 alpine:3.20 在后台运行 dk-trap,使它在收到 SIGTERM 时输出 caught-term,并以退出码 143结束。然后正常停止它。
Shell 中有一个用于注册信号处理程序的内置命令。在处理程序中以所需的退出码结束,该值就会直接成为容器退出码。
没有处理程序会发生什么
使用 alpine:3.20 在后台运行 dk-notrap(命令为 sleep 600),只给它 2 秒宽限时间后停止。退出码必须为 137。
未注册处理程序的 PID 1 会忽略 SIGTERM。将宽限时间设短,就能无需久等直接查看结果。
应用程序产生的退出码
使用 alpine:3.20 运行 dk-fail,使其以退出码 42结束,并将该值仅以数字形式写入 /root/dk2/exit42.txt。
因信号终止与应用自行结束的退出码范围不同。小于 128 的值是应用直接产生的。
仅在失败时重新启动
启动 dk-restart 容器,并将重启策略设为 on-failure,最多 3 次。
重启策略共有四种。请选择仅在失败时重启、且限制重试次数的值。
容器内的进程列表
在容器内导出进程列表并保存到 /root/dk2/pid1.txt。必须同时显示 PID 列。
**这个实验环境本身就是容器。**在这里运行 ps -e -o pid,ppid,comm,既可以确认 PID 1 是该容器的主命令,也可以看到可见进程屈指可数。
在容器内列出进程时,列表会非常短,并且一眼就能看出 1 号进程是什么。不要在主机上执行。
制作退出码表
在 /root/dk2/lifecycle.md 中逐行写下 dk-trap、dk-notrap、dk-fail 三个容器的名称和退出码。
通过实际 inspect 确认三个容器的退出码并写入表中。如果同时记下每个值为何如此,日后会很有帮助。