blog/20201121161159_d4edd487437ce0a1d3aa6e92f01ef349.png

前言 链接到标题

本文主要包含内容如下:

  • Systemd 是什么?
  • Systemd 常用命令。
  • Systemd 系统资源 Unit (单位)。
  • Systemd 系统资源管理 - 动手配置,实现开机自启动 Node.js 服务。

一,Systemd 概述 链接到标题

1.1. 基本介绍 链接到标题

Systemd (System Daemon),根据 Linux 命名惯例,字母 d 是守护进程 daemon 的缩写。如 Systemd 名字的含义一样,它作为 PID 1 进程,守护整个系统。Systemd 是一系列工具的集合,其作用也远远不仅是启动操作系统,它还接管了后台服务、结束、状态查询,以及日志归档、设备管理、电源管理、定时任务等许多职责。

systemdLennart Poettering 带头开发,并在 LGPL 2.1 及其后续版本许可证下开源发布。systemd 已纳入众多 Linux 发行版的软件源中。

1.2. 特点介绍 链接到标题

缺点是体系庞大,非常复杂。Systemd 的优点是功能强大,使用方便。其优点介绍如下:

  • 更少的进程 Systemd 提供了服务按需启动的能力。

  • 允许更多的进程并行启动 在 SysV-init 时代,将每个服务项目编号依次执行启动脚本。而 Systemd 通过 Socket 缓存、DBus 缓存和建立临时挂载点等方法进一步解决了启动进程之间的依赖,做到了所有系统服务并发启动。

  • 使用 CGroup 跟踪和管理进程的生命周期 Systemd 提供通过 CGroup 跟踪进程关系。CGroup 不仅能够实现服务之间访问隔离,限制特定应用程序对系统资源的访问配额,还能更精确地管理服务的生命周期。

  • 统一管理服务日志 Systemd 提供了一个专用的系统日志管理服务:Journald。其使用二进制格式保存所有的日志信息,因而日志内容很难被手工伪造。

1.3. 架构图 链接到标题

下图 是 Systemd 的架构图(来自网络) blog/20201121233602_a705b252a0dbb255d9c589dfd4da545d.png

二,Systemd 常用命令 链接到标题

Systemd 并不是一个命令,而是一组命令,涉及到系统管理的方方面面,是一系列工具的集合。

2.1. systemctl 链接到标题

systemctlSystemd 的主要命令,用于系统与服务管理。点击查看命令描述文档

  • 命令语法
$ systemctl [OPTIONS...] COMMAND [UNIT...]
  • 常用命令 下述命令以 Unit nginx.service 为列,后续会详细介绍 Unit。
# 重启系统
$ systemctl reboot

# 启用一个或多个单元或单元实例
$ systemctl enable nginx.service

# 禁用一个或多个单位
$ systemctl disable nginx.service

# 重新启用一个或多个单位
$ systemctl reenable nginx.service

# 重新载入 unit 配置
$ systemctl daemon-reload

# 启动 unit 资源  
$ systemctl start nginx.service

# 重启一个服务
$ systemctl restart nginx.service

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

# 停止 unit 资源
$ systemctl stop nginx.service

# 查看 unit 资源 状态
$ systemctl status nginx.service

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

# 命令行输出 unit 配置
$ systemctl cat nginx.service

# 显示 systemd Manager 环境块
$ systemctl show-environment

# 列出 systemd 当前在内存中的 unit
$ systemctl list-units

# 查看 Unit 存在依赖关系
$ systemctl list-dependencies nginx.service

# 显示某个 Unit 的所有底层参数
$ systemctl show nginx.service

2.2. systemd-analyze 链接到标题

systemd-analyze 分析和调试系统管理。点击查看命令描述文档

  • 命令语法
$ systemd-analyze [OPTIONS...] [time]

$ systemd-analyze [OPTIONS...] blame

$ systemd-analyze [OPTIONS...] critical-chain [UNIT...]
  • 常用命令
# 查看启动耗时
$ systemd-analyze time

# 查看每个服务的启动耗时
$ systemd-analyze blame

# 显示瀑布状的启动过程流
$ systemd-analyze critical-chain

# 显示指定服务的启动流
$ systemd-analyze critical-chain atd.service

2.3. hostnamectl 链接到标题

hostnamectl 可用于查询和更改系统主机名和相关设置。点击查看命令描述文档

  • 命令语法
$ hostnamectl [OPTIONS...] {COMMAND}
  • 常用命令
# 查看主机的信息
$ hostnamectl status

# 设置主机名
$ hostnamectl set-hostname york

2.4. journalctl 链接到标题

journalctl 查询系统日志。点击查看命令描述文档

  • 命令语法
$ journalctl [OPTIONS...] [MATCHES...]
  • 常用命令
# 查看所有日志
$ journalctl

# 查看指定 unit 日志
$ journalctl _SYSTEMD_UNIT=httpd.service

# 查看内核日志(不显示应用日志)
$ journalctl -k

# 查看系统本次启动的日志
$ journalctl -b
$ journalctl -b -0

# 查看上一次启动的日志(需更改设置)
$ journalctl -b -1

# 显示尾部的最新10行日志
$ journalctl -n

# 显示尾部指定行数的日志
$ journalctl -n 20

# 实时滚动显示最新日志
$ journalctl -f

# 查看指定服务的日志
$ journalctl /usr/lib/systemd/systemd

# 查看指定进程的日志
$ journalctl _PID=1

# 查看某个路径的脚本的日志
$ journalctl /usr/bin/bash

# 查看指定用户的日志
$ journalctl _UID=33 --since today

2.5. loginctl 链接到标题

loginctl 系统登陆管理器。点击查看命令描述文档

  • 命令语法
$ loginctl [OPTIONS...] {COMMAND} [NAME...]
  • 常用命令
# 列出当前登录用户
$ loginctl list-users

# 列出显示指定用户的信息
$ loginctl show-user root

# 查看 sission 详情
$ loginctl show-session  130423 559 59

2.6. timedatectl 链接到标题

timedatectl 系统时间和日期查看与管理。点击查看命令描述文档

  • 命令语法
$ timedatectl [OPTIONS...] {COMMAND}
  • 常用命令
# 查看当前时区设置
$ timedatectl

# 显示所有可用的时区
$ timedatectl list-timezones                                      

# 设置当前时区
$ timedatectl set-timezone America/New_York

三,Systemd 资源 链接到标题

Systemd 可以管理所有系统资源。不同的资源统称为 Unit(单位)。

点击查看 systemd.unit 描述文档 点击查看 systemd.service 描述文档

3.1. Unit 种类 链接到标题

Unit 文件是 ini 风格的纯文本文件。统一了过去各种不同系统资源配置格式,例如服务的启/停、定时任务、设备自动挂载、网络配置、虚拟内存配置等。而 Systemd 通过不同的文件后缀(如 .service)来区分这些配置文件。支持的 11 种 Unit 文件类型:

# 服务,封装守护进程的启动、停止、重启和重载操作,是最常见的一种 Unit 文件
service.service

# 套接字,监控来自于系统或网络的数据消息,用于实现基于数据自动触发服务启动
socket.socket

# 设备,对于 /dev 目录下的设备,主要用于定义设备之间的依赖关系
device.device

# 挂载点,定义系统结构层次中的一个挂载点,可以替代过去的 /etc/fstab 配置文件
mount.mount

# 自动挂载点,用于控制自动挂载文件系统,相当于 SysV-init 的 autofs 服务
automount.automount

# 交换分区或交换文件,定义一个用户做虚拟内存的交换分区
swap.swap

# 启动目标,用于对 Unit 文件进行逻辑分组,引导其它 Unit 的执行。它替代了 SysV-init 运行级别的作用,并提供更灵活的基于特定设备事件的启动方式
target.target

# 被监视的路径,用于监控指定目录或文件的变化,并触发其它 Unit 运行
path.path

# 任务计划,用于配置在特定时间触发的任务,替代了 Crontab 的功能
timer.timer

# 资源控制组,用于表示一个 CGroup 的树,通常用户不会自己创建这样的 Unit 文件 
slice.slice

# 一组外部创建的进程,这种 Unit 文件不是用户创建的,而是 Systemd 运行时产生的,描述一些系统服务的分组信息
scope.scope

3.2. Unit 文件结构 链接到标题

下面这个 foo.service Unit。

# [Unit]区块包含与单元类型无关的通用信息
[Unit]
Description=Foo

# [Service]区块包含服务启动信息
[Service]
ExecStart=/usr/sbin/foo-daemon

# [Install]区块包含单元的启用信息
[Install]
WantedBy=multi-user.target
  • 从上面的输出可以看到,配置文件分成几个区块。每个区块的第一行,是用方括号表示的区别名,比如:[Unit]
  • 区块内容 每个区块内部是一些等号连接的键值对。
    [Service]
    ExecStart=/usr/sbin/foo-daemon
    ExecStop=xxx
    
  • 配置文件注释使用 # 开头
  • 注意事项 配置文件的区块名和字段名,都是大小写敏感的 键值对的等号两侧不能有空格。

3.3. [Unit] 区块 链接到标题

Unit 文件中的 [Unit] 区块包含与 Unit 类型无关的通用信息。可用的如下配置指令如下:

Description:有利于人类阅读的、对单元进行简单描述的字符串。

Documentation:一组用空格分隔的文档URI列表, 这些文档是对此单元的详细说明。

Requires:设置此单元所必须依赖的其他单元。

Wants:此选项是 Requires= 的弱化版。

BindsTo:与 Requires= 类似,但是依赖性更强

Before, After:强制指定单元之间的先后顺序,接受一个空格分隔的单元列表。

Conflicts:指定单元之间的冲突关系。表明该单元不能与列表中的任何单元共存

3.4. [Service] 区块 链接到标题

[Service] 区块用来 Service 的配置,只有 Service 类型的 Unit 才有这个区块。包含服务启动信息。可用的如下配置指令如下:

Type:设置进程的启动类型。取值为 simple, exec, forking, oneshot, dbus, notify, idle 之一。

RemainAfterExit:当该服务的所有进程全部退出之后, 是否依然将此服务视为活动(active)状态。 默认值为 no

PIDFile:该服务PID文件的路径(一般位于 /run/ 目录下)。 强烈建议在 Type=forking 的情况下明确设置此选项。

BusName:设置与此服务通信 所使用的 D-Bus 名称。

ExecStart:在启动该服务时需要执行的 命令行(命令+参数),命令行必须以一个可执行文件(要么是绝对路径、要么是不含任何斜线的文件名)开始, 并且其后的那些参数将依次作为"argv[1] argv[2] …"传递给被执行的进程。

ExecReload:这是一个可选的指令, 用于设置当该服务 被要求重新载入配置时 所执行的命令行。 

ExecStop:这是一个可选的指令, 用于设置当该服务被要求停止时所执行的命令行。 

Restart:当服务进程 正常退出、异常退出、被杀死、超时的时候, 是否重新启动该服务。所谓"服务进程" 是指 ExecStartPre=, ExecStartPost=, ExecStop=, ExecStopPost=, ExecReload= 中设置的进程。

Environment:指定环境变量

User:指定运行服务的用户

Group:指定运行服务的用户组

WorkingDirectory:指定服务的工作目录

3.5. [Install] 区块 链接到标题

[Install] 区块包含单元的启用信息。 当执行命令 systemctl enable 与 disable 操作 Unit 时才会使用此小节。

Alias:启用时使用的别名,可以设为一个空格分隔的别名列表。

WantedBy:它的值是一个或多个 Target,当前 Unit 激活时(enable)符号链接会放入/etc/systemd/system目录下面以 Target 名 + .wants后缀构成的子目录中

RequiredBy:它的值是一个或多个 Target,当前 Unit 激活时,符号链接会放入/etc/systemd/system目录下面以 Target 名 + .required后缀构成的子目录中

Also:设置此单元的附属单元,表示当使用 systemctl enable 启用 或 systemctl disable 停用 此单元时, 也同时自动的启用或停用附属单元。

3.6. Unit 文件加载 链接到标题

Systemd 将会从一组在编译时设定好的 Unit 目录 中加载单元文件,目录拥有不同的优先级。高优先级目录中的文件, 将会覆盖低优先级目录中的同名文件。

  • 当 systemd 以系统实例(–system)运行时,加载单元的先后顺序(较前的目录优先级较高)
系统单元目录描述
/run/systemd/transient动态配置的临时单元(系统与全局用户共用)
/etc/systemd/system本地配置的系统单元
/run/systemd/system运行时配置的系统单元
/usr/lib/systemd/system本地软件包安装的系统单元
/usr/lib/systemd/system发行版软件包安装的系统单元
  • 当 systemd 以用户实例(–user)运行时,加载单元的先后顺序(较前的目录优先级较高)
系统单元目录描述
/etc/systemd/user本地配置的全局用户单元
/run/systemd/user运行时配置的全局用户单元
/usr/lib/systemd/user本地软件包安装的全局用户单元
/usr/lib/systemd/user发行版软件包安装的全局用户单元

3.7. 设置开机启动 链接到标题

可使用 systemctl enable 命令激活 Unit 开机启动。

Systemd 默认从目录 /etc/systemd/system/ 读取配置文件。但是,里面存放的大部分文件都是符号链接,指向目录 /usr/lib/systemd/system/,真正的配置文件存放在这个目录。

systemctl enable 命令用于在上面两个目录之间,建立符号链接关系。

# 激活开机启动
$ systemctl enable koa.service

# 等同于
$ ln -s '/usr/lib/systemd/system/koa.service' '/etc/systemd/system/multi-user.target.wants/koa.service'

四,Systemd 资源管理 链接到标题

该节使用 Systemd 管理 Node.js 应用,实现应用的开机自启动。

4.1. Node.js 应用 链接到标题

新建文件 /data/app/node.js/node-systemd-demo/app.js,其内容如下。

const http = require('http');

http.createServer((request, response) => {
    response.write('Systemd 从入门到实战');
    response.end();
}).listen(8091);

4.2. 配置 Unit 链接到标题

配置 Systemd 的 Unit 文件,用于管理 Node.js 应用。新建文件 /usr/lib/systemd/system/node-demo.service,其内容如下:

#!/bin/bash
# 服务说明
[Unit]
# 服务描述
Description=node-systemd-demo
# 前置需要启动的服务
After=sysinit.target

# 服务启动行为
[Service]
# 服务类型
Type=simple
ExecStart=/usr/local/services/nodejs/bin/node /data/app/node.js/node-systemd-demo/app.js 
# 设置预加载变量
Environment="PATH=/usr/local/services/nodejs/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/.ft:/root/bin"
# 执行用户
User=root
# 执行用户组
Group=root
WorkingDirectory=/data/app/node.js/node-systemd-demo

# 服务开机启动安装目标
[Install]
# 表示该服务所在的 Target
WantedBy=multi-user.targe

4.3. 启动应用 链接到标题

使用 Systemd 启动运行 node-demo.service,执行下命令:

# 设置可执行权限
$ chmod +x /usr/lib/systemd/system/node-demo.service

# 重新载入 Unit 配置
$ systemctl daemon-reload

# 启动 Unit 服务
$ systemctl start node-demo.service

# 查看 Unit 服务状态
$ systemctl status node-demo.service

# 请求 node-systemd-demo 服务
$ curl -v http://127.0.0.1:8091

blog/20201122153009_a36ee43dd7aeefc8076aa79a0a182a12.png

blog/20201122153133_9d90332a78ac2abb8a0b6f82763239ff.png

4.4. 设置开机启动 链接到标题

使用 Systemd 配置 node-demo.service 服务开机启动,执行下命令:

# 激活开机启动
$ systemctl enable node-demo.service

# 或者 ln 激活开机启动
ln -s /usr/lib/systemd/system/node-demo.service /etc/systemd/system/multi-user.target.wants/

# 重启 linux  
$ reboot

激活开机启动后,会在 /etc/systemd/system/multi-user.target.wants/ 目录中添加 node-demo.service 软链接。 blog/20201122154404_8d8fd04ca2203ed78344cf0f2a5c96f2.png

执行 reboot 后,执行命令 systemctl status node-demo.service 查看服务状态。 blog/20201122154551_6963d54009d7a5d941869d84de77b663.png

参考 链接到标题