Описание состояния
Я столкнулся со странной ситуацией с systemd и ssh на Ubuntu 18.04.3 LTS
Я проверил состояние устройства 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, шаблон службы[email protected]должен существовать, из которого создаются экземпляры служб для каждого входящего соединения
Итак, всего существует два разных способа запустить sshd:
ssh.service
(sshd.service
это просто псевдоним) запускает основной процесс sshd, и с этого момента процесс обрабатывает все входящие соединения, порождает дочерние процессы и т. д. и т. п.ssh.socket
+[email protected]
, здесь systemd подключает каждое входящее соединение с управляемого сокетом порта к новому экземпляру[email protected], inetd-style. Вот почему в шаблонной службе ,StandardInput=socket
иExecStart=/usr/sbin/sshd
есть-i
опция.
Очевидно, что одновременно можно использовать только один подход, поэтому Conflicts=
убедитесь, что оба не работают одновременно. (кстати: фактическое размещение строфы Conflicts=
не важно, эквивалентную строфу можно было бы написать в ssh.service, но одной достаточно)