Найти:

- Взлом
- Приватность
- Трюки
- Кодинг
- Админ
- Geek
- Обучение
- Магазин

- Windows
- Linux
- Android
- Железо
- Мессенджеры
- Утечки
- Коронавирус
- Все выпуски «Хакера»

### Содержание статьи

- Основы
- Сервисы типа oneshot — долой rc.local
- Делаем сервис из любой программы
- Зависимости и порядок запуска
- Порядок запуска сервисов
- Зависимости
- Внедряемся в зависимости к чужим сервисам
- Зависимости по умолчанию
- Заключение

Несмотря на множество проблем и противоречивые чувства пользователей, systemd уже стал стандартом де-факто в большинстве дистрибутивов Linux. С его помощью создать несложный сервис можно за пару минут и десяток строк настроек. В то же время многие более интересные возможности документированы не очень понятным языком или требуют углубленных познаний в тонкостях работы systemd.

## Основы

Если ты еще никогда не делал свои сервисы, начнем с основ. Systemd оперирует абстрактными единицами (unit), которые бывают разных типов, могут предоставлять различные ресурсы (процессы, сокеты, абстрактные «цели») и требовать других ресурсов для запуска.

Самый распространенный вид ресурса — сервис (service). Файлы с описаниями сервисов и всего прочего лежат в каталоге `/lib/systemd/system/`. Чтобы systemd нашел новый сервис, достаточно положить в этот каталог свой файл. Если этот сервис ранее не существовал, systemd прочитает файл и загрузит его в память. Однако, если ты редактируешь файл ранее запущенного сервиса, не забудь заставить systemd перечитать файлы командой `sudo systemctl daemon-reload`!

### Сервисы типа oneshot — долой rc.local

Когда-то стандартным способом добавить выполнение команд в загрузку системы было дописать их в /etc/rc.local. Очевидный недостаток — нет способов следить, насколько успешно они выполнились. В systemd легко создать для такой цели свой сервис типа oneshot, и им можно будет управлять через systemctl, как любым другим. В этом случае systemd выполнит команду и посчитает запуск сервиса успешным, если она завершилась с кодом ноль.

Сохраним следующий файл в `/lib/systemd/system/dumb-test.service`:

    [Unit]
      Description=Dumb test

    [Service]
      ExecStart=/bin/true
      Type=oneshot

    [Install]
      WantedBy=multiuser.target

Дополнительных действий не требуется, и теперь ты можешь делать с ним все то же, что с системными сервисами: запустить с помощью `sudo systemctl start dumb-test.service`, поставить на загрузку с помощью `sudo systemctl enable dumb-test.service` и так далее.

### Делаем сервис из любой программы

Любой долгоживущий процесс можно легко превратить в сервис с помощью опции `Type=idle`. В этом случае systemd перехватит стандартные потоки ввода-вывода и будет следить за жизнью процесса.

Для демонстрации напишем программу на Python, которая просто выводит сообщение в бесконечном цикле. Сохраним в `/usr/local/bin/test.py` следующее:

    import time

    while True:
        print("Test service is alive")
        time.sleep(5)

Затем создадим для нее файл сервиса в `/lib/systemd/system/smart-test.service`:

    [Unit]
      Description=Smart test

    [Service]
      ExecStart=/usr/bin/python3 -u /usr/local/bin/test.py
      Type=idle
      KillMode=process

      SyslogIdentifier=smart-test
      SyslogFacility=daemon

      Restart=on-failure

    [Install]
      WantedBy=multiuser.target

Теперь можно запустить наш сервис и убедиться, что он работает:

    $ sudo systemctl status smart-test.service
     smart-test.service - Smart test
       Loaded: loaded (/usr/lib/systemd/system/smart-test.service; static; vendor preset: disabled)
       Active: active (running) since Fri 2019-10-25 16:25:18 +07; 1s ago
     Main PID: 19893 (python3)
        Tasks: 1 (limit: 4915)
       Memory: 3.5M
       CGroup: /system.slice/smart-test.service
               └─19893 /usr/bin/python3 -u /usr/local/bin/test.py

Стандартный вывод программы пишется в journald, и его можно увидеть в `journalctl -u smart-test`. Ради интереса посмотрим на работу опции `Restart=on-failure`. Остановим наш процесс с помощью `kill -9 ${Main PID}` и заглянем в логи:

systemd[1]: Started Smart test.
Test service is alive
Test service is alive
smart-test.service: Main process exited, code=killed, status=9/KILL
smart-test.service: Failed with result 'signal'.
smart-test.service: Service RestartSec=100ms expired, scheduling restart.
smart-test.service: Scheduled restart job, restart counter is at 1.
Stopped Smart test.
Started Smart test.
Test service is alive

Для настоящих демонов нужно использовать тип `forking`, но мы не будем вдаваться в детали — авторы таких пакетов наверняка все уже знают сами.

### Зависимости и порядок запуска

Опций для настройки зависимости в systemd очень много. Прежде всего нужно отметить, что в нем есть два независимых механизма для указания порядка запуска сервисов и зависимостей между ними.

### Порядок запуска сервисов

Порядок запуска сервисов определяется опциями `Before` и `After`. Если в настройках сервиса foo написано `After=bar.service` и оба сервиса должны запуститься, то systemd сначала выполнит попытку запустить bar, а затем foo.

Однако опция `After=bar.service` сама по себе не поставит сервис на загрузку. Более того, она никак не повлияет на решение запускать foo, даже если запуск bar завершится неудачей.

Причина существования этих опций — способность systemd запускать сервисы параллельно.

Для примера возьмем типичный веб-сервер с набором из веб-приложения FCGI, СУБД и обратного прокси. В каком порядке запускать процесс FCGI и обратный прокси, не так важно. Запросы будут работать, только когда они оба запущены, но «неверный порядок» никак не помешает им запуститься.

Если веб-приложение требует данных из базы для инициализации, то мало убедиться, что и процесс FCGI, и СУБД запущены, — приложение нужно запускать только после полного запуска СУБД. Именно для этих случаев и предназначены опции `Before/After`.

### Зависимости

Зависимости бывают двух видов: мягкие и жесткие. Если оба сервиса запустились успешно, то никакой разницы между ними нет. Различие вступает в действие, если один из сервисов не смог запуститься: если зависимость мягкая, то зависимые сервисы все равно будут запущены, а если жесткая, то systemd не станет даже пробовать их запустить.

Мягкие зависимости указываются с помощью опции `Wants=` в секции `[Unit]`. Пример из `sshd.service`:

    [Unit]
    Description=OpenSSH server daemon
    Documentation=man:sshd(8) man:sshd_config(5)
    After=network.target sshd-keygen.target
    Wants=sshd-keygen.target

Цель `sshd-keygen.target`, очевидно, генерирует ключ хоста, если он отсутствует. Технически sshd не сможет запуститься без ключа хоста, поэтому, почему авторы решили сделать зависимость мягкой, можно только догадываться. Возможно, они посчитали, что в большинстве случаев ключ уже существует и устаревший ключ лучше неработающего SSH.

## INFO

При копировании настроек из пакетов дистрибутива нужно быть осторожным. Разработчики дистрибутивов тоже люди и вполне могут создавать неоптимальные или ошибочные конфигурации. Кроме того, если что-то работает для одного сервиса, совсем не факт, что оно же подойдет для другого, так что сверяйся с документацией и тестируй перед выпуском.

Жесткие зависимости можно указать с помощью опции `Requires`. К примеру, в `systemd-journal-flush.service` есть опция `Requires=systemd-journald.service` — очевидно, отправить команду journald невозможно, пока он не запущен.

У этой опции существуют вариации, например `RequiresMountsFor`. Посмотрим в файл `logrotate.service`:

    [Unit]
    Description=Rotate log files
    Documentation=man:logrotate(8) man:logrotate.conf(5)
    RequiresMountsFor=/var/log

Для работы logrotate нужен доступ к каталогу с логами и больше ничего. Опция `RequiresMountsFor=/var/log` позволяет выразить именно это: сервис запустится, как только будет примонтирован каталог, содержащий путь `/var/log`, даже если он находится не в корневом разделе.

## Внедряемся в зависимости к чужим сервисам

В системах с System V init добавить что-то в зависимости к чужому сервису можно было, лишь отредактировав его скрипт. Такие изменения, очевидно, не переживут обновления системы, поэтому сделать их постоянными можно было бы только пересборкой пакета.

В systemd есть несколько способов решить эту проблему. Если нужно именно внедриться к кому-то в зависимости, можно попробовать опции обратных зависимостей: `WantedBy` и `RequiredBy`. Они должны находиться в секции `[Install]`, а не `[Unit]`. Подводных камня здесь два: они обрабатываются только при установке сервиса с помощью `systemctl enable` и, как все в systemd, не всегда нормально работают во всех версиях.

Второй вариант, который позволяет менять любые настройки: скопировать файл сервиса в `/etc/systemd/system/`. Если один файл присутствует в обоих каталогах, то файл из `/etc/systemd/system` имеет приоритет.

Третий, менее радикальный вариант: создать файл вида `/etc/systemd/system/${unit}.d/local.conf` и прописать туда только нужные настройки.

Для примера притворимся, что наш сервис smart-test вовсе и не наш, и добавим ему в зависимости sshd.service третьим способом. Создадим файл `/etc/systemd/system/smart-test.service.d/local.conf` со следующим содержанием:

    [Unit]
      Requires=sshd.service

Теперь sshd.service будет запущен вместе со smart-test.service, даже если раньше был выключен.

Если важен не только сам факт запуска обоих сервисов, но и порядок их запуска, не забудь указать его с помощью опций `Before` или `After`.

### Зависимости по умолчанию

Нужно отметить, что systemd создает для каждого сервиса зависимости по умолчанию. В большинстве случаев это скорее благо, потому что пользовательские сервисы обычно требуют полностью инициализированной системы для своей работы. Но если ты хочешь добавить новый шаг в процесс загрузки системы, тебе нужно избавиться от этих зависимостей. Это можно сделать опцией `DefaultDependencies=no`.

Вот такой шаблон неплохо работает для сервисов, которые должны запускаться как можно раньше:

    [Unit]
    Description=My early boot step

    DefaultDependencies=no

    After=systemd-remount-fs.service

Просмотреть зависимости сервиса и убедиться, что там нет лишнего, можно командой `systemctl list-dependencies ${unit}`.

## Заключение

Systemd можно любить или ненавидеть, но игнорировать его невозможно — нужно уметь с ним работать. Надеюсь, эти знания помогут тебе обратить systemd себе на пользу.

#### Оцени статью:

###### Что тебе понравилось больше всего?

Статья легкая и понятная Статья глубокая и подробная Интересуюсь этой темой Данные новые и актуальные Приятный стиль изложения

###### Что тебе не понравилось больше всего?

Статья поверхностная Статья слишком сложная Тема мне не интересна Данные устарели Неприятный стиль изложения
← Ранее RusDate — сервис знакомств для тех, кто ищет любовь и серьезные отношения
Далее → В ноябре в Twitter запретят всю политическую рекламу
Открыть комментарии

#### Последние взломы

### HTB Driver. Эксплуатируем PrintNightmare и делаем вредоносный SCF

### Routing nightmare. Как пентестить протоколы динамической маршрутизации OSPF и EIGRP

### HTB Bolt. Эксплуатируем шаблоны в Python и разбираемся с PGP

### Краденые миллиарды и плохой рэп. Как арестовали супругов, которые отмывали деньги Bitfinex и снимали тиктоки

#### Компьютерные трюки

### Поездка в Sonerezh. Поднимаем сервер для стриминга музыки

### Терминальное счастье. Колонка главреда

### Анатомия терминала. Осваиваем текстуальную графику

### Змей-стражник. Сигнализация для велосипеда из старого смартфона на Android

#### Свежие новости

- 14 часов назад

  ### Внутренние чаты хак-группы Conti слили в открытый доступ

- 16 часов назад

  ### Toyota закрыла производство в Японии после взлома одного из поставщиков

- 17 часов назад

  ### Microsoft: малварь FoxBlade атаковала Украину до начала военных действий

- 18 часов назад

  ### Хакеры, взломавшие Nvidia, выставили на продажу инструмент для обхода занижения хэшрейта

- 2 дня назад

  ### Вымогатели выбирают стороны: одни поддерживают Россию, другие Украину

Вопросы по материалам и подписке: support@glc.ru
Отдел рекламы и спецпроектов: yakovleva.a@glc.ru
Контент 18+
Сайт защищен Qrator —
самой забойной защитой от DDoS в мире
Подписка для физлиц
Подписка для юрлиц
Реклама на «Хакере»
Контакты
Posting....
wpDiscuz