使用此图像(Caddy 网络服务器):
docker run --rm -p 80:80 caddy:latest
Run Code Online (Sandbox Code Playgroud)
我可以通过在终端内发送 CTRL+C来阻止它。
其他一些图像不会以这种方式工作,例如 MariaDB:
docker run -it --rm -p 3306:3306 -e MARIADB_ALLOW_EMPTY_ROOT_PASSWORD=true mariadb:latest
Run Code Online (Sandbox Code Playgroud)
我无法用 CTRL+C 停止它
我注意到在 Caddy 中Dockerfile没有butENTRYPOINT only CMD,而 MariaDB 有 anENTRYPOINT和 a CMD。
为什么?有什么理由不支持终止信号的处理吗?SIGTERM如果这是原因的话,如何支持docker 入口点呢?
Von*_*onC 14
但我有点好奇官方图片是如何解决这个问题的......
不要忘记Docker 1.13 附带了tini,最初来自krallin/tini.
任何运行的镜像都docker run --init将包含一个init转发信号和获取进程的容器内部。
正如这里提到的,tini工作透明,Dockerfiles 不需要以任何方式修改。
因此,在 Unix 系统中,当您按下CTRL+C终端时,一个SIGINT(信号中断)会被发送到前台进程组,在本例中是 Docker 容器。如果您使用CTRL+\,它会发送SIGQUIT,如果您使用CTRL+Z,它会发送SIGTSTP(信号停止)。
Docker 容器运行单个主进程,该进程以 PID 1 运行。PID
1 在 Linux 上很特殊:它是第一个运行的进程,也是所有其他进程的祖先。
它与 Unix 信号也有特殊的关系:它是唯一可以选择忽略SIGINT和 的进程SIGTERM。其他进程不能忽略这些信号,但它们可以具有在收到这些信号时执行的处理程序。
在 Docker 中,当您使用CMD指定要运行的进程时,Docker 会用一个小init系统(如tini)包装该进程,该系统可以正确处理 Unix 信号并将它们转发到主进程(我最初在这里提到过)。
这就是为什么您的caddy图像没有 且ENTRYPOINT只有CMD,可以处理CTRL+C.
然而,当你使用 时ENTRYPOINT,Docker 不会用这个小init系统包装进程,进程以 PID 1 运行。
如果进程没有内置处理 或SIGINT,SIGTERM则不会响应CTRL+C。这就是为什么当您按 时,mariadb带有 的图像ENTRYPOINT不会停止CTRL+C。
终止信号的处理是正常关闭的一个重要部分。当进程收到SIGTERM(或SIGINT) 时,它应该停止接受新工作,完成当前工作,然后退出。这允许它清理正在使用的任何资源并确保数据一致性。
如果进程不处理这些信号并且只是被终止(使用SIGKILL),则它没有机会进行清理,并且可能使资源处于不一致的状态。对于像 MariaDB 这样的数据库来说,这可能是有害的,因为它可能有未提交的事务或部分写入的数据。
要支持在 Docker 入口点中处理终止信号,您可以:
将信号处理添加到入口点脚本本身。这需要修改脚本,如果入口点是二进制文件,则可能不可行。
使用init可以处理信号并将其转发到主进程的系统。有一些init类似的小型系统tini就是为此目的而设计的。您可以在 Dockerfile 中使用它们,如下所示:
FROM your-base-image
RUN apt-get update && apt-get install -y tini
ENTRYPOINT ["/usr/bin/tini", "--", "your-command"]
Run Code Online (Sandbox Code Playgroud)
这将以 PID 1 运行tini,它将处理信号并将它们转发给您的命令。
使用 Docker 的内置 init,这是一个最小的tini实现。--init您可以在运行容器时使用以下选项启用它:
docker run --init -it --rm -p 3306:3306 -e MARIADB_ALLOW_EMPTY_ROOT_PASSWORD=true mariadb:latest
Run Code Online (Sandbox Code Playgroud)
这将运行 Docker 的内置 init 作为 PID 1,它将处理信号并将它们转发到 MariaDB。
这些方法确保您的 Docker 入口点可以处理终止信号并在必要时执行正常关闭。
有什么理由不支持终止信号的处理吗?
不确定,除非你希望你的图像是真的:
但一般来说,忽略终止信号可能会导致数据丢失、资源泄漏或僵尸进程等问题,应该避免。
剩下的唯一一件事是:如果不支持关闭信号对于像 MariaDB 这样的服务来说有点危险,为什么 MariaDB 本身不直接在入口点支持它?
这可能是由于遗留原因,继承自 MySQL,而 MariaDB 是 MySQL 的一个分支。MySQL 是在 Docker 出现之前开发的,在传统的服务器环境中,进程接收SIGINT. 更常见的是,SIGTERM当系统关闭时,进程会收到 ,MySQL 和 MariaDB 会处理这种情况。
它的入口点反映了这一点,并且您运行它--init以确保基本SIGINT支持。
但请记住,这不是唯一的问题。我犯了一个错误:在 Azure ACI(容器)而不是 AKS (Kubernetes) 上运行 MariaDB 实例。
当 ACI 关闭时(至少当我在 2021 年使用它时),它会发送……一个 SIGKILL(无法捕获、阻止或忽略的信号)。当内核向进程发送 SIGKILL 时,该进程会立即终止,并且在被终止之前没有机会进行清理或执行任何其他工作。
因此,无论您的映像是否支持正常关闭,都要注意您的执行环境,这可能首先不允许任何正常关闭。
| 归档时间: |
|
| 查看次数: |
1001 次 |
| 最近记录: |