Устранение неисправностей служб systemd: практическое руководство для системных администраторов

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

Устранение неисправностей служб systemd: практическое руководство для системных администраторов

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

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

Понимание сбоев служб systemd

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

Распространенные причины сбоев служб:

  • Ошибки конфигурации: Неправильные настройки в файле модуля .service или связанных файлах конфигурации.
  • Отсутствующие зависимости: Служба зависит от других системных ресурсов (таких как сеть, другие службы, определенные файловые системы), которые недоступны или еще не запущены.
  • Исчерпание ресурсов: Службе требуется больше памяти, процессорного времени или операций ввода-вывода, чем может предоставить система.
  • Проблемы с разрешениями: Процессу службы не хватает необходимых разрешений для доступа к требуемым файлам, каталогам или сетевым портам.
  • Ошибки в службе: В самом приложении есть ошибка, из-за которой оно аварийно завершается при запуске или работе.
  • Поврежденные данные: Важные файлы данных, используемые службой, повреждены.
  • Сетевые проблемы: Проблемы с сетевыми интерфейсами, DNS или правилами брандмауэра, препятствующие привязке службы к портам или связи.

Шаг 1: Проверка статуса службы

Первый шаг в устранении неисправностей любой неисправной службы — проверка ее текущего статуса. Команда systemctl systemd является вашим основным инструментом для этого.

Использование systemctl status

Команда systemctl status <имя_службы>.service предоставляет краткий обзор текущего состояния службы, последних записей журнала и информации о процессе.

sudo systemctl status nginx.service

Пример вывода (неисправная служба):

● nginx.service - Высокопроизводительный веб-сервер и обратный прокси-сервер
     Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
     Active: failed (result=exit-code) since Tue 2023-10-27 10:30:00 UTC; 1min ago
       Docs: man:nginx(8)
    Process: 1234 ExecStart=/usr/sbin/nginx -g daemon on; master_process on; (code=exited, status=1/FAILURE)
   Main PID: 1234 (code=exited, status=1/FAILURE)

Oct 27 10:30:00 your-server systemd[1]: Starting A high performance web server and reverse proxy...
Oct 27 10:30:00 your-server nginx[1234]: nginx: [emerg] bind() to port 80 failed (98: Address already in use)
Oct 27 10:30:00 your-server systemd[1]: nginx.service: Main process exited, code=exited, status=1/FAILURE
Oct 27 10:30:00 your-server systemd[1]: Failed to start A high performance web server and reverse proxy.

Ключевая информация, которую нужно искать в выводе systemctl status:

  • Active:: Эта строка указывает текущее состояние. failed — это состояние, которое нас интересует. Также может отображаться failed (result=exit-code) или failed (result=oom-kill). result часто дает подсказку.
  • Process:: Подробная информация о процессе, который systemd пытался запустить. Если отображается code=exited, status=..., это критично.
  • Записи журнала: Последние строки журнала часто содержат прямое сообщение об ошибке от службы.

Шаг 2: Анализ журналов с помощью journalctl

Команда journalctl — это мощный инструмент systemd для запроса и отображения журналов из журнала systemd. Она необходима для получения подробной информации о причине сбоя службы.

Базовое использование journalctl для служб

Чтобы просмотреть журналы для конкретной службы, используйте флаг -u:

sudo journalctl -u <имя_службы>.service

Чтобы следить за журналами в реальном времени:

sudo journalctl -f -u <имя_службы>.service

Чтобы просмотреть журналы с последней загрузки (полезно для служб, которые не запустились во время загрузки):

sudo journalctl -b -u <имя_службы>.service

Чтобы просмотреть журналы за определенное время:

sudo journalctl --since "2023-10-27 10:00:00" -u <имя_службы>.service

Интерпретация вывода journalctl

Ищите сообщения об ошибках, трассировки стека или конкретные коды ошибок, сообщаемые приложением или самим systemd. Пример вывода из systemctl status уже показал ключевую ошибку: bind() to port 80 failed (98: Address already in use). Это ясно указывает на то, что другой процесс уже использует порт 80, что мешает запуску Nginx.

Совет: Если служба очень многословна, вы можете ограничить вывод:

sudo journalctl -n 50 -u <имя_службы>.service  # Показать последние 50 строк

Шаг 3: Проверка зависимостей и требований службы

Службы systemd часто зависят от доступности других служб или системных ресурсов. Если зависимость не выполнена, служба не запустится.

Просмотр зависимостей

Вы можете проверить зависимости службы с помощью systemctl cat и поиска директив, таких как Requires=, Wants=, After=, Before= и PartOf=.

systemctl cat <имя_службы>.service

Например, службе, которая привязывается к определенному адресу, может потребоваться упорядочение после настройки сети. After=network-online.target управляет только порядком; сам по себе он не включает эту цель в транзакцию. Если службе это действительно нужно, вы часто видите оба:

Wants=network-online.target
After=network-online.target

Будьте консервативны с Requires=. Он создает более сильную связь и может остановить вашу службу, когда требуемый модуль останавливается. Многим прикладным службам нужны только Wants= плюс After=.

Проверка отсутствующих зависимостей

Хотя systemctl status часто указывает на проблемы с зависимостями, явная проверка активности требуемых служб может быть полезной.

systemctl is-active <имя_зависимой_службы>.service

Если требуемая служба замаскирована или остановлена, это может помешать запуску целевой службы.

systemctl list-dependencies <имя_службы>.service

Эта команда показывает полное дерево зависимостей.

Шаг 4: Понимание кодов завершения

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

  • Код завершения 0: Успех.
  • Код завершения 1: Общий сбой для многих программ. Конкретное значение зависит от приложения.
  • Код завершения 127: Команда не найдена (часто из-за неправильного пути ExecStart или отсутствующего исполняемого файла).
  • Код завершения 137: Убит сигналом SIGKILL. Это часто, но не всегда, связано с нехваткой памяти.
  • Код завершения 139: Убит сигналом SIGSEGV (Ошибка сегментации).

Из вывода systemctl status мы видели status=1/FAILURE. Это общий сбой, и предшествующие сообщения журнала необходимы для понимания того, почему он завершился с кодом 1.

Идентификация OOM-убийств

Если systemctl status показывает failed (result=oom-kill), это означает, что OOM-убийца Linux завершил процесс службы, потому что в системе критически не хватало памяти.

Чтобы подтвердить это, вы часто можете найти соответствующие сообщения в journalctl или dmesg:

dmesg | grep -i oom

Устранение ошибок OOM

  • Увеличьте объем оперативной памяти системы: Если возможно.
  • Уменьшите использование памяти: Оптимизируйте службу или другие запущенные процессы.
  • Настройте подкачку: Убедитесь, что доступно достаточное пространство подкачки.
  • Проверьте ограничения памяти службы: Параметр MemoryMax= может вызвать OOM для конкретной службы, даже если на хосте еще есть свободная память.
  • Просмотрите недавние развертывания: Сбои памяти часто следуют за изменением конфигурации, трафика или версии.

Шаг 5: Проверьте файл модуля, который systemd фактически использует

Не предполагайте, что файл в вашем редакторе является полным модулем. Пакеты, drop-in файлы и переопределения могут объединяться в окончательное определение:

systemctl cat <имя_службы>.service
systemctl show <имя_службы>.service -p FragmentPath -p DropInPaths

Это выявляет распространенную проблему: кто-то отредактировал /usr/lib/systemd/system/app.service, в то время как переопределение в /etc/systemd/system/app.service.d/override.conf все еще изменяет Environment= или ExecStart=.

После редактирования файлов модулей или drop-in файлов перезагрузите systemd:

sudo systemctl daemon-reload

Если вы забудете этот шаг, systemctl restart может продолжать использовать старое определение модуля.

Шаг 6: Распространенные проблемы и исправления для конкретных служб

Хотя приведенные выше шаги являются общими, у конкретных служб есть общие режимы сбоев.

Веб-серверы (Nginx, Apache)

  • Порт уже используется: Как показано в примере, другой процесс может прослушивать порт 80 или 443. Используйте sudo ss -tulnp | grep :80, чтобы найти процесс-нарушитель.
  • Синтаксические ошибки конфигурации: Запустите тест конфигурации веб-сервера (например, sudo nginx -t или sudo apachectl configtest).
  • Отсутствующие SSL-сертификаты: Убедитесь, что файлы сертификатов присутствуют и доступны для чтения.

Базы данных (MySQL, PostgreSQL)

  • Разрешения каталога данных: Убедитесь, что пользователь базы данных имеет правильные права на чтение/запись в свой каталог данных.
  • Поврежденные файлы данных: Может потребоваться восстановление из резервной копии или использование специальных инструментов восстановления базы данных.
  • Дисковое пространство заполнено: Базы данных могут потреблять значительное дисковое пространство.

Сетевые службы

  • Неверные IP-адреса или имена хостов: Проверьте сетевую конфигурацию.
  • Правила брандмауэра: Убедитесь, что необходимые порты открыты.
  • Проблемы с разрешением DNS: Проверьте /etc/resolv.conf и сетевое подключение.

Шаг 7: Продвинутые методы устранения неисправностей

Повторное включение и перезапуск службы

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

sudo systemctl daemon-reload # Перезагрузить конфигурацию менеджера systemd
sudo systemctl restart <имя_службы>.service

Использование systemctl --failed

Эта команда выводит список всех модулей, которые в настоящее время находятся в состоянии сбоя.

systemctl --failed

Проверка ограничений ресурсов (ulimit)

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

Для служб, управляемых systemd, свойства модуля часто более актуальны, чем ulimit интерактивной оболочки:

systemctl show <имя_службы>.service -p LimitNOFILE -p User -p Group -p MemoryMax -p TasksMax

Если приложение сообщает too many open files, сравните LimitNOFILE с количеством подключений и использованием файлов приложения. Если служба не может создавать потоки или дочерние процессы, посмотрите на TasksMax.

Флаги отладки

Многие приложения имеют режимы отладки или подробное ведение журнала, которые можно включить с помощью аргументов командной строки в строке ExecStart файла .service. Обратитесь к документации приложения.

Краткий пример: Служба работает вручную, но не запускается при загрузке

Это одна из самых распространенных жалоб на systemd. Разработчик запускает команду вручную, и она работает. Та же команда не работает как служба. Обычное отличие — окружение.

Проверьте пользователя службы и рабочий каталог:

systemctl show myapp.service -p User -p Group -p WorkingDirectory
systemctl cat myapp.service

Затем ищите предположения в приложении: относительные пути, файлы в домашнем каталоге, переменные окружения из .bashrc или учетные данные, загруженные интерактивной оболочкой. systemd не читает ваши файлы запуска оболочки для службы. Если приложению нужны APP_ENV=production или DATABASE_URL=..., поместите эту конфигурацию в модуль с помощью Environment=, EnvironmentFile= или вашего обычного пути управления секретами.

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

Wants=network-online.target
After=network-online.target
RequiresMountsFor=/srv/myapp

RequiresMountsFor= полезен, когда службе нужен определенный путь, особенно если этот путь поступает с отдельного диска или сетевого монтирования. Это понятнее, чем надеяться, что широкая цель случайно завершится первой.

Сброс состояния сбоя

После сбоя службы systemd запоминает состояние сбоя, пока оно не будет сброшено или модуль не завершится успешно. Это полезно для видимости, но может сбивать с толку проверки статуса после того, как вы уже исправили проблему:

sudo systemctl reset-failed myapp.service
sudo systemctl restart myapp.service
systemctl status myapp.service

Используйте reset-failed после того, как вы собрали необходимые доказательства. Во время инцидента состояние сбоя и временные метки журнала являются полезными подсказками.

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

systemctl show myapp.service -p NRestarts -p RestartUSec

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

Надежный шаблон: прочитайте status, прочитайте журнал, проверьте эффективный модуль с помощью systemctl cat, проверьте зависимости и пути, а затем перезапускайте только после того, как узнаете, что изменилось. Это делает устранение неисправностей systemd скучным, а это именно то, что вам нужно во время простоя.