文章目录
很多时候我们希望Linux系统启动时,同时启动一些服务。比如:我们期望部署MySQL的服务器重启后自动启动MySQL服务,部署Redis的服务器重启后自动启动redis-server服务…
一、背景说明
- Ubuntu 18.04不再使用initd管理系统,改用systemd,包括用systemctl命令来替换了service和chkconfig的功能。
- systemd 默认读取 /etc/systemd/system 下的配置文件,该目录下的文件会链接/lib/systemd/system/下的文件。
- 不同于以往的版本,ubuntu18.04默认不带/etc/rc.local文件,我们需要通过配置来让rc.local.service生效。
二、操作步骤
根据背景说明中的内容,我们首先确定/etc/systemd/system目录下是否有rc-local.service文件。
2.1、检查/etc/systemd/system/rc-local.service是否存在
默认/etc/systemd/system目录中是不存在rc-local.service文件的:
此时再检查下/lib/systemd/system/rc-local.service文件是否存在:
# 检查/lib/systemd/system/rc-local.service是否存在
cd /lib/systemd/system/ && ll|grep rc
结果如下:
可以看到文件是存在的。
2.2、链接文件
执行如下命令:
# 链接文件
ln -s /lib/systemd/system/rc-local.service /etc/systemd/system/rc-local.service
打开目录:
cd /etc/systemd/system && ll
可以看到目录下多了一个链接文件:
注:其实这一节的步骤是可以省略的,后面3.1.1节会说明为什么可以省略。
2.3、rc-local.service追加Install配置
打开目录/lib/systemd/system/rc-local.service:
vim /lib/systemd/system/rc-local.service
内容如下:
在末尾追加配置:
...
[Install]
WantedBy=multi-user.target
Alias=rc-local.service
有关rc-local.service各个节的说明见:3.1.1
2.4、创建/etc/rc.local
在Ubuntu18.04中默认是没有/etc/rc.local这个文件(而上一节的配置中是指向这个文件的),所以需要手动创建:
# 创建rc.local文件
touch rc.local
# 编辑rc.local
vim rc.local
输入如下内容:
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.
/usr/local/redis/bin/redis-server /usr/local/redis/conf/redis.conf
exit 0
注:这个文件是开机启动的重点,前面的设置只需要设置一次。如果后续需要添加新的开机启动服务,只需要修改/etc/rc.local这一个文件。
查看并设置权限
# 查看权限
ll|grep rc.local
# 增加执行权限
chmod +x rc.local
效果如下所示:
2.5、设置开机自动启动
设置开启启动:
systemctl enable rc-local
注:这里使用服务的别名(rc-local.service)。但是没有后缀.service
上面的命令只是将服务设为开机启动。如果不打算立即重启系统,但是又想立即启动 开机启动项,需要手动启动相关服务:
# 启动服务
systemctl start rc-local.service
# 查看服务是否启动
systemctl status rc-local.service
2.6、重启系统验证
重启系统:
reboot
重启好后,验证服务:
systemctl status rc-local.service
如若结果如下:
说明服务成功开机启动!!!
三、问题与总结
3.1、问题
3.1.1、Q1:rc-local.service文件的结构是怎样的?每个部分的作用分别是什么?
首先,systemd将系统资源划分为12种,每一种资源称为单元,对应的单元文件也有12种。其中扩展名为.service的资源文件作用如下:
封装守护进程的启动、停止、重启和重载操作,是最常见的一种 Unit 文件。
可以通过如下命令显示加载到内存的所有单元:
systemctl --all
或是通过如下命令查询服务类型的单元:
systemctl --type=service
Unit 文件可以分为三个配置区段:
- Unit段 (通用段)
- Service段 【服务(Service)类型的 Unit 文件(后缀为 .service)特有的】
- Install段 (通用段)
下面结合rc-local.service文件的内容介绍每个配置的意义
Unit段
该段定义:服务的启动顺序、依赖关系。
- Description
当前服务的简单描述
- Documentation
文档地址,可以是一个或多个文档的URL路径
但是图中的 man:systemd-rc-local-generator(8) 不是太明白是什么意思。
可能下面的命令man 8 systemd-rc-local-generator
用于打开systemd-rc-local-generator的操作手册
- ConditionFileIsExecutable
检查指定的绝对路径是否存在,是否是regular file,并且是否是可执行的。
相关配置可参考:https://manpages.ubuntu.com/manpages/lunar/en/man5/systemd.unit.5.html
- After
指定的 Unit 全部启动完成以后,才会启动当前 Unit
图中network.target也是一种单元文件。它表示系统的一种状态(网络可用的状态)
Service段
- Type
默认类型是simple,ExecStart字段启动的进程为主进程。
forking类型时,ExecStart字段以fork()方式启动子进程,子进程创建后父进程退出,子进程变为主进程。
- 通常需要指定PIDFile字段,以便 Systemd 能够跟踪服务的主进程。
但是我设置了PIDFile字段后,启动服务发生了报错。报错信息如下:
root@proxy_server_01:/var/run# systemctl status rc-local
● rc-local.service - /etc/rc.local Compatibility
Loaded: loaded (/lib/systemd/system/rc-local.service; enabled-runtime; vendor preset: enabled)
Drop-In: /lib/systemd/system/rc-local.service.d
└─debian.conf
Active: activating (start) since Sat 2023-08-19 10:08:38 UTC; 3min 12s ago
Docs: man:systemd-rc-local-generator(8)
Tasks: 5 (limit: 1104)
CGroup: /system.slice/rc-local.service
└─2943 /usr/local/redis/bin/redis-server *:6379
Aug 19 10:08:38 proxy_server_01 systemd[1]: Stopped /etc/rc.local Compatibility.
Aug 19 10:08:38 proxy_server_01 systemd[1]: Starting /etc/rc.local Compatibility...
Aug 19 10:08:38 proxy_server_01 systemd[1]: rc-local.service: Can't open PID file /var/run/rc_local.pid (yet?) after start: No such file or direct
上面rc-local.service内容发生改变时,需要执行如下命令重新加载单元:
systemctl daemon-reload
说明:
- 重启服务前,手动创建了/var/run/rc-local.pid文件
- 重启时,手动创建的文件会被删除。
有些网友的解释是每次服务重启时都会清空原pid文件。
那么如何配置才能使得PIDFile生效,并且服务启动成功呢?
- ExecStart
启动当前服务的命令
- TimeoutSec
停止当前服务前等待的秒数
- RemainAfterExit
值为yes时,表示服务进程退出时,服务依然保持执行(状态是激活的)。这样即使进程不存在了(可能是服务停止)依然可以重启服务。
- GuessMainPID
指定systemd在无法确切的查明服务的时候是否需要猜测服务的main pid。
当Type=forking,且PIDFile没有指定值时,该配置才有意义,否则会忽略这个字段。
Install段
- WantedBy
值是一个或多个target。
对应这个参数官方的解释是这样的:
“After running systemctl enable, a symlink
/etc/systemd/system/multi-user.target.wants/foo.service linking to the actual unit will be
created. It tells systemd to pull in the unit when starting multi-user.target. The inverse
systemctl disable will remove that symlink again.”
来源:https://manpages.ubuntu.com/manpages/lunar/en/man5/systemd.unit.5.htmlWantedBy=multi-user.target
在systemctl enable执行后,会在/etc/systemd/system/multi-user.target.wants/目录生成符号链接?
但是好像没有找到…
重新执行如下命令后:
# 禁用服务
systemctl disable rc-local
# 结果输出:
Removed /etc/systemd/system/rc-local.service.
# 开机启动
systemctl enable rc-local.service
# 结果:重新创建链接
Created symlink /etc/systemd/system/rc-local.service → /lib/systemd/system/rc-local.service.
Created symlink /etc/systemd/system/multi-user.target.wants/rc-local.service → /lib/systemd/system/rc-local.service.
查看符号链接
符号链接1:
符号链接2:
可以看到第二次执行systemctl enable后,重新生成了2个符号链接。由此可知官方文档所言非虚。
其中第一个符号链接是在2.2中生成过的。
那么,是不是2.2中的操作可以省略呢?
执行命令
# 禁用服务 systemctl disable rc-local.service # 禁用服务的结果:删除2个符号链接 Removed /etc/systemd/system/rc-local.service. Removed /etc/systemd/system/multi-user.target.wants/rc-local.service.
重新执行:
systemctl enable rc-local systemctl start rc-local.service
服务可以正常启动,reboot后服务也可以随系统启动。
所以,步骤2.2是可以省略的。
- Alias
该单元的别名
有关systemd的详细讲解可参考下面的文章:
3.2、总结
本文主要介绍了Ubuntu18.04中如何增加开机启动,我们是基于/lib/systemd/system/rc-local.service去配置开机启动的。当然也可以选择创建自己的.service文件。
需要将/lib/systemd/system/rc-local.service链接到/etc/systemd/system,并在rc-local.service中追加Install段。rc-local.service前面介绍过是一种单元文件。符号链接无需像2.2节那样手动生成,执行systemctl enable时会自动生成2个符号链接(/etc/systemd/system/rc-local.service和 /etc/systemd/system/multi-user.target.wants/rc-local.service)
所有的服务启动命令是定义在/etc/rc.local中的,但是系统默认是没有该文件的,所以需要手动创建。输入启动命令后,为该文件赋执行权限(chmod +x)。
使用systemctl enable 启用服务随系统开机启动。