Python-служба: ModuleNotFoundError при запуске
Служба запускает интерпретатор по указанному пути, и набор доступных модулей определяется именно им. Виртуальное окружение, активное в вашем сеансе, службе неизвестно: в unit-файле путь должен указывать прямо на интерпретатор окружения.
Вероятные причины
По порядку: сверху то, что встречается чаще.
-
Указан системный интерпретатор вместо интерпретатора окружения
Активация окружения — это изменение переменных оболочки. Служба их не наследует, поэтому активировать окружение в unit-файле нечем.
-
Зависимости установлены другому пользователю
Установка модулей в домашний каталог даёт их только этому пользователю. Служба от другого пользователя их не видит.
-
Путь к модулям задан переменной, которой у службы нет
Переменная с путями поиска модулей из профиля службе недоступна.
Диагностика
Команды идут в том порядке, в котором их стоит выполнять: каждая следующая проверяет то, что осталось после предыдущей.
Интерпретатор и окружение службы.
systemctl cat myapp.service | grep -E "^Exec|^Environment"Трассировка с именем отсутствующего модуля.
journalctl -u myapp.service -n 20 --no-pager | tail -10Проверка от пользователя службы.
sudo -u app /opt/myapp/venv/bin/python -c "import myapp" 2>&1 | tail -3Решение
Решение своё для каждой причины. Сначала определите, какая из них ваша, — иначе правки наложатся друг на друга.
- Почему происходит
- Активация окружения — это изменение переменных оболочки. Служба их не наследует, поэтому активировать окружение в unit-файле нечем.
- Как проверить
-
Посмотрите команду запуска и содержимое окружения.
systemctl cat myapp.service | grep ExecStart ls -l /opt/myapp/venv/bin/python
- Как исправить
-
Указывайте путь к интерпретатору внутри окружения: он сам подставляет нужные пути к модулям.
ExecStart=/opt/myapp/venv/bin/python -m myapp
- Почему происходит
- Установка модулей в домашний каталог даёт их только этому пользователю. Служба от другого пользователя их не видит.
- Как проверить
-
Посмотрите, где лежат модули, и от кого работает служба.
systemctl show myapp.service -p User ls -d /home/*/.local/lib/python3*/site-packages 2>/dev/null | head
- Как исправить
- Устанавливайте зависимости в окружение проекта, а не в домашний каталог: тогда они не зависят от пользователя.
- Почему происходит
- Переменная с путями поиска модулей из профиля службе недоступна.
- Как проверить
-
Посмотрите окружение службы.
systemctl show myapp.service -p Environment | tr " " "\n" | grep -i python
- Как исправить
- Задайте переменную в unit-файле либо, что лучше, установите проект в окружение как пакет.
Пример вывода
Служба запускает системный интерпретатор вместо интерпретатора окружения. Пример показательный: он собран на тестовой машине специально для этой страницы, а не взят из чужого журнала.
myapp[4100]: Traceback (most recent call last):
myapp[4100]: File "/opt/myapp/main.py", line 3, in <module>
myapp[4100]: import fastapi
myapp[4100]: ModuleNotFoundError: No module named 'fastapi'
systemd[1]: myapp.service: Main process exited, code=exited, status=1/FAILURE
Связанные ошибки
- status=203/EXEC в systemd Код 203/EXEC означает, что systemd не смог выполнить программу из ExecStart=. Разбор причин: путь, права, интерпретатор, синтаксис оболочки.
- В терминале работает, а под systemd нет Самая частая жалоба: программа запускается руками, но не как служба. Полный разбор отличий окружения.
- status=127 в systemd: команда не найдена Код 127 без имени: оболочка не нашла команду. Появляется, когда ExecStart запускает скрипт или sh -c, а внутри команды нет.
- Address already in use при запуске службы Порт или адрес уже занят: bind() failed (98: Address already in use). Как найти владельца порта и что делать с остатками прежнего процесса.
- Exec format error при запуске службы Ошибка формата исполняемого файла: не та архитектура, нет строки #!, повреждённый файл или попытка запустить не программу.
- Job for … failed because a timeout was exceeded Задание на запуск прервано по таймауту. Как отличить медленный старт от заблокированного и правильно настроить TimeoutStartSec.
- status=1/FAILURE в systemd Код 1/FAILURE означает, что программа запустилась и сама завершилась с ошибкой. Как найти настоящую причину в журнале службы.
- Журнал службы пуст, хотя приложение работает Вывод приложения не появляется в журнале: буферизация вывода при перенаправлении в канал.
Источники
-
systemd.exec(5)
Окружение службы и отсутствие наследования от оболочки. -
Воспроизведено на тестовой машине, systemd 255 (Ubuntu 24.04)
Воспроизведено службой с системным интерпретатором при зависимостях в окружении проекта.