파이썬 프로그램 Systemd로 관리하기

dong5854·2022년 6월 29일
0

간단한 파이썬 프로그램을 백그라운드로 실행할 일이 생겨서 nohup으로 돌리고 있었습니다. 하지만 nohup은 실패시 프로세스가 종료되기 때문에 아래와 같은 스크립트를 크론탭에서 1분 단위로 실행해 다시 프로그램을 실행 할 수 있도록 해뒀습니다.

#!/bin/sh

cd /var/www/myproject

check=`ps -ef | grep mypython_file.py | wc | awk '{print $1}'`

if [ $check -gt 1 ]
then
    echo "RUNNING"
else
    nohup /root/.poetry/bin/poetry run python mypython_file.py > /dev/null 2>&1 &
fi

문제점

이상태로 몇일동안 사용해본 결과 문제점이 몇가지 생겼습니다.

  1. 프로세스의 상태를 모니터링 하는 것이 번거로웠습니다.

  2. 프로세스를 끄기 위해서는 PID를 찾아서 kill 해주는 것이 생각보다 번거로웠습니다.

위의 문제점들을 개선하기 위해 파이썬 파일을 systemd를 사용해 관리해보려고 방법을 구글링 해가면서 시도해봤습니다.

해당 게시물은 대부분 https://github.com/torfsen/python-systemd-tutorial 의 내용에 따라 작성되었습니다.


System과 User Services

systemd는 System과 User 서비스를 지원하는데, 이 둘의 차이는 아래와 같습니다.

System service: 시스템 자체의 systemd 인스턴스에서 작동하고 전체 시스템과 모든 유저들에게서 동작 할 수 있습니다.

User Service: 리눅스 유저에게 종속된 systemd 인스턴스에서 작동합니다.

제가 본 자료에서는 system service를 개발할 예정이라고 해도 user service를 먼저 만들어보기를 권장했는데, 이는 system service가 user service에 비해 설정이 복잡하기 때문에 user 프로세스를 만들어 일단은 서비스를 성공적으로 띄우는것에 집중하고 나중에 이 복잡한 설정들을 완료하기 위해서 라고 합니다.

Unit Files

systemd 서비스를 만들기 위해서는 ini 파일 형식의 unit file이 필요합니다.

Unit file이 위치할 경로는 여러 장소있습니다.
제가 본 자료들은 ~/.config/systemd/user//usr/lib/systemd/system/ 두 군데를 보통 사용했는데 전자는 User service이고 후자가 System Service입니다.

일단 제가 참고하고 있는 자료에서는 user service를 먼저 띄우는 것을 추천했기 때문에 이에 따라 ~/.config/systemd/user/my_python.service파일을 작성했습니다.

[Unit]
# Human readable name of the unit
Description=Python Demo Service

my_python.service를 작성하고 난 후에 systemd에서 .service를 찾는지 확인해 볼 수 있습니다.

$ systemctl --user list-unit-files | grep python_demo_service
python_demo_service.service         static

파이썬 스크립트와 연결

실행할 파이썬 파일에 대한 내용을 unit 파일에 추가적으로 기입해줍니다.

[Unit]
Description=Python Demo Service

[Service]
# Command to execute when the service is started
ExecStart=/usr/bin/python path/to/your/python_demo_service.py

위의 파일은 제가 참고하고 있는 자료에서 가져온 것이고 실제로 저는 poetry를 이용해 개발을 진행했게 때문에 이에 맞추어 아래의 추가적인 절차를 진행했습니다.

  1. poetry의 경로를 확인합니다.
$ which poetry
/home/dong/.poetry/bin/poetry
  1. 확인한 경로를 ExecStart에 넣어줍니다.
[Unit]
Description=Python Demo Service

[Service]
# Command to execute when the service is started
ExecStart=/home/dong/.poetry/bin/poetry run python path/to/your/python_demo_Service.py
  1. pyproject.toml이 있는 디렉토리를 WorkingDirectory를 추가해줍니다.
[Unit]
Description=Python Demo Service

[Service]
# directory of project
WorkingDirectory=path/to/project
# Command to execute when the service is started
ExecStart=/home/dong/.poetry/bin/poetry run python path/to/your/python_demo_Service.py
  1. [service]의 Restart에 on-failure를 추가해 non-zero-exit-code 즉 비정상 종료일 때 재시작 할 수 있도록 해줍니다.

Restart를 비롯한 다양한 옵션에 대해서는 이 문서를 통해 확인해 볼 수 있습니다.

  1. user 데몬을 리로드해 서비스를 찾은 수 실행할 수 있도록 합니다.
$ systemctl --user daemon-reload
  1. 서비스를 실행합니다.
$ systemctl --user start python_demo_service
  1. 서비스가 정상적으로 실행중인지 확인합니다.
$ systemctl --user status python_demo_service
● python_demo_service.service - Python Demo Service
   Loaded: loaded (/home/torf/.config/systemd/user/python_demo_service.service; static; vendor preset: enabled)
   Active: active (running) since So 2018-12-30 17:46:03 CET; 2min 35s ago
 Main PID: 26218 (python)
   CGroup: /user.slice/user-1000.slice/user@1000.service/python_demo_service.service
           └─26218 /usr/bin/python /home/torf/projects/python-systemd-tutorial/python_demo_service.py

User Services가 세션이 닫히면 인스턴스 종료

User Service로 systemd를 실행하면 해당 유저에 대한 세션이 닫히면 systemd 인스턴스가 꺼지는 문제점이 있다. 해당 문제를 해결하려면 아래 명령어를 실행해야 합니다.

$ sudo loginctl enable-linger $USER

System Service 만들기

User Service를 성공적으로 만들었다면 이를 System Service로 바꿀 구 있지만 제대로 적용되지 않으면 system service로 만들 경우 시스템의 안정성과 보안상의 문제가 발생할 가능성이 있습니다. 그래서 내가 참고한 자료에서는 System Service로 바꾸지 않고 user service를 사용하기를 장려합니다.

user service 멈춘 후 종료

user service를 system service로 바꾸기 전에 먼저 user service를 멈추고 종료해야합니다.

$ systemctl --user stop python_demo_service
$ systemctl --user disable python_demo_service

Unit File 경로 변경

user service를 system service로 바꾸기 위해서는 Unit File의 경로를 user service를 위한 경로에서 system service를 위한 경로로 바꾸고 권한을 알맞게 수정해줘야합니다. system unit file은 여러 경로에 위치 할 수 있는데 예시에서는 /etc/systemd/system/에 넣었습니다.

$ sudo mv ~/.config/systemd/user/python_demo_service.service /etc/systemd/system/
$ sudo chown root:root /etc/systemd/system/python_demo_service.service
$ sudo chmod 644 /etc/systemd/system/python_demo_service.service

성공적으로 옮겨지면 이제 user service가 system service가 되어 --user옵션 없이 실행이 가능합니다.

$ systemctl list-unit-files | grep python_demo_service
python_demo_service.service                disabled

추가적으로 파이썬 스크립트의 경로를 홈 디렉토리에서 /usr/local/lib로 바꾸는 과정과 보안 취약점을 해결하기 위해 system service를 root가 아닌 사용자 계정으로 실행하기 위한 과정이 해당 문서에 나와 있기 때문에 같이 확인해보는것이 좋을 것 같습니다.

끝.

참고자료
https://www.freedesktop.org/wiki/Software/systemd/
https://www.freedesktop.org/software/systemd/man/systemd.directives.html
https://github.com/torfsen/python-systemd-tutorial
https://www.freedesktop.org/software/systemd/man/systemd.service.html
https://unix.stackexchange.com/questions/545195/systemd-service-does-not-last-more-than-6-hours

profile
https://github.com/dong5854?tab=repositories

0개의 댓글