Может ли systemd управлять конвейером аналогично тому, как это делает семейство daemontools? И если да, то как лучше всего этого добиться?
Я хочу запустить эквивалент service1 | service2
где оба service1
и service2
являются (отдельными или нет) службами, управляемыми systemd.
Я хотел бы перезапустить service2
процесс без прерывания service1
. Другими словами, дескриптор файла, к которому service1
пишет, нельзя закрывать, когда service2
выходы. Когда новый экземпляр service2
запускается, он должен наследовать существующий дескриптор файла, чтобы stdout из service1
потечет в новый service2
. (Подобно тому, как daemontools поддерживает канал между run
и log/run
, хотя конвейер не обязательно должен быть службой и регистратором.)
Возможно, что-то с управляемым системой FIFO между ними?
Наконец-то появилась возможность и необходимость самому проработать это. Мое решение требует поддержки fd
возможность StandardOutput=
, который доступен (как минимум) в systemd версии 232, но не доступен в версии 215.
Есть три сервиса и два FIFO. Вместе они создают трубопровод input | filter | output
, и любая часть конвейера может быть индивидуально перезапущена без потери данных.
В input
процесс записывает в FIFO, из которого filter
читает, который, в свою очередь, записывает в FIFO, который output
читает.
input.service
[Unit]
Description=The input process
Requires=filter.socket
After=filter.socket
Wants=filter.service output.service
[Service]
TimeoutStartSec=infinity
Sockets=filter.socket
StandardInput=null
StandardOutput=fd:filter.socket
StandardError=journal
ExecStart=/path/to/input
Restart=always
RestartSec=5s
[Install]
WantedBy=multi-user.target
filter.service
[Unit]
Description=The filter process
Requires=filter.socket output.socket
After=filter.socket output.socket
[Service]
TimeoutStartSec=infinity
Sockets=filter.socket
Sockets=output.socket
StandardInput=fd:filter.socket
StandardOutput=fd:output.socket
StandardError=journal
ExecStart=/path/to/filter
Restart=always
RestartSec=5s
filter.socket
[Unit]
Description=Filter process reads from this
[Socket]
ListenFIFO=/run/filter
SocketMode=0600
RemoveOnStop=false
output.service
[Unit]
Description=The output process
Requires=output.socket
After=output.socket
[Service]
TimeoutStartSec=infinity
Sockets=output.socket
StandardInput=fd:output.socket
StandardOutput=journal
StandardError=journal
ExecStart=output
Restart=always
RestartSec=5s
output.socket
[Unit]
Description=Output process reads from this
[Socket]
ListenFIFO=/run/output
SocketMode=0600
RemoveOnStop=false
Попросите службу записать в стандартный вывод и настройте StandardOutput в файле модуля systemd, чтобы служба записывала в журнал:
http://0pointer.de/public/systemd-man/systemd.exec.html
Это делает журналы доступными для службы journald, которая предлагает другие варианты использования журналов.
http://0pointer.de/public/systemd-man/journald.conf.html
Настраиваемый «регистратор» может быть клиентом журнала и может напрямую извлекать из журнала, и, если он недоступен, вышестоящая служба, конечно, не пострадает. Регистратор также может быть настроен с собственным файлом модуля, поэтому им управляет systemd.