神奇的服务管理工具 Systemd
作者: dkvirus 发表于: 2018-06-25 15:41:00 最近更新: 2018-08-02 00:04:39

最初是因为我在 Xshell 上启动一个 Node 程序,每当我将 Xshell 关闭时,Node 服务也就自动停止了。在网上查了一番,有人说用 nohup 可以解决,又有人说 nohup 不稳定,把 Node 程序做成系统服务是最优解,于是就接触了 Systemd,才发现这真是一片新大陆,功能强大无比。本文为学习笔记。

一、猜想

为什么 Xshell 一关闭,Node 程序就死了?我想先探讨下这个问题。

在实验楼文档里有这么一种说法:Xshell 打开一个终端,提供 Shell 程序用于操作 Linux。Shell 本身是个程序,此时在 Linux 上启动一个进程,称为父进程。在 Shell 上通过命令 $ node app.js 再运行 Node 程序,是在 Shell 进程下又启动了一个子进程运行 Node 程序,这样关闭 Shell,父进程关闭,子进程自然也就关闭了。(也不知是不是这么回事~)

如果想要 Node 程序不随 Shell 的退出而中止,那就把 Node 程序变成系统服务,而不是 Shell 进程的子进程。Systemd 就可以做这件事儿。

二、概述

centos7.0+、ubuntu16.0+ 以后的发行版才添加的 Systemd,在此之前的老的发行版貌似没有这个系统工具。

2.1 为什么让 Systemd 管理服务

记得接触 Linux 的第一个发行版是 centos6.4,当时通过 yum 安装完 Nginx,每次启动都要找到 Nignx 的启动目录,一般在 /usr/bin/nignx 下面;如果改了 Nginx 的配置文件想要重启,还要再去那个目录下整一遍;想要关闭 Ningx,还要先去查找 Ningx 启动进程,再通过 $ kill -9 pid 干掉 Nignx,很是麻烦;

后来用了 centos7.2 发行版,启动 Nginx 只需要键入 $ systemctl start nginx。Systemd 提供一系列简单的命令来管理你的服务,列举如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 立即启动一个服务
$ systemctl start nginx

# 立即停止一个服务
$ systemctl stop nginx

# 重启一个服务
$ systemctl restart ngixn

# 杀死一个服务的所有子进程
$ systemctl kill nginx

# 重新加载一个服务的配置文件
$ systemctl reload nginx

Systemd 默认只管理系统服务,通过 yum 安装的第三方软件是如何被 Systemd 管理的呢?

2.2 服务配置文件

Systemd 管理服务,每个服务都有一个配置文件,查看服务配置文件:$ ll /usr/lib/systemd/system,可以看到很多 service 后缀的文件。

像 Nginx 这类第三方软件在安装时都会自动把自个的 nginx.service 服务配置文件整到 /usr/lib/systemd/system 目录下,这样才能使用 Systemd 工具来管理它。

我们自己写的程序,如 Node 程序,要想让 Systemd 管理,也要写这么个服务配置文件。

2.3 自定义 Node 服务

2.3.1 编写 node 程序

/home/dkvirus 目录下写一个 Node 程序 app.js 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const http = require('http');

const hostname = '127.0.0.1';
const port = 3000;

const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World\n');
});

server.listen(port, hostname, () => {
console.log(`服务器运行在 http://${hostname}:${port}/`);
});

正常情况下启动需要 $ node /home/dkvirus/app.js(前提是已安装 Node),但这种方式当终端关闭 node 程序也就自动停止了。

2.3.2 编写服务配置文件

/usr/lib/systemd/system 目录下创建文件 nodetest.service 文件并编辑:

1
2
3
4
5
[Unit]
Description="node-test"

[Service]
ExecStart=/root/.nvm/versions/node/v8.0.0/bin/node /home/dkvirus/app.js

在配置文件中,分为两部分,被 [] 包裹的为每部分标题。

  • [Unit] 定义元数据。Description 字段为该服务的描述性信息;
  • [Service] 定义服务具体做的事。ExecStart 字段值表示当运行 $ systemctl start nodetest 时执行的语句,这里 /root/.nvm/versions/node/v8.0.0/bin/node /home/dkvirus/app.js 其实就是 node /home/dkvirus/app.js,前面那一串 /root/.nvm/versions/node/v8.0.0/bin/node 是我系统中 node 的安装路径,在服务配置文件中必须写全路径。如果你不知道全路径,$ which node 可以查看 node 的安装路径;

想要了解更多服务配置文件字段含义,传送门 《阮一峰 - Systemd 入门教程:命令篇》

2.4 测试是否成功

每当新增或修改服务配置文件,需要先键入 $ systemctl daemon-reload 让修改生效;

编写完服务配置文件之后,启动命令 $ systemctl start nodetest.service,可以简写为 $ systemctl start nodetest

查看是否启动成功,$ ss -lnt 查看当前系统打开的端口,可以看到 3000 端口被打开了;

关闭终端,再重新打开终端,$ ss -lnt 可以看到 node 程序的 3000 端口仍然存在,这就解决了最开始提出的问题,将 Node 程序变成了系统服务。

2.5 查看服务运行状态

1
2
3
4
5
6
7
8
9
10
11
12
$ systemctl status nodetest
1 ● nodetest.service - "node-test"
2 Loaded: loaded (/usr/lib/systemd/system/nodetest.service; enabled; vendor preset: disabled)
3 Active: active (running) since Sun 2018-04-29 10:28:53 CST; 1 day 1h ago
4 Main PID: 12839 (node)
5 CGroup: /system.slice/nodetest.service
6 └─12839 /root/.nvm/versions/node/v8.0.0/bin/node /home/dkvirus/app.js

Apr 29 10:28:53 hd1h2g systemd[1]: Started "node-test".
Apr 29 10:28:53 hd1h2g systemd[1]: Starting "node-test"...
Apr 29 10:28:54 hd1h2g node[12839]: server is starting on port: 3000.
Apr 29 10:28:54 hd1h2g node[12839]: 连接数据库成功test
  • 第一行打印 Node 程序服务名称以及描述信息;
  • 第二行打印 Node 程序服务配置文件路径,可以看到确实是在 /usr/lib/systemd/system/ 目录下;
  • 第三行打印运行状态 active(running),什么时候开始运行的;
  • 第四行打印服务的主进程号;
  • 第五行打印服务所有子进程;
  • 第六行打印服务的日志;

2.6 查看服务日志

Systemd 不仅管理服务,还管理服务对应的日志。常用命令列举如下:

1
2
3
4
5
# 实时滚动显示最新日志
$ sudo journalctl -f

# 查看某个服务的日志
$ sudo journalctl -u nginx.service

想要查看 Nginx 服务的日志并实时滚动

# 可别写成了 journalctl -u -f nginx,-u 参数后面紧跟服务名称,可省略 .service 后缀
$ journalctl -f -u nginx

2.7 Systemd 其它功能

Systemd 不仅仅可以将自定义程序写成系统服务,还可以写定时任务,设置开机启动等强大功能。

首页
友链
归档
dkvirus
动态
RSS