Skip to content

Latest commit

 

History

History
59 lines (34 loc) · 4.88 KB

init-process.md

File metadata and controls

59 lines (34 loc) · 4.88 KB

init 进程

Q

init 进程的原理是什么?它是如何工作的?什么情况需要开启?

基本介绍

当在 Docker Compose 中中配置了 init: true,容器的 PID 1 进程将变为一个特殊的初始化进程——Tini。Tini 负责在容器启动时执行一些初始化任务,并在完成后将控制权转交给实际的服务进程,使其成为容器的新 PID 1 进程。

工作流程

init 的工作流程如下:

  1. 容器启动时,Docker 创建一个 init 进程
  2. init 进程负责初始化容器的环境,例如设置 PID 命名空间、挂载文件系统等
  3. init 进程执行指定的初始化任务,例如等待其他容器就绪、加载配置文件、设置环境变量等
  4. 初始化任务完成后,init 进程会使用 exec 系统调用将控制权交给主服务进程
  5. 主服务进程成为容器的新 PID 1 进程,并接管容器的进程管理责任

Tini 进程的职责

Tini 是一个极其轻量级的 init 系统和信号转发器,专门为 Docker 容器设计。在 Docker 容器中,PID(进程ID)为 1 的进程有一些特殊的职责,这些职责通常由 init 系统(如 systemd、sysvinit 等)处理。然而,很多在 Docker 容器中运行的程序并不是作为 init 系统设计的,如果直接将它们作为容器的 PID 1 进程运行,可能会导致一些问题。

其中一个问题是,当一个进程启动子进程后,如果该进程在子进程之前结束,那么子进程会成为"僵尸"进程。在正常的 Linux 系统中,init 系统会负责清理这些僵尸进程,但在 Docker 容器中,如果 PID 1 进程不具备这种能力,这些僵尸进程就不会被正确处理。

另一个问题是,很多程序并不能正确处理 UNIX 信号。例如,当 Docker 容器收到一个停止信号(SIGTERM)时,PID 1 进程需要确保这个信号被正确地传递给容器中的所有进程,然后在所有进程都处理完该信号后,再结束自己。如果 PID 1 进程不具备这种能力,可能会导致容器中的一些进程提前结束,或者没有机会进行清理工作。

Tini 就是为了解决这些问题而创建的。当你在 Docker 容器中使用 Tini,Tini 会作为 PID 1 进程运行,并负责处理子进程和信号转发等工作。这使得在 Docker 容器中运行的程序可以不必考虑这些问题,从而简化了程序的编写。

Tini 是 Docker 官方推荐的 init 系统,从 Docker 1.13 开始,Docker 也直接内置了一个 --init 参数,可以直接在运行容器时启用 Tini,而不需要在 Dockerfile 中显示地安装和使用 Tini。例如:

docker run --init -it docker.io/library/python:3.11

使用 --init 参数运行的 Docker 容器,将会自动使用 Tini 作为 PID 1 进程。

或者,在 Docker Compose 中配置 init: true,也是一样的。

何时启用

开启 init 的情况通常是在容器中运行一些需要特殊初始化处理的应用程序或服务。以下情况可能需要考虑开启 init

  1. 容器内有多个进程,需要更好地处理信号、进程终止和孤儿进程问题。而 init 进程可以正确地将终止信号(如SIGTERM和SIGINT)传递给其他子进程
  2. 容器中的应用程序需要与宿主机的进程管理类似的行为,例如使用 systemd

非必要不配置

需要注意的是,并不是所有的容器都需要开启 init,很多简单的应用程序或服务并不需要这个特性,而且在某些情况下,init 可能会引入一些额外的复杂性。因此,在决定是否使用 init 时,需要根据具体应用的需求和特点来进行考虑。

配置 init: true 可能会引起以下问题:

  1. 初始化冲突:如果你同时在被依赖的服务和依赖它的服务上配置了 init: true,可能会导致初始化顺序冲突。因为这两个服务都会尝试执行初始化操作,无法保证哪个会先执行。这可能导致依赖服务在未完成初始化的情况下启动,从而导致错误或服务不可用。
  2. 资源浪费:被依赖的服务通常不需要额外的初始化进程。将它们配置为 init: true 可能会增加不必要的资源消耗,特别是当这些服务已经拥有良好的初始化和启动机制时。

对于像 PostgreSQL 和 ZooKeeper 这样的服务,它们已经被设计为在容器启动时自动初始化。它们会在容器内部进行必要的配置和启动过程,确保它们能够正确运行并接受来自其他服务的连接请求。

因此,对于这些被依赖的核心服务,不建议配置 init: true。相反,你应该信任它们的自动初始化机制,并确保它们在容器启动时正确运行。同时,对于依赖这些服务的其他服务,根据需要决定是否配置 init: true,以确保整个容器编排系统的正常运行。