Systemd管理gunicorn服务
2024年4月11日 - 由Bo 0 评论 289 阅读
以前做python的web server用了uwsgi还不错,后来换了gunicorn也相当巴适。
在新的linux服务器上,为了方便启动和管理web服务进程,于是用了systemd。
在systemd中每个系统服务被称为一个服务单元unit,服务单元又可以区分为service、socket、target、path、snapshot、timer等多种不同类型,最常见的是以.service结尾的文件来定义服务单元的信息,并由systemctl来做各种操作。
像以前古老时候,维持服务的方式有手动(进入虚拟环境,启动gunicorn),或者用shell文件来启动,乃至在crontab里定时检查,或者在initd中配置。但systemd比这些方便得多。
首先进入目录/usr/lib/systemd/system/,创建一个文件,取名类似于gunicorn.service,编辑如下内容:
[Unit]
Description=Python Web Server
Wants=network-online.target
[Service]
Type=forking
PIDFile=/path/gunicorn.pid # gunicorn的pid
User=root
WorkingDirectory=/web_service_folder_path # 工作目录路径
ExecStart=/path/venv/bin/gunicorn -c configuration/guni-cfg.py API.wsgi:application # 用虚拟环境启动命令,指定配置文件,指定django等项目的wsgi
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID
KillMode=mixed
TimeoutStopSec=5
RestartSec=3s
Restart=always
[Install]
WantedBy=multi-user.target
其实ExecStart也可以直接用gunicorn的命令,不用指定配置文件,只是配置项较多时,命令行难免过长,所以指定文件,而配置文件内容可以是:
from multiprocessing import cpu_count
import os
current_dir = os.path.dirname(os.path.abspath(__file__))
gun_log_dir = os.path.join(current_dir, "gunicorn_log")
os.makedirs(gun_log_dir, exist_ok=True, mode=0o775)
bind = ["127.0.0.1:8001"]
daemon = True
workers = cpu_count()
threads = 2
worker_class = "gevent"
worker_connections = 65535
keepalive = 60
timeout = 30
graceful_timeout = 10
capture_output = True
loglevel = "debug"
pidfile = os.path.join(gun_log_dir, 'gunicorn.pid')
accesslog = os.path.join(gun_log_dir, 'access.log')
errorlog = os.path.join(gun_log_dir, 'error.log')
接着运行systemctl命令,启动,并随开机运行,指定.service文件的时候可以不用给全名
systemctl start gunicorn
systemctl enable gunicorn
之后便可开机即有服务,异常退出了也能自动重启服务。
补充:
除了能方便启动、停止、自动启动、开机启动等,还可以设置定时器,类似crontab或者apscheduler。
比如现在有一个简单的备份数据的db-backup.service
[Unit]
Description=db backup periodically
[Service]
Type=simple
ExecStart=/usr/bin/python3 /home/backup/auto_backup.py > /home/backup/backup.log
如果运行systemctl start db-backup, 则会看到生成了一份db备份文件,如同py文件里的逻辑。
这里没有设置自动启动,因为没必要,数据备份往往只在特定时间点运行一次就可以,不用长时间保持存在。
于是这里可以加一个同名的timer文件:db-backup.timer
[Unit]
Description=Runs db backup timer
[Timer]
OnCalendar=Sun *-*-* 02:00:00
Unit=db-backup.service
Persistent=true
[Install]
WantedBy=multi-user.target
这个timer的意思是在每周天的凌晨2点运行备份的service。
install代表随开机启动。persistent代表即使timer没有运行,到时间也会运行对应的service。
unit是指定定时运行的service,默认是同名的service。
定时则有多个选择,比如:
- OnActiveSec:定时器生效后,多少时间开始执行任务
- OnBootSec:系统启动后,多少时间开始执行任务
- OnStartupSec:Systemd 进程启动后,多少时间开始执行任务
- OnUnitActiveSec:该单元上次执行后,等多少时间再次执行
- OnCalendar:基于绝对时间,而不是相对时间执行,比如hourly
这里用的OnCalendar,可以设置周期比如Sun *-*-* 02:00:00就代表每个星期天的凌晨2点,跟crontab类似。
也可以赋值为1h代表每隔一个小时执行12m代表12分钟,比如OnActiveSec=1h OnUnitActiveSec=12m
然后运行systemctl start db-backup.timer启动定时器,也可以systemctl enable db-backup.timer随开机。
设置完成后,运行systemctl list-timers就能看到对应的timer运行时间和下一次运行时间,只要不是na那就正常了。
另外还有个方式,就是只用service,但是指定restart的时间间隔,比如:
[Unit]
Description=db backup periodically
[Service]
Type=simple
ExecStart=/usr/bin/python3 /home/backup/auto_backup.py > /home/backup/backup.log
Restart=always
RestartSec=18000s