病情描述
我在 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。
答案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 中編寫等效的一節,但一個就足夠了)