我们在linux系统中往往需要将自己的程序或脚本开机自启动,linux也提供了多种方法,这里简单介绍下3种常用的方法,详细说明下linux下的service。
方法一:修改rc.local,自动启动脚本
Linux操作系统在启动时,会调用init进程,获取runlevel信息,执行对于runlevel下的脚本,启动各个服务;接着会执行/etc/rc.d/rc.local文件。
所以,如果我们有任何想要开机启动时需要进行的工作,都可以把它写入rc.local文件。
注意:并不是所linux系统都有此文件,自ubuntu16.10后,此文件就不存在了。
方法二:将用户脚本添加到/etc/init.d中
这里先简单介绍下流程:
- 编写一个自定义的脚本,添加执行权限:例如chmod +x test
- 将文件放入/etc/init.d目录中,然后将脚本链接到开机运行序列中。
这里我们可以自己结案率软链接,链接到不同runlevel的执行目录下:
例如runlevel3启动时,希望启动test.sh,则:ln –s /etc/init.d/test /etc/rc3.d/S95test
另外,我们也可以通过update-rc.d来辅助:
update-rc.d test defaults 95
需要注意的是我们脚本可能需要在开头添加一些固定的文本:可以参看如何写一个init.d的启动脚本。
删除时,使用:update-rc.d –f test remove
这样,在rc*.d下就会出现S95test软链接了。
关于rc*.d下软链接的命名:
此类链接文件一般以K或S开头,其中K表示停止(Kill)一个服务,会向脚本传递stop参数;S表示启动(Start)一个服务,会向脚本传递start参数;所以他们可以指向同一个脚本文件,只是传递不同的参数,以产生不同执行结果。
S\K后面会跟数字,表示脚本的执行顺序,数字越小执行顺序越靠前。
Ps:我在某些系统上测试时,发现“update-rc.d test defaults 95”设置启动顺序95可能会失败,启动顺序变成了1,即:S01test,这是需要注意的。
方法三:编写一个service文件
自ubuntu16后,已不再使用initd管理系统,很多启动脚本以service的方式存在,所以service还是需要好好了解一番的。
一般service都存放于/lib/system/system目录下,以xxx.service命名,且内部采用统一的格式:
[Unit]
Description=xxxxxxxxxxxxxxxx #描述服务
After=network.target #用于指定服务启动的前置条件
Documentation= #帮助文件的地址,可缺省
[Service]
#Type= 启动时进程行为,比如设为:simple
#EnvironmentFile= 指定环境变量,不指定可以设为no
#User= 启动用户
#Group= 启动用户组
ExecStart= /usr/bin/test #服务启动命令,此项必填
ExecStop= /usr/bin/test #服务终止命令,可缺省
#Restart= 指定重启条件,比如设为:on-failure
#RestartSec= 自动重启当前服务的间隔秒数,比如设为:1s
[Install] #用来定义如何启动,以及是否开机启动。
WantedBy=multi-user.target #当服务开机启动后,会放入什么文件夹,影响启动顺序
以上是一个简单的服务文件,大致可以看出分为3各部分,下面对每个部分做进一步的解释:
【Unit】区块:
Description:简短描述
Documentation:文档地址,比如:http:\\www.xxx.com
Requires:当前 Unit 依赖的其他 Unit,如果它们没有运行,当前 Unit 会启动失败
Wants:与当前 Unit 配合的其他 Unit,如果它们没有运行,当前 Unit 不会启动失败
BindsTo:与Requires类似,它指定的 Unit 如果退出,会导致当前 Unit 停止运行
Before:如果该字段指定的 Unit 也要启动,那么必须在当前 Unit 之后启动
After:如果该字段指定的 Unit 也要启动,那么必须在当前 Unit 之前启动
Conflicts:这里指定的 Unit 不能与当前 Unit 同时运行
单位文件可能还包含许多Condition…=和 Assert…=设置。在启动设备之前,systemd将验证指定条件是否正确。如果不是,则将跳过该单元的启动(几乎无提示):
Condition...:当前 Unit 运行必须满足的条件,否则不会运行
Assert...:当前 Unit 运行必须满足的条件,否则会报启动失败
关于Condition的具体设置可以看文章后面给出的官方连接,里面有更加详细的说明。
【Service】区块
Type:定义启动时的进程行为。它有以下几种值:
Type=simple:默认值,执行ExecStart指定的命令,启动主进程
Type=forking:以 fork 方式从父进程创建子进程,创建后父进程会立即退出
Type=oneshot:一次性进程,Systemd 会等当前服务退出,再继续往下执行
Type=dbus:当前服务通过D-Bus启动
Type=notify:当前服务启动完毕,会通知Systemd,再继续往下执行
Type=idle:若有其他任务执行完毕,当前服务才会运行
ExecStart:启动当前服务的命令
ExecStartPre:启动当前服务之前执行的命令
ExecStartPost:启动当前服务之后执行的命令
ExecReload:重启当前服务时执行的命令
ExecStop:停止当前服务时执行的命令
ExecStopPost:停止当其服务之后执行的命令
RestartSec:自动重启当前服务间隔的秒数
Restart:定义何种情况 Systemd 会自动重启当前服务,可能的值包括always(总是重启)、on-success、on-failure、on-abnormal、on-abort、on-watchdog
TimeoutSec:定义 Systemd 停止当前服务之前等待的秒数
【Install】区块
Alias:当前 Unit 可用于启动的别名
WantedBy/RequiredBy:可以多次使用此选项,也可以使用空格分隔的单位名称列表;
WantedBy:它的值是一个或多个 Target,当前Unit激活时(enable)符号链接会放入/etc/systemd/system目录下面,以Target名+.wants后缀构成的子目录中。
RequiredBy:它的值是一个或多个 Target,当前Unit激活时,符号链接会放入/etc/systemd/system目录下面以Target名+.required后缀构成的子目录中
Also:当前Unit激活(enable)时,会被同时激活的其他 Unit
DefaultInstance:在模板单元文件中,这指定了如果在没有任何显式设置实例的情况下启用了模板,则应为哪个实例启用该单元。此选项在非模板单元文件中无效。指定的字符串必须可用作实例标识符。
官方给出的更多解释:https://www.freedesktop.org/software/systemd/man/systemd.unit.html
https://www.freedesktop.org/software/systemd/man/systemd.service.html#
当我们写好一个,比如test.service的服务文件后,将其放入/lib/systemd/system目录下,并执行以下命令:
systemctl reload-daemon
systemctl enable test.service
systemctl start test.service
这三个命令的含义是:重新加载服务配置文件、设置服务开机自启动、启动服务。