如何在Linux中使用systemd在启动时运行脚本

时间:2020-02-23 14:40:22  来源:igfitidea点击:

在本文中,我将共享一个示例systemd单位文件,我们可以使用该文件在systemd启动时运行脚本,而无需在RHEL/CentOS 7/8 Linux中使用crontab。

当我们期望启动时调用脚本或者命令时,可能有多种情况,例如

  • 等待N分钟的启动后执行脚本

  • 加载所有systemd服务后执行脚本

  • 登录提示出现后立即执行脚本

  • 在登录提示出现之前执行脚本

在本文中,我将介绍以下两个主题,因为它们几乎相似

  • 网络可达后,在启动时使用systemd运行脚本

  • 加载所有systemd服务后,在starup上执行脚本

我将使用CentOS/RHEL 7/8 Linux节点来验证本文中的步骤,以在登录提示之前立即使用systemd运行脚本。

第1步:systemd概述

希望我们已经熟悉以下主题

  • systemd概述以及它与旧版SysV脚本的区别

  • 如何在Linux中创建systemd单位文件

创建示例脚本

现在要使用systemd在启动时运行脚本,首先我们需要一个脚本或者命令。
为了这篇文章,我创建了一个虚拟的shell脚本/tmp/startup_script.sh,我们将使用它来测试本文。

[root@centos-8 ~]# cat /tmp/startup_script.sh
#!/bin/bash
SCRIPT_NAME=$(basename -- "
[root@centos-8 ~]# chmod u+x /tmp/startup_script.sh
") z=0 for i in {1..5}; do sleep 1m ((z++)) wall $SCRIPT_NAME: finished minute ${z} done wall $SCRIPT_NAME: COMPLETELY FINISHED

该脚本将继续运行5分钟,并使用" wall"命令为每一个节点上的所有Linux用户每分钟在屏幕上打印一条echo语句作为广播消息。

并在第5分钟结束时将打印完整的广播。
这样,如果脚本继续运行5分钟,我们还可以确保该脚本不会被systemd杀死。

提供脚本的可执行权限

[root@centos-8 ~]# systemctl enable run-at-startup.service
Created symlink /etc/systemd/system/default.target.wants/run-at-startup.service → /etc/systemd/system/run-at-startup.service.

启用服务以确保重新启动后自动调用该服务

[root@centos-8 ~]# cat /etc/systemd/system/run-at-startup.service
[Unit]
Description=Run script at startup after network becomes reachable
After=network.target
[Service]
Type=simple
RemainAfterExit=yes
ExecStart=/tmp/startup_script.sh
TimeoutStartSec=0
[Install]
WantedBy=default.target

为不同情况创建系统化的单位文件

.1:网络可访问后,在启动时使用systemd运行脚本

在这种情况下,我们将在网络可访问时(即,在启动阶段network.target开始运行时使用After = network.target)开始执行脚本。
单位文件应该位于/usr/lib/systemd/system或者/etc/systemd/system中。
我将其放置在"/etc/systemd/system"下,因为它用于放置自定义单元文件。

[root@centos-8 ~]# cat /etc/systemd/system/run-at-startup.service
[Unit]
Description=Run script at startup after all systemd services are loaded
After=default.target
[Service]
Type=simple
RemainAfterExit=yes
ExecStart=/tmp/startup_script.sh
TimeoutStartSec=0
[Install]
WantedBy=default.target

.2:在加载所有systemd服务之后,使用systemd在启动时运行脚本

现在,在此senario中,我们必须确保在启动脚本之前已加载了相应目标的所有系统服务。
因此,要在加载所有systemd服务之后使用systemd在启动时运行脚本,我们必须相应地定义After =指令。
由于default.target会根据环境而变化,因此,我们将使用After = default.target而不是指定特定的目标名称,因此systemd将决定它自己的default.target并在Linux启动时调用脚本。

[root@centos-8 ~]# cat /etc/systemd/system/run-at-startup.service
[Unit]
Description=Run script at startup after all systemd services are loaded
After=getty.target
[Service]
Type=simple
RemainAfterExit=yes
ExecStart=/tmp/startup_script.sh
TimeoutStartSec=0
[Install]
WantedBy=default.target

.3:在出现登录提示后,使用systemd在启动时运行脚本

现在在这种情况下,我们也将只使用单位文件的After =指令。
现在,由于要求是在出现登录提示后使用systemd在启动时运行脚本,因此我们将使用After = getty.target

After=        If the script needs any other system facilities (networking, etc), modify the [Unit] section to include appropriate 
		   After=, Wants=, or Requires= directives, as described in: man systemd.unit
Type=              Switch Type=simple for Type=idle in the [Service] section to delay execution of the script until all other 
		   jobs are dispatched (see man systemd.service for even more choices -- e.g., Type=oneshot can be useful in concert with other services).
TimeoutStartSec=   When a service doesn't signal start-up completion within TimeoutStartSec, systemd considers the service failed;
		   for long-running shell scripts it is essential to modify TimeoutStartSec or disable the timeout logic altogether 
		   as above, with TimeoutStartSec=0. See man systemd.service for more details.

其中

[root@centos-8 ~]# systemctl daemon-reload
[root@centos-8 ~]# systemctl enable run-at-startup.service

其中如果我们观察到,我们已经定义了After = network.target以确保脚本

刷新systemd配置文件并启用服务

[root@centos-8 ~]# ps -ef | grep startup
root       805     1  0 11:38 ?        00:00:00 /bin/bash /tmp/startup_script.sh
root      1198  1147  0 11:39 pts/0    00:00:00 grep --color=auto startup

验证systemd单元文件配置

现在,我们的配置已经就绪,可以在CentOS/RHEL 7/8 Linux中启动时运行脚本。

提示:

我们还可以在脚本中使用systemctl list-jobs来监视启动时执行脚本时的活动作业列表。

现在,在重新启动Linux节点后,我们可以看到startup_script.sh在后台运行

Broadcast message from [email protected] (somewhere) (Thu Jan 16 11:39:
startup_script.sh: finished minute 1

Broadcast message from [email protected] (somewhere) (Thu Jan 16 11:40:
startup_script.sh: finished minute 2

Broadcast message from [email protected] (somewhere) (Thu Jan 16 11:41:
startup_script.sh: finished minute 3

Broadcast message from [email protected] (somewhere) (Thu Jan 16 11:42:
startup_script.sh: finished minute 4

Broadcast message from [email protected] (somewhere) (Thu Jan 16 11:43:
startup_script.sh: finished minute 5

Broadcast message from [email protected] (somewhere) (Thu Jan 16 11:43:
startup_script.sh: COMPLETELY FINISHED

同样在一段时间后,我们开始从root用户那里获取广播消息。

##代码##

我已经验证了这两种方案的脚本,以便在Linux中使用systemd(不使用crontab)启动时运行脚本,但是由于两种情况的输出相同,因此我没有将这两种方案的输出都放入。

说明:

引导后,使用systemd-analyze plot> file.svg生成引导过程的镜像以进行检查。
我们可以使用任何浏览器来查看此file.svg并验证启动过程。
在run-at-startup.service之后,可能会有一两个短暂的服务开始。
如果有问题,请修改/etc/systemd/system/run-at-startup.service以设置Type = idle。