Служба Systemd працює без виходу


30

Я створив власну службу для jekyll, і коли я запускаю службу, то здається, що вона не працює як фоновий процес, тому що я змушений ctrl+ cвийти з неї. Він просто залишається на передньому плані через - годинник. Я не впевнений, як обійти його і зробити так, щоб він працював у фоновому режимі. Будь-які думки?

# /etc/systemd/system/jekyll-blog.service

[Unit]
Description=Start blog jekyll

[Service]
Type=forking
WorkingDirectory=/home/blog
ExecStart=/usr/local/bin/jekyll build --watch --incremental -s /home/blog -d /var/www/html/blog &
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
User=root
Group=root

[Install]
WantedBy=multi-user.target

systemd запустить ваш процес і очікує, що він розщепить інший процес, якщо ви використовуєте Type=forking. Більше того, він не працюватиме execStartяк розширення оболонки, так що &в кінці ніколи не буде розумітися як фоновий прапор.
grochmal

мій поганий & був я тестував це. Так що тип повинен бути простим?
madmanali93

2
Якщо я не помиляюся, jekyll - це тип рейки, тобто невеликий веб-сервер у рубіні. Так так, Type=simpleбуло б доречно. Крім того, це не та програма, яку я запускав би як root, принаймні, не на Інтернет-машині (що може бути не вашим випадком).
grochmal

Дякую, так просто. Також ця команда генерує статичний html для Apache, щоб jekyll не працював на сервері. Я думаю, це має бути добре, якщо він працює як root. Не впевнений, хоча це обговорював.
madmanali93

Ну добре, так це і є --incremental:). Так, я не бачу проблем із захистом у відновленні файлів як root. Звичайно, враховуючи, що ці файли не надаються користувачем.
грочмал

Відповіді:


54

Systemd може обробляти різні типи послуг, зокрема, одне з наступних

  • simple - Тривалий процес, який не спрацьовує, а залишається прив’язаним до оболонки.
  • forking - Типовий демон, який розщеплює себе від процесу, який його здійснював, фактично фоновий.
  • oneshot - недовговічний процес, який, як очікується, завершиться.
  • dbus - Як просто, але повідомлення про завершення запуску процесів надсилається через dbus.
  • notify - Як просто, але сповіщення про завершення запуску процесів надсилається через inotify.
  • idle - Як просто, але двійковий файл запускається після відправлення завдання.

У вашому випадку ви вибрали, Type=forkingщо означає, що systemd чекає, коли процес розщепиться і батьківський процес закінчиться, що це сприймає як ознаку того, що процес почався успішно. Однак ваш процес цього не робить - він залишається на передньому плані і так systemctl startбуде зависати нескінченно або до тих пір, поки процеси не завершаться.

Натомість ви хочете Type=simple, що є типовим, щоб ви могли повністю видалити рядок, щоб отримати той самий ефект. У цьому режимі systemd не чекає запуску процесів (оскільки не має можливості знати, коли це сталося), і тому продовжує виконувати та залежні служби відразу. У вашому випадку таких немає, тому це не має значення.

Невелика примітка про безпеку:

Ви запускаєте послугу як root, це відлякує, оскільки вона менш безпечна, ніж запуск її як непривілейованого користувача. Причиною цього є те, що якщо в jekyll є вразливість, яка якось дозволяє виконувати команди (можливо, через код, який він розбирає), то зловмиснику не потрібно нічого більше робити, щоб повністю володіти вашою системою. Якщо, з іншого боку, він працює як непривілейований користувач, зловмисник здатний завдати стільки ж шкоди, скільки й користувачеві, і тепер повинен намагатися отримати кореневі привілеї, щоб повністю володіти вашою системою. Це просто додає додатковий шар, зловмисники повинні йти.

Ви можете просто запустити його як того самого користувача, на якому працює ваш веб-сервер, але це залишає вас відкритим для іншої потенційної атаки. Якщо на вашому веб-сервері є вразливість, яка дозволяє користувачеві маніпулювати файлами у вашій системі, вони можуть змінювати згенеровані файли html або, в гіршому випадку, вихідні файли та примушувати ваш сервер обслуговувати все, що завгодно. Однак якщо згенеровані файли та вихідні файли читаються тільки веб-сервером і можуть бути записані іншим непривілейованим користувачем, вони не зможуть, як легко, змінити їх, атакуючи веб-сервер.

Однак, якщо ви просто подаєте статичні файли з цього сервера і постійно оновлюєте сервер, ці атаки є дуже малоймовірними - але все-таки можливими. Ви несете відповідальність за те, щоб зважувати ризики та накладні витрати, якщо їх налаштувати, виходячи з того, наскільки важливою є ваша система, але обидва ці поради дуже прості у налаштуванні та поруч з ними не мають накладних витрат на обслуговування.


0

На додаток до рішення @ Майкла Даффіна , ви також можете використовувати інструмент демонізувати , щоб досягти використання, forkingяк показано в наступному прикладі.

З огляду на невеликий скрипт оболонки, який я хочу демонізувати і який я хочу контролювати над systemd, я зберег його як /home/pi/testscript.sh:

#!/bin/bash

while true;
do
    sleep 1
    echo -n "."
done

Якщо у вас його ще немає, встановіть демонізування, як це:

sudo apt install daemonize

Тепер створіть файл визначення файлової служби:

sudo vi /etc/systemd/system/testomat.service
# It is not recommended to modify this file in-place, because it will
# be overwritten during package upgrades. If you want to add further
# options or overwrite existing ones then use
# $ systemctl edit testomat.service
# See "man systemd.service" for details.

# copied from https://github.com/bitcoin/bitcoin/blob/master/contrib/init/bitcoind.service and modified by Michael 

[Unit]
Description=Test service
After=network.target

[Service]
ExecStart=daemonize -p /run/testomat/testomat.pid -o /home/pi/testscript.log /home/pi/testscript.sh
TimeoutSec=1200

# Make sure the config directory is readable by the service user
PermissionsStartOnly=true

# Process management
####################
Type=forking
PIDFile=/run/testomat/testomat.pid
Restart=on-failure
GuessMainPID = true

# Directory creation and permissions
####################################

# Run as pi:pi
User=pi
Group=pi

# /run/testomat
RuntimeDirectory=testomat
RuntimeDirectoryMode=0710

# /var/lib/testomat
StateDirectory=testomat
StateDirectoryMode=0710

# Hardening measures
####################

# Provide a private /tmp and /var/tmp.
PrivateTmp=true

# Mount /usr, /boot/ and /etc read-only for the process.
ProtectSystem=full

# Allow access to /home, /root and /run/user
# Chosing "false" is actually no hardening, this is just to demonstrate the usage of a service. Well, I could have omitted it. True. :)
ProtectHome=false

# Disallow the process and all of its children to gain
# new privileges through execve().
NoNewPrivileges=true

# Use a new /dev namespace only populated with API pseudo devices
# such as /dev/null, /dev/zero and /dev/random.
PrivateDevices=true

# Deny the creation of writable and executable memory mappings.
MemoryDenyWriteExecute=true

[Install]
WantedBy=multi-user.target

Новостворений сервіс повинен бути оголошений систематизованим:

systemctl daemon-reload

Тепер ви можете запустити службу та вилки сценарію. Як і очікувалося, запуск служби повертається до оболонки негайно. Результат очевидний:

$ tail -f testscript.log 
.....................


Яка перевага використання daemonize+ Type=forkingзамість того, Type=simpleаби дозволити systemd піклуватися про запуск послуги? Type=forkingє свого роду налаштуванням сумісності в systemd для підтримки застарілих програм, записаних у форк.
Йохан Мірен

Я думаю, що це рівнозначне рішення; Я просто хотів запропонувати ОП альтернативне рішення та дати йому знати про цей інструмент, який я вже використовував у /etc/init.d разів, оскільки питання також небагато про те, як демонізувати процес.
Майкл
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.