Вопрос или проблема
У меня есть скрипт на Python, который я хотел бы запустить в тюрьме FreeNAS. Он работает без демона сервиса, но я хотел бы запустить его как сервис. Я создал следующий скрипт сервиса /etc/rc.d/attendance
#!/bin/sh
# PROVIDE: attendance
# REQUIRE: DAEMON
# KEYWORD: shutdown
. /etc/rc.subr
name=attendance
rcvar=attendance_enable
load_rc_config $name
: ${attendance_enable="NO"}
pidfile="/var/run/${name}.pid"
command="/root/Zkteco/app.py"
command_interpreter=/usr/local/bin/python
run_rc_command "$1"
Я также добавил attendance_enable="YES"
в /etc/rc.conf
.
Когда я запускаю service attendance start
, я получаю
Запуск attendance
limits: /root/Zkteco/app.py: Нет такого файла или каталога
/etc/rc.d/attendance: WARNING: не удалось запустить attendance
Хотя каталог существует, я попытался переместить его из /etc/rc.d/attendance
в /usr/local/etc/rc.d/attendance
, и, похоже, это сработало, но он снова не уходит в фоновый процесс, и мне нужно нажимать Ctrl+C, чтобы остановить его.
Есть ли какие-то рекомендации? Скрипт является веб-приложением, использующим FastAPI и Uvicorn, есть ли связь с этим? Как я могу увидеть логи ошибок сервиса, пытающегося запуститься.
Что я пробовал
Я создал бинарный файл с помощью pyinstaller --onefile
из скрипта. И изменил
#!/bin/sh
.
.
.
command="/usr/local/bin/app"
run_rc_command "$1"
Это изменение заставило сервис запуститься, но опять же, он никогда не уходит в фон.
Файлы в /etc/rc.d
считаются частью операционной системы и управляются ею. Вы должны только работать с /usr/local/etc/rc.d
. Обратите внимание, что это местоположение также предназначено для rc-скриптов всех пакетов.
rc.d – это фреймворк управления сервисами. Но он ничего не делает для создания “сервиса” или, точнее, “демонизации процесса”. Он предназначен для обеспечения единого способа обработки “сервисов”.
Вы заметили, что ваше приложение не уходит в фон, как вы ожидали, и вам нужно было нажимать CTRL-C. Ваши ожидания не соответствуют тому, что должно происходить. Ответственность за демонизацию лежит на вашем скрипте/программе/приложении (уйти в фон и т.д.). Скрипт rc – это всего лишь оболочка вокруг вашего приложения.
Я не знаю ваше приложение и uvicorn очень хорошо. Но из документации uvicorn, похоже, не поддерживает демонизацию. Это обычно происходит при указании параметра командной строки. Ваш базовый тест на это: Можете ли вы запустить свое приложение из командной строки и заставить его отсоединиться от консоли самостоятельно?
Если вы хотите чисто питоновский способ сделать это, обратите внимание на PEP 3143 – стандартная библиотека процессов-демонов.
Простой подход FreeBSD состоит в том, чтобы использовать daemon(8). Очень простой пример был бы следующим:
#!/bin/sh
# REQUIRE: LOGIN
. /etc/rc.subr
name=attendance
rcvar=`set_rcvar`
pidfile="/var/run/${name}.pid"
attendance_user="somenotrootuser"
command="/usr/sbin/daemon"
command_args="-c -f -P ${pidfile} -u ${attendance_user} -r /usr/local/bin/app"
load_rc_config $name
run_rc_command "$1"
(См. Есть ли простой способ создать скрипт rc для FreeBSD? и Скрипт FreeBSD rc.d не стартует как демон)
Я замечаю, что вы разместили свое приложение в /root
. Это наводит на мысль, что вы запускаете вещи от имени root. Хорошей практикой является запуск вещей от имени непривилегированного пользователя.
Это должно работать для вашего простого случая. Если это полноценный развертывание в производстве, вам нужно сделать больше, но это связано с uvicorn, а не с FreeBSD. Если вы прочитаете о https://www.uvicorn.org/deployment/, вы заметите, что в производстве вы часто будете использовать gunicorn и, возможно, nginx тоже.
Вышеуказанное – это “правильный” способ делать вещи в FreeBSD. Если вам нравится использовать FreeBSD, это полезно учить и с чем работать.
Но если вы больше программист на Python/веб-программист и находите настройку gunicorn и т.д. трудной, то вам может быть легче установить supervisord. Он легко устанавливается как пакет sysutils/py-supervisor/. Это можно рассматривать как альтернативу rc/демону, и вы найдете много примеров онлайн, специально для использования с проектами веб на Python.
Ответ или решение
Запуск Python скрипта в FreeNAS Jail как службы (rc)
Создание службы для вашего Python скрипта в окружении FreeNAS или FreeBSD — это тема, к которой стоит подойти с пониманием архитектуры операционной системы и самой концепции демонизации процессов. Давайте разберемся по порядку, чтобы вы могли эффективно настроить свою службу.
Проблема и начальная информация
Вы уже разработали скрипт /etc/rc.d/attendance
, который не запускается должным образом. Ошибка:
limits: /root/Zkteco/app.py: No such file or directory
/etc/rc.d/attendance: WARNING: failed to start attendance
указывает на то, что указанный файл не найден. Следовательно, перед тем как выполнять любые дальнейшие шаги, убедитесь, что путь к вашему скрипту правильный и сам файл доступен для чтения. Например, стоит изменить файл на /usr/local/Zkteco/app.py
, так как работать с файлами в домашнем каталоге root — плохая практика, особенно для служб, которые должны работать под управлением другого пользователя.
Оптимизация скрипта службы
Переместим ваш скрипт службы в правильное место и улучшим его. Это должен быть каталог /usr/local/etc/rc.d
, и скрипт может выглядеть так:
#!/bin/sh
# PROVIDE: attendance
# REQUIRE: DAEMON
# KEYWORD: shutdown
. /etc/rc.subr
name=attendance
rcvar=`set_rcvar`
pidfile="/var/run/${name}.pid"
attendance_user="название_пользователя" # Укажите пользователя, под которым будет работать служба
# Убедитесь, что интерпретатор установлен
command_interpreter="/usr/local/bin/python"
# Измените путь на правильный
command="/usr/local/Zkteco/app.py"
load_rc_config $name
run_rc_command "$1"
Демонизация процесса
Проблема, с которой вы столкнулись, связана с тем, что Uvicorn не демонизирует себя независимо. Это означает, что вам нужно явно указать процессу перейти в фоновый режим. Одним из способов сделать это является использование утилиты daemon
, которая идет вместе с FreeBSD.
Для этого измените command
на вызов daemon
следующим образом:
command="/usr/sbin/daemon"
command_args="-c -f -P ${pidfile} -u ${attendance_user} -r ${command_interpreter} ${command}"
Таким образом, ваша служба будет правильно работать в фоновом режиме.
Логи и диагностика ошибок
Чтобы отслеживать ошибки службы, вы можете перенаправить вывод и ошибки в файл журнала:
command_args="-c -f -P ${pidfile} -u ${attendance_user} -r ${command_interpreter} ${command} >> /var/log/attendance.log 2>&1"
Создайте файл лога и отредактируйте права доступа, чтобы ваша служба могла записывать в него информацию.
Альтернативы и советы
Дополнительно, вы можете рассмотреть использование supervisord
, если вам необходимо более простое управление процессами. Он предоставляет графический интерфейс и простые команды для управления вашими приложениями. Установка осуществляется через менеджер пакетов FreeBSD:
pkg install py36-supervisor
Заключение
Настройка вашего Python скрипта как службы в FreeBSD требует понимания не только самой службы, но и механики работы процессов в UNIX-подобных системах. Следуя приведенным выше рекомендациям, вы обеспечите корректный запуск вашего приложения и избавитесь от необходимости вручную управлять процессами.