Эффективное устранение распространенных сбоев служб systemd
Диагностируйте распространенные сбои служб systemd с помощью systemctl, journalctl, кодов завершения, проверок модулей и практических шагов по исправлению.
Эффективное устранение распространенных сбоев служб systemd
Большинство сбоев служб systemd не являются загадочными, если разделить три вопроса: прочитал ли systemd файл модуля, удалось ли ему выполнить команду и осталось ли приложение работоспособным после запуска? Это разные точки отказа, и они оставляют разные подсказки.
Ошибка, которую я вижу чаще всего, — это немедленный переход к редактированию файла модуля. Сначала прочитайте статус и журналы. Неудачная служба обычно сообщает, столкнулась ли она с отсутствующим исполняемым файлом, неправильным пользователем, проблемой с разрешениями, проблемой с порядком зависимостей или сбоем приложения. Точная формулировка имеет значение.
Основной диагностический набор инструментов
Эффективное устранение неисправностей опирается на два основных инструмента systemd, которые предоставляют немедленную обратную связь о состоянии службы и журналах операций.
1. Проверка статуса службы
Команда systemctl status предоставляет мгновенный снимок состояния модуля, включая его текущее состояние, последние журналы и критически важные метаданные, такие как идентификатор процесса (PID) и код завершения.
$ systemctl status myapp.service
Ключевая информация, на которую следует обратить внимание:
Load:Подтверждает, что файл модуля был прочитан правильно.loaded— хорошо. Если отображаетсяnot found, ваш файл службы находится в неправильном месте или содержит опечатку.Active:Это основной статус. Если он показываетfailed, служба пыталась запуститься и неожиданно завершилась.Exit Code:Этот числовой код, часто отображаемый вместе сActive: failed, имеет решающее значение. Он указывает причину завершения процесса (например, 0 для чистого выхода, 1 или 2 для общих ошибок приложения, 203 для ошибок пути выполнения).- Последние журналы: Systemd часто включает последние несколько строк вывода журнала от службы, которые могут мгновенно выявить ошибку.
2. Глубокое погружение в журналы с помощью Journalctl
В то время как systemctl status дает сводку, journalctl предоставляет полный контекст истории выполнения службы, включая стандартный вывод и потоки стандартных ошибок.
Используйте следующую команду для просмотра журнала, относящегося к вашей сбойной службе, используя флаг -x для объяснения и флаг -e для перехода в конец (самые последние записи):
$ journalctl -xeu myapp.service
Совет: Если сбой произошел несколько часов или дней назад, используйте параметры фильтрации по времени, например
journalctl -u myapp.service --since "2 hours ago".
Пошаговая диагностика распространенных сбоев
Сбои systemd обычно делятся на несколько предсказуемых категорий. Изучив статус и журналы, вы можете быстро классифицировать проблему и применить соответствующее решение.
Тип сбоя 1: Ошибки выполнения (Код завершения 203)
Код завершения 203/EXEC означает, что systemd не смог выполнить файл, указанный в директиве ExecStart. Это одна из самых распространенных ошибок конфигурации.
Причины и решения:
Неправильный путь: Путь к исполняемому файлу неверен или не является абсолютным.
- Решение: Всегда используйте полный абсолютный путь в
ExecStart. Убедитесь, что исполняемый файл существует именно в этом месте.
# НЕПРАВИЛЬНО ExecStart=myapp # ПРАВИЛЬНО ExecStart=/usr/local/bin/myapp- Решение: Всегда используйте полный абсолютный путь в
Отсутствие разрешений: Файл не имеет разрешения на выполнение для пользователя, запускающего службу.
- Решение: Проверьте и примените разрешения на выполнение:
chmod +x /path/to/executable.
- Решение: Проверьте и примените разрешения на выполнение:
Отсутствие интерпретатора (Shebang): Если
ExecStartуказывает на скрипт (например, Python или Bash), строка shebang (#!/usr/bin/env python) может отсутствовать или быть неправильной, что препятствует выполнению.- Решение: Убедитесь, что скрипт имеет правильную строку shebang.
Тип сбоя 2: Сбои приложения (Код завершения 1 или 2)
Если служба успешно запускается (systemd находит исполняемый файл), но затем немедленно переходит в состояние failed с общим кодом ошибки приложения (обычно 1 или 2), проблема заключается в логике приложения или его окружении.
Причины и решения:
Ошибки файлов конфигурации: Приложение не смогло прочитать требуемый файл конфигурации или файл содержит неверный синтаксис.
- Решение: Внимательно просмотрите вывод
journalctl. Приложение обычно выводит конкретное сообщение об ошибке, касающееся пути или синтаксиса файла конфигурации. Используйте директивуWorkingDirectory=, если файлы конфигурации указаны относительно.
- Решение: Внимательно просмотрите вывод
Конкуренция за ресурсы / Отказ в доступе: Приложению не удалось открыть необходимый порт, получить доступ к базе данных или записать в файл журнала из-за ограничений разрешений.
- Решение: Проверьте директиву
User=в файле службы и убедитесь, что этот пользователь имеет права на чтение/запись ко всем необходимым ресурсам и каталогам.
- Решение: Проверьте директиву
Тип сбоя 3: Сбои зависимостей
Служба может выйти из строя, потому что она запускается до того, как будет готова необходимая зависимость, такая как база данных, сетевой интерфейс или смонтированная файловая система.
Причины и решения:
Сеть не готова: Службы, требующие сетевого подключения (например, веб-серверы, прокси), часто выходят из строя, если они запускаются до инициализации сетевого стека.
- Решение: Если службе требуется адрес или маршрут во время запуска, добавьте
network-online.targetв порядок и убедитесь, что служба ожидания подключения вашего дистрибутива включена для вашего сетевого менеджера:
[Unit] Description=Моя веб-служба After=network-online.target Wants=network-online.target- Решение: Если службе требуется адрес или маршрут во время запуска, добавьте
Файловая система не смонтирована: Служба пытается получить доступ к файлам на томе, который еще не смонтирован (особенно критично для вторичного хранилища или сетевых монтирований).
- Решение: Используйте
RequiresMountsFor=, чтобы явно указать systemd, какой путь должен быть доступен перед запуском.
[Unit] RequiresMountsFor=/mnt/data/storage- Решение: Используйте
Тип сбоя 4: Проблемы с пользователем и окружением (Код завершения 217)
Код завершения 217/USER часто указывает на сбой, связанный с директивами пользователя или группы, или с недоступностью переменных окружения.
Причины и решения:
Неверный пользователь/группа: Пользователь, указанный в директиве
User=илиGroup=, не существует в системе.- Решение: Проверьте существование имени пользователя с помощью
id <username>.
- Решение: Проверьте существование имени пользователя с помощью
Отсутствие переменных окружения: Службы systemd работают в чистом окружении, то есть переменные оболочки (такие как
PATHили пользовательские ключи API) не наследуются.- Решение: Определите необходимые переменные непосредственно в файле службы или через файл окружения.
[Service] # Прямое определение Environment="API_KEY=ABCDEFG" # Использование внешнего файла (например, /etc/sysconfig/myapp) EnvironmentFile=/etc/sysconfig/myapp
Рабочий процесс устранения неполадок и лучшие практики
При изменении файла службы всегда следуйте этому трехэтапному циклу, чтобы убедиться, что ваши изменения приняты и протестированы правильно.
1. Проверка синтаксиса конфигурации
Используйте systemd-analyze verify для проверки файла модуля службы перед попыткой его запуска. Это позволяет выявить простые синтаксические ошибки.
$ systemd-analyze verify /etc/systemd/system/myapp.service
2. Перезагрузка демона
Systemd кэширует файлы конфигурации. После любого изменения файла модуля вы должны сообщить systemd о необходимости перезагрузить его конфигурацию.
$ systemctl daemon-reload
3. Перезапуск и проверка статуса
Попробуйте перезапустить службу и немедленно проверьте ее статус и журналы.
$ systemctl restart myapp.service
$ systemctl status myapp.service
Обработка немедленных перезапусков и тайм-аутов
Если ваша служба входит в цикл restarting или немедленно завершается сбоем без очевидного сообщения в журнале, рассмотрите возможность настройки следующих директив в разделе [Service]:
| Директива | Назначение | Лучшая практика |
|---|---|---|
Type= |
Как systemd управляет процессом (например, simple, forking). |
Используйте simple, если только приложение явно не демонизируется. |
TimeoutStartSec= |
Как долго systemd ожидает сигнала успеха от основного процесса. | Увеличьте это значение, если приложение имеет длительный запуск (например, большая инициализация базы данных). |
Restart= |
Определяет, когда служба должна быть автоматически перезапущена (например, always, on-failure). |
Используйте on-failure для производственных приложений, чтобы предотвратить бесконечные циклы перезапуска при повторяющихся ошибках конфигурации. |
Более внимательное чтение состояний сбоя
failed — не единственное плохое состояние. Модуль может быть inactive (dead) после чистого выхода, что нормально для заданий Type=oneshot, но подозрительно для демона, который, как ожидается, будет работать постоянно. Модуль может быть activating до истечения TimeoutStartSec=. Модуль может быть active (exited), когда команда завершилась и systemd считает это приемлемым. Прежде чем изменять политику перезапуска, убедитесь, что тип службы соответствует программе.
Для обычного процесса переднего плана начните с:
[Service]
Type=simple
ExecStart=/usr/local/bin/myapp
Для скрипта, который выполняется один раз и завершается:
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/rotate-reports
Для старых демонов, которые сами форкаются в фоновый режим, может потребоваться Type=forking, но не используйте его по привычке. Многие современные приложения остаются на переднем плане при запуске под systemd. Если вы укажете systemd ожидать форкинг, а процесс не форкнется так, как ожидает systemd, вы можете получить вводящие в заблуждение сбои при запуске.
Контрольный список для триажа, который работает под давлением
Когда служба не работает, а люди ждут, используйте фиксированную последовательность:
systemctl status myapp.service --no-pager
journalctl -u myapp.service -b --no-pager
systemctl cat myapp.service
systemctl show myapp.service -p FragmentPath -p User -p Group -p WorkingDirectory -p ExecStart
Ищите первую реальную ошибку, а не последнюю строку. Последняя запись в журнале может только сообщать, что systemd пометил модуль как сбойный. Полезная строка часто находится выше: Permission denied, No such file or directory, Address already in use, Failed at step USER или исключение, специфичное для приложения.
Если служба недавно редактировалась, проверьте синтаксис и состояние перезагрузки:
sudo systemd-analyze verify /etc/systemd/system/myapp.service
sudo systemctl daemon-reload
Если systemctl status говорит, что файл модуля изменился на диске, systemd предупреждает вас, что менеджер не перезагрузил новое определение. Перезапуск службы до daemon-reload может продолжать использовать устаревшие настройки.
Проблемы с разрешениями, которые не выглядят как проблемы с разрешениями
Служба может отлично работать из вашей оболочки и выходить из строя под systemd, потому что она работает не от вашего имени. Проверьте User=, Group=, WorkingDirectory= и любые параметры усиления защиты, такие как ProtectSystem=, ReadWritePaths=, PrivateTmp= или NoNewPrivileges=.
Например:
[Service]
User=webapp
WorkingDirectory=/srv/webapp
ExecStart=/srv/webapp/bin/server
ReadWritePaths=/srv/webapp/var
ProtectSystem=strict
С ProtectSystem=strict большая часть файловой системы доступна службе только для чтения. Это хороший параметр усиления защиты, но он означает, что приложение должно записывать только в пути, которые вы явно разрешили. Если в журнале сказано, что приложение не может создать файл PID, файл кэша, базу данных SQLite или каталог для загрузки, причиной может быть изоляция модуля.
Также проверьте разрешения родительского каталога. Исполняемый файл может быть в режиме 755, но если /srv/webapp недоступен для поиска пользователем службы, systemd все равно не сможет его выполнить. Используйте:
namei -l /srv/webapp/bin/server
sudo -u webapp /srv/webapp/bin/server --check-config
Запуск безопасной проверки конфигурации от имени пользователя службы выявляет многие проблемы без запуска полного демона.
Циклы перезапуска и ограничения частоты
Restart=on-failure полезен, но он может скрыть исходную ошибку в потоке повторных запусков. Systemd также применяет ограничение частоты запуска. Когда служба выходит из строя слишком много раз за короткий промежуток времени, вы можете увидеть start-limit-hit.
Полезные команды:
systemctl status myapp.service
systemctl reset-failed myapp.service
sudo systemctl start myapp.service
reset-failed не исправляет причину. Он только очищает состояние сбоя systemd и память ограничения частоты, чтобы вы могли снова протестировать после внесения изменений. Если вам постоянно это нужно, сбавьте темп и исправьте первый сбой в журнале.
Отладка постоянных проблем
Если стандартные журналы не раскрывают проблему, приложение может перенаправлять свой вывод.
- Проверьте
StandardOutputиStandardError: По умолчанию они направляются в журнал. Если они установлены в/dev/nullили файл, вы должны проверить эти места напрямую на наличие сообщений об ошибках. - Временная подробность: Если возможно, временно настройте приложение (или его аргументы командной строки в
ExecStart) на работу с максимальной подробностью (например,--debugили-v), чтобы генерировать более детальный вывод журнала при сбое.
Разумная точка остановки
После запуска службы проверьте еще одну вещь: выполняет ли она реальную работу. systemctl status может сообщить вам только состояние процесса с точки зрения systemd. Веб-служба может быть активной, возвращая 500-е ошибки. Воркер может быть активным, проваливая каждое задание. После устранения проблемы на уровне модуля запустите собственную проверку работоспособности приложения, просмотрите его журналы приложения и убедитесь, что зависимость, с которой он общается, доступна.
Для большинства инцидентов полезный путь короток: systemctl status, затем journalctl -u, затем проверка модуля с помощью systemctl cat, затем тестирование команды от имени настроенного пользователя службы. Это держит вас рядом с доказательствами и вдали от случайных изменений файла модуля.
Запишите окончательную причину в журнал эксплуатации службы или заметки по развертыванию, пока она еще свежа. "Исправлен systemd" бесполезно позже. "Служба завершилась с ошибкой 203/EXEC, потому что развертывание создало /opt/app/current/bin/server без разрешения на выполнение" — полезно. Следующий инцидент обычно будет похож на предыдущий.