S_lion's Studio

创建开机自启程序(上篇)

字数统计: 2.3k阅读时长: 9 min
2021/08/01 Share

在我们实现如何创建开机自启程序前,先简单了解下linux的启动过程。

linux启动过程

Linux 系统的启动,从计算机开机通电自检开始,一直到登陆系统,需要经历多个过程。

CentOS/RHEL6

  1. 服务器加电,加载 BIOS 信息,BIOS 进行系统检测。依照 BIOS 设定,找到第一个可以启动的设备(一般是硬盘);
  2. 读取第一个启动设备的 MBR (主引导记录),加载 MBR 中的 Boot Loader(启动引导程序,最为常见的是 GRUB)。
  3. 依据 Boot Loader 的设置加载内核,内核会再进行一遍系统检测。系统一般会采用内核检测硬件的信息,而不一定采用 Bios 的自检信息。内核在检测硬件的同时,还会通过加载动态模块的形式加载硬件的驱动。
  4. 内核启动系统的第一个进程,也就是 /sbin/init。
  5. 由 /sbin/init 进程调用 /etc/init/rcS.conf 配置文件,通过这个配置文件调用 /etc/rc.d/rc.sysinit 配置文件。而 /etc/rc.d/rc.sysinit 配置文件是用来进行系统初始化的,主要用于配置计算机的初始环境。
  6. 还是通过 /etc/init/rcS.conf 配置文件调用 /etc/inittab 配置文件。通过 /etc/inittab 配置文件来确定系统的默认运行级别。
  7. 确定默认运行级别后,调用 /etc/init/rc.conf 配置文件。
  8. 通过 /etc/init/rc.conf 配置文件调用并执行 /etc/rc.d/rc 脚本,并传入运行级别参数。
  9. /etc/rc.d/rc 确定传入的运行级别,然后运行相应的运行级别目录 /etc/rc[0-6].d/ 中的脚本。
  10. /etc/rc[0-6].d/ 目录中的脚本依据设定好的优先级依次启动和关闭。
  11. 最后执行 /etc/rc.d/rc.local 中的程序。
  12. 如果是字符界面启动,就可以看到登录界面了。如果是图形界面启动,就会调用相应的 X Window 接口。

img

CentOS/RHEL7

  1. 服务器加电,加载 BIOS 信息,BIOS 进行系统检测。依照 BIOS 设定,找到第一个可以启动的设备(一般是硬盘);

  2. 读取第一个启动设备的 MBR (主引导记录),加载 MBR 中的 OSLoader(启动引导程序GRUB2)。

  3. OSLoader 加载其相关配置 , 并显示相关的配置 菜单来引导用户选择相关操作(/etc/grub.d,/etc/default/grub,/boot/grub2/grub.cfg)

  4. 在用户选择后 ( 或 timeout 后 ),GRUB2 将加载 内核及 initramfs 至内存中 .initramfs 属于一个 img 的虚拟磁盘。

    initramfs 包含了动态的内核模块 , 初始化脚本及非常多的硬件驱动等 , 在 RHEL7 中 initramfs 自身即包含了一个完整的可用系统。(/etc/dracut.conf)

  5. GRUB2 将控制系统切换到 kernel, 通过对 GRUB2 的控制可以添加各种 kernel 的选项 . 并将 这些选项同时传递至内存中 , 影响 kernel 及 initramfs 的运行 . (/etc/grub.d,/etc/default/grub,/boot/grub2/gr ub.cfg)

  6. kernel 在启动后将初始化所有的硬件 , 通过 initramfs 找到硬件相关的驱动程序 , 而后从 initramfs 中执行 PID 1 的 /sbin/init 命令 ( 最高 进程 ). 在 RHEL 中 init 属 于 /lib/systemd/systemd 的软连接 , 以及一个 udev 进程来自动建立已经存在的硬件的设备。(/etc/fstab)

  7. 由 initramfs 建立的内存的根分区 /sysroot( 物理 ‘/‘ 分区 ) 在成功挂载之后,将切 换到此根分区上 , 并将 systemd 重新执行安装至真实的根分区中。

  8. systemd 开始查找所有的服务 , 开始执行 ( 停止 ) 相关的服务 , 以符合该服务的配置并解决相关的依赖问题。(/etc/systemd/system/default.target)

Systemd引入了并行启动的概念,它会为每个需要启动的守护进程建立一个套接字,这些套接字对于使用它们的进程来说是抽象的,这样它们可以允许不同守护进程之间进行交互。Systemd会创建新进程并为每个进程分配一个控制组(cgroup)。处于不同控制组的进程之间可以通过内核来互相通信。

从 7.x 版本开始,引入了 systemd 来管理服务,/etc/rc.local 是为向前兼容而保留。

开机自启

我们现在大多都在使用CentOS/RHEL7中,实现开机启动程序主要有两种方法:

  • 在/etc/rc.local脚本文件中编写启动程序的脚本

  • 把要启动的程序配置成自定义的systemd服务(推荐)

通过rc.local实现开机自启程序

/etc/rc.local是/etc/rc.d/rc.local的软链接

1
2
[root@slions_pc1 home]# ll /etc/rc.local
lrwxrwxrwx. 1 root root 13 5月 21 16:45 /etc/rc.local -> rc.d/rc.local

rc.local配置文件解读

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@slions_pc1 home]# cat /etc/rc.local
#!/bin/bash
# THIS FILE IS ADDED FOR COMPATIBILITY PURPOSES
# 添加此文件是为了兼容。
# It is highly advisable to create own systemd services or udev rules
# to run scripts during boot instead of using this file.
# 强烈建议创建自己的systemd服务或udev规则,以便在引导期间运行脚本,而不是使用此文件。
# In contrast to previous versions due to parallel execution during boot
# this script will NOT be run after all other services.
# 请注意,必须运行'chmod+x/etc/rc.d/rc.local',以确保在引导期间执行此脚本。
# Please note that you must run 'chmod +x /etc/rc.d/rc.local' to ensure
# that this script will be executed during boot.

#默认会touch这个文件,每次系统启动时都会touch这个文件,这个文件的修改时间就是系统的启动时间
touch /var/lock/subsys/local

rc.local本质上是一个shell脚本文件,可以把启动时需要执行的命令写在里面,启动时将按顺序执行。

rc.local编写注意

  • rc.local脚本在操作系统启动时只执行一次
  • 环境变量的问题
    • 在rc.local脚本中执行程序时是没有环境变量的,如果执行的程序需要环境变量,可以在脚本中设置环境变量
  • 命令需写绝对路径
  • 不要让rc.local挂起
    • rc.local是一个脚本,是按顺序执行的,执行完一个程序后才会执行下一个程序,如果某程序不是后台程序,就应该加&让程序运行在后台,否则rc.local会挂起。
  • 切记chmod+x/etc/rc.d/rc.local赋予执行权限

通过system实现开机自启程序

systemd可管理的服务

操作系统使用systemd后,所有用户进程都是systemd的后代进程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
[root@slions_pc1 ~]# pstree -p
systemd(1)─┬─NetworkManager(8829)─┬─{NetworkManager}(8881)
│ └─{NetworkManager}(8883)
├─VGAuthService(8844)
├─abrt-dbus(14768)─┬─{abrt-dbus}(14802)
│ └─{abrt-dbus}(14813)
├─abrt-watch-log(8832)
├─abrtd(8830)
├─atd(8850)
├─auditd(8793)───{auditd}(8794)
├─chronyd(8869)
├─crond(8853)
├─dbus-daemon(8821)───{dbus-daemon}(8827)
├─irqbalance(8834)
├─login(8866)───bash(14656)
├─lsmd(8849)
├─lvmetad(4420)
├─master(9397)─┬─pickup(9415)
│ └─qmgr(9416)
├─polkitd(8818)─┬─{polkitd}(8826)
│ ├─{polkitd}(8828)
│ ├─{polkitd}(8833)
│ ├─{polkitd}(8839)
│ ├─{polkitd}(8840)
│ └─{polkitd}(8841)
├─rngd(8835)
├─rpcbind(8824)
├─rsyslogd(9174)─┬─{rsyslogd}(9237)
│ └─{rsyslogd}(9258)
├─smartd(8820)
├─sshd(9171)─┬─sshd(19034)───bash(19040)───pstree(19161)
│ └─sshd(19038)───sftp-server(19075)
├─systemd-journal(4398)
├─systemd-logind(8846)
├─systemd-udevd(4427)
├─tuned(9172)─┬─{tuned}(9926)
│ ├─{tuned}(9928)
│ ├─{tuned}(9984)
│ └─{tuned}(10117)
└─vmtoolsd(8845)───{vmtoolsd}(8935)

虽然从进程树关系来看,所有进程都直接或间接地受到systemd的管理,但是,并非所有systemd的子进程都受Systemd Unit管理单元的管理。只有那些由systemd方式启动的服务进程(比如systemctl命令启动)才受到Systemd Unit管理单元的监控和管理。为了简化描述,后面均直接以『systemd管理』来描述受systemd unit管理单元的管理。

比如,用户可以通过下面两种方式启动Nginx服务进程:

1
2
nginx                    # (1)
systemctl start nginx # (2)

但systemd只能监控、管理第(2)种方式启动的nginx服务。比如第一种方式启动的nginx,无法使用systemctl stop nginx来停止。

systemd管理服务的命令

systemctl是 Systemd 的主命令,用于管理系统。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# 启动、停止服务:
systemctl start Service_Name1 Service_Name2
systemctl stop Service_Name
# 开机启动服务:
systemctl enable Service_Name

# 有时候,该命令可能没有响应,服务停不下来。这时候就不得不"杀进程"了,向正在运行的进程发出kill信号。
systemctl kill Service_Name
# 服务重载、重启相关操作:
# 重载服务:服务未运行时不做任何事
systemctl reload Service_Name

# 重启服务:服务已运行时重启之,服务未运行时启动之
systemctl restart Service_Name

# 服务已运行时重启之,未运行时不启动之
systemctl try-restart Service_Name

# 服务已运行时,如果支持reload,则reload,如果不支持则restart
# 服务未运行时,启动之
systemctl reload-or-restart Service_Name

# 服务已运行时,如果支持reload,则reload,如果不支持则restart
# 服务未运行时,不做任何事
systemctl reload-or-try-restart Service_Name

# 查看服务状态
systemctl status Service_Name

# 检查服务是否active: 服务是否已启动
# 至少一个服务active时,返回0,否则返回非0退出状态码
systemctl is-active Service_Name1 Service_Name2
systemctl --quiet is-active Service_Name # 静默模式

# 检查服务是否failed: 服务启动命令退出状态码非0或启动超时
systemctl is-failed Service_Name

因为篇幅问题,下篇继续介绍如何编写systemd service

CATALOG
  1. 1. linux启动过程
    1. 1.1. CentOS/RHEL6
    2. 1.2. CentOS/RHEL7
  2. 2. 开机自启
    1. 2.1. 通过rc.local实现开机自启程序
      1. 2.1.1. rc.local配置文件解读
      2. 2.1.2. rc.local编写注意
    2. 2.2. 通过system实现开机自启程序
      1. 2.2.1. systemd可管理的服务
      2. 2.2.2. systemd管理服务的命令