在应急响应时,开机启动项是必查的项,下面梳理一下关于开机启动与服务相关需要排查的点。直接从init开始说。
RHEL5、RHEL6、RHEL7的init系统分别为SysV init、Upstart、Systemd
CentOS 5
启动流程如下:
1)加载BIOS的硬件信息与进行自我测试,并依据设置取得第一个可启动设备;
2)读取并执行第一个启动设备内MBR(主引导分区)的Boot Loader(即是gurb等程序);
3)依据Boot Loader的设置加载Kernel,Kernel会开始检测硬件与加载驱动程序;
4)在硬件驱动成功后,Kernel会主动调用init进程(/sbin/init),init的配置文件/etc/inittab;
5)init执行/etc/rc.d/rc.sysinit文件来准备软件的操作环境(如网络、时区等);
6)init执行runlevel的各个服务的启动(script方式);
7)init执行/etc/rc.d/rc.local文件;
8)init执行终端机模拟程序mingetty来启动login程序,最后等待用户登录。
init程序会读取init的配置文件/etc/inittab,并依据此文件来进行初始化工作。/etc/inittab文件主要作用是指定运行级别,执行系统初始化脚本(/etc/rc.d/rc.sysinit),启动相应运行级别下的服务和启动终端。
[root@jianshe_28 admin]# cat /etc/inittab
#
# inittab This file describes how the INIT process should set up
# the system in a certain run-level.
#
# Author: Miquel van Smoorenburg, <miquels@drinkel.nl.mugnet.org>
# Modified for RHS Linux by Marc Ewing and Donnie Barnes
#
# Default runlevel. The runlevels used by RHS are:
# 0 - halt (Do NOT set initdefault to this)
# 1 - Single user mode
# 2 - Multiuser, without NFS (The same as 3, if you do not have networking)
# 3 - Full multiuser mode
# 4 - unused
# 5 - X11
# 6 - reboot (Do NOT set initdefault to this)
#
id:3:initdefault:
# System initialization.
si::sysinit:/etc/rc.d/rc.sysinit
l0:0:wait:/etc/rc.d/rc 0
l1:1:wait:/etc/rc.d/rc 1
l2:2:wait:/etc/rc.d/rc 2
l3:3:wait:/etc/rc.d/rc 3
l4:4:wait:/etc/rc.d/rc 4
l5:5:wait:/etc/rc.d/rc 5
l6:6:wait:/etc/rc.d/rc 6
# Trap CTRL-ALT-DELETE
ca::ctrlaltdel:/sbin/shutdown -t3 -r now
# When our UPS tells us power has failed, assume we have a few minutes
# of power left. Schedule a shutdown for 2 minutes from now.
# This does, of course, assume you have powerd installed and your
# UPS connected and working correctly.
pf::powerfail:/sbin/shutdown -f -h +2 "Power Failure; System Shutting Down"
# If power was restored before the shutdown kicked in, cancel it.
pr:12345:powerokwait:/sbin/shutdown -c "Power Restored; Shutdown Cancelled"
# Run gettys in standard runlevels
1:2345:respawn:/sbin/mingetty tty1
2:2345:respawn:/sbin/mingetty tty2
3:2345:respawn:/sbin/mingetty tty3
4:2345:respawn:/sbin/mingetty tty4
5:2345:respawn:/sbin/mingetty tty5
6:2345:respawn:/sbin/mingetty tty6
# Run xdm in runlevel 5
x:5:respawn:/etc/X11/prefdm -nodaemon
inittab文件中的值都是如下格式:
id:runlevel:action:process
id:
id是指入口标识符,他是个字符串,对于getty、mingetty等,需求id和tty的编号相同,否则getty将不能正常工作。
runlevel:
指定runlevel的级别。能指定多个runlevel级别,也能不为runlevel字段指定特定的值。
运行级别决定了系统启动的绝大部分行为和目的。这个级别从0到6,具有不同的功能。不同的运行级定义如下:
# 0 - 停机(千万别把initdefault设置为0,否则系统永远无法启动)
# 1 - 单用户模式
# 2 - 多用户,没有 NFS
# 3 - 完全多用户模式(标准的运行级)
# 4 - 系统保留的
# 5 - X11 (x window)
# 6 - 重新启动
action:
定义了该进程应该运行在何种状态下,其中action常用的种类有:
下面看一下具体的配置
id:3:initdefault:
设置runlevel
si::sysinit:/etc/rc.d/rc.sysinit
执行了/etc/rc.d/rc.sysinit,一个shell脚本,他主要是完成一些系统初始化的工作,例如激活交换分区,检查磁盘,加载硬件模块及其他一些需要优先执行任务。
l0:0:wait:/etc/rc.d/rc 0
l1:1:wait:/etc/rc.d/rc 1
l2:2:wait:/etc/rc.d/rc 2
l3:3:wait:/etc/rc.d/rc 3
l4:4:wait:/etc/rc.d/rc 4
l5:5:wait:/etc/rc.d/rc 5
l6:6:wait:/etc/rc.d/rc 6
/etc/rc.d/rc是个shell脚本,接受runlevel参数,去执行该runlevel目录下的所有的rc启动脚本。以启动级别为3为例,/etc/rc.d/rc3.d/其实都是一些链接文件,真正的rc启动脚本实际上都是放在/etc/rc.d/init.d/目录下。而这些rc启动脚本有着类似的用法,他们一般能接受start、stop、restart、status等参数。
凡是以Kxx开头的,都以stop为参数来调用;凡是以Sxx开头的,都以start为参数来调用。xx是数字、表示的是启动顺序,按xx从小到大来执行。
我们来用chkconfig修改一下试试
另外说明一下应急响应中我们都会检查/etc/rc.local,其实也是在rcN.d中。
/etc/rc.local是软链到了/etc/rc.d/rc.local
Redhat中的运行模式2、3、5都把/etc/rc.d/rc.local做为初始化脚本中的最后一个
1:2345:respawn:/sbin/mingetty tty1
2:2345:respawn:/sbin/mingetty tty2
3:2345:respawn:/sbin/mingetty tty3
4:2345:respawn:/sbin/mingetty tty4
5:2345:respawn:/sbin/mingetty tty5
6:2345:respawn:/sbin/mingetty tty6
init接下来会打开6个终端,以便用户登录系统。
总结一下,针对CentOS5系统,需要排查的点:
1)/etc/inittab
该文件是可以运行process的,这里我们添加一行
0:235:once:/bin/vinc
内容如下
重启
2)/etc/rc.d/rc.sysinit
在最后插入一行/bin/vinc
3)/etc/rc.d/init.d
4)/etc/rc.d/rc.local
CentOS 6
启动流程如下:
init会读取配置文件/etc/inittab 和 /etc/init/*.conf。先看一下/etc/inittab
[root@server120 src]# cat /etc/inittab
# inittab is only used by upstart for the default runlevel.
#
# ADDING OTHER CONFIGURATION HERE WILL HAVE NO EFFECT ON YOUR SYSTEM.
#
# System initialization is started by /etc/init/rcS.conf
#
# Individual runlevels are started by /etc/init/rc.conf
#
# Ctrl-Alt-Delete is handled by /etc/init/control-alt-delete.conf
#
# Terminal gettys are handled by /etc/init/tty.conf and /etc/init/serial.conf,
# with configuration in /etc/sysconfig/init.
#
# For information on how to write upstart event handlers, or how
# upstart works, see init(5), init(8), and initctl(8).
#
# Default runlevel. The runlevels used are:
# 0 - halt (Do NOT set initdefault to this)
# 1 - Single user mode
# 2 - Multiuser, without NFS (The same as 3, if you do not have networking)
# 3 - Full multiuser mode
# 4 - unused
# 5 - X11
# 6 - reboot (Do NOT set initdefault to this)
#
id:3:initdefault:
通过注释可以看到,upstart只使用inittab读取默认的runlevel。添加其他的配置都不会生效,其他的配置都移动到了/etc/init/*.conf下。
系统初始化/etc/init/rcS.conf
对应runlevel的服务启动/etc/init/rc.conf
终端配置/etc/init/tty.conf
….
总结一下,针对CentOS6系统,需要排查的点:
1)/etc/init/*.conf
vim tty.conf,添加一行
exec /bin/vinc
内容如下
重启
2)/etc/rc.d/rc.sysinit
3)/etc/rc.d/init.d
4)/etc/rc.d/rc.local
0x03 CentOS7
开机启动流程如下:
1)UEFi或BIOS初始化,运行POST开机自检
2)选择启动设备
3)引导装载程序, centos7是grub2
4)加载装载程序的配置文件: /etc/grub.d/ /etc/default/grub /boot/grub2/grub.cfg
5)加载initramfs驱动模块
6)加载内核选项
7)内核初始化, centos7使用systemd代替init
8)执行initrd.target所有单元,包括挂载/etc/fstab
9)从initramfs根文件系统切换到磁盘根目录
10)systemd执行默认target配置,配置文件/etc/systemd/system/default.target
11)systemd执行sysinit.target初始化系统及basic.target准备操作系统
12)systemd启动multi-user.target下的本机与服务器服务
13)systemd执行multi-user.target下的/etc/rc.d/rc.local
14)systemd执行multi-user.target下的getty.target及登入服务
15)systemd执行graphical需要的服务
CentOS7使用的是systemd,相较于以前的init有很大的不同。
/etc/inittab是空的
[root@localhost init.d]# cat /etc/inittab | grep -v "^$" | grep -v "^#"
[root@localhost init.d]#
也没有/etc/init目录
[root@localhost init.d]# ls -al /etc/init
ls: cannot access /etc/init: No such file or directory
/etc/rc3.d/和/etc/rc.d/init.d/还存在,所以向后兼容sysv init脚本,在centos5、6系统上/etc/init.d/目录下的服务脚本,systemd也能够对其进行管理
[root@localhost init.d]# ls -al /etc/rc3.d/
total 4
drwxr-xr-x. 2 root root 81 May 30 14:09 .
drwxr-xr-x. 10 root root 4096 May 30 14:31 ..
lrwxrwxrwx. 1 root root 20 Nov 7 2016 K50netconsole -> ../init.d/netconsole
lrwxrwxrwx. 1 root root 17 Nov 7 2016 S10network -> ../init.d/network
lrwxrwxrwx. 1 root root 23 Jan 17 2017 S90zabbix_agentd -> ../init.d/zabbix_agentd
lrwxrwxrwx. 1 root root 15 May 30 14:09 S99ossec -> ../init.d/ossec
systemd提供更优秀的框架以表示系统服务间的依赖关系,尽可能启动更少进程,尽可能将更多进程并行启动,尽可能减少对shell脚本的依赖。systemd的核心概念是unit,unit表示不同类型的systemd对象,通过配置文件进行标识和配置,文件中主要包含了系统服务,监听socket,保存的系统快照以及其他与init相关的信息。
查看所有的unit类型:
[root@localhost system]# systemctl -t help
Available unit types:
service
socket
busname
target
snapshot
device
mount
automount
swap
timer
path
slice
scope
用途如下:
Service unit:文件扩展名.service 用于定义系统服务
Target unit:文件扩展名.target 用于模拟实现运行级别
Device unit: .device 用于定义内核识别的设备
Mount unit: .mount 定义文件系统的挂载点
Socket unit: .socket 用于标识进程间通行用的socket文件,也可在系统启动时,延迟启动服务,实现按需启动
Snapshot unit: .snapshot 管理系统快照
Swap unit: .swap 用于标识swap设备
Automount unit: .automount 文件系统的自动挂载点
Path unit: .path 用于定义文件系统中的一个文件或目录使用,常用于当文件系统变化时,延迟激活服务,如spool目录
配置文件中主要保存在:
/usr/lib/systemd/system/ 每个服务最主要的启动脚本设置,类似于之前的/etc/init.d/
/run/systemd/system/ 系统执行过程中所产生的服务脚本,比上面目录优先运行
/etc/systemd/system/ 管理员建立的执行脚本,类似于/etc/rc.d/rcN.d/Sxx类的功能,比上面目录优先运行
[root@localhost system]# ls /usr/lib/systemd/system/
abrt-ccpp.service psacct.service
abrtd.service quotaon.service
abrt-oops.service rc-local.service
...
[root@localhost system]# ls /run/systemd/system/
session-1006.scope session-161401.scope session-24243.scope session-54837.scope
session-1160.scope session-162551.scope session-24243.scope.d session-54837.scope.d
...
[root@localhost system]# ls /etc/systemd/system/
basic.target.wants default.target sockets.target.wants
dbus-org.fedoraproject.FirewallD1.service default.target.wants sysinit.target.wants
dbus-org.freedesktop.NetworkManager.service getty.target.wants system-update.target.wants
dbus-org.freedesktop.nm-dispatcher.service multi-user.target.wants
我们来看下sshd.service
[root@localhost system]# cat sshd.service | grep -v "^$" | grep -v "^#"
[Unit]
Description=OpenSSH server daemon
Documentation=man:sshd(8) man:sshd_config(5)
After=network.target sshd-keygen.service
Wants=sshd-keygen.service
[Service]
EnvironmentFile=/etc/sysconfig/sshd
ExecStart=/usr/sbin/sshd -D $OPTIONS
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartSec=42s
[Install]
WantedBy=multi-user.target
文件包含三部分。
[Unit]:描述信息与依赖关系
[Service]:ExecStartPre 定义启动服务之前应该运行的命令;ExecStart 定义启动服务的具体命令行语法。
[Install]:WangtedBy 表明这个服务是在多用户模式下所需要的。
我们再来看下multi-user.target
[root@localhost system]# cat multi-user.target | grep -v "^$" | grep -v "^#"
[Unit]
Description=Multi-User System
Documentation=man:systemd.special(7)
Requires=basic.target
Conflicts=rescue.service rescue.target
After=basic.target rescue.service rescue.target
AllowIsolate=yes
Requires表明 multi-user.target 启动的时候 basic.target 也必须被启动,basic.target 停止的时候,multi-user.target 也必须停止。接着查看 basic.target 文件,会发现它又指定了 sysinit.target 等其他的单元必须随之启动。同样 sysinit.target 也会包含其他的单元。采用这样的层层链接的结构,最终所有需要支持多用户模式的组件服务都会被初始化启动好。
此外在/etc/systemd/system 目录下还可以看到诸如*.wants 的目录
[root@localhost system]# ls multi-user.target.wants/
brandbot.path plymouth-quit.service systemd-logind.service
dbus.service plymouth-quit-wait.service systemd-update-utmp-runlevel.service
getty.target systemd-ask-password-wall.path systemd-user-sessions.service
放在该目录下的配置单元文件等同于在[Unit]小节中的 wants 关键字,即本单元启动时,还需要启动这些单元。
查看multi-user.target的依赖关系
[root@localhost system]# systemctl list-dependencies multi-user.target
multi-user.target
├─abrt-ccpp.service
├─abrt-oops.service
├─abrt-vmcore.service
├─abrt-xorg.service
├─abrtd.service
├─atd.service
├─auditd.service
查看systemd管理的所有单元
[root@localhost system]# systemctl list-unit-files
UNIT FILE STATE
proc-sys-fs-binfmt_misc.automount static
dev-hugepages.mount static
dev-mqueue.mount static
查看服务状态
[root@localhost system]# systemctl list-unit-files --type service
UNIT FILE STATE
abrt-ccpp.service enabled
abrt-oops.service enabled
State的状态如下:
loaded:Unit配置文件已处理
active(running):一次或多次持续处理的运行
active(exited):成功完成一次性的配置
active(waiting):运行中,等待一个事件
inactive:不运行
enabled:开机启动
disabled:开机不启动
static:开机不启动,但可被另一个启用的服务激活
使用 systemctl 控制单元时,通常需要使用单元文件的全名,包括扩展名(例如 sshd.service),如果无扩展名,systemctl 默认把扩展名当作 .service。
启动httpd服务
[root@localhost system]# systemctl start httpd
停止httpd服务
[root@localhost system]# systemctl stop httpd
查看httpd服务运行状态
[root@localhost system]# systemctl status httpd
在centOS7上由.target来代替运行级别。
查看我们的机器上有多少个target
[root@localhost system]# ls /usr/lib/systemd/system/*.target | head -n 5
/usr/lib/systemd/system/basic.target
/usr/lib/systemd/system/bluetooth.target
/usr/lib/systemd/system/cryptsetup-pre.target
/usr/lib/systemd/system/cryptsetup.target
/usr/lib/systemd/system/ctrl-alt-del.target
运行级别与target的对照如下:
runlevel0.target -> poweroff.target
runlevel1.target -> rescue.target
runlevel2.target -> multi-user.target
runlevel3.target -> multi-user.target
runlevel4.target -> multi-user.target
runlevel5.target -> graphical.target
runlevel6.target -> reboot.target
运行级别切换
在centOS6上,我们切换级别使用init,在centOS7上来切换用:
systemctl isolate poweroff.target
要想切换运行级别,AllowIsolate=yes才可以。
[root@localhost system]# cat poweroff.target | grep Allow
AllowIsolate=yes
修改文件需执行systemctl daemon-reload才能生效。
查看默认运行级别
[root@localhost system]# systemctl get-default
multi-user.target
修改默认运行级别
[root@localhost system]# systemctl set-default graphical.target
Removed symlink /etc/systemd/system/default.target.
Created symlink from /etc/systemd/system/default.target to /usr/lib/systemd/system/graphical.target.
查看开机启动程序(相当于chkconfig –list)
ls /etc/systemd/system/multi-user.target.wants/
开机启动(相当于chkconfig httpd on)
[root@localhost system]# systemctl enable httpd.service
Created symlink from /etc/systemd/system/multi-user.target.wants/httpd.service to /usr/lib/systemd/system/httpd.service.
去除开机启动(相当于chkconfig httpd off)
[root@localhost system]# systemctl disable httpd.service
Removed symlink /etc/systemd/system/multi-user.target.wants/httpd.service.
查看服务是否开机启动(相当于chkconfig –list httpd)
[root@localhost system]# systemctl is-enabled httpd.service
enabled
CentOS7下rc.local文件默认不会在开机执行,我们来看一下rc.local文件的内容
[root@localhost system]# 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.
#
# In contrast to previous versions due to parallel execution during boot
# this script will NOT be run after all other services.
#
# Please note that you must run 'chmod +x /etc/rc.d/rc.local' to ensure
# that this script will be executed during boot.
可以看到一段注释,翻译如下:
#这个文件是为了兼容性的问题而添加的。
#强烈建议创建自己的systemd服务或udev规则来在开机时运行脚本而不是使用这个文件。
#与以前的版本引导时的并行执行相比较,这个脚本将不会在其他所有的服务后执行。
#请记住,你必须执行“chmod +x /etc/rc.d/rc.local”来确保确保这个脚本在引导时执行。
然后我们看/usr/lib/systemd/system/rc-local.service
[root@localhost system]# cat /usr/lib/systemd/system/rc-local.service | grep ExecStart
ExecStart=/etc/rc.d/rc.local start
那我们启动下rc-local.service
[root@localhost system]# chmod u+x /etc/rc.d/rc.local
[root@localhost system]# systemctl start rc-local
总结一下,针对CentOS7系统,需要排查的点:
1)排查修改的service
find /usr/lib/systemd/system/ -name "*.service" | xargs ls -alt | head -n 5
find /etc/systemd/system/ -name "*.service" | xargs ls -alt | head -n 5
2)/etc/rc.d/init.d
3)/etc/rc.d/rc.local
不过需要看/etc/rc.d/rc.local是否有x权限。