Linux systemd 系统服务管理

本文详细介绍了Systemd系统管理和Linux服务脚本的使用,包括其在Linux中的地位、与传统init的区别、服务脚本的结构与编写、启动顺序、依赖关系以及如何通过systemctl进行服务控制。涵盖了开机自启动、服务类型、环境变量配置等内容。
摘要由CSDN通过智能技术生成

Systemd 是一个系统和服务管理器,也是 Linux 操作系统中最常用的初始化系统之一。它的设计目标是提供更快、更有效、更可靠的系统启动过程,并提供强大的管理和监控服务的能力。本文首先介绍 systemd 服务脚本的基本情况,并通过一个简单的示例带领读者学习如何编写 systemd 服务脚本,实现 Linux 服务的自启动、启动、停止和重启管理。

Systemd 是什么

Systemd 是 Linux 系统中一个重要的系统和服务管理器,最早是为了代替传统的 SysV 初始化系统(init)而开发的,相较于传统 init,systemd 具有许多优势。例如支持并行启动,可同时启动多个服务,提高系统启动速度;引入了单一进程(PID 1)和 cgroups 技术,可以更好地管理系统和服务进程。目前,许多主流 Linux 发行版都采用了 systemd 作为其默认的初始化系统,包括 Ubuntu、Debian、Fedora、CentOS、Arch Linux 等。

总的来说,使用 systemd 可以更加简单灵活地管理各种系统服务,它提供了统一的命令行工具和配置文件格式,使得对系统和服务的管理更加一致和简化。用户可以通过 systemctl 命令来控制 systemd 系统和管理服务。

service 脚本

Linux 的 service 脚本一般存放在 /etc/systemd/ 和 /usr/lib/systemd 路径下,前者包含着多个 *.target.wants 文件,如 multi-user.target.wants 等;而后者为安装软件生成 service 的目录,一般编写自己的 service 可以放在此目录下。但需要注意的是,位于 /usr/lib/systemd/ 中服务脚本可能会在下次更新时被覆盖。

无论是 /etc/systemd/ 还是 /usr/lib/systemd 目录,其中又包含 system 和 user 目录。前者是系统服务,开机不需要用户登录即可运行的服务;后者是用户服务,需要用户登录后才能运行的服务。

  • /etc/systemd/system/
  • /etc/systemd/user/
  • /usr/lib/systemd/system/
  • /usr/lib/system/user/

服务脚本文件以 .service 结尾,由 Unit、Service 和 Install 三个区块组成,以下是一个 service 脚本样例:

[Unit]   
Description=test        # 简单描述服务
After=network.target    # 描述服务类别,表示本服务需要在network服务启动后在启动
Before=xxx.service      # 表示需要在某些服务启动之前启动,After和Before字段只涉及启动顺序,不涉及依赖关系

[Service] 
Type=forking            # 设置服务的启动方式
User=USER               # 设置服务运行的用户
Group=USER              # 设置服务运行的用户组
WorkingDirectory=/PATH  # 设置服务运行的路径(cwd)
KillMode=control-group  # 定义systemd如何停止服务
Restart=no              # 定义服务进程退出后,systemd的重启方式,默认是不重启
ExecStart=/start.sh     # 服务启动命令,命令需要绝对路径(采用sh脚本启动其他进程时Type须为forking)

[Install]   
WantedBy=multi-user.target  # 多用户

参数说明

service 脚本的参数分为三个区块,各区块作用如下:

区块描述
[Unit] 区块启动顺序与依赖关系
[Service] 区块启动行为定义
[Install] 区块服务安装定义

Unit 区块

服务描述

  • Description:给出当前服务的简单描述。
  • Documentation:给出文档位置。

启动顺序

  • After:定义 xxx.service 应该在哪些 target 或 service 服务之后启动,例如网络服务 network.target。
  • Before:定义 xxx.service 应该在哪些 target 或 service 服务之前启动。

依赖关系

  • Wants:表示 xxx.service 与定义的服务存在“弱依赖”关系,即指定的服务启动失败或停止运行不影响 xxx 的运行。
  • Requires:则表示“强依赖”关系,即指定服务启动失败或异常退出,那么 xxx 也必须退出;反之 xxx 启动则指定服务也会启动。

Service 区块

启动命令

  • EnvironmentFile:指定当前服务的环境参数文件(路径),如 EnviromentFile=-/etc/sysconfig/xxx,连词号表示抑制错误,即发生错误时,不影响其他命令的执行。
  • Environment:后面接多个不同的 shell 变量,如 Environment=DATA_DIR=/dir/data
  • User:设置服务运行的用户。
  • Group:设置服务运行的用户组。
  • WorkingDirectory:设置服务运行的路径。
  • Exec*:各种与执行相关的命令。
  • ExecStart:定义启动服务时执行的命令。
  • ExecStop:定义停止服务时执行的命令。
  • ExecStartPre:定义启动服务前执行的命令。
  • ExecStartPost:定义启动服务后执行的命令。
  • ExecStopPost:定义停止服务后执行的命令。
  • ExecReload:定义重启服务时执行的命令。

启动类型

  • Type:字段定义启动类型,可以设置的值如下:
  • simple(默认值):ExecStart 字段启动的进程为主进程,即直接启动服务进程。
  • forking:ExecStart 字段将以 fork() 方式启动,此时父进程将会退出,子进程将成为主进程(例如用 shell 脚本启动服务进程)。
  • oneshot:类似于 simple,但只执行一次,systemd 会等它执行完,才启动其他服务。
  • dbus:类似于 simple,但会等待 D-Bus 信号后启动。
  • notify:类似于 simple,启动结束后会发出通知信号,然后 systemd 再启动其他服务。
  • idle:类似于 simple,但是要等到其他任务都执行完,才会启动该服务。一种使用场合是为让该服务的输出,不与其他服务的输出相混合。
  • RemainAfterExit:设为 yes,表示进程退出以后,服务仍然保持执行。

重启行为

  • KillMode:定义 systemd 如何停止服务,可以设置的值如下:
  • control-group(default):当前控制组里面的所有子进程,都会被杀掉。
  • process:只杀主进程。
  • mixed:主进程将收到 SIGTERM 信号,子进程收到 SIGKILL 信号。
  • none:没有进程会被杀掉,只是执行服务的 stop 命令。
  • Restart:定义了服务退出后,Systemd 的重启方式,可以设置的值如下(对于守护进程,推荐设为 on-failure,对于那些允许发生错误退出的服务,可以设为 on-abnormal):
  • no(default):退出后不会重启。
  • on-success:只有正常退出时(退出状态码为0),才会重启。
  • on-failure:非正常退出时(退出状态码非0),包括被信号终止和超时,才会重启。
  • on-abnormal:只有被信号终止和超时,才会重启。
  • on-abort:只有在收到没有捕捉到的信号终止时,才会重启。
  • on-watchdog:超时退出,才会重启。
  • always:不管是什么退出原因,总是重启。
  • RestartSec:表示 systemd 重启服务之前,需要等待的秒数。

Install 区块

WantedBy:表示该服务所在的 Target。

Target 的含义是服务组,如 WantedBy=multi-user.target 指的是该服务所属于 multi-user.target。当执行 systemctl enable xxx.service 命令时,xxx.service 的符号链接就会被创建在 /etc/systemd/system/multi-user.target 目录下。

可以通过 systemctl get-default 命令查看系统默认启动的 target,一般为 multi-user 或者是 graphical。因此配置好相应的 WantedBy 字段,可以实现服务的开机启动。

简单示例

示例代码:systemd-example

准备工作

下面通过一个简单的示例演示如何编写 systemd 服务脚本。为了更加简单,我们编写一个 example.sh 脚本作为服务程序,该脚本的功能是往 /tmp 目录写一个带时间信息的文件,用于验证服务是否被执行。

example.sh 脚本内容如下:

#!/bin/bash
echo "The script works. `date`" > /tmp/diditwork.txt

接着,给 example.sh 脚本添加可执行权限,并拷贝到 /usr/sbin/ 系统目录。

$ chmod +x example.sh
$ sudo cp example.sh /usr/sbin/

尝试执行 example.sh,通过 cat /tmp/diditwork.txt 命令查看是否写入成功。

The script works. 2023年 08月 20日 星期日 15:08:23 CST

编写服务脚本

在 /etc/systemd/system 目录中创建一个 example.service 服务单元文件,内容如下:

[Unit]
Description=example systemd service unit file.

[Service]
ExecStart=/bin/bash /usr/sbin/example.sh

[Install]
WantedBy=multi-user.target

这样,一个最简单的 systemd 服务脚本就写好了!这里的关键是在 ExecStart 参数中填入 example.sh 脚本的路径。

使脚本生效

完成服务脚本编写后,需要执行以下命令重新加载所有的 systemd 服务,否则会找不到 example.service 服务。

sudo systemctl daemon-reload

接着就可以通过 systemctl 命令来控制服务启停,控制命令语法如下:

# 管理服务 [使能自启动|启动|停止|重启|查看状态]
sudo systemctl [enable|start|stop|restart|status] xxx.service

现在,执行下面命令启动 example.service 服务。

sudo systemctl start example.service

通过 tmp/diditwork.txt 文件检查 example.service 服务是否成功启动。

$ cat /tmp/diditwork.txt
The script works. 2023年 08月 20日 星期日 15:45:37 CST

如果你想要在每次重启系统后都自动启动 example.service 服务,则需要执行下面命令:

sudo systemctl enable example.service

设置开机自动执行

假设需要在系统开机时自动运行一个基于 Qt 图形界面的应用程序,那么可以在 /etc/systemd/system 目录添加一个 autorun.service 文件,内容如下:

[Unit]
Description=Test Qt Application
After=multi-user.target local-fs.target weston.service

[Service]
User=root
Restart=no
Type=simple
EnvironmentFile=/opt/root_env
ExecStart=/opt/autorun.sh
StandardOutput=console

[Install]
WantedBy=multi-user.target weston.service

/opt/root_env 包含一系列环境变量(包括 Qt 的一些配置),该文件可由 env 命令生成。

env > /opt/root_env

执行脚本 /opt/autorun.sh 的内容如下,其中 /opt/mainwindow 是一个 Qt 自带的 example 程序。

#!/bin/sh

# Run a simple Qt application
/opt/mainwindow

准备好上述几个文件后,即可执行下面命令将其加入 systemd 系统管理。

systemctl enable autorun.service

重启系统,mainwindow 程序就会自动运行。

设置关机自动执行

既然可以设置开机自动执行,那能不能设置关机自动执行呢?例如在关机之前记录当前的时间,以便下次启动时能获知上次关机时间。

为了达到这个目的,可以在 /etc/systemd/system 目录添加一个 before-shutdown.service 文件,内容如下:

[Unit]
Description=Do something before shutdown
After=getty@tty1.service display-manager.service plymouth-start.service
Before=systemd-poweroff.service systemd-reboot.service systemd-halt.service
DefaultDependencies=no

[Service]
ExecStart=/opt/shutdown.sh
Type=forking

[Install]
WantedBy=poweroff.target
WantedBy=reboot.target
WantedBy=halt.target

执行脚本 /opt/shutdown.sh 的内容如下,其实就是将 date 命令获取的时间写入一个文件里面。

#!/bin/bash

# record shutdown time
echo `date +"%Y-%m-%d %H:%M:%S"` > /home/root/shutdown_time

将 before-shutdown 服务加入 systemd 系统管理。

systemctl enable before-shutdown.service

这样,当系统关机(包括 poweroff、reboot 或 halt)的时候,就会先执行 /opt/shutdown.sh 脚本,记录系统时间。

更多

想要获得 systemd 服务的完整文档说明,可访问 systemd service documentation

  • 11
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

踏马潜行

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值