systemd小学习

0x00 前言

systemd就不多介绍了,用于linux中的进程管理。功能太强大了,看文档看的一脸懵逼。最近有个实际需求,有个web项目要上线,部署的时候需要用到进程管理来保障服务的存活,以及在出错时需要服务自动重启,实现一些监控的需求。所以就简单学习了一下systemd这款工具,做个记录。

0x01 最简单配置

web项目使用django开发,本地sqlite3做数据库和缓存,nginx做前置端口转发和静态资源的代理,gunicorn做web容器。需要用systemd添加一个service来启动gunicorn,简单配置如下:

/etc/systemd/system下创建web.service文件,文件名即为服务名,也就是这里的“web”。后续需要通过这个服务名来启动服务

文件内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[Unit]
Description = web service

# follow the system start
After = network.target

[Service]
WorkingDirectory=/var/www/html/wooyun/wooyun
ExecStart=bash /var/www/html/wooyun/wooyun/start_gunicorn.sh

# restart when gunicorn is down
Restart=on-failure

[Install]
# follow the system start
WantedBy=multi-user.target

简单说一下配置,After = network.targetWantedBy=mutil-user.target用于服务器重启后自动启动该服务,ExecStart为启动命令,Restart=on-failure是在gunicorn挂掉时自动重启服务。

保存文件后,还需要一条命令来让自动重启生效

1
systemctl enable web

启动服务

1
systemctl start web

查看服务状态

1
systemctl status web

注意:如果修改了服务的配置文件,也就是/etc/systemd/system下的web.service后,需要一条命令让配置生效

1
systemctl daemon-reload

查看系统日志(system logs),用于查看一些详细的错误信息

1
journalctl

0x02 问题排查

这里由于我的web项目在python的虚拟环境中,不能直接用脚本的形式启动了,需要改一下配置文件,直接用虚拟环境里的二进制程序启动,把ExecStart改为

1
ExecStart=/var/www/html/wooyun/bin/gunicorn wooyun.wsgi -b 0.0.0.0:8000 -w 3

0x03 优化

将gunicorn的参数写在一个配置文件里,这样如果配置需要改变,就不需要来改变service文件中的启动命令了,也不用systemctl daemon-reload这条命令了。以后只要更改配置文件后重启一下服务就可以,这也是大多数应用程序的做法,如nginx

在项目目录下写一个gunicorn_config.py的文件,写gunicorn的配置

1
2
3
4
5
6
7
8
9
10
11
12
13
import os

bind = "0.0.0.0:8000"

workers = os.cpu_count() * 2 - 1

cur_dir = os.path.dirname(__file__)

loglevel = 'warning'

errorlog = os.path.join(cur_dir, 'error.log')

accesslog = os.path.join(cur_dir, 'access.log')

然后在wooyun.com.service中将ExecStart改为

1
ExecStart=/var/www/html/wooyun/bin/gunicorn -c gunicorn_config.py wooyun.wsgi

0x04 ngrok

同理,配置ngrok服务,实现内网穿透

首先创建ngrok的配置文件,在~/.config/ngrok/ngrok.yml下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
version: "2"
authtoken: 换成你自己的
log_level: info
log_format: json
log: /var/log/ngrok.log
web_addr: 0.0.0.0:4040
tunnels:
ssh:
proto: tcp
addr: 22
web_wooyun:
proto: http
addr: 80
basic_auth:
- "username:password"

翻官网文档看到ngrok本身支持用service,那就不用我们自己写service文件了,直接上命令

首先安装服务:

1
ngrok service install --config /root/.config/ngrok/ngrok.yml

再然后启动服务就完事了,满心欢喜

1
ngrok service start

诶,怎么报错了。。。服务启动失败。。也看不到报错信息

journalctl看看系统日志,再最下面翻到了报错信息,看到这么一句话

Your account is not authorized to run the agent as a service. Upgrade to a new Pro or Enterprise plan at:……

意思就是把ngrok作为service来运行这是付费功能,要充钱。。。

得,那我自己手动创建服务试试

创建服务文件ngrokd.service

1
2
3
4
5
6
7
8
9
10
11
12
#/etc/systemd/system/ngrokd.service

[Unit]
Description=ngrok
After=network.target

[Service]
ExecStart=ngrok start --all
Restart=always

[Install]
WantedBy=multi-user.target

接下来就是启动服务:

1
systemctl start ngrokd

依旧报错,行吧,你赢了,那我就只能以 后台进程 的方式启动了

众所周知,linux中在命令的后面加一个&代表命令在后台运行,并且在命令前面加上nohup可以不受挂断信号(hang up)的影响,也就是说session退出后命令依旧在服务器上跑着。于是构成以下命令

1
nohup ngrok start --all &

但有个问题,这样就看不到ngrok的输出的地址了,其实我们刚刚在配置文件中开启了web interface访问管理界面也就是4040端口,就可以看到线上地址了

参考

https://www.bilibili.com/video/BV1e4411z73Z


systemd小学习
https://wanf3ng.github.io/2022/05/30/systemd小学习/
作者
wanf3ng
发布于
2022年5月30日
许可协议