我正在启动 Docker 容器(可能是https://github.com/ibuildthecloud/systemd-docker,我刚刚发现)来自“systemd --user”单元文件。我希望他们一开始就启动。
问题是你不能这样做After=docker.service
,因为 systemd 用户模式单元看不到 systemd 系统模式单元。
有没有人有好方法来解决这个问题?
到目前为止,我的“最好”想法是制作一个运行一次的 systemd 单元,该单元运行一个睡眠循环的脚本,直到“docker info”返回一些合理的内容,然后 After= 那,但这看起来很糟糕。方式。
答案1
解决这个问题的一个好方法是让 Docker 守护进程(运行在系统systemd 的实例)使用套接字激活。
这样,当您启动 docker 命令时(比如从用户systemd 单元),它将有一个套接字可以连接,但它会阻塞,直到 Docker 守护进程真正准备好为其提供服务。
套接字激活以消除显式依赖关系的基本思想描述于systemd 博客中的这篇文章,它讨论了传统上通过显式依赖关系处理的四种服务,但通过套接字激活,不再需要配置它们。摘录如下(虽然很长,但很能说明问题):
套接字激活使得可以完全同时启动所有四个服务,而无需任何顺序。由于侦听套接字的创建已移至守护进程本身之外,因此我们可以同时启动它们,并且它们能够立即连接到彼此的套接字。即,在一个步骤中创建了
/dev/log
和/run/dbus/system_bus_socket
套接字,并且在下一步中同时生成了所有四个服务。当 D-Bus 想要记录到 syslog 时,它只需将其消息写入/dev/log
.只要套接字缓冲区未满,它就可以立即继续执行其他初始化操作。一旦系统日志服务赶上,它将处理排队的消息。如果套接字缓冲区已满,则客户端日志记录将暂时阻塞,直到套接字再次可写,并在可以写入日志消息时继续。这意味着我们服务的调度完全由内核完成:从用户空间的角度来看,所有服务都是同时运行的,当一个服务无法跟上其他需要它的服务时,它会暂时阻止它们的请求,但一旦有服务就会继续运行。这些请求已被发送。所有这些都是完全自动的并且对用户空间不可见。因此,套接字激活使我们能够极大地并行化启动,从而能够同时启动以前被认为严格需要序列化的服务。大多数 Linux 服务使用套接字作为通信通道。套接字激活允许同时启动这些通道的客户端和服务器。
Docker 守护进程支持套接字激活自2014年起,因此您使用的版本可能已经支持该功能。
检查您的发行版是否附带了一个docker.socket
单元,在这种情况下,您所需要做的就是启用它。
如果您的 Docker 守护进程支持套接字激活,但您的发行版不包含该docker.socket
单元,请查看本教程有关如何设置的说明。
另一种值得考虑的选择是从 Docker 切换到播客。
Podman 试图成为 Docker 的直接兼容替代品(因此您可以使用相同的命令行,只需替换docker
为podman
.)
它们之间的主要区别是 podman 不需要守护进程,因此您无需等待守护进程启动即可启动容器。 Podman 在最新版本的 Linux 发行版中作为软件包提供。而且您可以像今天一样使用它,这一事实docker
应该会让您很容易开始使用它。
答案2
顺便说一下,我没有使用 systemd 运行容器,而是使用docker-systemctl-替换完全脚本。
在这种情况下,用户模式具有不同的含义,因为容器使用“USER=”设置运行,将所有进程推送给非 root 所有者。这是一些 docker-cloud 实现的要求 - 示例可以在docker-systemctl-图像