Linux 系统 Systemd 服务简介及编写

👌 2020-02-17 Linux 系统 systemd 服务简介及编写

FileInfo Filename - Linux 编写系统 systemd 服务.md Version - v1.1.2002(2020/02/18 ~ 2020/02/19) Author - standuke Email - shadowdoker@gmail.com DescriptionKey - Linux Systemd Configure Set

本文约定

在文中将有以下提示符对重点进行标注说明,请注意文中提示。

⚠️ - 文中出现此标记,代表重要提示,指需要格外注意的地方 🔘 - 文中出现此标记,代表可选配置,建议配置,但不必要 ✅ - 文中出现此标记,代表检查项目,需要检查对应的配置文件 ❗️ - 文中出现此标记,代表该操作不可随意修改,如更改此步操作,请预先测试

[TOC]

systemd 概述

Red Hat Enterprise Linux 7(RHEL7)已经将服务管理工具从 SysVinit 和 Upstart(ubuntu) 迁移到了 systemd 上。 之前版本的所有启动脚本都是放在 /etc/rc.d/init.d/ 目录下。这些脚本都是 bash 脚本,可以让系统管理员控制这些服务的状态。通常,这些脚本中包含了 start \ stop \ restart 这些方法,以提供系统自动调用这些方法。但是在 RHEL7 中已经完全摒弃了这种方法,而采用了一种叫 systemd 的 unit 的配置文件来管理服务。 unit 文件可用来描述:系统服务(.service)、挂载点(.mount)、sockets(.sockets)、系统设备(.device)、交换分区(.swap)、文件路径(.path)、启动目标(.target)、由 systemd 管理的计时器(.timer)

systemd 命令集

  • systemctl 是 Systemd 的主命令,用于管理系统。
  • systemd-analyze 用于查看启动耗时。
  • hostnamectl 用于查看当前主机的信息。
  • localectl 用于查看本地化设置。
  • timedatectl 用于查看当前时区设置。
  • loginctl 用于查看当前登录的用户。

RHEL7 服务启动相关文件

init

在 RHEL7 种与启动相关的 SysVinit(init) 文件以及文件夹如下所示,大部分使用的文件都是软链接

ll /etc/
lrwxrwxrwx.  1 root root     11 1月  16 08:59 init.d -> rc.d/init.d
// inittab 已弃用
-rw-r--r--.  1 root root    511 8月   9 2019 inittab
lrwxrwxrwx.  1 root root     10 1月  16 08:59 rc0.d -> rc.d/rc0.d
lrwxrwxrwx.  1 root root     10 1月  16 08:59 rc1.d -> rc.d/rc1.d
lrwxrwxrwx.  1 root root     10 1月  16 08:59 rc2.d -> rc.d/rc2.d
lrwxrwxrwx.  1 root root     10 1月  16 08:59 rc3.d -> rc.d/rc3.d
lrwxrwxrwx.  1 root root     10 1月  16 08:59 rc4.d -> rc.d/rc4.d
lrwxrwxrwx.  1 root root     10 1月  16 08:59 rc5.d -> rc.d/rc5.d
lrwxrwxrwx.  1 root root     10 1月  16 08:59 rc6.d -> rc.d/rc6.d
drwxr-xr-x. 10 root root    127 1月  16 08:59 rc.d
lrwxrwxrwx.  1 root root     13 1月  16 08:59 rc.local -> rc.d/rc.local

ll /etc/rc.d/
drwxr-xr-x. 2 root root  70 1月  16 08:59 init.d
drwxr-xr-x. 2 root root  45 1月  16 08:59 rc0.d
drwxr-xr-x. 2 root root  45 1月  16 08:59 rc1.d
drwxr-xr-x. 2 root root  45 1月  16 08:59 rc2.d
drwxr-xr-x. 2 root root  45 1月  16 08:59 rc3.d
drwxr-xr-x. 2 root root  45 1月  16 08:59 rc4.d
drwxr-xr-x. 2 root root  45 1月  16 08:59 rc5.d
drwxr-xr-x. 2 root root  45 1月  16 08:59 rc6.d
-rw-r--r--. 1 root root 473 8月   8 2019 rc.local

systemd

在 RHEL7 种与启动相关的 systemd 文件以及文件夹如下所示

/etc/systemd/system/*
# 供系统管理员和用户使用 ⚠️ 自定义服务需要放置在该目录
/run/systemd/system/*
# 运行时配置文件
/usr/lib/systemd/system/*
# 安装程序时默认的 unit 文件存放位置(如 RPM 包安装)

编写一个 服务

  1. 编写 unit 文件 demo.service
[Unit]
Description=My-demo Service

[Service]
Type=oneshot
ExecStart=/bin/bash /root/test.sh
StandardOutput=syslog
StandardError=inherit

[Install]
WantedBy=multi-user.target
  1. 将上述的文件拷贝到 RHEL7 系统中 /usr/lib/systemd/system/* 目录下
cp demo.service /usr/lib/systemd/system/demo.service
  1. 编写 unit 文件中 ExecStart=/bin/bash /root/test.sh 所定义的 test.sh 文件,将其放在定义的目录当中,此文件是服务的执行主体。
#!/bin/bash
date >> /tmp/date
  1. 将 demo.service 设置为开机自启
systemctl enable demo.service

关键词详解

[Unit]:记录unit文件的通用信息 [Service]:记录Service的信息 [Install]:安装信息

Unit

●  Description:对本service的描述。 ●  Before, After:定义启动顺序,Before=xxx.service,代表本服务在xxx.service启动之前启动。After=xxx.service,代表本服务在xxx之后启动。 ●  Requires: 这个单元启动了,那么它"需要"的单元也会被启动; 它"需要"的单元被停止了,它自己也活不了。但是请注意,这个设定并不能控制某单元与它"需要"的单元的启动顺序(启动顺序是另外控制的),即 Systemd 不是先启动 Requires 再启动本单元,而是在本单元被激活时,并行启动两者。于是会产生争分夺秒的问题,如果 Requires 先启动成功,那么皆大欢喜; 如果 Requires 启动得慢,那本单元就会失败(Systemd 没有自动重试)。所以为了系统的健壮性,不建议使用这个标记,而建议使用 Wants 标记。可以使用多个 Requires。 ●  RequiresOverridable:跟 Requires 很像。但是如果这条服务是由用户手动启动的,那么 RequiresOverridable 后面的服务即使启动不成功也不报错。跟 Requires 比增加了一定容错性,但是你要确定你的服务是有等待功能的。另外,如果不由用户手动启动而是随系统开机启动,那么依然会有 Requires 面临的问题。 ●  Requisite:强势版本的 Requires。要是这里需要的服务启动不成功,那本单元文件不管能不能检测等不能等待都立刻就会失败。 ●  Wants:推荐使用。本单元启动了,它"想要"的单元也会被启动。但是启动不成功,对本单元没有影响。 ●  Conflicts:一个单元的启动会停止与它"冲突"的单元,反之亦然。

Service

●  Type:service的种类,包含下列几种类型:            —-simple 默认,这是最简单的服务类型。意思就是说启动的程序就是主体程序,这个程序要是退出那么一切都退出。            —–forking 标准 Unix Daemon 使用的启动方式。启动程序后会调用 fork() 函数,把必要的通信频道都设置好之后父进程退出,留下守护精灵的子进程            —–oneshot种服务类型就是启动,完成,没进程了。 notify,idle类型比较少见,不介绍。 ●  ExecStart:服务启动时执行的命令,通常此命令就是服务的主体。            ——如果你服务的类型不是 oneshot,那么它只可以接受一个命令,参数不限。            ——多个命令用分号隔开,多行用 \ 跨行。 ●  ExecStartPre, ExecStartPost:ExecStart执行前后所调用的命令。 ●  ExecStop:定义停止服务时所执行的命令,定义服务退出前所做的处理。如果没有指定,使用systemctl stop xxx命令时,服务将立即被终结而不做处理。 ●  Restart:定义服务何种情况下重启(启动失败,启动超时,进程被终结)。可选选项:no, on-success, on-failure,on-watchdog, on-abort ●  SuccessExitStatus:参考ExecStart中返回值,定义何种情况算是启动成功。     eg:SuccessExitStatus=1 2 8 SIGKILL    

Install

●  WantedBy:何种情况下,服务被启用。     eg:WantedBy=multi-user.target(多用户环境下启用) ●  Alias:别名

自启脚本接入

init 方式接入

⚠️ 默认 rc.local 弃用,但是仍然可以通过赋予执行权限 chmod +x /etc/rc.d/rc.local 来启用 rc.local 文件,此种方法即为 init 方式设置开机启动。

linux 启动时,先加载内核,然后加载 inittab 文件,inittab 文件中有个条目 si::sysinit:/etc/rc.d/rc.sysinit 指定了下一个要加载的文件 rc.sysinit,这个文件加载完之后,加载 /etc/rc.d/rc.RUNLEVEL.d 目录中的启动脚本,最后加载 /etc/rc.d/rc.local 文件。

inittabrc.sysinit 文件就不说了,在 rc.RUNLEVEL.d 文件夹里,所存的都是软链接,链接到 /etc/rc.d/init.d 中的脚本文件,而 /etc/rc.d/init.d 文件夹和 /etc/init.d 文件夹是一样的,/etc/init.d 其实是软链接到 /etc/rc.d/init.d 文件夹中。

若脚本需要开机启动,则方法如下

  • 把脚本注册为系统服务,把它放到 /etc/init.d 目录下,并且在脚本中,加一行 # chkconfig: 345 85 35,然后就可以用 chkconfig 命令让其开机启动。因为在 /etc/init.d 目录下,所以也可以用 service 命令控制该脚本。
  • 建议/etc/rc.d/rc.local 文件中,直接把该脚本的路径写进去,在开机加载 rc.local 文件时,自然会启动这个脚本。这个脚本就不能用 chkconfigservice 命令控制。

systemd 方式接入

  1. 创建服务 unit 描述文件
  2. 设置开启自启
systemctl enable ***.service
  1. 重启检验
systemctl status ***.service

老版本兼容性

RHEL7 默认已经不再使用 SysVinit 和 Upstart,但是仍然可以兼容 SysVinit 和 Upstart

老版本 新版本 描述
service name start systemctl start name.service   Starts a service
service name stop  systemctl stop name.service Stops a service
service name restart systemctl restartname.service Restarts a service
service name reload systemctl reloadname.service Reloads configuration
service name status systemctl status name.service Checks if a service status
chkconfig name on  systemctl enablename.service Enables a service
chkconfig name off  systemctl disablename.service Disables a service
  1. 默认的 RunLevel(在 /etc/inittab 文件设置)现在被默认的 Target 取代,位置是 /etc/systemd/system/default.target,通常符号链接到 graphical.target(图形界面)或者 multi-user.target(多用户命令行)。
  2. 启动脚本的位置,以前是 /etc/init.d 目录,符号链接到不同的 RunLevel 目录 (比如 /etc/rc3.d、/etc/rc5.d 等),现在则存放在 /lib/systemd/system 和 /etc/systemd/system 目录。
  3. 配置文件的位置,以前init进程的配置文件是 /etc/inittab,各种服务的配置文件存放在 /etc/sysconfig 目录。现在的配置文件主要存放在 /lib/systemd 目录,在 /etc/systemd 目录里面的修改可以覆盖原始设置。

相关参考

systemd - Arch Linux https://wiki.archlinux.org/index.php/Systemd_(简体中文)#systemd_基本工具 阮一峰的网络日志 http://www.ruanyifeng.com/blog/2016/03/systemd-tutorial-commands.html IBM 浅析 Linux 初始化 init 系统,第 3 部分 https://www.ibm.com/developerworks/cn/linux/1407_liuming_init3/index.html 编写systemd下服务脚本 https://blog.csdn.net/fu_wayne/article/details/38018825