Система systemd с динамическим указанием имени службы

Вопрос или проблема

Есть ли способ динамически задать имя службы в файле службы?

Я запускаю несколько экземпляров службы, где все службы используют разные входные аргументы. Для отладки это не оптимально, так как все службы вызываются одинаково, и может быть утомительно выяснить, какая служба на самом деле вызывает жалобы. Поэтому я хочу дать службе уникальное имя для данного входа. Файлы службы systemd поддерживают это, изменяя arg[0] в ExecStart с помощью префикса “@”, где вторым аргументом будет значение arg[0].

Информация о команде ExecStart и префиксе @:
https://www.freedesktop.org/software/systemd/man/systemd.service.html

Итак, вот что у меня есть на данный момент в файле службы:

ExecStart=@/usr/bin/foo foo-%I %I

Входной аргумент – это файл, поэтому он будет называться что-то вроде bar-123.json. Это работает, и имя службы будет foo-bar-123.json, когда я использую top, ps или QA-инструменты, которые мы используем. Входные файлы создаются другой службой, которая также запускает экземпляр службы “foo” с помощью API dbus systemctl.

Однако называть службу foo-bar-123.json не лучшее решение, и вместо этого я хотел бы называть ее foo-bar.

Я пытался запустить, в качестве теста:

**ExecStartPre=/bin/sh -c 'export NAME=bar'**
**ExecStart=@/usr/bin/foo foo-${NAME} %I**

Но тогда имя будет “foo-“. Я предполагаю, что это ожидаемо, так как файл службы не является сценарием оболочки, однако это было единственное решение, которое я мог придумать.

Другие решения для этой проблемы также приветствуются. Я знаю, что PR_SET_NAME в функции prctl также должен изменять имя процесса, но я не уверен, как они связаны друг с другом. Причина, по которой я не хочу использовать функцию prctl, заключается в том, что она говорит, что имя может быть только длиной 16 байт, включая нулевой байт, это ограничение, от которого было бы неплохо избавиться.

Обычно есть два способа работы с экземплярами юнитов службы systemd. Либо использовать файлы в /etc/sysconfig для каждого экземпляра, которые заменяют, например, переменную по умолчанию OPTIONS (файл EnvironmentFile в определении службы загрузит такой файл и заполнит OPTIONS, см., например, systemctl show -p ExecStart sshd), либо переопределить больше определений юнитов через директорию “drop-in”, например, <служба>@экземпляр.service.d.

Кстати, экземпляр ДОЛЖЕН содержать ‘@’, иначе это не будет экземпляром.

Смотрите, как это используется в юнитах службы getty.

$ ls -l /usr/lib/systemd/system/[email protected]
-rw-r--r-- 1 root root 1958 Apr  9 00:22 /usr/lib/systemd/system/[email protected]
$ grep ^ExecStart /usr/lib/systemd/system/[email protected]
ExecStart=-/sbin/agetty -o '-p -- \\u' --noclear %I $TERM
$ systemctl -t service --state running list-units | grep getty
[email protected]       loaded active running Getty on tty1 

Ответ или решение

Вопрос о динамическом назначении имен служб в systemd — это важная тема, особенно при управлении несколькими экземплярами одной и той же службы. Как вы уже заметили, использование префикса «@» в командах ExecStart позволяет передавать различные аргументы в качестве имени процесса. Однако вам необходимо еще более гибкое управление, которое обеспечивало бы наилучшие условия для отладки и мониторинга.

Динамическое назначение имен служб в systemd

Когда вы работаете с динамическими экземплярами служб, основным инструментом является шаблонный юнит (unit template), который вы уже используете. Например, ваш файл службы имеет следующий вид:

[Unit]
Description=Foo Service Instance

[Service]
ExecStart=@/usr/bin/foo foo-%I %I

Здесь ваш экземпляр службы будет запускаться с именем foo-bar-123.json. Однако, как вы правильно заметили, это не является оптимальным решением для отладки, так как полное имя включает идентификатор файла.

Предложение по улучшению

Ваше предложение по использованию переменных среды через ExecStartPre имеет смысл, но, как вы заметили, это не работает так, как ожидается. К сожалению, systemd не обрабатывает переменные оболочки в ExecStart, что ограничивает возможности использования динамических имен.

Однако есть альтернативный подход, который может помочь в данном контексте. Вы можете использовать следующие методы:

  1. Параметры командной строки для запуска:

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

    [Service]
    ExecStart=/usr/bin/foo foo-%I %I

    В вашем исполняемом файле foo вы можете обработать входные параметры и назначить соответствующее имя процессу внутри самого кода.

  2. Использование Environment и EnvironmentFile:

    Вместо использования ExecStartPre, вы можете создать файл окружения, который будет загружен в вашем юнит-файле. Например, создайте файл /etc/sysconfig/foo-instance, который будет содержать:

    NAME=bar

    Затем в вашем юнит-файле используйте:

    [Service]
    EnvironmentFile=/etc/sysconfig/foo-instance
    ExecStart=/usr/bin/foo foo-${NAME} %I

    Таким образом, NAME будет динамическим, и на его основе может формироваться более удобное имя, например foo-bar.

  3. Логирование и мониторинг:

    Для лучшего отслеживания ошибок и состояний служб можно использовать встроенные инструменты systemd для логирования, такие как journald. Это позволит вам отслеживать выходные сообщения ваших служб, что упрощает диагностику.

Заключение

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

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

Оцените материал
Добавить комментарий

Капча загружается...