Linux에서 Python 스크립트를 서비스 또는 데몬처럼 실행하는 방법
특정 이메일 주소를 확인하고 새로운 이메일을 외부 프로그램에 전달하는 Python 스크립트를 작성했습니다.Linux에서 데몬이나 서비스로 전환하는 등 이 스크립트를 24시간 365일 실행하려면 어떻게 해야 합니까?프로그램에서 끝나지 않는 루프가 필요합니까?아니면 코드를 여러 번 재실행하는 것만으로 할 수 있습니까?
여기에는 두 가지 옵션이 있습니다.
스크립트를 호출하는 적절한 cron 작업을 만듭니다.Cron은 사용자가 설정한 일정에 따라 정기적으로 스크립트를 실행하는 GNU/Linux 데몬의 일반적인 이름입니다.스크립트를 crontab에 추가하거나 스크립트에 심볼링크를 특별한 디렉토리에 배치하면 데몬이 백그라운드에서 실행하는 작업을 처리합니다.당신은 위키피디아에서 더 많이 읽을 수 있습니다.다양한 cron 데몬이 있지만 GNU/Linux 시스템에 이미 설치되어 있어야 합니다.
스크립트 자체를 데몬화하려면 일종의 python 접근법(라이브러리 등)을 사용합니다.예, 단순한 이벤트 루프(이벤트가 타이머를 트리거하는 경우, sleep 기능에 의해 제공될 수 있음)가 필요합니다.
실제로는 cron 기능을 반복하고 있기 때문에 2.를 선택하는 것은 권장하지 않습니다.Linux 시스템 패러다임은 여러 개의 간단한 도구를 상호 작용시켜 문제를 해결하는 것입니다.정기적으로 트리거하는 것 외에 데몬을 작성해야 하는 다른 이유가 없는 한 다른 방법을 선택합니다.
또, 루프와 함께 데몬라이즈를 사용해 크래시가 발생했을 경우, 그 후에 아무도 메일을 체크하지 않습니다(Ivan Nevostruev가 이 답변의 코멘트에서 지적하고 있습니다).반면 만약 대본이cron 일로 추가 다시 유발시킬 것 같다.
여기 여기에서 납치는 좋은 수업입니다.
#!/usr/bin/env python
import sys, os, time, atexit
from signal import SIGTERM
class Daemon:
"""
A generic daemon class.
Usage: subclass the Daemon class and override the run() method
"""
def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
self.stdin = stdin
self.stdout = stdout
self.stderr = stderr
self.pidfile = pidfile
def daemonize(self):
"""
do the UNIX double-fork magic, see Stevens' "Advanced
Programming in the UNIX Environment" for details (ISBN 0201563177)
http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
"""
try:
pid = os.fork()
if pid > 0:
# exit first parent
sys.exit(0)
except OSError, e:
sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))
sys.exit(1)
# decouple from parent environment
os.chdir("/")
os.setsid()
os.umask(0)
# do second fork
try:
pid = os.fork()
if pid > 0:
# exit from second parent
sys.exit(0)
except OSError, e:
sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))
sys.exit(1)
# redirect standard file descriptors
sys.stdout.flush()
sys.stderr.flush()
si = file(self.stdin, 'r')
so = file(self.stdout, 'a+')
se = file(self.stderr, 'a+', 0)
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())
# write pidfile
atexit.register(self.delpid)
pid = str(os.getpid())
file(self.pidfile,'w+').write("%s\n" % pid)
def delpid(self):
os.remove(self.pidfile)
def start(self):
"""
Start the daemon
"""
# Check for a pidfile to see if the daemon already runs
try:
pf = file(self.pidfile,'r')
pid = int(pf.read().strip())
pf.close()
except IOError:
pid = None
if pid:
message = "pidfile %s already exist. Daemon already running?\n"
sys.stderr.write(message % self.pidfile)
sys.exit(1)
# Start the daemon
self.daemonize()
self.run()
def stop(self):
"""
Stop the daemon
"""
# Get the pid from the pidfile
try:
pf = file(self.pidfile,'r')
pid = int(pf.read().strip())
pf.close()
except IOError:
pid = None
if not pid:
message = "pidfile %s does not exist. Daemon not running?\n"
sys.stderr.write(message % self.pidfile)
return # not an error in a restart
# Try killing the daemon process
try:
while 1:
os.kill(pid, SIGTERM)
time.sleep(0.1)
except OSError, err:
err = str(err)
if err.find("No such process") > 0:
if os.path.exists(self.pidfile):
os.remove(self.pidfile)
else:
print str(err)
sys.exit(1)
def restart(self):
"""
Restart the daemon
"""
self.stop()
self.start()
def run(self):
"""
You should override this method when you subclass Daemon. It will be called after the process has been
daemonized by start() or restart().
"""
당신은, 그것은 모든 것에서python-daemon 도서관을 사용해야 한다.
PyPI부터:도서관 품행이 단정한 유닉스daemon 과정을 구현해야 합니다.
정말로 당신의 고리는 배경의 서비스로 24시간 뛰기를 원할 것으로 가정한다.
이후 linux을 사용하고 있는 도서관을 갖춘 당신의 코드를 주입함과 관련이 없어 대한 해결 방법은, 단순히,:서비스 템플릿을 만들 수 있습니다.
[Unit]
Description = <Your service description here>
After = network.target # Assuming you want to start after network interfaces are made available
[Service]
Type = simple
ExecStart = python <Path of the script you want to run>
User = # User to run the script as
Group = # Group to run the script as
Restart = on-failure # Restart when there are errors
SyslogIdentifier = <Name of logs for the service>
RestartSec = 5
TimeoutStartSec = infinity
[Install]
WantedBy = multi-user.target # Make it accessible to other users
폴더(통상은 「」)에 격납합니다./etc/systemd/system/
에서는,*.service
다음 systemctl 명령을 사용하여 파일을 작성하고 설치합니다(sudo 권한이 필요할 수 있습니다).
systemctl enable <service file name without .service extension>
systemctl daemon-reload
systemctl start <service file name without .service extension>
그런 다음 다음 명령을 사용하여 서비스가 실행 중인지 확인할 수 있습니다.
systemctl | grep running
다음과 같이 fork()를 사용하여 스크립트를 tty에서 분리하여 계속 실행할 수 있습니다.
import os, sys
fpid = os.fork()
if fpid!=0:
# Running as daemon now. PID is fpid
sys.exit(0)
물론 무한 루프를 구현해야 합니다.
while 1:
do_your_check()
sleep(5)
이게 시작이었으면 좋겠네요.
셸 스크립트를 사용하여 python 스크립트를 서비스로 실행할 수도 있습니다.먼저 셸 스크립트를 생성하여 다음과 같은 python 스크립트를 실행합니다(스크립트명 임의명).
#!/bin/sh
script='/home/.. full path to script'
/usr/bin/python $script &
이제 /etc/init.d/scriptname에 파일을 만듭니다.
#! /bin/sh
PATH=/bin:/usr/bin:/sbin:/usr/sbin
DAEMON=/home/.. path to shell script scriptname created to run python script
PIDFILE=/var/run/scriptname.pid
test -x $DAEMON || exit 0
. /lib/lsb/init-functions
case "$1" in
start)
log_daemon_msg "Starting feedparser"
start_daemon -p $PIDFILE $DAEMON
log_end_msg $?
;;
stop)
log_daemon_msg "Stopping feedparser"
killproc -p $PIDFILE $DAEMON
PID=`ps x |grep feed | head -1 | awk '{print $1}'`
kill -9 $PID
log_end_msg $?
;;
force-reload|restart)
$0 stop
$0 start
;;
status)
status_of_proc -p $PIDFILE $DAEMON atd && exit 0 || exit $?
;;
*)
echo "Usage: /etc/init.d/atd {start|stop|restart|force-reload|status}"
exit 1
;;
esac
exit 0
이제 /etc/init.d/scriptname start 또는 stop 명령을 사용하여 python 스크립트를 시작하고 중지할 수 있습니다.
단순하고 지원되는 버전은 다음과 같습니다.Daemonize
.
Python 패키지 색인(PyPI)에서 설치합니다.
$ pip install daemonize
다음으로 다음과 같이 사용합니다.
...
import os, sys
from daemonize import Daemonize
...
def main()
# your code here
if __name__ == '__main__':
myname=os.path.basename(sys.argv[0])
pidfile='/tmp/%s' % myname # any name
daemon = Daemonize(app=myname,pid=pidfile, action=main)
daemon.start()
cron
분명히 여러 가지 목적에 적합한 선택입니다.그러나 OP에서 요청한 서비스나 데몬은 생성되지 않습니다. cron
작업을 정기적으로(작업이 시작 및 중지됨을 의미) 실행할 뿐이며, 1분에 1회만 실행할 수 있습니다.가 있다.cron
가 다음 에 아직 중인 -- " " " " " " " " " " " " "cron
스케줄이 바뀌어 새로운 인스턴스가 시작됩니다.괜으???? cron
는 의존관계를 처리하지 않고 스케줄이 지시했을 때 작업을 시작하려고 합니다.
데몬이는, 「」를 .supervisord
데몬화되지 않은 일반 스크립트 또는 프로그램을 래핑하여 데몬처럼 작동시키는 간단한 방법을 제공합니다.이것은 네이티브 Python 데몬을 만드는 것보다 훨씬 더 좋은 방법입니다.
'어디서'를 요?$nohup
령어를 사용 ?? ???? ???
Bluehost 서버에서 명령어를 실행할 때 사용합니다.
제가 틀렸다면 조언해 주세요.
Ubuntu에는 서비스를 관리하는 매우 간단한 방법이 있습니다.python의 경우 모든 종속성(패키지)이 메인 파일이 실행되는 동일한 디렉토리에 있어야 한다는 점이 다릅니다.
저는 고객에게 날씨 정보를 제공하는 서비스를 만들 수 있을 뿐입니다.순서:
python 어플리케이션프로젝트를 통상대로 만듭니다.
sudo pip3 install package_name -t 등의 모든 의존관계를 로컬로 설치합니다.
명령줄 변수를 생성하여 코드로 처리합니다(필요한 경우).
서비스 파일을 만듭니다.다음과 같은 것(미니멀리스트):
[Unit] Description=1Droid Weather meddleware provider [Service] Restart=always User=root WorkingDirectory=/home/ubuntu/weather ExecStart=/usr/bin/python3 /home/ubuntu/weather/main.py httpport=9570 provider=OWMap [Install] WantedBy=multi-user.target
파일을 myweather.service로 저장합니다(예:
현재 디렉터리에서 시작된 경우 앱이 실행 중인지 확인합니다.
python3 main.py httpport=9570 provider=OWMap
위에서 작성한 myweather.service라는 이름의 서비스 파일(확장자 .service를 갖는 것이 중요합니다)은 시스템에서 서비스 이름으로 취급됩니다.서비스와의 상호 작용에 사용하는 이름입니다.
서비스 파일을 복사합니다.
sudo cp myweather.service /lib/systemd/system/myweather.service
demon 레지스트리 새로 고침:
sudo systemctl daemon-reload
서비스를 중지합니다(실행 중인 경우).
sudo service myweather stop
서비스를 시작합니다.
sudo service myweather start
상태를 확인합니다(인쇄문이 있는 로그 파일).
tail -f /var/log/syslog
또는 다음을 사용하여 상태를 확인합니다.
sudo service myweather status
필요에 따라 다른 반복으로 처음부터 돌아가기
이 서비스는 현재 실행 중이며 로그아웃해도 영향을 받지 않습니다.호스트가 셧다운되고 재시작되면 이 서비스가 재시작됩니다.
터미널(ssh 등)을 사용하고 있으며 터미널에서 로그아웃한 후에도 장시간 스크립트를 계속 작동시키려면 다음과 같이 하십시오.
screen
apt-get install screen
abc, abc로 하다 screen -dmS abc
abc: abc abc abc로 연결하겠습니다.screen -r abc
스크립트를 할 수 .python 스크립트: python python python python 。python keep_sending_mails.py
이제부터는 직접 단말기를 닫을 수 있지만 python 스크립트는 종료되지 않고 계속 실행됩니다.
★★★★★★
keep_sending_mails.py
의 PID가 의 자
상태를 다시 하려면 , 「」를 할 수 .screen -r abc
하다
먼저 메일 별칭을 읽어 보십시오.메일 에일리어스는 데몬이나 서비스 같은 것을 가지고 장난칠 필요 없이 메일 시스템 내에서 이 작업을 수행합니다.
메일 메시지가 특정 우편함에 발송될 때마다 발송 메일로 실행되는 간단한 스크립트를 작성할 수 있습니다.
http://www.feep.net/sendmail/tutorial/intro/aliases.html 를 참조해 주세요.
불필요한 복잡한 서버를 작성하려면 이 작업을 수행할 수 있습니다.
nohup python myscript.py &
그것만 있으면 돼.스크립트는 단순히 루프하고 sleeve 상태가 됩니다.
import time
def do_the_work():
# one round of polling -- checking email, whatever.
while True:
time.sleep( 600 ) # 10 min.
try:
do_the_work()
except:
pass
을 사용하다.run
.
import sys
import os
from signal import SIGTERM
from abc import ABCMeta, abstractmethod
class Daemon(object):
__metaclass__ = ABCMeta
def __init__(self, pidfile):
self._pidfile = pidfile
@abstractmethod
def run(self):
pass
def _daemonize(self):
# decouple threads
pid = os.fork()
# stop first thread
if pid > 0:
sys.exit(0)
# write pid into a pidfile
with open(self._pidfile, 'w') as f:
print >> f, os.getpid()
def start(self):
# if daemon is started throw an error
if os.path.exists(self._pidfile):
raise Exception("Daemon is already started")
# create and switch to daemon thread
self._daemonize()
# run the body of the daemon
self.run()
def stop(self):
# check the pidfile existing
if os.path.exists(self._pidfile):
# read pid from the file
with open(self._pidfile, 'r') as f:
pid = int(f.read().strip())
# remove the pidfile
os.remove(self._pidfile)
# kill daemon
os.kill(pid, SIGTERM)
else:
raise Exception("Daemon is not started")
def restart(self):
self.stop()
self.start()
서비스처럼 동작하는 것을 작성하려면 , 다음의 것을 사용할 수 있습니다.
먼저 시멘트 프레임워크를 설치해야 합니다.시멘트 프레임워크는 어플리케이션을 전개할 수 있는 CLI 프레임워크입니다
앱 명령줄 인터페이스:
인터페이스입니다.화이
from cement.core.foundation import CementApp
from cement.core.controller import CementBaseController, expose
from YourApp import yourApp
class Meta:
label = 'base'
description = "your application description"
arguments = [
(['-r' , '--run'],
dict(action='store_true', help='Run your application')),
(['-v', '--version'],
dict(action='version', version="Your app version")),
]
(['-s', '--stop'],
dict(action='store_true', help="Stop your application")),
]
@expose(hide=True)
def default(self):
if self.app.pargs.run:
#Start to running the your app from there !
YourApp.yourApp()
if self.app.pargs.stop:
#Stop your application
YourApp.yourApp.stop()
class App(CementApp):
class Meta:
label = 'Uptime'
base_controller = 'base'
handlers = [MyBaseController]
with App() as app:
app.run()
YourApp.py 클래스:
import threading
class yourApp:
def __init__:
self.loger = log_exception.exception_loger()
thread = threading.Thread(target=self.start, args=())
thread.daemon = True
thread.start()
def start(self):
#Do every thing you want
pass
def stop(self):
#Do some things to stop your application
데몬이 되려면 앱이 스레드에서 실행되어야 합니다.
앱을 실행하려면 명령줄에서 이 작업을 수행하십시오.
python interface.py --도움말
Ubuntu use upstart 등 시스템에서 제공하는 모든 서비스 매니저를 사용합니다.부팅 시 시작, 크래시 시 재시작 등 모든 세부 정보를 처리합니다.
도커를 이용해 보세요.이 경우 필요한 것은 스크립트를 영원히 실행하는 것 뿐입니다.예를 들어,while True
.
- 스크립트:
#!/usr/bin/env python3 import time from datetime import datetime while True: cur_time = datetime.now().isoformat() print(f"Hey! I'm still there! The time is: {cur_time}") time.sleep(1)
- 실행할 명령어
장소:docker run \ -d -it \ --restart always \ -v "$(pwd)/script.py:/opt/script.py" \ --entrypoint=python3 \ --name my_daemon \ pycontribs/alpine:latest \ /opt/script.py
pycontribs/alpine:latest
- Python 3.8이 프리 인스톨 되어 있는 경량 Linux 디스트로의 이미지입니다.--name my_daemon
- 컨테이너의 명확한 이름입니다.--entrypoint=python3
- 컨테이너를 시작할 프로그램,python3
예시로-v "$(pwd)/script.py:/opt/script.py"
- 스크립트를 컨테이너 안에 호스트로부터/opt/script.py
.어디에$(pwd)/script.py
- 호스트 시스템의 스크립트에 대한 경로입니다.절대 경로로 바꾸는 게 좋을 것 같아요. 그러면 뭐랄까?-v "/home/user/Scripts/script.py:/opt/script.py"
/opt/script.py
- 인수인계python3
우선, 컨테이너 안에 있는 것은python3 /opt/script.py
--restart always
- 호스트 시스템 부팅 시 컨테이너 자동 부팅
- 스크립트가 백그라운드에서 실행 중인지 확인합니다.
$ docker logs my_daemon -f Hey! I'm still there! The time is: 2022-04-20T07:09:11.308271 Hey! I'm still there! The time is: 2022-04-20T07:09:12.309203 Hey! I'm still there! The time is: 2022-04-20T07:09:13.310255 Hey! I'm still there! The time is: 2022-04-20T07:09:14.311309 Hey! I'm still there! The time is: 2022-04-20T07:09:15.312361 Hey! I'm still there! The time is: 2022-04-20T07:09:16.313175 Hey! I'm still there! The time is: 2022-04-20T07:09:17.314242 Hey! I'm still there! The time is: 2022-04-20T07:09:18.315321 Hey! I'm still there! The time is: 2022-04-20T07:09:19.315465 Hey! I'm still there! The time is: 2022-04-20T07:09:20.315807 Hey! I'm still there! The time is: 2022-04-20T07:09:21.316895 Hey! I'm still there! The time is: 2022-04-20T07:09:22.317253 ^C
스크립트 내 또는 이와 같은 다른 스크립트에서 하위 프로세스로 프로세스를 실행할 수 있습니다.
subprocess.Popen(arguments, close_fds=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, stdin=subprocess.DEVNULL)
또는 기성 유틸리티를 사용합니다.
https://github.com/megashchik/d-handler
언급URL : https://stackoverflow.com/questions/1603109/how-to-make-a-python-script-run-like-a-service-or-daemon-in-linux
'source' 카테고리의 다른 글
처음 사용한 후 재할당 시 로컬 변수의 UnboundLocalError (0) | 2022.09.15 |
---|---|
Python Panda 오류 데이터 토큰화 (0) | 2022.09.15 |
컴파일된 .pyc 파일을 .py 파일로 디컴파일 할 수 있나요? (0) | 2022.09.15 |
브라우저 뒤로 버튼 이벤트 검출 방법 - 크로스 브라우저 (0) | 2022.09.13 |
numpy 배열의 일부 치수만 평탄하게 만드는 방법 (0) | 2022.09.13 |