Вопрос или проблема
Я пытаюсь устранить проблему с тем, что служба sysVinit не запускается должным образом при загрузке в среде systemd. Я обнаружил, что когда в /etc/systemd/system/
отсутствуют файлы службы или переопределения для указанной службы, она правильно автозапускается. В этом случае, как я понимаю, systemd должен динамически загружать скрипт запуска, читая “наследственные” скрипты sysvinit, присутствующие в системе, хотя я не на 100% уверен в этом.
Меня смущает то, что как только я передаю опцию edit –full в systemctl для указанной службы, в /etc/systemd/system/
генерируется обычный файл, и указанная служба теперь не может автозапуститься при загрузке. Использование опции редактирования и попытка добавить какие-либо переопределения также, похоже, приводит к тому, что служба не запускается.
Примеры, если нужно, приведены ниже…
Пример работы системы
Служба (на Centos), в этом примере названная “ProgramExample”, имеет скрипт инициализации, размещенный в /etc/init.d/programexample
и также /etc/rc.d/init.d/programexample
:
# ls -l /etc/rc.d/init.d/programexample
-rwxr-xr-x. 1 root root 2264 Mar 29 14:11 /etc/rc.d/init.d/programexample
Файл службы отсутствует в /etc/systemd/system/
:
# ls -lh /etc/systemd/system/programexample.service
ls: cannot access /etc/systemd/system/programexample.service: No such file or directory
Вывод состояния systemctl в этой конфигурации:
# systemctl status programexample.service
● programexample.service - LSB: Start Program Example at boot time
Loaded: loaded (/etc/rc.d/init.d/programexample; bad; vendor preset: disabled)
Active: active (exited) since Wed 2017-03-29 15:53:06 CDT; 14min ago
Docs: man:systemd-sysv-generator(8)
Process: 1297 ExecStart=/etc/rc.d/init.d/programexample start (code=exited, status=0/SUCCESS)
Mar 29 15:53:05 centos7-box systemd[1]: Starting LSB: Start ProgramExample at boot time...
Mar 29 15:53:05 centos7-box su[1307]: (to programexample) root on none
Mar 29 15:53:06 centos7-box programexample[1297]: ProgramExample (user programexample): имя экземпляра установлено на centos7-box
Mar 29 15:53:06 centos7-box programexample[1297]: публичный базовый URI экземпляра установлен на https://192.168.0.148.programexample.net/programexample/
Mar 29 15:53:06 centos7-box programexample[1297]: часовой пояс экземпляра установлен на US/Central
Mar 29 15:53:06 centos7-box programexample[1297]: запуск java-сервисов
Mar 29 15:53:06 centos7-box programexample[1297]: Сервер ProgEx запущен.
Mar 29 15:53:06 centos7-box systemd[1]: Started LSB: Start ProgramExample at boot time.
При вышеизложенной конфигурации, без каких-либо файлов, созданных/размещенных в /etc/systemd/system/, служба ProgramExample автозапускается должным образом.
Как только используется systemctl edit --full
(или просто edit
):
После того как любые изменения были переданы в systemctl, я наблюдал следующее:
- Обычный файл или каталог переопределения будет размещен в /etc/systemd/system/
- Указанная служба, в данном случае ProgramExample, не запускается при загрузке.
- Я не смогу “включить” указанную службу, используя systemctl
Вывод состояния systemctl в этой конфигурации (после редактирования):
# systemctl status programexample.service
● programexample.service - LSB: Start ProgramExample at boot time
Loaded: loaded (/etc/rc.d/init.d/programexample; static; vendor preset: disabled)
Active: inactive (dead)
Docs: man:systemd-sysv-generator(8)
Это файл службы, который генерируется и размещается в /etc/systemd/system/
при использовании опции edit --full
:
# Автоматически сгенерировано генератором systemd-sysv
[Unit]
Documentation=man:systemd-sysv-generator(8)
SourcePath=/etc/rc.d/init.d/programexample
Description=LSB: Start ProgramExample at boot time
Before=runlevel2.target
Before=runlevel3.target
Before=runlevel4.target
Before=runlevel5.target
Before=shutdown.target
Before=adsm.service
After=all.target
After=network-online.target
After=postgresql-9.4.service
Conflicts=shutdown.target
[Service]
Type=forking
Restart=no
TimeoutSec=5min
IgnoreSIGPIPE=no
KillMode=process
GuessMainPID=no
RemainAfterExit=yes
ExecStart=/etc/rc.d/init.d/programexample start
ExecStop=/etc/rc.d/init.d/programexample stop
ExecReload=/etc/rc.d/init.d/programexample reload
Что здесь происходит? Правильно ли я понимаю, что без обычного файла службы и/или каталога переопределения в /etc/systemd/system/ systemd динамически читает эту информацию из скрипта инициализации указанной службы? Я пробовал множество вариантов редактирования файла службы в /etc/systemd/system/ и оставлял файл по умолчанию на месте, и не смог заставить автозапуск работать или службу перейти в состояние “включена”.
Я считаю, что было бы предпочтительно иметь файл .service для конфигураций systemd вместо того, чтобы полагаться на systemd для чтения заголовков LSB из скрипта инициализации по причинам совместимости и параллелизма, но стандартный файл, который создаёт systemd, не запускается и не включается, наряду с множеством других более простых вариантов файла .service, которые я пробовал.
Я теперь обнаружил, что проблема заключалась в том, что файл службы, автоматически созданный systemd-sysv-generator, не содержит раздела install с опцией WantedBy. Я добавил следующее в созданный файл в /etc/systemd/system/programexample.service, что позволило мне правильно включить службу:
[Install]
WantedBy = multi-user.target
После этого я выполнил
systemctl daemon-reload
чтобы убедиться, что файл службы был прочитан systemd.
Теперь я получил правильное уведомление о том, что моя служба на самом деле символически связана где-то, чтобы быть “включенной”:
[root@centos7-box ~]# systemctl enable programexample.service
Создана символическая ссылка из /etc/systemd/system/multi-user.target.wants/programexample.service на /etc/systemd/system/programexample.service.
Эта ссылка помогла мне лучше понять файл службы.
Мне не нравится, что systemd-sysv-generator по умолчанию не включает раздел install с опцией WantedBy. Если systemd может динамически читать заголовки LSB и правильно запускать службы при загрузке, почему он не генерирует файл службы соответственно? Думаю, некоторые “старые болезни” systemd были ожидаемы.
Обновление 7 июля 2020 года:
Работая с Debian Buster и пытаясь включить устаревшую службу SysVInit, я получил это замечательное сообщение, которое, я считаю, сэкономило бы мне время, когда я сталкивался с этой проблемой в 2017 году:
Синхронизация состояния службы programexample.service с скриптом службы SysV с
/lib/systemd/systemd-sysv-install.
Выполняется: /lib/systemd/systemd-sysv-install enable programexample
Файлы единиц не имеют конфигурации установки (WantedBy=, RequiredBy=, Also=,
Alias= настройки в разделе [Install], и DefaultInstance= для шаблонных единиц).
Это означает, что их не следует включать с помощью systemctl.
Возможные причины наличия таких единиц:
• Единица может быть статически включена за счет создания символической ссылки из другой единицы
в /wants/ или
.requires/ директории.
• Цель единицы может заключаться в том, чтобы выступать в качестве помощника для другой единицы, у которой есть
зависимость.
• Единица может быть запущена по мере необходимости путем активации (сокет, путь, таймер,
D-Bus, udev, вызов systemctl по сценарию и т.д.).
• В случае шаблонных единиц единица предназначена для включения с заданным
именем экземпляра.
В моем случае проблема возникла из-за наличия двух разных версий Java в системе, одна из которых (Oracle JDK) была установлена позже установки Jenkins в моей системе. Я выполнил команду alternatives -config java и установил Java на версию open JDK, которая была установлена вместе с Jenkins, и перезапустил службу сервера Jenkins. Вот и все.
Ответ или решение
Когда вы работаете с системами, которые используют как системы инициализации SysVinit, так и systemd, может возникнуть ситуация, когда служба, которая раньше работала корректно, перестает запускаться после создания файла службы systemd. В данном случае, вы столкнулись с проблемой, связанной с генерацией файла службы для SysVinit и тем, что он не содержит необходимых секций для включения службы. В данной статье мы рассмотрим возможные причины и способы решения данной проблемы.
Причины проблемы
-
Отсутствие раздела [Install]: Основная причина, почему ваша служба не могла быть активирована и не запускалась при загрузке, заключается в том, что автоматически сгенерированный файл службы, созданный
systemd-sysv-generator
, не содержал раздела[Install]
. Этот раздел необходим для того, чтобы указывать, в какой цели (target) должна быть включена служба. Например, добавлениеWantedBy=multi-user.target
в этот раздел позволяет системе понять, что служба должна быть активирована при достижении уровня многопользовательского режима. -
Генерация файлов служб: При отсутствии специального файла службы в
/etc/systemd/system/
,systemd
автоматически генерирует его на основе скриптов SysVinit, что позволяет поддерживать совместимость с более старыми системами. Однако, как вы заметили, система не всегда создает все необходимые секции, что может привести к проблемам с автозапуском. -
Проблемы с версиями Java: В вашем обновлении указано, что служба Jenkins не могла запуститься из-за конфликтов между различными версиями Java. Это подчеркивает важность управления версиями программного обеспечения в системах, где многие сервисы могут зависеть от общего окружения.
Решения проблемы
-
Добавление секции [Install]: После создания файла службы вручную или редактирования автоматически созданного файла, добавьте следующий код в секцию
[Install]
:[Install] WantedBy=multi-user.target
Это позволит системе понять, что служба должна быть запущена при многопользовательском доступе.
-
Перезагрузка демона systemd: После внесения изменений, всегда выполняйте команду:
systemctl daemon-reload
Это позволит
systemd
перезагрузить конфигурацию служб и учитывать все изменения в файлах. -
Включение службы: После обновления файла и перезагрузки демона, выполните команду включения службы:
systemctl enable programexample.service
Это создаст необходимые символические ссылки, позволяющие службе автоматически запускаться при загрузке системы.
-
Проверка статуса: После всех изменений, проверьте статус службы командой:
systemctl status programexample.service
Это даст вам отчет о состоянии службы и поможет диагностировать, успешно ли она запустилась.
Заключение
Понимание того, как systemd работает с наследием SysVinit, имеет ключевое значение для работы с системными службами в современных Linux-дистрибутивах. Важно помнить о необходимых секциях в файлах служб и конфликтах версий программного обеспечения, особенно в окружениях, где запускаются несколько сервисов. Применение вышеприведенных рекомендаций поможет в эффективном управлении системными службами и устранении конфликта, обеспечивая плавную работу вашей системы.
Если у вас возникнут дополнительные вопросы или потребуется помощь, не стесняйтесь обращаться к сообществу или профессионалам для получения более детальной поддержки.