Вопрос или проблема
Я создал службу systemd для сканирования ClamAV при доступе, чтобы она была постоянной, чтобы я мог включить, запустить её и забыть, не касаясь её снова.
Я могу вручную запустить службу, и она работает нормально. Но она продолжает не запускаться автоматически после входа в систему, как ожидалось. В обоих случаях нет активных сетевых соединений.
Я полагаю, что следующий вывод журнала (найденный в последней секции поста) может быть подсказкой:
rc.local[1188]: ERROR: ClamClient: could not connect to remote clam daemon, Couldn't connect to server
rc.local[1188]: ERROR: Clamonacc: daemon is local, but a connection could not be established
Но я всё ещё не понимаю, почему я могу вручную запустить службу, но не могу заставить её запускаться автоматически.
Системная информация
$ uname -a
Linux debian 4.19.0-12-amd64 #1 SMP Debian 4.19.152-1 (2020-10-18) x86_64 GNU/Linux
Файл rc-local.service
$ sudo cat /etc/systemd/system/rc-local.service
[Unit]
Description=ClamAV On-Access Scanner
ConditionPathExists=/etc/rc.local
[Service]
Type=forking
User=root
Require=network.target
RemainAfterExit=yes
ExecStart=/etc/rc.local start
TimeoutSec=200
Restart=on-failure
StartLimitInterval=10
[Install]
WantedBy=multi-user.target
Скрипт rc.local
$ sudo cat /etc/rc.local
#!/bin/sh -e
/usr/bin/clamonacc --log=/var/log/clamav/clamonacc.log
exit 0
Статус после входа в систему
● rc-local.service - ClamAV On-Access Scanner
Loaded: loaded (/etc/systemd/system/rc-local.service; enabled; vendor preset: enabled)
Drop-In: /lib/systemd/system/rc-local.service.d
└─debian.conf
Active: failed (Result: exit-code) since Wed 2020-10-21 08:06:33 BST; 12min ago
Process: 1483 ExecStart=/etc/rc.local start (code=exited, status=2)
Oct 21 08:06:33 debian systemd[1]: rc-local.service: Service RestartSec=100ms expired, scheduling restart.
Oct 21 08:06:33 debian systemd[1]: rc-local.service: Scheduled restart job, restart counter is at 5.
Oct 21 08:06:33 debian systemd[1]: Stopped ClamAV On-Access Scanner.
Oct 21 08:06:33 debian systemd[1]: rc-local.service: Start request repeated too quickly.
Oct 21 08:06:33 debian systemd[1]: rc-local.service: Failed with result 'exit-code'.
Oct 21 08:06:33 debian systemd[1]: Failed to start ClamAV On-Access Scanner.
Статус после ручного запуска службы
● rc-local.service - ClamAV On-Access Scanner
Loaded: loaded (/etc/systemd/system/rc-local.service; enabled; vendor preset: enabled)
Drop-In: /lib/systemd/system/rc-local.service.d
└─debian.conf
Active: active (running) since Wed 2020-10-21 08:23:04 BST; 52s ago
Process: 7171 ExecStart=/etc/rc.local start (code=exited, status=0/SUCCESS)
Main PID: 7173 (clamonacc)
Tasks: 8 (limit: 4915)
Memory: 2.6M
CGroup: /system.slice/rc-local.service
└─7173 /usr/bin/clamonacc --log=/var/log/clamav/clamonacc.log
Oct 21 08:23:04 debian systemd[1]: Starting ClamAV On-Access Scanner...
Oct 21 08:23:04 debian systemd[1]: Started ClamAV On-Access Scanner.
Журнал
$ sudo journalctl | grep rc-local
Oct 21 08:06:22 debian systemd[1]: /etc/systemd/system/rc-local.service:7: Unknown lvalue 'Require' in section 'Service', ignoring
Oct 21 08:06:31 debian systemd[1]: rc-local.service: Control process exited, code=exited, status=2/INVALIDARGUMENT
Oct 21 08:06:31 debian systemd[1]: rc-local.service: Failed with result 'exit-code'.
Oct 21 08:06:31 debian systemd[1]: rc-local.service: Service RestartSec=100ms expired, scheduling restart.
Oct 21 08:06:31 debian systemd[1]: rc-local.service: Scheduled restart job, restart counter is at 1.
Oct 21 08:06:31 debian systemd[1]: rc-local.service: Control process exited, code=exited, status=2/INVALIDARGUMENT
Oct 21 08:06:31 debian systemd[1]: rc-local.service: Failed with result 'exit-code'.
Oct 21 08:06:32 debian systemd[1]: rc-local.service: Service RestartSec=100ms expired, scheduling restart.
Oct 21 08:06:32 debian systemd[1]: rc-local.service: Scheduled restart job, restart counter is at 2.
Oct 21 08:06:32 debian systemd[1]: rc-local.service: Control process exited, code=exited, status=2/INVALIDARGUMENT
Oct 21 08:06:32 debian systemd[1]: rc-local.service: Failed with result 'exit-code'.
Oct 21 08:06:32 debian systemd[1]: rc-local.service: Service RestartSec=100ms expired, scheduling restart.
Oct 21 08:06:32 debian systemd[1]: rc-local.service: Scheduled restart job, restart counter is at 3.
Oct 21 08:06:32 debian systemd[1]: rc-local.service: Control process exited, code=exited, status=2/INVALIDARGUMENT
Oct 21 08:06:32 debian systemd[1]: rc-local.service: Failed with result 'exit-code'.
Oct 21 08:06:32 debian systemd[1]: rc-local.service: Service RestartSec=100ms expired, scheduling restart.
Oct 21 08:06:32 debian systemd[1]: rc-local.service: Scheduled restart job, restart counter is at 4.
Oct 21 08:06:32 debian systemd[1]: rc-local.service: Control process exited, code=exited, status=2/INVALIDARGUMENT
Oct 21 08:06:32 debian systemd[1]: rc-local.service: Failed with result 'exit-code'.
Oct 21 08:06:33 debian systemd[1]: rc-local.service: Service RestartSec=100ms expired, scheduling restart.
Oct 21 08:06:33 debian systemd[1]: rc-local.service: Scheduled restart job, restart counter is at 5.
Oct 21 08:06:33 debian systemd[1]: rc-local.service: Start request repeated too quickly.
Oct 21 08:06:33 debian systemd[1]: rc-local.service: Failed with result 'exit-code'.
$ sudo journalctl | grep rc.local
Oct 21 13:47:57 debian rc.local[1097]: ERROR: ClamClient: could not connect to remote clam daemon, Couldn't connect to server
Oct 21 13:47:57 debian rc.local[1097]: ERROR: Clamonacc: daemon is local, but a connection could not be established
Oct 21 13:47:57 debian systemd[1]: rc-local.service: Control process exited, code=exited, status=2/INVALIDARGUMENT
Oct 21 13:47:57 debian systemd[1]: rc-local.service: Failed with result 'exit-code'.
Oct 21 13:47:57 debian systemd[1]: rc-local.service: Service RestartSec=100ms expired, scheduling restart.
Oct 21 13:47:57 debian systemd[1]: rc-local.service: Scheduled restart job, restart counter is at 1.
Oct 21 13:47:57 debian rc.local[1188]: ERROR: ClamClient: could not connect to remote clam daemon, Couldn't connect to server
Oct 21 13:47:57 debian rc.local[1188]: ERROR: Clamonacc: daemon is local, but a connection could not be established
Oct 21 13:47:57 debian systemd[1]: rc-local.service: Control process exited, code=exited, status=2/INVALIDARGUMENT
Oct 21 13:47:57 debian systemd[1]: rc-local.service: Failed with result 'exit-code'.
Oct 21 13:47:58 debian systemd[1]: rc-local.service: Service RestartSec=100ms expired, scheduling restart.
Oct 21 13:47:58 debian systemd[1]: rc-local.service: Scheduled restart job, restart counter is at 2.
Oct 21 13:47:58 debian rc.local[1361]: ERROR: ClamClient: could not connect to remote clam daemon, Couldn't connect to server
Oct 21 13:47:58 debian rc.local[1361]: ERROR: Clamonacc: daemon is local, but a connection could not be established
Oct 21 13:47:58 debian systemd[1]: rc-local.service: Control process exited, code=exited, status=2/INVALIDARGUMENT
Oct 21 13:47:58 debian systemd[1]: rc-local.service: Failed with result 'exit-code'.
Oct 21 13:47:58 debian systemd[1]: rc-local.service: Service RestartSec=100ms expired, scheduling restart.
Oct 21 13:47:58 debian systemd[1]: rc-local.service: Scheduled restart job, restart counter is at 3.
Oct 21 13:47:58 debian rc.local[1372]: ERROR: ClamClient: could not connect to remote clam daemon, Couldn't connect to server
Oct 21 13:47:58 debian rc.local[1372]: ERROR: Clamonacc: daemon is local, but a connection could not be established
Oct 21 13:47:58 debian systemd[1]: rc-local.service: Control process exited, code=exited, status=2/INVALIDARGUMENT
Oct 21 13:47:58 debian systemd[1]: rc-local.service: Failed with result 'exit-code'.
Oct 21 13:47:58 debian systemd[1]: rc-local.service: Service RestartSec=100ms expired, scheduling restart.
Oct 21 13:47:58 debian systemd[1]: rc-local.service: Scheduled restart job, restart counter is at 4.
Oct 21 13:47:58 debian rc.local[1374]: ERROR: ClamClient: could not connect to remote clam daemon, Couldn't connect to server
Oct 21 13:47:58 debian rc.local[1374]: ERROR: Clamonacc: daemon is local, but a connection could not be established
Oct 21 13:47:58 debian systemd[1]: rc-local.service: Control process exited, code=exited, status=2/INVALIDARGUMENT
Oct 21 13:47:58 debian systemd[1]: rc-local.service: Failed with result 'exit-code'.
Oct 21 13:47:59 debian systemd[1]: rc-local.service: Service RestartSec=100ms expired, scheduling restart.
Oct 21 13:47:59 debian systemd[1]: rc-local.service: Scheduled restart job, restart counter is at 5.
Oct 21 13:47:59 debian systemd[1]: rc-local.service: Start request repeated too quickly.
Oct 21 13:47:59 debian systemd[1]: rc-local.service: Failed with result 'exit-code'.
Oct 21 13:48:14 debian sudo[2222]: squire : TTY=pts/0 ; PWD=/home/squire ; USER=root ; COMMAND=/usr/sbin/service rc-local status
Oct 21 13:54:30 debian sudo[16421]: squire : TTY=pts/1 ; PWD=/home/squire ; USER=root ; COMMAND=/usr/sbin/service rc-local status
После множества проб и ошибок, пробуя различные опции, найденные в ходе моего исследования, я нашёл комбинацию, которая работает, как ожидалось.
Я полагаю, что причинами предыдущих неудач было отсутствие:
After=clamav-daemon.service syslog.target network-online.target
Requires=clamav-daemon.service
и
Type=simple
Файл rc-local.service
[Unit]
Description=ClamAV On-Access Scanner
After=clamav-daemon.service syslog.target network-online.target
Requires=clamav-daemon.service
[Service]
Type=simple
User=root
RemainAfterExit=yes
ExecStart=/etc/rc.local start
Restart=on-failure
RestartSec=10s
[Install]
WantedBy=multi-user.target
Я заметил, что после одного успешного старта при втором тесте он не сработал. Я понял, что это произошло из-за кода выхода 1
при попытке mkdir /tmp/clamonacc-quarantine
, которая уже существовала из-за предыдущего теста, выполненного в той же сессии. Я добавил комментарии, чтобы прояснить/объяснить мои изменения.
Скрипт rc.local
#!/bin/sh -e
dir=clamonacc-quarantine
# Проверяем, существует ли папка для карантина. Если да, то сразу переходим к основному процессу
if $(/bin/ls /tmp/$dir)
then
# Запускаем основной процесс, начинаем логгирование и перемещаем все инфицированные файлы в карантин
/usr/bin/clamonacc --log=/var/log/clamav/clamonacc.log --move=/tmp/$dir/
else
/bin/mkdir /tmp/$dir
/usr/bin/clamonacc --log=/var/log/clamav/clamonacc.log --move=/tmp/$dir/
fi
exit 0
Процесс активен
$ ps -aux | grep clamonacc
root 2514 0.0 0.0 213552 5064 ? Ssl 17:21 0:00 /usr/bin/clamonacc --log=/var/log/clamav/clamonacc.log --move=/tmp/clamonacc-quarantine/
Без нужды в пробах и ошибках, через которые вам пришлось пройти, вот как вы могли бы решить эту задачу иначе:
Ваш лог-файл описывает, почему ClamClient не удалось:
rc.local[1097]: ERROR: ClamClient: could not connect to remote clam daemon, Couldn't connect to server
Это происходит из-за отсутствия сети. Это также объясняет, почему он работает при ручном запуске.
man systemd.special
определяет некоторые специальные цели, которые представляют, когда конкретные компоненты машины готовы. Вы должны начинать свою службу только “после того, как сеть будет в сети”. То есть After=network-online.target
.
Вы почти это сделали, но я заметил другую ошибку в ваших журналах:
/etc/systemd/system/rc-local.service:7: Unknown lvalue 'Require' in section 'Service', ignoring
man systemd.unit
говорит нам, что ключевое слово Requires=
, а не Require=
, и оно находится в секции [Unit]
, а не в секции [Service]
. Также говорится, что Requires=network.target
просто означает, что запуск rc-local.service
также запустит network.target
, но не говорит о том, что rc-local.service
будет ждать, пока network.target
будет запущена. Ман-страница далее описывает эффект отношения After=
, который именно то, что вам нужно.
[Unit]
After=network-online.target
Requires=network-online.target
.
Ответ или решение
При решении проблемы с системой systemd, когда служба не стартует автоматически и выходит с кодом ошибки 2, важно рассмотреть несколько аспектов настройки вашей службы. Рассмотрим ситуацию более подробно, используя концепцию TEA (Теория, Пример, Применение).
Теория
Код ошибки 2 в приведенном контексте часто связан с неправильно настроенным запуском службы, что приводит к ее прерыванию или незавершению. Основная задача — убедиться, что служба может корректно запускаться при старте системы. Служба ClamAV, как указано, зависит от сети, что подразумевает необходимость ожидания готовности сетевых интерфейсов перед запуском самой службы.
В systemd разные ключевые слова и директивы объясняют, когда и как должен произойти запуск службы. Директивы Requires=
и After=
обеспечивают соответствие ключевых моментов запуска между службами, позволяя одной службе начинаться только после успешного старта другой. В вашем случае важно настроить rc-local.service
так, чтобы она задействовалась после того, как система обеспечила сетевые соединения.
Пример
Ваш конфигурационный файл rc-local.service
выглядел так:
[Unit]
Description=ClamAV On-Access Scanner
After=clamav-daemon.service syslog.target network-online.target
Requires=clamav-daemon.service
[Service]
Type=simple
User=root
RemainAfterExit=yes
ExecStart=/etc/rc.local start
Restart=on-failure
RestartSec=10s
[Install]
WantedBy=multi-user.target
Ошибка возникала из-за неправильной директивы в разделе [Service]
, а именно Require=network.target
, которая не существует. Вместо этого следует использовать Requires=
, а также описывать зависимости в разделе [Unit]
. Это гарантирует, что служба ClamAV начнет работу только после того, как will ensure that ClamAV will start only after these services have been successfully started.
Применение
Оптимальная конфигурация описана в этой части:
[Unit]
After=network-online.target
Requires=network-online.target
Нужно всегда удостоверяться, что служба clamav-daemon
запущена перед началом работы clamonacc
. Разрешение этой проблемы требует вложения ресурсов в настройку и управление системными службами. Например, добавление директивы After=clamav-daemon.service
гарантировало бы, что clamonacc
не будет запускаться до того, как демоны ClamAV будут готовы.
Также, важно отметить, что настройка Type=simple
подходит для служб, которые создают процесс перед завершением выполнения команды ExecStart=
. Это важно для rc.local
, поскольку скрипты могут выполнять команды асинхронно, не завершив работу в процессе команды.
Наконец, настройки вашего скрипта rc.local
тоже требуют внимания. Избегайте ситуаций, когда скрипт завершает работу с ошибкой, к примеру, повторное создание уже существующей директории. В скрипте можно использовать проверки на существование ресурсов перед выполнением команды, чтобы избежать таких ситуаций.
Заключение
Решение данной проблемы требует уверенного управления зависимостями служб и правильной конфигурации порядка их активации. Внимание к деталям в конфигурации systemd, а также в содержании скриптов, существенно уменьшает вероятность ошибок и повышает надежность запуска службы в автоматическом режиме. Таким образом, изучение документации systemd и внимательное прочтение журналов помогают профессионально настроить сервисы на вашем Linux-сервере.
Эти рекомендации помогут минимизировать неполадки и обеспечить стабильную работу автоматизированных сервисов в вашей системе. 💡