Systemd编写服务管理脚本
# systemd 编写服务管理脚本
# Unit(单元)的配置文件
Unit 是 systemd 进行任务管理的基本单位。我们在前文中已经介绍过,service 类型的 unit 代表一个后台服务进程。接下来我们详细介绍如何配置 service 类型的 unit。下面是一个简单的服务配置:
[Unit]
Description=Prometheus Server
Documentation=https://prometheus.io/docs/introduction/overview/
After=network.target
[Service]
User=prometheus
Restart=on-failure
WorkingDirectory=/usr/local/share/prometheus/
ExecStart=/usr/local/share/prometheus/prometheus \
-config.file=/usr/local/share/prometheus/prometheus.yml
[Install]
WantedBy=multi-user.target
2
3
4
5
6
7
8
9
10
11
12
13
14
这是 Prometheus 服务的配置文件。将上述内容保存到文件 /lib/systemd/system/prometheus.service 中,然后就可以使用 systemctl 命令管理 Prometheus 服务了。注意,服务类型的配置文件名称必须以 .service 结尾。
查看上面配置信息的详细内容,我们会发现整个配置分为三个部分:
- [Unit]:
unit本身的说明,以及与其它有依赖关系的服务的设置,包括在什么服务之后才启动此unit。 - [Service]: 不同的
unit类型需要使用相对应的设置项目,服务类型的unit就是 [Service],这个项目主要规范服务启动的脚本、环境配置文件名、重新启动的方式等等。 - [Install]: 这个部分主要设置该
unit安装到哪个 target。
# 服务类型 unit 的详细配置
配置文件分为三个部分,每个部分都可以提供详细的配置信息。为了精确控制服务的运行方式,我们需要了解这些详细的配置选项,并让服务以期望的方式运行。
# [Unit] 部分
- Description: 关于该
unit的简易说明。 - Documentation: 文档相关内容,如
Documentation=https://prometheus.io/docs/introduction/overview/。 - After: 说明本
unit是在哪个服务启动后才启动,仅说明服务启动顺序,并没有强制要求。 - Before: 与 After 相反,指定的服务启动前最好启动本服务。
- Requires: 本
unit需要在某个服务启动后才能启动,设置服务间的依赖性。 - Wants: 与 Requires 相反,规范的是本
unit之后还要启动哪些服务,如果设置的服务未启动成功,不会影响本unit。 - Conflicts: 这个项目后面接的服务如果已启动,则本
unit无法启动,反之亦然。
# [Service] 部分
Type: 说明服务的启动方式,会影响到
ExecStart,主要有以下几种类型:simple: 默认值,由ExecStart设置的程序来启动,启动后常驻于内存中。forking: 由ExecStart指定的启动程序通过spawns产生子进程提供服务,然后父进程退出。oneshot: 与simple类似,但程序工作完毕后即结束,不会常驻内存。dbus: 与simple类似,但需在取得一个 D-Bus 名称后,才继续运行。idle: 与simple类似,意思是要执行此服务必须在所有工作顺利执行完毕后才执行。notify: 与simple类似,但需收到一个sd_notify()函数发送的消息后,才会继续运行。
ExecStart: 实际执行此服务的程序,接受 "命令 参数 参数..." 的格式,不能接受特殊字符,许多 bash 语法也不支持。
ExecStartPre 和 ExecStartPost: 分别在服务启动前后,执行额外的命令。
ExecStop: 用来实现
systemctl stop命令,关闭服务。ExecReload: 用来实现
systemctl reload命令,重新加载服务的配置信息。Restart: 定义服务在何种情况下自动重启,常用值包括:
no(默认值,不重启),on-failure(仅在服务失败时重启),always(总是重启),on-abnormal(在异常退出时重启)等。RestartSec: 与
Restart配合使用,设置服务终止多长时间后重新启动,默认是 100ms。KillMode: 定义systemd如何停止服务,可以是
process,control-group,mixed,none之一。TimeoutSec: 设置服务启动或关闭时的超时时间。
RemainAfterExit: 当设置为
yes时,服务所属的所有程序都终止后,服务仍被视为活动状态。适用于Type=oneshot的服务。User 和 Group: 指定服务以哪个用户和组的身份运行。
WorkingDirectory: 指定服务的工作目录。
Environment: 用来设置环境变量,可以多次使用。
EnvironmentFile: 通过文件方式设置环境变量,指定文件路径,内容格式类似
KEY=VALUE。
# [Install] 部分
- WantedBy: 设置
unit附挂在哪个targetunit下面。 - Also: 当前
unit被 enable 时,Also 后面接的unit也要 enable。 - Alias: 当
systemctl enable相关服务时,此服务会进行链接文件的创建。
# Timer 类型 unit 的详细配置
Timer 类型的 unit 主要用来执行定时任务,有可能取代 cron 服务。与服务类型的 unit 不同,timer unit 配置文件中的主要部分是 [Timer]。
- OnActiveSec: 当
timers.target启动后多久执行此unit。 - OnBootSec: 当开机后多久执行此
unit。 - OnStartupSec: 当
systemd第一次启动后多久执行此unit。 - OnUnitActiveSec: 管理的服务最后一次启动后,隔多久再执行一次。
- OnUnitInactiveSec: 管理的服务最后一次停止后,隔多久再执行一次。
- OnCalendar: 使用实际时间(非循环时间)的方式来启动服务,支持复杂的日期时间表达式。
例如:
OnCalendar=*-*-* 02:00:00表示每天凌晨2点执行 或者:OnCalendar=Mon,Tue *-*-* 00:00:00表示每周一、二的零点执行 - Unit: 一般不需要设置,若服务名称和
timer名称不相同,则在.timer文件中通过Unit项指定服务名称。 - Persistent: 当使用
OnCalendar设置时,如果设为yes,则表示如果因为系统关机错过了执行时间,则在下次启动时会立即执行一次。
# 配置 Redis 服务
在 Ubuntu 上,我们一般会手动编译并安装 Redis。在安装完成后需要将 Redis 配置为 systemd 管理的服务,具体配置过程如下:
# 添加 Redis 配置文件
首先手动创建 /etc/redis 目录并添加配置文件:
$ sudo mkdir /etc/redis
然后将 Redis 配置文件 redis.conf 拷贝到 /etc/redis 目录中:
$ sudo cp /tmp/redis-4.0.0/redis.conf /etc/redis/
修改配置文件 /etc/redis/redis.conf 中的 supervised 为 systemd:
supervised systemd
继续修改配置文件 /etc/redis/redis.conf 中的工作目录:
dir /var/lib/redis
# 配置由 systemd 管理的 Redis 服务
创建 /etc/systemd/system/redis.service 文件:
$ sudo vim /etc/systemd/system/redis.service
编辑其内容如下:
[Unit]
Description=Redis In-Memory Data Store
After=network.target
[Service]
User=redis
Group=redis
ExecStart=/usr/local/bin/redis-server /etc/redis/redis.conf
ExecStop=/usr/local/bin/redis-cli shutdown
Restart=always
[Install]
WantedBy=multi-user.target
2
3
4
5
6
7
8
9
10
11
12
13
启动服务并配置为开机启动:
$ sudo systemctl start redis
$ sudo systemctl enable redis
$ sudo systemctl status redis
2
3
# 通过脚本定时备份文件
备份文件的 bash 脚本:
#!/bin/bash
mydate()
{
date "+%Y%m%d%H%M%S"
}
backupdate=$(mydate)
tar -zcf /tmp/backup.${backupdate}.tar.gz /home/nick/learn
2
3
4
5
6
7
将上述代码保存到 /usr/local/bin/backupdir.sh 文件,并添加可执行权限:
$ sudo chmod +x /usr/local/bin/backupdir.sh
然后创建 service unit 配置文件:
[Unit]
Description=nick backup learn dir service
[Service]
User=nick
Group=nick
Type=simple
ExecStart=/usr/local/bin/backupdir.sh
[Install]
WantedBy=multi-user.target
2
3
4
5
6
7
8
9
10
11
将上述 unit 配置保存到 /etc/systemd/system/nickbak.service 文件中。然后执行以下命令测试服务执行情况:
$ sudo systemctl daemon-reload
$ sudo systemctl start nickbak.service
2
这样的备份任务只会在执行 sudo systemctl start nickbak.service 时执行一次。下面我们通过 timer unit 将其配置为定时执行。
# 创建 Timer unit 配置文件
[Unit]
Description=nick backup learn dir timer
[Timer]
OnCalendar=*:0/15
Persistent=true
Unit=nickbak.service
[Install]
WantedBy=multi-user.target
2
3
4
5
6
7
8
9
10
将上述 unit 配置保存到 /etc/systemd/system/nickbak.timer 文件中。配置中的 OnCalendar=*:0/15 表示每 15 分钟执行一次 nickbak.service 服务。
执行以下命令将 nickbak.timer 设置为开机启动,并启动 nickbak.timer:
$ sudo systemctl daemon-reload
$ sudo systemctl enable nickbak.timer
$ sudo systemctl start nickbak.timer
2
3
查看 nickbak.timer 的状态:
$ sudo systemctl status nickbak.timer
从现在开始 nickbak.timer 会每隔 15 分钟执行一次 nickbak.service 服务。