病情描述
我在 Ubuntu 18.04.3 LTS 上使用 systemd 和 ssh 遇到了奇怪的情况
我检查了设备的状态ssh.socket
:
$ systemctl status ssh.socket
● ssh.socket - OpenBSD Secure Shell server socket
Loaded: loaded (/lib/systemd/system/ssh.socket; disabled; vendor preset: enabled)
Active: inactive (dead)
Listen: [::]:22 (Stream)
Accepted: 0; Connected: 0
它处于非活动状态,但我同时使用 ssh 登录,并且服务本身正在运行,并且 SSH 的套接字和相应端口已打开:
$ lsof -P -i -n | grep sshd
sshd 26785 root 3u IPv4 14858764 0t0 TCP 10.200.130.28:22->10.100.40.141:42188 (ESTABLISHED)
sshd 26875 xxx_root 3u IPv4 14858764 0t0 TCP 10.200.130.28:22->10.100.40.141:42188 (ESTABLISHED)
sshd 63859 root 3u IPv4 238437 0t0 TCP *:22 (LISTEN)
sshd 63859 root 4u IPv6 238439 0t0 TCP *:22 (LISTEN)
所以我查看了 ssh.socket 的单元文件/lib/systemd/system/ssh.socket
:
[Unit]
Description=OpenBSD Secure Shell server socket
Before=ssh.service
Conflicts=ssh.service
ConditionPathExists=!/etc/ssh/sshd_not_to_be_run
[Socket]
ListenStream=22
Accept=yes
[Install]
WantedBy=sockets.target
由于该Before=ssh.service
指令应该在 ssh 服务之前启动,并且该Conflicts=ssh.service
指令将导致它在 ssh 服务启动时停止。
这解释了为什么它发生在单元文件方面,但提出了其他问题。
问题
为什么 ssh.socket 单元的非活动状态对实际的 ssh 套接字没有影响?
为什么维护者添加了该Conflict
指令?例如,如果您检查docker.socket
它的单元文件没有设置为与docker.service
. sshd 的情况有何不同?
附加信息
我还在旧的 Fedora 30 工作站上检查了这一点。它具有相同的条件,但有细微的差别:它使用sshd.service
和作为单元名称,并且单元文件中sshd.socket
没有指令。Before
sshd.socket
在这两个系统上,我没有注意到这种情况造成的任何问题,我怀疑它有某种目的,但找不到。
答案1
systemd 套接字是一种特殊类型的单元,它使 systemd 自身绑定到端口(或其他资源,例如 unix 域套接字文件路径),并为任何连接生成一个新的服务实例。启用 ssh.service 后,其 sshd 会连续运行并绑定到套接字,如 lsof 所示。相反,启用 ssh.socket 意味着 sshd 不会连续运行,而是仅调用它的一个实例来处理一个客户端。相反,它会显示 systemd 正在侦听端口 22。由于 systemd 和 sshd 不能同时侦听同一端口,因此 ssh.socket 指定 ssh.service 存在冲突。
答案2
需要理解的重要一点是,您所看到的是“套接字”单元的一种特定用法,总共有三:http://0pointer.de/blog/projects/inetd.html
所以在 的具体情况下ssh.socket
,这相当于旧式类似inetd的调用(核心套接字单元设置:)Accept=yes
,其中端口 22 上的每个传入请求(由 systemd 管理)都会导致单独的启动[email protected]
实例。
另请参阅 systemd.socket 手册页:https://www.freedesktop.org/software/systemd/man/systemd.socket.html
如果设置 Accept=yes,则服务模板[电子邮件受保护]必须存在,为每个传入连接实例化服务
所以,一共有两种不同的方式来启动 sshd:
ssh.service
(sshd.service
只是一个别名)启动主 sshd 进程,然后该进程处理所有传入连接、生成子进程等。ssh.socket
+[email protected]
,这里 systemd 将来自套接字管理端口的每个传入连接连接到一个新实例[电子邮件受保护],inetd 风格。这就是为什么在模板服务中,StandardInput=socket
、 和ExecStart=/usr/sbin/sshd
有-i
选项。
显然,一次只能使用一种方法,因此Conflicts=
请确保两种方法不会同时运行。 (顺便说一句:该节的实际位置Conflicts=
并不重要,可以在 ssh.service 中编写等效的一节,但一个就足够了)