table of contents
SYSTEMD.SERVICE(5) | systemd.service | SYSTEMD.SERVICE(5) |
НАЗВА¶
systemd.service — налаштування модуля служби
КОРОТКИЙ ОПИС¶
служба.service
ОПИС¶
У файлі налаштувань модуля, назва якого завершується суфіксом «.service», закодовано відомості щодо процесу, керування і нагляд за яким здійснює systemd.
На цій сторінці підручника наведено список параметрів налаштувань, які є специфічними для цього типу модулів. Див. systemd.unit(5), щоб дізнатися більше про загальні параметри усіх файлів налаштувань модулів. Загальні пункти налаштувань визначаються у типових розділах [Unit] і [Install]. Специфічні для служби параметри налаштувань визначаються у розділі [Service].
Список додаткових параметрів наведено на сторінці підручника з systemd.exec(5), програми, яка визначає середовище виконання команд, systemd.kill(5), програми, яка визначає спосіб, у який переривається робота процесів служби, та systemd.resource-control(5), програми, яка налаштовує параметри керування ресурсами для процесів служби.
Якщо увімкнено сумісність із SysV init, systemd автоматично створює модулі, які включають скрипти ініціалізації SysV (назва служби збігатиметься із назвою скрипту, суфіксом буде «.service»); див. systemd-sysv-generator(8).
Команда systemd-run(1) уможливлює створення модулів .service і .scope динамічно і інтерактивно з командного рядка.
ШАБЛОНИ СЛУЖБ¶
Служби systemd можуть приймати одинарний аргумент, який передають синтаксичною конструкцією «служба@аргумент.service». Такі служби називають «реалізованими», а визначення модулів без параметра аргумент називають «шаблоном». Прикладом може бути шаблон служби dhcpcd@.service, який приймає назву інтерфейсу мережі яка параметр при формуванні реалізованої служби. У файлі служби доступ до цього параметра або «назви екземпляра» можна отримати за допомогою %-специфікаторів. Див. systemd.unit(5), щоб дізнатися більше.
АВТОМАТИЧНІ ЗАЛЕЖНОСТІ¶
Неявні залежності¶
Неявним чином додано такі залежності:
Додаткові неявні залежності можна додавати як результат параметри керування виконанням і ресурсами, як це документовано на сторінках підручника щодо systemd.exec(5) і systemd.resource-control(5).
Типові залежності¶
Буде додано такі залежності, якщо не встановлено DefaultDependencies=no:
ПАРАМЕТРИ¶
Файли модулів служб можуть включати розділи [Unit] і [Install], які описано на сторінці підручника щодо systemd.unit(5).
Файли модулів служб мають включати розділ [Service], який містить відомості щодо служби і процесу, за яким вона наглядає. Численні параметри, які може буде використано у цьому розділі, є спільними із іншими типами модулів. Ці параметри документовано на сторінках підручника щодо systemd.exec(5), systemd.kill(5) і systemd.resource-control(5). Параметрами, які є специфічними для розділу [Service] модулів служб, є такими:
Type=
Очікується, що процес, який налаштовано за допомогою ExecStart= є основним процесом служби. У цьому режимі, якщо процес надає функціональні можливості іншим процесам у системі, його канали обміну даними має бути встановлено до запуску служби (наприклад, сокети має бути налаштовано systemd за допомогою активації сокетів), оскільки засіб керування службами негайно продовжить запуск наступних модулів, одразу після створення процесу основної служби і до виконання виконуваного файла служби. Зауважте, що це означає, що рядки команд systemctl start для служб simple повідомлятимуть про успіх, навіть якщо виконуваний файл служби не вдасться викликати успішно (наприклад, оскільки вибраного користувача User= не існує або не буде знайдено виконуваного файла служби).
Процес, який налаштовано за допомогою ExecStart=, має викликати fork(), як частину свого запуску. Батьківський процес має завершити роботу при завершенні запуску, а усі канали обміну даними має бути налаштовано. Дочірній процес продовжуватиме працювати як основний процес служби, а засіб керування службами вважатиме модуль запущеним, коли батьківський процес завершить роботу. Це поведінка традиційних служб UNIX. Якщо використано цей параметр, рекомендуємо також скористатися параметром PIDFile=, щоб systemd можна було надійно ідентифікувати основний процес служби. Засіб керування продовжить запускати наступні модулі, після завершення роботи батьківського процесу.
Модулі служб, якщо вказано цей варіант, неявно отримуватимуть залежності від модуля dbus.socket. Модуль служби цього типу вважається таким, що перебуває в активному стані, аж доки не буде отримано вказаної назви каналу. Він вважається активованим, доки чинною є отримана назва каналу. Щойно назву каналу буде вивільнено, служба вважається нефункціональною, що спричиняє те, що засіб керування службами спробує перервати будь-які залишкові процеси, що належать службі. Через це, служби, які скидають назву каналу у процесі логіки завершення своєї роботи, слід приготувати до отримання SIGTERM (або будь-якого іншого сигналу, який налаштовано у KillSignal=).
Якщо для служби передбачено підтримку перезавантаження, і вона використовує сигнал для запуску перезавантаження, рекомендуємо замість цього варіанта скористатися notify-reload.
При започаткуванні процесу перезавантаження від служби очікують відповіді з повідомленням-сповіщенням через sd_notify(3). У повідомленні має міститися поле «RELOADING=1» у поєднанні і встановленням «MONOTONIC_USEC=» у значення поточного монотонного часу (тобто CLOCK_MONOTONIC у clock_gettime(2)) у мкс, форматованого у десятковий рядок. Щойно перезавантаження буде завершено, має бути надіслано ще одне повідомлення-сповіщення, що містить «READY=1». Використання цього типу служби і реалізація цього протоколу перезавантаження є ефективною альтернативою використанню команди ExecReload= для перезавантаження налаштувань служби.
Надісланий сигнал можна скоригувати за допомогою ReloadSignal=, див. нижче.
Рекомендуємо користуватися Type=notify для служб, які працюють довго, оскільки так можна буде належним чином стежити за помилками у налаштовування процесів (наприклад помилками, подібними до неможливості знайти виконуваний файл служби або невказаного користувача). Втім, оскільки для цього типу служби критичні помилки у власному коді запуску служби не поширюються (на відміну від критичних помилок на кроках приготування, які засіб керування службами виконує до execve()), і він не дозволяє упорядковування інших модулів за результатами завершення ініціалізації самого коду служби (що, наприклад, є корисним, якщо клієнти потребують з'єднання із службою за допомогою певної форми IPC, а канал IPC буде встановлено самою службою, на відміну від виконання цього завдання наперед за допомогою сокета, активації каналу або подібної дії), його може бути недостатньо у багатьох випадках. Якщо це так, notify, notify-reload або dbus (останній лише у випадку, якщо служба надає інтерфейс D-Bus) є пріоритетнішими варіантами, оскільки вони уможливлюють для коду програм служб точне планування того, коли слід вважати запуск служби успішним, і коли слід слід продовжити обробку наступних модулів. Типи служби notify/notify-reload потребують явної підтримки у коді служби (оскільки службі доведеться у відповідний момент викликати sd_notify() або еквівалентний програмний інтерфейс) — якщо її підтримки не передбачено, альтернативою є forking: у цьому варіанті передбачено підтримку традиційного важкого протоколу запуску служб UNIX. Зауважте, що використання будь-якого типу, відмінного від simple, ймовірно, затримає процес завантаження системи, оскільки засобу керування системою доведеться чекати на завершення ініціалізації принаймні якоїсь служби. (Також зауважте, що, загалом, не рекомендовано користуватися idle або oneshot для служб, які працюватимуть довго.)
Зауважте, що різні параметри служб (наприклад User=, Group= через libc NSS) можуть призводити до «прихованого» блокування викликів IPC для інших служб. Іноді варто скористатися типом служби simple для забезпечення того, що на логіку обміну даними засобу керування службами не вплинуть такі потенційно повільні дії та приховані залежності, оскільки це єдиний тип служби, за якого засіб керування службами не чекатиме на завершення таких дій з налаштовування запуску служб, перш ніж продовжувати роботу.
ExitType=
Загалом, рекомендовано використовувати ExitType=main, якщо служба має відому модель відгалуження і основний процес може бути надійно визначено. Варіант ExitType= cgroup призначено для програм, чия модель відгалуження є наперед невідомою і які можуть не мати певного основного процесу. Його добре пристосовано для тимчасових або автоматично створених служб, зокрема графічних програм у стільничному середовищі.
Додано у версії 250.
RemainAfterExit=
GuessMainPID=
PIDFile=
Зауважте, що у сучасних проєктах слід уникати файлів PID. Де це можливо, використовуйте Type=notify, Type=notify-reload або Type=simple, типи, які не вимагають використання файлів PID для визначення основного процесу служби, і не потребують зайвого відгалуження.
BusName=
ExecStart=
Якщо для Type= не встановлено значення oneshot, має бути задано точно одну команду. Якщо використано Type=oneshot, може бути вказано нуль або більшу кількість команд. Команди можна вказати заданням декількох рядків команд у одній інструкції або, інакше, цей параметр можна вказати декілька разів з тими самими наслідками. Якщо цьому параметру надано порожнє значення, список команд, які слід запустити, буде скинуто, попередні надання значень цьому параметру втратять чинність. Якщо значення ExecStart= не вказано, служба повинна мати RemainAfterExit=yes і принаймні один встановлений рядок ExecStop=. (Служби, для яких не вказано обох, ExecStart= і ExecStop=, не є чинними.)
Якщо вказано декілька команд, команди буде викликано послідовно у тому порядку, у якому їх вказано у файлі модуля. Якщо виконання однієї з команд завершиться помилкою (і для неї не вказано префікса «-»), інші рядки не буде виконано, а модуль вважатиметься таким, виконання якого завершилося помилкою.
Якщо не встановлено Type=forking, процес, який запущено за допомогою цього рядка команди, буде вважатися основним процесом фонової служби.
ExecStartPre=, ExecStartPost=
Якщо виконання будь-якої з цих команд (у якої немає префікса «-») завершиться помилкою, решту команд не буде виконано, а виконання модуля вважатиметься таким, що завершилося помилкою.
Команди ExecStart= буде виконано лише після того, як виконання усіх команд ExecStartPre=, до яких не було додано префікса «-», буде успішно завершено.
Команди ExecStartPost= буде запущено лише після успішного виклику команд, які вказано в ExecStart=, якщо це визначено Type= (тобто запуску процесу для Type=simple, або успішного завершення останнього процесу ExecStart= для Type=oneshot, успішного завершення початкового процесу для Type=forking, надсилання «READY=1» для Type=notify/Type=notify-reload, або отримання BusName= для Type=dbus).
Зауважте, що ExecStartPre= не можна використовувати для запуску довготривалих процесів. Усі процеси, які відгалужено процесами, які викликано за допомогою ExecStartPre=, буде завершено примусово до того, як буде запущено наступний процес служби.
Зауважте, що якщо будь-яка з цих команд, вказаних у ExecStartPre=, ExecStart= або ExecStartPost=, завершить роботу критичною помилкою (і для неї не буде вказано префікса «-», див. вище) або перевищить час очікування на дані до повного запуску служби, буде продовжено виконання команд, які вказано у ExecStopPost=. Команди в ExecStop= буде пропущено.
Зауважте, що виконання ExecStartPost= буде взято до уваги для упорядковувальних обмежень Before=/After=.
ExecCondition=
Поведінка буде подібною до ExecStartPre= і гібриду перевірки умов: якщо команда ExecCondition= завершить роботу із кодом виходу від 1 до 254 (включно), решту команд буде пропущено, а модуль не буде позначено як такий, виконання якого завершилося помилкою. Втім, якщо команда ExecCondition= завершить роботу зі станом виходу 255 або у критичному режимі (тобто через перевищення часу очікування, переривання сигналом тощо), модуль вважатиметься таким, виконання якого завершилося помилкою (і решту команд буде пропущено). Якщо кодом виходу буде 0 або код із SuccessExitStatus=, буде продовжено виконання наступних команд.
Ті самі рекомендації щодо того, що не слід запускати довготривалі процеси в ExecStartPre=, стосуються і ExecCondition=. ExecCondition= також запускатиме команди в ExecStopPost=, як частину процедури зупинення роботи служби у випадку будь-яких ненульових або нештатних виходів, подібних до тих, які описано вище.
Додано у версії 243.
ExecReload=
Буде встановлено одну додаткову спеціальну змінну середовища: буде встановлено $MAINPID у значення, якщо воно відоме, назви основного процесу фонової служби, і цією змінною можна буде скористатися у рядках команд, подібних до такого:
ExecReload=kill -HUP $MAINPID
Втім, зауважте, що перезавантаження фонової служби надсиланням до черги обробки сигналу (як і з прикладом рядка вище), зазвичай, не дуже вдалий вибір, оскільки це асинхронна дія, яка є непридатною для упорядкованого перезавантаження одразу декількох служб. Наполегливо рекомендуємо або скористатися Type=notify-reload замість ExecReload=, або встановити для ExecReload= значення команди, яка не лише ініціює перезавантаження налаштувань фонової служби, але також синхронно очікує на його завершення. Наприклад, dbus-broker(1) використовує таке:
ExecReload=busctl call org.freedesktop.DBus \
/org/freedesktop/DBus org.freedesktop.DBus \
ReloadConfig
ExecStop=
Зауважте, що, зазвичай, для цього параметра недостатньо вказати команду, якщо лише попросить службу припинити роботу (наприклад, надсиланням у певній формі сигналу щодо переривання), але не очікує на завершення припинення роботи. Оскільки роботу решти процесів служби буде припинено відповідно до KillMode= і KillSignal= або RestartKillSignal=, як це описано вище, негайно після завершення роботи команди, зупинення роботи може статися нештатно. Отже, вказана команда має бути синхронною, а не асинхронною дією.
Зауважте, що команди, вказані в ExecStop=, буде виконано, лише коли спочатку запущено службу. Їх не буде викликано, якщо службу не було взагалі запущено або якщо спроба запуску завершилася помилкою, наприклад, оскільки спроба виконання якоїсь із команд, які вказано в ExecStart=, ExecStartPre= або ExecStartPost=, завершилося помилкою (і до команди не було дописано префікс «-», див. вище) або було перевищено час очікування на дані. Скористайтеся ExecStopPost= для виклику команд, якщо служба не може запуститися належним чином і завершує роботу знову. Також зауважте, що дію з зупинення завжди буде виконано, якщо службу успішно запущено, навіть якщо процеси у службі перервано самим процесом або ззовні. Команди зупинення має бути приготовано для роботи у цьому випадку. Встановлення значення $MAINPID буде скасовано, якщо systemd стане відомо, що основний процес завершив роботу на момент виклику команд зупинення.
Запити щодо перезапуску служби реалізовано як дії з зупинення, за якими слідують дії із запуску. Це означає, що ExecStop= і ExecStopPost= буде виконано під час дії із перезапуску служби.
Рекомендуємо скористатися цим параметром для команд, які обмінюються даними зі службою, яка потребує штатного переривання роботи. Для кроків чищення після завершення роботи скористайтеся замість цього параметра параметром ExecStopPost=.
ExecStopPost=
Рекомендуємо скористатися цим параметром для дій з чищення, які буде виконано, навіть якщо службу не вдасться запустити належним чином. Команди, які налаштовано за допомогою цього параметра повинні діяти, навіть якщо запуск служби завершився невдачею десь на проміжному етапі і лишив десь неповністю ініціалізовані дані. Оскільки процеси служби вже перервали роботу на момент виконання команд, які задано цим параметром, команди не повинні обмінюватися даними із процесами служби.
Зауважте, що усі команди, які налаштовано за допомогою цього параметра, буде викликано із кодом результату служби, а також кодом виходу і стану основного процесу, які встановлено у змінних середовища $SERVICE_RESULT, $EXIT_CODE і $EXIT_STATUS. Див. systemd.exec(5), щоб дізнатися більше.
Зауважте, що виконання ExecStopPost= буде взято до уваги для упорядковувальних обмежень Before=/After=.
RestartSec=
RestartSteps=
Цей параметр працюватиме, лише якщо також встановлено RestartMaxDelaySec=.
Додано у версії 254.
RestartMaxDelaySec=
Цей параметр працюватиме, лише якщо також встановлено RestartSteps=.
Додано у версії 254.
TimeoutStartSec=
Якщо служба із типом Type=notify/Type=notify-reload надсилає «EXTEND_TIMEOUT_USEC=...», це може спричинити розширення часу запуску за межі TimeoutStartSec=. Перше отримання цього повідомлення має статися до перевищення TimeoutStartSec=, і щойно час запуску було розширено за межі TimeoutStartSec=, засіб керування службами дозволить продовження запуску служби, якщо служба повторює «EXTEND_TIMEOUT_USEC=...» протягом вказаного інтервалу, аж доки стан запуску служби буде завершено «READY=1». (див. sd_notify(3)).
Додано у версії 188.
TimeoutStopSec=
Якщо служба із типом Type=notify/Type=notify-reload надсилає «EXTEND_TIMEOUT_USEC=...», це може спричинити розширення часу зупинення за межі TimeoutStopSec=. Перше отримання цього повідомлення має статися до перевищення TimeoutStopSec=, і щойно час зупинення було розширено за межі TimeoutStopSec=, засіб керування службами дозволить продовження зупинення служби, якщо служба повторює «EXTEND_TIMEOUT_USEC=...» протягом вказаного інтервалу, або сама не припинить свою роботу (див. sd_notify(3)).
Додано у версії 188.
TimeoutAbortSec=
Приймає безрозмірне значення у секундах або значення проміжку часу, наприклад, «5min 20s». Передайте порожнє значення, щоб пропустити обробку часу очікування на переривання відповідним засобом нагляду і повернутися до TimeoutStopSec=. Передайте значення «infinity» для вимикання механізму граничного часу очікування. Типове значення DefaultTimeoutAbortSec= буде взято з файла налаштування засобу керування служб (див. systemd-system.conf(5)).
Якщо служба із типом Type=notify/Type=notify-reload надсилає SIGABRT самостійно (замість того, щоб покластися на запис дампу ядра програми ядром системи), вона може надіслати «EXTEND_TIMEOUT_USEC=...», щоб продовжити час переривання за межі TimeoutAbortSec=. Перше отримання цього повідомлення має статися до перевищення TimeoutAbortSec=, і щойно час переривання було розширено за межі TimeoutAbortSec=, засіб керування службами дозволить продовження переривання служби, якщо служба повторює «EXTEND_TIMEOUT_USEC=...» протягом вказаного інтервалу, або сама не припинить свою роботу (див. sd_notify(3)).
Додано у версії 243.
TimeoutSec=
TimeoutStartFailureMode=, TimeoutStopFailureMode=
Якщо встановлено значення terminate, службу буде штатно перервано надсиланням сигналу, який вказано за допомогою KillSignal= (типовим сигналом є SIGTERM, див. systemd.kill(5)). Якщо роботу служби не буде перервано, FinalKillSignal= буде надіслано після TimeoutStopSec=. Якщо встановлено значення abort, буде, натомість, надіслано WatchdogSignal=, а TimeoutAbortSec= буде застосовано до надсилання FinalKillSignal=. Цим параметром можна скористатися для аналізу служб, які періодично не вдається запустити або завершити. Якщо використано kill, роботу служби буде негайно перервано надсиланням FinalKillSignal= без будь-якого подальшого часу очікування. Цим параметром можна скористатися для спрощення вимикання служб, роботу яких було завершено помилками.
Додано у версії 246.
RuntimeMaxSec=
Якщо служба Type=notify/Type=notify-reload надсилає «EXTEND_TIMEOUT_USEC=...», це може спричинити розширення часу виконання за RuntimeMaxSec=. Перше отримання цього повідомлення має статися до перевищення RuntimeMaxSec=, і щойно час виконання буде розширено за межі RuntimeMaxSec=, засіб керування службами дозволить службі продовжити роботу, якщо служба повторить «EXTEND_TIMEOUT_USEC=...» протягом проміжку часу, який вказано до досягнення завершення роботи служби шляхом «STOPPING=1» (або переривання роботи). (див. sd_notify(3)).
Додано у версії 229.
RuntimeRandomizedExtraSec=
Додано у версії 250.
WatchdogSec=
Restart=
Приймає одне зі значень no, on-success, on-failure, on-abnormal, on-watchdog, on-abort або always. Якщо встановлено значення no (типове значення), службу не буде перезапущено. Якщо встановлено значення on-success, перезапуск буде виконано, лише якщо вихід з процедури служби буде виконано штатно. У цьому контексті штатний вихід означає будь-який з вказаних нижче варіантів:
Якщо встановлено значення on-failure, службу буде перезапущено, коли процес завершує роботу із ненульовим кодом виходу, буде перервано сигналом (включно із дампом ядра, але без згаданих вище чотирьох сигналів),коли буде перевищено час очікування на завершення дії (зокрема перезавантаження служби), і якщо буде активовано налаштований час очікування для засобу нагляду. Якщо встановлено значення on-abnormal, службу буде перезапущено, якщо процес буде перервано сигналом (включно із дампом ядра, але виключно для згаданих вище чотирьох сигналів), коли буде перевищено час очікування на завершення дії або коли буде активовано час очікування для засобу нагляду. Якщо встановлено значення on-abort, службу буде перезапущено, лише якщо процес служи завершить роботу через неперехоплений сигнал, який не вказано як стан штатного завершення роботи. Якщо встановлено значення on-watchdog, службу буде перезапущено, лише якщо буде перевищено час очікування на службу для засобу нагляду. Якщо встановлено значення always, службу буде перезапущено, незалежно від того, чи було її завершено штатно, перервано у нештатному режимі сигналом або завершено унаслідок перевищення часу очікування. Зауважте, що служби Type=oneshot ніколи не буде перезапущено при штатному стані виходу, тобто для них always і on-success просто відкидатимуться.
Таблиця 1. Причини
виходу та
результат
дії
параметрів
Restart=
Параметри перезапуску/Причини виходу | no | always | on-success | on-failure | on-abnormal | on-abort | on-watchdog |
Безпроблемний код виходу або сигнал | X | X | |||||
Проблемний код виходу | X | X | |||||
Проблемний сигнал | X | X | X | X | |||
Час очікування | X | X | X | ||||
Засіб нагляду | X | X | X | X |
Як виключення наведеного вище параметра, службу буде перезапущено, якщо код виходу або сигнал буде вказано у RestartPreventExitStatus= (див. нижче) або службу буде зупинено за допомогою systemctl stop або еквівалентної дії. Також служби буде завжди перезапущено, якщо код виходу або сигнал буде вказано у RestartForceExitStatus= (див. нижче).
Зауважте, перезапуск служби підлягатиме обмеженню на частоту запуску модуля, яку налаштовано за допомогою StartLimitIntervalSec= і StartLimitBurst=, див. systemd.unit(5), щоб дізнатися більше.
Встановлення для цього параметра значення on-failure є рекомендованим варіантом для довготривалих служб, призначеним для підвищення надійності роботи шляхом спроб автоматично відновлення після помилок. Для служб, які повинні мати можливість переривати свою роботу самостійно (і уникати негайного перезапуску) альтернативним варіантом є on-abnormal.
RestartMode=
Цей параметр корисний у випадках, коли можлива тимчасова непрацездатність залежності, а ми не хочемо, щоб помилки ці тимчасові помилки призводили до помилок у залежних модулях. Якщо для цього параметра встановлено значення direct, залежним модулям не надсилатиметься сповіщення про ці тимчасові помилки.
Додано у версії 254.
SuccessExitStatus=
Зауважте, що цей параметр не змінює зв'язку між числовими станами виходу та їхніми назвами, тобто, незалежно від того, чи використано цей параметр, 0 все одно буде пов'язано із «SUCCESS» (а отже, типово показано як «0/SUCCESS» у виведенні інструментів) і 1 буде пов'язано із «FAILURE» (а отже, типово показаний як «1/FAILURE») тощо. Параметр керує лише тим, що трапиться у результаті отримання цих станів виходу, і як ці коди буде поширено до стану служби цілком.
Цей параметр можна вказувати декілька разів, у випадку чого список успішних станів виходу буде об'єднано. Якщо для цього параметра буде встановлено значення порожнього рядка, буде відновлено початкове значення списку — усі попередні значення для цього параметра буде відкинуто.
Приклад 1. Служба із параметром SuccessExitStatus=
SuccessExitStatus=TEMPFAIL 250 SIGKILL
Стан виходу 75 (TEMPFAIL), 250 та сигнал переривання SIGKILL вважатимуться штатними перериваннями роботи служби.
Зауваження: для отримання списку станів виходу і трансляції між числовими значеннями стану та назвами можна скористатися systemd-analyze exit-status.
Додано у версії 189.
RestartPreventExitStatus=
RestartPreventExitStatus=1 6 SIGABRT
призводить до того, що коди виходу 1 і 6 та сигнал переривання SIGABRT не призведуть до автоматичного перезавантаження служби. Цей параметр можна вказувати декілька разів — у цьому випадку списки станів запобігання перезапуску буде об'єднано. Якщо для цього параметра визначено порожній рядок, буде відновлено початкове значення списку, а усі попередні призначення для цього параметра буде відкинуто.
Зауважте, що цей параметр не впливає на процеси, які налаштовано за допомогою ExecStartPre=, ExecStartPost=, ExecStop=, ExecStopPost= або ExecReload=, але лише для основного процесу служби, тобто процесу, який викликано за допомогою ExecStart= або (залежно від Type=, PIDFile=, ...) якимось іншим налаштованим основним процесом.
Додано у версії 189.
RestartForceExitStatus=
Додано у версії 215.
RootDirectoryStartOnly=
NonBlocking=
Зауважте, що якщо налаштовано один модуль сокета для передавання декільком модулям служб (за допомогою параметра Sockets=, див. нижче), і ці служби мають різні налаштування NonBlocking=, точний стан O_NONBLOCK залежить від порядку, у якому відбувається виклик цих служб, і, можливо, зміниться після того, як код служби вже оволодіє дескриптором файла сокета, просто через те, що стан O_NONBLOCK сокета є спільним для усіх дескрипторів файлів, що на нього посилаються. Отже, суттєвим є те, щоб усі служби, що спільно використовують той самий сокет, використовували ті самі налаштування NonBlocking= і не змінювали прапорець у коді служби.
NotifyAccess=
Зауважте, що сповіщення sd_notify() може бути належним чином пов'язано із модулями, лише якщо або процес, що їх надіслав, усе ще працює на момент, коли PID 1 обробляє повідомлення, або якщо за процесом, що їх надіслав, явним чином стежить у режимі виконання засіб керування службами. Другий випадок трапляється, якщо засіб керування службами спочатку відгалужує процес, тобто для усіх процесів, які відповідають main або exec. Навпаки, якщо допоміжний процес модуля надсилає повідомлення sd_notify() і негайно завершує роботу, засіб керування службами може не змогти належним чином пов'язати повідомлення із модулем, а отже, проігнорує його, навіть якщо для нього встановлено NotifyAccess=all.
Отже, щоб усунути конкурентність у пошуку модуля клієнта та належної прив'язки сповіщень до модулів, можна скористатися sd_notify_barrier(). Цей виклик працює як точка синхронізації і забезпечує надсилання усіх сповіщень до отримання результатів цього виклику засобом керування службами при успішному поверненні керування. Користуватися sd_notify_barrier() слід для клієнтів, які не викликано засобом керування службами, інакше цей механізм синхронізації стане непотрібним для прив'язування сповіщень до модуля.
Sockets=
Зауважте, що ті самі дескриптори файлів сокетів може бути передано одночасно декільком процесам. Також зауважте, що для вхідного обміну даними сокетом може бути активовано іншу службу, ніж та, для якої зрештою налаштовано успадкування дескрипторів файлів сокетів. Або, іншими словами, параметр Service= модулів .socket не повинен за значенням збігатися зі зворотним параметром Sockets= файла .service, на який він посилається.
Цей параметр може бути вказано декілька разів — список модулів сокетів буде об'єднано. Зауважте, що можливості очищення списку сокетів після встановлення (наприклад, встановленням для цього параметра порожнього значення) не передбачено.
FileDescriptorStoreMax=
Командою fdstore systemd-analyze(1) можна скористатися для отримання списку поточного вмісту сховища дескрипторів файлів служби.
Зауважте, що засіб керування службами передасть дескриптори файлів, які містяться у сховищі дескрипторів файлів, лише власним процесам служби, ніколи іншим клієнтам за IPC або подібним протоколом. Втім, він дозволяє непривілейованим клієнтам надсилати запит щодо списку поточних відкрити дескрипторів файлів служби. Тому до таких файлів можна безпечно записувати конфіденційні дані, але не слід долучати їх до метаданих (наприклад, включених до назв файлів) збережених дескрипторів файлів.
Якщо для цього параметра встановлено ненульове значення, для процесів, викликаних для цієї служби, буде встановлено змінну середовища $FDSTORE. Див. systemd.exec(5), щоб дізнатися більше.
Щоб дізнатися більше про сховище файлових дескрипторів, ознайомтеся із оглядом щодо сховища файлових дескрипторів[1].
Додано у версії 219.
FileDescriptorStorePreserve=
Скористайтеся systemctl clean --what=fdstore ..., щоб очистити сховище дескрипторів файлів явним чином.
Додано у версії 254.
USBFunctionDescriptors=
Додано у версії 227.
USBFunctionStrings=
Додано у версії 227.
OOMPolicy=
Цей параметр приймає одне з таких значень: continue, stop або kill. Якщо встановлено значення continue, і процес модуля буде завершено засобом запобігання OOM, дані про завершення роботи буде записано до журналу, але модуль продовжить роботу. Якщо встановлено значення stop, запис події буде додано до журналу, а роботу модуля буде штатно перервано засобом керування службами. Якщо встановлено значення kill, і один із процесів модуля буде завершено засобом припинення роботи OOM, ядру буде наказано припинити роботу решти процесів модуля встановленням атрибуту memory.oom.group у значення 1; див. також сторінку ядра Control Group v2[3].
Типовим для параметра є значення DefaultOOMPolicy= у systemd-system.conf(5), окрім модулів, для яких увімкнено Delegate=, де типовим значенням є continue.
Скористайтеся параметром OOMScoreAdjust= для налаштовування того, чи будуть процеси модуля пріоритетними кандидатами на переривання роботи механізмами завершення роботи у результаті OOM Linux. Див. systemd.exec(5), щоб дізнатися більше.
Цей параметр також стосується systemd-oomd.service(8); подібно до OOM-завершень, що виконується ядром, цей параметр визначає стан модуля після того, як systemd-oomd знищить cgroup, яку пов'язано із модулем.
Додано у версії 243.
OpenFile=
Файл або сокет буде відкрито засобом керування службами, а дескриптор файла буде передано службі. Якщо шлях є сокетом, для нього буде викликано connect(). Див. sd_listen_fds(3), щоб дізнатися більше про те, як отримати ці дескриптори файлів.
Цей параметр корисний для уможливлення для служб доступу до файлів або сокетів, доступ до яких вони не можуть отримати самі (через запуск у окремому просторі назв монтування, недостатні привілеї тощо).
Можна вказати декілька таких параметрів одночасно; у такому випадку буде відкрито усі вказані шляхи, а дескриптори файлів передано службі. Якщо буде призначено порожній рядок, буде скинуто увесь список відкритих файлів, які було визначено до цього призначення.
Додано у версії 253.
ReloadSignal=
Додано у версії 253.
Ознайомтеся зі сторінками підручника щодо systemd.unit(5), systemd.exec(5) і systemd.kill(5), щоб дізнатися більше про інші параметри.
РЯДКИ КОМАНД¶
У цьому розділі описано обробку рядка команди і підставляння змінних і специфікаторів для параметрів ExecStart=, ExecStartPre=, ExecStartPost=, ExecReload=, ExecStop= і ExecStopPost=.
Декілька рядків команд може бути об'єднано у одну інструкцію, розділивши їх крапкою з комою (ці крапки з комами має бути передано як окремі слова). Окремі крапки з комами можна екранувати: «\;».
Екранування у кожному з рядків команд буде вилучено з використанням правил, які описано у розділі «Нейтралізація» («Quoting») на сторінці підручника systemd.syntax(7). Перший запис стане командою, яку слід виконати, а наступні записи є аргументами команди.
Цей синтаксис є похідним від синтаксису командної оболонки, але буде розпізнано лише метасимволи і розгортання з наступних абзаців, а розгортання змінних є іншим. Зокрема, не передбачено підтримки елементів синтаксису командної оболонки, зокрема переспрямування за допомогою «<», «<<», «>» і «>>», каналів переспрямовування за допомогою «|», запуску програм у фоновому режимі за допомогою «&».
Запис команди для виконання може містити пробіли, але не можна використовувати керівні символи.
До кожної з команд можна дописати префікс із декількома спеціальними символами:
Таблиця 2. Особливі
префікси
виконуваних
файлів
Префікс | Результат |
"@" | Якщо шлях до виконуваного файла має префікс «@», другий вказаний елемент буде передано як argv[0] до виконуваного процесу (замість справжньої назви файла), а потім подальші вказані аргументи. |
"-" | Якщо шлях до виконуваного файла має префікс «-», код виходу з команди, який за звичайних умов вважається критичною помилкою (тобто ненульовий стан виходу або ненормальний вихід через надсилання сигналу), буде записано, але не матиме подальшого впливу на роботу і вважатиметься еквівалентом успіху. |
":" | Якщо шлях до виконуваного файла має префікс «:», не буде застосовано заміну змінних середовища (як це описано під цією таблицею). |
"+" | Якщо шлях до виконуваного файла має префікс «+», процес буде виконано із усіма привілеями. У цьому режимі обмеження привілеїв, яке налаштовано за допомогою User=, Group=, CapabilityBoundingSet= або різноманітних параметрів простору назв файлової системи (зокрема PrivateDevices=, PrivateTmp=), не буде застосовано до викликаного рядка команди (але вони усе ще впливатимуть на будь-які інші рядки ExecStart=, ExecStop=, ...). Втім, зауважте, що це не призведе до ігнорування параметрів, які застосовуються до усієї групи керування, зокрема DevicePolicy=; див. systemd.resource-control(5), щоб ознайомитися із повним списком. |
"!" | Подібно до символу «+», обговорення якого наведено вище, цей символ надає змогу викликати рядки команд із розширеними привілеями. Втім, на відміну від «+», символ «!» виключно змінює наслідки застосування User=, Group= і SupplementaryGroups=, тобто лише фрагменти, які стосуються реєстраційних даних користувача і групи. Зауважте, що цей параметр можна поєднувати із DynamicUser=, у випадку чого динамічну пару користувач/група буде створено перед викликом команди, але зміна реєстраційних даних буде покладено на сам виконуваний процес. |
"!!" | Цей префікс є дуже подібним до «!», втім, він працює лише у системах, де немає підтримки можливості зовнішніх процесів, тобто без підтримки AmbientCapabilities=. Його призначено для використання для файлів модулів, у яких використано зовнішні можливості для запуску, де це можливо, процесів з мінімальними привілеями, не порушуючи сумісності з системами, у яких не передбачено підтримки зовнішніх можливостей. Зауважте, що якщо використано «!!» і буде виявлено, що у системі немає підтримки зовнішніх можливостей, усі налаштовані команди SystemCallFilter= і CapabilityBoundingSet= буде неявним чином змінено, щоб надати змогу породженим процесам скидати реєстрацію та можливості самостійно, навіть якщо налаштуваннями це заборонено. Більше того, якщо буде використано цей префікс, і буде виявлено нестачу підтримки зовнішніх можливостей, AmbientCapabilities= буде пропущено і не буде застосовано. У системах з підтримкою зовнішніх можливостей, «!!» ні на що не впливає і є зайвим. |
«@», «-», «:» і один із префіксів «+»/«!»/«!!» можна поєднати у будь-якому порядку. Втім, одночасно можна використовувати лише один з префіксів «+», «!», «!!».
Для усіх команд першим аргументом має бути або абсолютний шлях до виконуваного файла або проста назва файла без символів похилих рисок. Якщо команда не є повним (абсолютним) шляхом, її буде оброблено як повний шлях з використанням фіксованого шляху пошуку, який визначено під час компіляції. Серед каталогів для пошуку /usr/local/bin/, /usr/bin/, /bin/ у системах, у яких використано окремі каталоги /usr/bin/ і /bin/, та їхні відповідники з sbin/ у системах, де використано окремі каталоги bin/ і sbin/. Таким чином, можна безпечно скористатися простою назвою виконуваного файла, якщо виконувані файли зберігаються у будь-якому із «стандартних» каталогів. У інших випадках слід користуватися абсолютним шляхом. Підказка: список шляхів для пошуку можна отримати за допомогою команди systemd-path search-binaries-default.
У рядку команди можна використовувати специфікатори «%», як їх описано на сторінці підручника щодо systemd.unit(5).
Передбачено підтримку заміни базових змінних середовища. Скористайтеся «${ЩОСЬ}», як частиною слова, або окремим словом у рядку команди; цей рядок буде замінено точним значенням змінної середовища (якщо таке визначено) разом із усіма пробілами, які у ньому містяться, так, щоб результатом був завжди один аргумент. Скористайтеся «$FOO», як окремим словом, у рядку команди; цей рядок буде замінено на значення змінної середовища, поділену на пробілах — результатом буде нуль або більше аргументів. Для цього типу розгортання лапки буде враховано при поділі на слова, а після цього буде вилучено.
Приклад:
Environment="ONE=one" 'TWO=two two' ExecStart=echo $ONE $TWO ${TWO}
Буде виконано /bin/echo із чотирма аргументами: «one», «two», «two» і «two two».
Приклад:
Environment=ONE='one' "TWO='two two' too" THREE= ExecStart=/bin/echo ${ONE} ${TWO} ${THREE} ExecStart=/bin/echo $ONE $TWO $THREE
Результатом буде виклик /bin/echo двічі, перший раз із аргументами "'one'", "'two two' too", "", а другий раз із аргументами "one", "two two", "too".
Щоб передати сам символ долара, скористайтеся "$$". Змінні, чиї значення є невідомими, під час розгортання буде оброблено як порожні рядки. Зауважте, що перший аргумент (тобто програма, яку слід виконати) не може бути змінною.
Змінні, які буде використано у цей спосіб, можна визначити за допомогою Environment= і EnvironmentFile=. Крім того, може бути використано змінні зі списку «Змінні середовища у породжених процесах» («Environment variables in spawned processes») сторінки підручника щодо systemd.exec(5), які вважають «статичними налаштуваннями» (це стосується, зокрема, $USER, але не $TERM).
Зауважте, безпосередньої підтримки рядків команд оболонки не передбачено. Якщо має бути використано рядки команд оболонки, їх слід передати явним чином до реалізації командної оболонки якогось типу. Приклад:
ExecStart=sh -c 'dmesg | tac'
Приклад:
ExecStart=echo one ; echo "two two"
Буде виконано echo двічі, кожного разу із одним аргументом: "one" і "two two", відповідно. Оскільки задано дві команди, слід використовувати Type=oneshot.
Приклад:
Type=oneshot ExecStart=:echo $USER ; -false ; +:@true $TEST
Буде виконано /usr/bin/echo із буквальним аргументом «$USER» («:» придушує розгортання змінних), а потім /usr/bin/false (повернуте значення буде проігноровано, оскільки «-» придушує перевірку повернутого значення) і /usr/bin/true (із підвищеними привілеями з «$TEST» як argv[0]).
Приклад:
ExecStart=echo / >/dev/null & \; \ ls
Буде виконано echo із п'ятьма аргументами: "/", ">/dev/null", "&", ";" і "ls".
ПРИКЛАДИ¶
Приклад 2. Проста служба
Вказаний нижче файл модуля створює службу, яка виконає фонову службу /usr/sbin/foo-daemon. Оскільки Type= не вказано, буде неявним чином використано Type=simple. systemd припускатиме, що модуль буде запущено негайно після того, як почнеться виконання програми.
[Unit] Description=Foo [Service] ExecStart=/usr/sbin/foo-daemon [Install] WantedBy=multi-user.target
Зауважте, що systemd тут припускає, що виконання процесу, запущеного за допомогою systemd, продовжуватиметься, аж доки роботу служби не буде припинено. Якщо програма сама себе переводить у режим фонової служби (тобто виконує відгалуження), будь ласка, скористайтеся Type=forking.
Оскільки не вказано ExecStop=, systemd надішле SIGTERM усім процесам, які запущено з цієї служби, і після завершення часу очікування, також SIGKILL. Цю поведінку можна змінити, див. systemd.kill(5), щоб дізнатися більше.
Зауважте, що до цього типу модулів не включено жодного типу сповіщень щодо завершення службою ініціалізації. Для цього вам слід користуватися іншими типами модулів, зокрема Type=notify/notify-reload, якщо служба розуміє протокол сповіщень systemd, Type=forking, якщо служба може перевести себе у фоновий режим, або Type=dbus, якщо модуль отримує назву DBus, щойно ініціалізацію буде завершено. Див. нижче.
Приклад 3. Служба oneshot
Іноді, модулі мають просто виконати дію без підтримання процесів активними, зокрема виконати перевірку файлової системи або дію з чищення при завантаженні системи. Для цього існує Type=oneshot. Модулі цього типу чекатимуть на завершення вказаного процесу, а потім повертатимуться до неактивного стану. Дію з чищення буде виконано таким модулем:
[Unit] Description=Чищення якихось застарілих даних [Service] Type=oneshot ExecStart=/usr/sbin/foo-cleanup [Install] WantedBy=multi-user.target
Зауважте, що systemd вважатиме модуль таким, що перебуває у стані «запуск», аж доки роботу програми не буде перервано, отже, упорядковані залежності чекатимуть на завершення роботи програми до свого запуску. Модуль повернеться до стану «неактивний» після завершення виконання — він ніколи не досягне стану «активний». Це означає, що ще один запит щодо запуску модуля, призведе до повторного виконання дії.
Type=oneshot є єдиними модулями служб, для яких можна вказувати декілька ExecStart=. Для модулів із декількома командами (Type=oneshot), буде знову запущено усі команди.
Для Type=oneshot not можна використовувати Restart=always і Restart=on-success.
Приклад 4. Придатна до зупинки одноразова служба
Подібно до одноразових служб, іноді існують модулі, які мають виконати програму для налаштовування чогось, а потім виконати іншу програму для завершення цієї програми, але не буде активного процесу, доки ці програми вважатимуться «запущеними». Налаштування мережі можуть іноді потрапляти до цієї категорії. Іншим випадком може бути одноразова служба, яку не буде виконано кожного разу, а лише першого разу, коли її викликатимуть як залежність.
Для цього systemd отримує параметр RemainAfterExit=yes, який спричиняє те, що systemd вважатиме модуль активним, якщо дію із запуску буде успішно завершено. Цю директиву може бути використано із усіма типами, але найкорисніша вона з Type=oneshot і Type=simple. З Type=oneshot systemd очікує, доки буде завершено дію із запуску, перш ніж почне вважати, що модуль є активним, тому запуск залежностей розпочнеться після успішного завершення дії із запуску. З Type=simple залежності буде запущено негайно після розміщення у розкладі дії із запуску. Наведений нижче модуль є прикладом для простого статичного брандмауера.
[Unit] Description=Simple firewall [Service] Type=oneshot RemainAfterExit=yes ExecStart=/usr/local/sbin/simple-firewall-start ExecStop=/usr/local/sbin/simple-firewall-stop [Install] WantedBy=multi-user.target
Оскільки модуль вважається таким, що працює, після завершення дії зі запуску, повторний виклик systemctl start для цього модуля не призведе до виконання жодних дій.
Приклад 5. Традиційні служби із відгалуженням
Багато традиційних фонових та звичайних служб під час запуску переводять себе у фоновий режим (тобто виконують відгалуження, переведення у режим демона). Встановіть Type=forking у файлі модуля служби для підтримки цього режиму роботи. systemd вважатиме службу такою, що перебуває у процесі ініціалізації, доки початкова програма продовжуватиме роботу. Щойно роботу програми буде успішно завершено, і лишиться принаймні один процес (і RemainAfterExit=no), служба вважатиметься запущеною.
Часто традиційна фонова служба складається з одного процесу. Тому, якщо після завершення початкового процесу лишається лише один процес, systemd вважатиме цей процес основним процесом служби. У цьому випадку змінна $MAINPID буде доступною у ExecReload=, ExecStop= тощо.
Якщо лишиться більше одного процесу, systemd не зможе визначити основний процес, тому не вважатиме, що такий процес існує. У такому випадку $MAINPID матиме порожнє значення. Втім, якщо процес вирішить записати традиційний PID, systemd зможе прочитати основний PID з нього. Будь ласка, встановіть PIDFile= відповідним чином. Зауважте, що фонова служба має записати цей файл до завершення ініціалізації. Якщо цього не буде зроблено, systemd може спробувати прочитати файл, перш ніж він почне існувати.
У наведеному нижче прикладі показано просту фонову службу, яка відгалужує і просто запускає один процес у фоновому режимі:
[Unit] Description=Якась проста фонова служба [Service] Type=forking ExecStart=/usr/sbin/my-simple-daemon -d [Install] WantedBy=multi-user.target
Будь ласка, ознайомтеся зі сторінкою підручника щодо systemd.kill(5), щоб дізнатися більше про те, як вплинути на спосіб, у який systemd перериває роботу служби.
Приклад 6. Служби DBus
Для служб, яка надсилає запит щодо назви на системному каналі DBus, скористайтеся Type=dbus і встановіть BusName= відповідним чином. Служба не повинна виконувати відгалуження (переходити у фоновий режим). systemd вважатиме службу ініціалізованою, щойно буде отримано назву на системному каналі. У наведеному нижче прикладі показано типову службу DBus:
[Unit] Description=Проста служба DBus [Service] Type=dbus BusName=org.example.simple-dbus-service ExecStart=/usr/sbin/simple-dbus-service [Install] WantedBy=multi-user.target
Для служб bus-activatable не включайте розділ [Install] у файлі служби systemd, а скористайтеся параметром SystemdService= у відповідному файлі служби DBus. Приклад (/usr/share/dbus-1/system-services/org.example.simple-dbus-service.service):
[D-BUS Service] Name=org.example.simple-dbus-service Exec=/usr/sbin/simple-dbus-service User=root SystemdService=simple-dbus-service.service
Будь ласка, ознайомтеся зі сторінкою підручника щодо systemd.kill(5), щоб дізнатися більше про те, як вплинути на спосіб, у який systemd перериває роботу служби.
Приклад 7. Служби, які сповіщають systemd про свою ініціалізацію
Служби Type=simple дуже просто писати, але у них є великий недолік — для таких служб systemd не зможе визначити, коли завершено ініціалізацію служби. Через це, у systemd передбачено підтримку простого протоколу сповіщення, за допомогою якого фонові служби можуть повідомляти systemd про завершення ініціалізації. Для того, щоб ним скористатися, використайте Type=notify або Type=notify-reload. Типовий файл служби для такої фонової служби має виглядати ось так:
[Unit] Description=Проста служба сповіщення [Service] Type=notify-reload ExecStart=/usr/sbin/simple-notifying-service [Install] WantedBy=multi-user.target
Зауважте, що у фоновій службі має бути передбачено підтримку протоколу сповіщень systemd, інакше systemd вважатиме, що службу ще не запущено і завершить її роботу, щойно завершиться відлік часу очікування. Приклад того, як оновлювати фонові служби для забезпечення прозорої підтримки цього протоколу, наведено у підручнику з sd_notify(3). systemd вважатиму модуль таким, що перебуває у стані «запуск», доки не буде отримано сповіщення про готовність.
Будь ласка, ознайомтеся зі сторінкою підручника щодо systemd.kill(5), щоб дізнатися більше про те, як вплинути на спосіб, у який systemd перериває роботу служби.
Щоб уникнути дублювання коду, бажано використовувати, якщо можливо, sd_notify(3), особливо, якщо використано також інші програмні інтерфейси, які надаються libsystemd(3), але зауважте, що протокол сповіщень є дуже простим, і його стабільність не гарантовано за розділом Придатність до портування інтерфейсу та гарантії стабільності[4], тому його може бути повторно реалізовано службами без зовнішніх залежностей. Самодостатній приклад наведено у підручнику з sd_notify(3).
ДИВ. ТАКОЖ¶
systemd(1), systemctl(1), systemd-system.conf(5), systemd.unit(5), systemd.exec(5), systemd.resource-control(5), systemd.kill(5), systemd.directives(7), systemd-run(1)
ПРИМІТКИ¶
- 1.
- Сховище дескрипторів файлів
- 2.
- USB FunctionFS
- 3.
- Control Group v2
- 4.
- Придатність до портування інтерфейсу та гарантії стабільності
ПЕРЕКЛАД¶
Український переклад цієї сторінки посібника виконано Yuri Chornoivan <yurchor@ukr.net>
Цей переклад є безкоштовною документацією; будь ласка, ознайомтеся з умовами GNU General Public License Version 3. НЕ НАДАЄТЬСЯ ЖОДНИХ ГАРАНТІЙ.
Якщо ви знайшли помилки у перекладі цієї сторінки підручника, будь ласка, надішліть електронний лист до списку листування перекладачів: trans-uk@lists.fedoraproject.org.
systemd 255 |