LabHub
学习 学习路径 课程

Docker 基础

创建、启动、结束与退出码

在 LabHub 中继续学习

本实验在真正的 VM 中运行

这个环境不是 Pod,而是由 KubeVirt 启动的虚拟机。Linux 内核独立运行,systemd 真正管理服务,docker 也不是模拟工具,而是真正的 Docker 引擎。通过 docker run 启动的容器会成为实际进程,docker execdocker logs 也都能照常工作。

过去,这个实验在 Pod 中运行。由于该环境放弃了所有内核权限,启动容器的步骤无法进行,因此只能学习直接解开镜像归档的变通方法。现在不再需要绕路了。

有两点需要了解。

目标

亲手触发容器的状态转换,并有意重现退出码 143、137 和 42,切身体会它们各自的含义。

为什么重要

运维中最常收到的反馈是“容器挂了”。但容器至少有三种死亡方式,每一种的处理方法都完全不同。如果应用自行结束,就需要检查代码;如果收到 SIGTERM 后结束,则是正常部署;如果被 SIGKILL 杀死,应用日志中什么也不会留下。退出码是区分这三种情况成本最低的信号。只要知道大于 128 的值遵循 128 + 신호번호 这一规则,就能立即读出 143 = 128+15 = SIGTERM,137 = 128+9 = SIGKILL。

步骤

  1. 创建 /root/dk2,使用 alpine:3.20 仅创建一个名为 dk-life 的容器。命令为 sleep 600
  2. 启动 dk-life,使其进入 running 状态。
  3. 使用 alpine:3.20 在后台运行 dk-trap,使它在收到 SIGTERM 时输出 caught-term,并以退出码 143结束。然后正常停止它。
  4. 使用 alpine:3.20 在后台运行 dk-notrap(命令为 sleep 600),只给它 2 秒宽限时间后停止。退出码必须为 137。
  5. 使用 alpine:3.20 运行 dk-fail,使其以退出码 42结束,并将该值仅以数字形式写入 /root/dk2/exit42.txt
  6. 启动 dk-restart 容器,并将重启策略设为 on-failure,最多 3 次
  7. 在容器内导出进程列表并保存到 /root/dk2/pid1.txt。必须同时显示 PID 列。 **这个实验环境本身就是容器。**在这里运行 ps -e -o pid,ppid,comm,既可以确认 PID 1 是该容器的主命令,也可以看到可见进程屈指可数。
  8. /root/dk2/lifecycle.md 中逐行写下 dk-trapdk-notrapdk-fail 三个容器的名称和退出码。

参考

只创建而不运行

创建 /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-trapdk-notrapdk-fail 三个容器的名称和退出码。

通过实际 inspect 确认三个容器的退出码并写入表中。如果同时记下每个值为何如此,日后会很有帮助。