Systemd、交互式脚本和计时器

Systemd、交互式脚本和计时器

介绍

在针对 Linux 进行开发时,会出现创建在系统打开或关闭时执行的交互式脚本的任务。 在 System V 中这很容易,但在 systemd 中则需要进行调整。 但它可以有自己的计时器。

为什么我们需要目标?

人们常说目标相当于系统 V -init 中的运行级别。 我从根本上不同意。 它们有更多,您可以将包分组,例如,使用一个命令启动一组服务并执行其他操作。 而且,它们没有层次结构,只有依赖关系。

启用时运行交互式脚本的目标示例(功能概述)

目标本身的描述:

cat installer.target
[Unit]
Description=My installer
Requires=multi-user.target 
Conflicts=rescue.service rescue.target
After=multi-user.target rescue.service rescue.target 
AllowIsolate=yes
Wants=installer.service

该目标将在 multi-user.target 启动并调用 installer.service 时启动。 然而,可能有多个这样的服务。

cat installer.service
[Unit]
# описание
Description=installer interactive dialog

[Service]
# Запустить один раз, когда остальное будет запущенно
Type=idle
# Команда запуска - вызов скрипта
ExecStart=/usr/bin/installer.sh
# Интерактивное взаимодействие с пользователем через tty3
StandardInput=tty
TTYPath=/dev/tty3
TTYReset=yes
TTYVHangup=yes

[Install]
WantedBy=installer.target

最后是正在执行的脚本的示例:

#!/bin/bash
# Переходим в tty3
chvt 3
echo "Install, y/n ?"
read user_answer

最重要的是选择final.target - 系统启动时应到达的目标。 在启动过程中,systemd 将遍历依赖项并启动它所需的一切。
有不同的方法来选择 Final.target,我为此使用了 loader 选项。

最终的启动看起来像这样:

  1. 引导加载程序启动
  2. 引导加载程序通过传递 Final.target 参数开始启动固件
  3. Systemd 开始启动系统。 按顺序从 basic.target 通过其依赖项(例如,multi-user.target)转到 installer.target 或 work.target。 后者使系统以所需的模式工作

准备启动固件

创建固件时,总是会出现在启动时恢复系统状态并在关闭时保存系统状态的任务。 状态意味着配置文件、数据库转储、接口设置等。

Systemd 在同一目标中并行运行进程。 有些依赖项允许您确定脚本的启动顺序。

它在我的项目中如何工作( https://habr.com/ru/post/477008/ https://github.com/skif-web/monitor)

  1. 系统启动
  2. settings_restore.service服务启动,它检查数据部分中是否存在settings.txt文件。 如果不存在,则将参考文件放在其位置。接下来,恢复系统设置:
    • 管理员密码
    • 主机名,
    • 时区
    • 语言环境
    • 确定是否所有媒体都在使用。 默认情况下,图像尺寸较小 - 以便于复制和记录到媒体。 启动时,它会检查是否仍有未使用的空间。 如果有,则对磁盘重新分区。
    • 从 MAC 地址生成机器 ID。 这对于通过 DHCP 获取相同的地址很重要
    • 网络设置
    • 限制日志的大小
    • 外部驱动器正在准备工作(如果启用了相应的选项并且驱动器是新的)
  3. 启动 postgresq
  4. 恢复服务启动。 需要准备zabbix本身及其数据库:
    • 检查是否已经有zabbix数据库。 如果没有,它是从初始化转储创建的(包含在 zabbix 中)
    • 创建时区列表(需要在 Web 界面中显示它们)
    • 找到当前IP,显示在issue中(邀请登录控制台)
  5. 邀请发生变化 - 出现“准备工作”短语
  6. 固件可供使用

服务文件很重要,它们决定了启动顺序

[Unit]
Description=restore system settings
Before=network.service prepare.service postgresql.service systemd-networkd.service systemd-resolved.service

[Service]
Type=oneshot
ExecStart=/usr/bin/settings_restore.sh

[Install]
WantedBy=multi-user.target

正如您所看到的,我安装了依赖项,以便我的脚本首先起作用,然后网络才会启动并且 DBMS 才会启动。

以及第二个服务(zabbix准备)

#!/bin/sh
[Unit]
Description=monitor prepare system
After=postgresql.service settings_restore.service
Before=zabbix-server.service zabbix-agent.service

[Service]
Type=oneshot
ExecStart=/usr/bin/prepare.sh

[Install]
WantedBy=multi-user.target

这里有点复杂。启动也是在 multi-user.target 中,但是在启动 postgresql DBMS 和我的setting_restore 之后。 但在启动 zabbix 服务之前。

logrotate 的定时器服务

Systemd 可以替代 CRON。 严重地。 而且,精度不是精确到分钟,而是精确到秒(如果需要的话怎么办)。或者您可以创建一个单调的计时器,由事件的超时调用。
这是一个单调的计时器,从我创建的机器启动开始计算时间。
这将需要 2 个文件
logrotateTimer.service - 服务的实际描述:

[Unit]
Description=run logrotate

[Service]
ExecStart=logrotate /etc/logrotate.conf
TimeoutSec=300

很简单 - 启动命令的描述。
第二个文件 logrotateTimer.timer 是计时器工作的地方:

[Unit]
Description=Run logrotate

[Timer]
OnBootSec=15min
OnUnitActiveSec=15min

[Install]
WantedBy=timers.target

这里有什么:

  • 定时器描述
  • 首次启动时间,从系统启动开始
  • 进一步推出的时期
  • 对定时器服务的依赖,其实就是这个字符串让定时器

关机时的交互式脚本和您的关机目标

在另一个开发中,我必须通过我自己的目标执行更复杂的关闭机器版本,以便执行许多操作。 通常建议使用 RemainAfterExit 选项创建一次性服务,但这会阻止您创建交互式脚本。

但事实是 ExecOnStop 选项启动的命令是在 TTY 之外执行的! 检查很容易 - 粘贴 tty 命令并保存其输出。

因此,我通过我的目标实现了关闭。 我不敢保证 100% 正确,但它确实有效!
它是如何完成的(一般而言):
我创建了一个目标 my_shutdown.target,它不依赖于任何人:
my_shutdown.target

[Unit]
Description=my shutdown
AllowIsolate=yes
Wants=my_shutdown.service 

当转到这个目标时(通过 systemctlisolate my_shutdwn.target),它启动了 my_shutdown.service 服务,其任务很简单 - 执行 my_shutdown.sh 脚本:

[Unit]
Description=MY shutdown

[Service]
Type=oneshot
ExecStart=/usr/bin/my_shutdown.sh
StandardInput=tty
TTYPath=/dev/tty3
TTYReset=yes
TTYVHangup=yes

WantedBy=my_shutdown.target

  • 在此脚本中,我执行必要的操作。 为了灵活性和方便性,您可以向目标添加许多脚本:

my_shutdown.sh

#!/bin/bash --login
if [ -f /tmp/reboot ];then
    command="systemctl reboot"
elif [ -f /tmp/shutdown ]; then
    command="systemctl poweroff"
fi
#Вот здесь нужные команды
#Например, cp /home/user/data.txt /storage/user/
    $command

笔记。 使用 /tmp/reboot 和 /tmp/shutdown 文件。 您不能使用参数调用目标。 只有服务是可能的。

但我使用目标是为了在工作中具有灵活性和有保证的行动顺序。

然而,最有趣的事情来了。 机器需要关闭/重新启动。 并且有 2 个选项:

  • 将reboot、shutdown 和其他命令(它们仍然是systemctl 的符号链接)替换为您的脚本。在脚本内,转到my_shutdown.target。 然后目标内部的脚本直接调用systemctl,例如systemctl restart
  • 一个更简单的选择,但我不喜欢它。 所有接口中,不要调用shutdown/reboot/other,而是直接调用目标systemctlisolate my_shutdown.target

我选择了第一个选项。 在 systemd 中,重新启动(如关机)是 systemd 的符号链接。

ls -l /sbin/poweroff 
lrwxrwxrwx 1 root root 14 сен 30 18:23 /sbin/poweroff -> /bin/systemctl

因此,您可以用自己的脚本替换它们:
重新启动

#!/bin/sh
    touch /tmp/reboot
    sudo systemctl isolate my_shutdown.target
fi

来源: habr.com

添加评论