Bob's Blog

Web开发、测试框架、自动化平台、APP开发、机器学习等

返回上页首页

Systemd管理gunicorn服务



以前做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

 

下一篇:  MAUI加Blazor做一个跨平台的记账APP(一)环境准备
上一篇:  记录桌面端应用的自动化的一些坑和解决方式

共有0条评论

添加评论

暂无评论