15. Linux启动流程和内核管理
1 CentOS6的启动管理
1.1 Linux组成
内核: 实现进程管理, 内存管理, 网络管理, 驱动程序管理, 文件系统管理, 安全管理等功能
rootfs: 根文件系统, 包含程序和glibc库
程序: 二进制执行文件
库: 函数集合, function, 调用接口
1.2 CentOS6 启动流程
1.2.1 CentOS6 启动流程
图片.png资料来自51cto: http://s4.51cto.com/wyfs02/M02/87/20/wKiom1fVBELjXsvaAAUkuL83t2Q304.jpg
1. 加载BIOS的硬件信息, 获取第一个启动设备
2. 读取第一个启动设备MBR的引导加载程序(grub)的启动信息
3. 加载核心操作系统的核心信息, 核心开始解压缩, 并尝试驱动所有的硬件设备
4. 核心执行init程序, 并获取默认的运行信息
5. init程序执行/etc/rc.d/rc.sysinit文件, 重新挂载根文件系统
6. 启动核心的外挂模块
7. init执行运行的各个批处理文件(scripts)
8. init执行/etc/rc.d/rc.local
9. 执行/bin/login程序, 等待用户登录
10. 登录之后开始以shell控制主机
1.2.2 硬件启动POST
POST: Power On Self Test, 加电自检, 是BIOS功能的一个主要部分, 与操作系统无关, 是硬件功能. 负责完成对CPU, 主板, 内存, 硬盘子系统, 显示子系统, 串并行接口, 键盘等硬件情况的检测
主板的ROM: BIOS, Basic Output System, 保存着有关计算机系统最重要的基本输入输出程序, 系统信息设置, 开机加电自检程序和系统启动自举程序等. 服务器加电后, BIOS会自动把BIOS内的程序加载到CPU, 然后进行加电自检
主板的RAM: CMOS互补金属氧化物半导体, 保存各项参数的设定, 按次序查找引导设备, 第一个有引导程序的设备为本次启动设备
1.2.3 启动加载器 bootloader
1.2.3.1 bootloader
引导加载器, 用来引导程序, 不同操作系统的bootloader不一样
Windows: ntloader, 仅支持启动OS
Linux: 功能丰富, 提供菜单, 允许用户选择要启动的系统或不同的内核版本, 把用户选定的内核装在到内存的特定空间中, 解压, 展开, 并把系统控制权移交给内核
1.2.3.2 Linux的bootloader
LILO: Linux Loader, 早期的bootloader, 功能单一
GRUB: Grand Unified Bootloader, CentOS 6 GRUB 0.97:GRUB Legacy, CentOS7 以后使用 GRUB 2.02
1.2.3.3 GRUB启动阶段
- primary bootloader
1st stage: MBR的前446个字节, 存放GRUB第一阶段的数据
1.5 stage: MBR之后的扇区(加载对应的文件系统驱动), 让stage1中的bootloader能识别stage2所在分区上的文件系统
启动菜单, 内核等文件都是存在文件系统上的, 因此, 需要1.5阶段, 帮助GRUB去识别文件系统, 进到对象的目录拿到相应的文件
MBR, 磁盘的第一个扇区, 512个字节
前446个字节用来引导GRUB第一阶段
中间64个字节分区表
后两个字节标记位
- secondary bootloader: 2阶段, 分区文件/boot/grub, 保存二阶段相关内容, 比如启动菜单
[08:30:10 root@centos-7-1 ~]#ll /boot/grub2 # CentOS6上保存在/boot/grub
total 32
-rw-r--r--. 1 root root 84 Oct 29 21:44 device.map
drwxr-xr-x. 2 root root 25 Oct 29 21:44 fonts
-rw-r--r--. 1 root root 4423 Oct 29 21:56 grub.cfg # 启动菜单文件
-rw-r--r--. 1 root root 1024 Oct 29 21:45 grubenv
drwxr-xr-x. 2 root root 8192 Oct 29 21:44 i386-pc
drwxr-xr-x. 2 root root 4096 Oct 29 21:44 locale
grub.conf启动菜单的修复-案例1
initramfs-3.10.0-1127.el7.x86_64.img # 存放文件系统驱动, 让内核加载操作系统的根, 模拟一个小型根系统
而1.5阶段, 利用MBR后续扇区是为了让bootloader能识别/boot分区, 而/boot分区和根分区不一样在同一分区, 所有要有单独的文件来帮助内核加载根分区
initramfs和内核文件都存放在了/boot目录里, 因此在启动菜单中, initramfs要放在kernel后, 先加载内核
图片.png
- 如果启动菜单的顺序有问题, 开机会提示initramfs需要在kernel之前启动, 这时可以在开机菜单选择中按e, 进入菜单编辑
- 选中错误的选项, 按d删除, 这时只是临时删除, 之后系统启动后, 还要去修改文件
- 添加正确的菜单, 按o键,再按e键, 输入文件路径, 可以tab补全, 启动菜单必须有三行信息
- 写完按回车, 检查菜单
-
确认无误后, 按b启动
-
启动后修改grub.conf, 否则下次重启还是无法启动
grub.conf启动菜单的修复-案例2
grub.conf存着启动的菜单, 一旦该文件丢失, 系统将无法启动
- 模拟文件丢失
mv /boot/grub/grub.conf /data
- 重启测试
- 在错误界面, 补全菜单文件内容, 按boot启动
- 启动后恢复grub.conf文件
CentOS6破解root口令
CentOS6启动过程中, 加载完bootloader会加载内核, 根文件系统, 加载init进程, 然后启动init进程
init进程启动时会读取其配置文件, /etc/inittab, 其中定义了系统启动的模式,7种模式: 0 - 6
图片.png
- 如果启动模式错误的改成6, 那么服务器会无限重启, 这时也是需要修改启动菜单, 启动时先按任意键进入菜单
- 选择版本, 然后按a键
- 在quiet后加入本次启动时想进入的模式
- 输入的数字相当于内核参数, 也是通过干预本次启动时菜单选项来修复
-
按回车, 进入启动, 然后修改/etc/inittab文件
-
若要破解root用户, 需要启动时进入1,单用户模式
单用户模式, 只有一个用户能使用Linux, 远程连接都会端断开
可以切换用户, 但是不能开启多个终端, 也不能远程
一般在系统维护时可以使用
- 进入启动界面, 按任意键, 选择版本, 然后按a键
-
输入1, 按回车进入单用户模式
-
再次启动后, 会直接进入系统, 而且身份是root, 无需密码
-
passwd重置密码即可
破解口令必须能到机房或者服务器面前去破解, 因此 虽然破解过程简单, 但并不是所有人都有机会
给grub加密, 防止root破解
- 生成grub口令
- 添加到grub配置文件/boot/grub/grub.conf
- 此时服务器启动时, 是没有a键选项的, 要想修改启动默认, 需要按p键, 然后输入grub密码
- 输入密码后, 再用a键进入菜单修改
注意: 即使grub加密了, 还是可以通过救援模式破解口令, 因此, 一定要确保服务器的物理安全
1.2.3.4 修复GRUB第一阶段故障(CentOS6)
破坏GRUB第一阶段, MBR前446个字节, 可以通过救援模式修复, 但是,grub.conf菜单文件是无法修复的, 需要手写
1.2.4 加载内核
内核自身初始化的过程
1. 探测可识别到的所有硬件设备
2. 加载硬件驱动程序(借助于ramdisk加载驱动)
3. 以只读方式挂载根文件系统
4. 运行用户空间的第一个应用程序: /sbin/init
内核特点:
支持模块化: .ko(内核对象), 如: 文件系统, 硬件驱动, 网络协议等
支持内核模块的动态装载和卸载
内核组成部分:
核心文件: /boot/vmlinuz/VERSION-release
ramdisk: 辅助的伪根系统, 加载相应的硬件驱动, ramdisk --> ramfs提高速度
CentOS5 /boot/initrd-VERSION-release.img
CentOS6以后版本/波特/initramfs-VERSION-release.img
模块文件: /lib/modules/VERSION-release
范例: 误删除内核文件/boot/vmlinuz-2.6.32-754.el6.x86_64无法启动的故障恢复
rm -rf /boot/vmlinuz-2.6.32-754.el6.x86_64
reboot
进入救援模式
切根 chroot /mnt/sysimage
挂载光盘 mount /dev/sr0 /mnt
复制内核文件 cp /mnt/isolinux/vmlinuz /boot/vmlinuz-2.6.32-754.el6.x86_64
sync
exit
reboot
ramdisk文件的制作
- mkinitrd命令
mkinitrd /boot/initramfs-$(uname -r).img $(uname -r)
- dracut命令
dracut /boot/initramfs-$(uname -r).img $(uname -r)
案例: 误删除/boot/initramfs-2.6.32-754.el6.x86_64.img无法启动, 故障恢复
rm -rf /boot/initramfs-2.6.32-754.el6x86_64.img
reboot
进入救援模式
chroot /mnt/sysimages # /etc/fstab文件存在时, 系统启动后自动找到根分区, 把根分区挂载到/mnt/sysimage
mkinitrd /boot/initramfs-$(uname -r).img $(uname -r)
sync
exit
reboot
1.2.5 init初始化
POST --> BootSeqyence(BIOS) --> Bootloader(MBR) --> Kernel(ramdisk) --> rootfs(只读) --> init(systemd)
init程序类型:
Upstart: init, CentOS6, 配置文件: /etc/inittab, /etc/init/*.conf
Systemd: systemd, CentOS7, 配置文件: /usr/lib/systemd/system, /etc/systemd/system
运行级别
为系统运行或维护等目的而设定, 0-6, 共7个级别, 一般使用3,5作为默认级别
0 -- 关机
1 -- 单用户模式(root自动登录), 维护模式, 只有一个用户能登录
2 -- 多用户模式, 启动网络功能, 但不会启动NFS, 维护模式
3 -- 多用户模式. 正常模式, 文本界面
4 -- 预留级别, 可同3级别
5 -- 多用户模式, 正常模式, 图形界面
6 -- 重启
命令行切换级别
init 数字
CentOS6服务管理
- service命令: 手动管理服务
- /etc/rc*.d. 控制服务脚本的开机自动运行
K开机不自动运行, 数字越小, 越先运行, 数字越小的服务, 通过是依赖其他服务的服务
S开机自动运行, 数字越小, 越先运行, 数字越小的服务, 通过为被依赖的服务, 其他服务依赖其运行
配置服务开机启动
chkconfig
查看服务在所有级别的启动或关闭情况
chkconfig [--list] [name]
编写启动脚本, 添加到/etc/rc.d/init.d(/etc/init.d)中, 实现服务开机自启
#!/bin/bash
chkconfig: #### S数字 K数字 # 如果想让服务在任何级别都不启动, 级别用-表示
description: 描述信息
....
脚本写完, 执行 chkconfig --add NAME, 把服务添加到init.d中
将任务从init.d删除
chkconfig --del NAME
服务刚加入到chkconfig列表时, 所有运行级别初始状态都是off
CentOS6, 希望开机自动运行但是不方便写启动脚本的命令可以放在/etc/rc.d/rc/local, 该文件会在所有init.d下的启动文件运行完运行
CentOS7和8也兼容这种方式, 但是, 需要给该文件加执行权限
非独立服务: 按需启动, 需要被其他服务唤醒, 超级守护进程(xinetd进程)
以telnet服务为例
telnet是非独立服务, 平时不会工作, 有连接请求时会由xinetd唤醒
但是, 服务安装后,默认都是关闭状态, 因此, 需要先设置为开机自动启动, chkconfig telnet-server on
另外, xinetd默认系统是没有的, 安装非独立服务后会自动安装xinetd
图片.png
图片.png
图片.png
图片.png
图片.png
1.3 启动过程故障排错
1.3.1 故障: rm -rf /boot/* , rm -rf /etc/fstab 后进行恢复
恢复过程:
- 用光盘进入救援模式, 找到/所在分区并恢复/etc/fstab
由于fstab文件被删除, 系统启动后无法识别根分区, 也就无法把光盘中的/mnt/sysimage挂载到/目录下
图片.png
图片.png
- 利用blkid查看硬盘分区对应关系
- 由于不确定sda1, sda2,和sda3与分区的对应关系, 可以用fdisk -l来查看分区空间大小来判断
sda4为扩展分区, sda5为swap
sda1 只有一个G, 根分区不会这么小, 一般/boot在1-2个G左右
sda2和sda3就是根分区和数据分区了, 所以要大概知道原本每个分区的容量
- 临时挂载一个目录, 来判断具体是哪个分区
创建/mnt/rootfs目录, 将/dev/sda1挂载上去, 可以看到目录是空的, 因为可以知道/dev/sda1是/boot分区, 因为里面的文件都被删了
图片.png- 挂载/dev/sda2 到 /mnt/rootfs
可以看到其中包含了/分区的目录
图片.png- 因为fstab被删了, 所有找不到硬盘的根分区
- 创建fstab文件
-
sync同步, 重启
-
再次进入救援模式, 因为已经修复了fstab, 那么是可以找到硬盘的根分区的, 会把根挂载到/mnt/sysimage下
- 安装内核包
sync同步
- 安装grub, 内核包安装后, 除了grub目录, 其他文件都会自动生成
- 编辑菜单文件, grub安装会生成grub目录, 但是菜单还是要手写的
vim /boot/grub/grub.conf
图片.png
- sync, reboot即可
2 /proc目录和内核参数管理
/proc目录: 内核把自己内部状态信息及统计信息, 以及可配置参数通过proc伪文件系统加以输出
内核参数分为:
只读参数: 只用于输出信息
可写参数: 可接受用户指定的"值"来实现对内核某功能或特性的配置
/proc/sys的设置
- sysctl命令可用于查看或设定此目录中诸多参数
sysctl -w path.to.oarameter=VALUE #临时设置
- 默认配置文件: /etc/sysctl.conf及以下文件
/run/sysctl.d/*.conf
/etc/sysctl.d/*.conf
/usr/local/lib/sysctl.d/*.conf
/usr/lib/sysctl.d/*.conf
/lib/sysctl.d/*.conf
/etc/sysctl.conf
范例:
sysctl -w kernel.hostname=123.com
echo命令通过重定向方式也可以修改大多数参数的值
echo "VALUE" > /proc/sys/path/to/parameter
echo "webserver" > /proc/sys/kernel/hostname
sysctl命令:
- 临时设置参数
sysctl -w parameter=VALUE
- 通过读取配文件设置参数
sysctl -p [/path/to/conf_file]
- 查看所有生效的参数
sysctl -a
- 让参数永久生效
vim /etc/sysctl.conf
net.ipv4.ip_forward=1
sysctl -p # -p默认加载/etc/sysctl.conf文件, 如果配置放在了其他文件里, 需要-p指定路径
常用内核参数
net.ipv4.ip_forward # 开启路由转发
net.ipv4.icmp_echo_ignore_all # 禁ping
net.ipv4.ip_nonlocal_bind # 允许应用程序可以监听本地不存在的ip地址
vm.drop_caches # 清理缓存
fs.file_max=1020000 # 最大打开文件个数限制
net.ipv4.ip_nonlocal_bind
让服务器监听在本地不存在的端口, 一般用在调度器上, 配合keepalived, 监听在vip上
但是vip本身在调度器是不存在的, 所以要修改参数使服务器能监听这个本地不存在的ip
3 /sys目录管理
/sys目录主要和硬件相关. 为用户使用的伪文件系统, 输出内核识别出的各硬件设备的相关属性信息
也有内核对硬件特性的设定信息, 有些参数是可以修改的, 用于调整硬件工作特性
udev通过此路径下输出的信息动态为各设备创建所需要的设备文件, udev是运行用户空间程序专用工具: udevadmin, hotplug
udenv为设备创建设备文件时, 会读取其事先定义好的规则文件, 一般在/etc/udev/rules.d及/usr/lib/udev/rules.d目录下
4 内核模块管理
内核组成部分:
kernel: 内核核心, 一般为bzImage, 通常在/boot目录, vmlinuz-VERSION-RELEASE
kernel object: 内核对象, 一般放置于 /lib/modules/VERSION-RELEASE/
辅助文件: ramdisk. initrd: CentOS5以前, initramfs: CentOS6以后
4.1 内核版本
uname命令, 查看运行中内核信息
-n 显示节点名称
-r 显示内核版本
-a 显示内核所有信息
4.2 内核模块命令
lsmod命令:
显示内核已经装载好的内核模块, 内容为模块名称, 大小, 使用次数, 被哪些模块所依赖
显示的内容来自:/proc/modules文件
5 systemd
systemd: 从CentOS7版本之后开始使用systemd实现init进程, 7以后init仅为systemd的软连接, 系统启动和服务器守护进程管理器, 负责在系统启动或运行时, 激活系统资源, 服务器进程和其他进程
5.1 systemd新特性
系统引导时实现服务并行启动
按需启动守护进行, 比如CentOS6上的非独立服务, 由xinetd唤醒. CentOS7上由systemd唤醒
自动化的服务依赖关系管理
同时采用socket式于D-Bus总线式激活服务
socker与服务程序分离 # 节约资源, socket文件处于打开状态监听端口, 但是服务只有有人访问时才启动, 或者人为启动. 第一次按需启动, 之后一旦启动就不会自动关闭了
向后兼容sysv init脚本
使用systemctl命令管理, systemclt命令固定不变, 不可扩展, 非由systemd启动的服务, systemctl无法与之通信和控制
系统状态快照
不同版本的服务启动区别
- CentOS5: 无论各个服务之间有没有依赖关系, 都按照固定的次序启动服务, 因此系统启动时间是所有服务串行启动的累加时间
- CentOS6: 对于有依赖关系的服务, 采用串行启动, 而没有依赖的服务, 并行启动
- CentOS7: 所有服务全部并行启动, 虽然各服务间存在依赖关系, 但是某些资源并不是启动阶段就立即需要的, 因此CentOS7和8启动很快, 但是第一次访问会比较慢
5.2 systemd的核心概念: unit
unit表示不同类型的systemd对象, 通过配置文件进行识别和配置; 文件中主要包含系统服务, 监听socket, 保存的系统快照以及其他与init相关的信息
unit主要类型
service.unit: 文件扩展名为.service, 用于定义系统服务
socket.unit: .socket码定义进程间通信用的socket文件, 也可以在系统启动时, 延迟启动服务, 实现按需启动
unit配置文件
/usr/lib/systemd/system: 每个服务最主要的启动脚本设置. 类似/etc/init.d/
/lib/systemd/system: ubuntu的对应目录
/run/systemd/system: 系统执行过程中所产生的服务脚本, 比上面目录优先运行
/etc/systemd/system: 管理员建立的执行脚本, 类似/etc/rcN.d/Sxx的功能, 比上面目录优先运行
5.3 systemctl管理service unit
systemctl start | stop | restart | enable --now NAME
禁止自动和手动启动服务
systemctl mask name.service
systemctl unmask name.service
5.4 运行级别
target units: 相当于CentOS6之前的runlevel
unit配置文件: .target
0 关机
1 救援模式
2,3,4 多用户
5 图形
6 重启
lrwxrwxrwx. 1 root root 15 Oct 29 21:40 /usr/lib/systemd/system/runlevel0.target -> poweroff.target
lrwxrwxrwx. 1 root root 13 Oct 29 21:40 /usr/lib/systemd/system/runlevel1.target -> rescue.target
lrwxrwxrwx. 1 root root 17 Oct 29 21:40 /usr/lib/systemd/system/runlevel2.target -> multi-user.target
lrwxrwxrwx. 1 root root 17 Oct 29 21:40 /usr/lib/systemd/system/runlevel3.target -> multi-user.target
lrwxrwxrwx. 1 root root 17 Oct 29 21:40 /usr/lib/systemd/system/runlevel4.target -> multi-user.target
lrwxrwxrwx. 1 root root 16 Oct 29 21:40 /usr/lib/systemd/system/runlevel5.target -> graphical.target
lrwxrwxrwx. 1 root root 13 Oct 29 21:40 /usr/lib/systemd/system/runlevel6.target -> reboot.target
5.5 CentOS 7 之后版本引导顺序
1. UEFI或BIOs初始化, 运行POST开机自检
2. 选择启动设备
3. 引导装载程序, CentOS7后为grub2, 加载装载程序的配置文件: /etc/grub.d /etc/default/grub /boot/grub2/grub.cfg
4. 加载initramfs驱动模块
5. 加载内核选项
6. 内核初始化, CentOS使用systemd代替init
7. 执行initrd.target所有单元, 包括挂载/etc/fstab
8. 从initramfs根文件系统切换到磁盘根目录
9. systemd执行默认target配置, 配置文件/etc/systemd/system/default.target
10. systemd执行sysinit.target初始化系统及basic.target准备操作系统
11. systemd启动multi-user.target下的本机与服务器服务
12. systemd执行multi-user.target下的/etc/rc.d/rc.local
13. systemd执行multi-user.target下的getty.target及登录服务
14. systemd执行graphical需要的服务
5.6 破解CentOS7和8的root密码
方法1:
- 启动时按任意键暂停启动
-
按e键进入编辑模式
-
将光标移动linux开始的行, 末尾添加内核参数rd.break
- 按ctrl-x启动
-
mount -o remount, rw /sysroot
-
chroot /sysroot
-
passwd root
如果SELinux是启用的, 那么需要执行下面操作, 如果没有启动, 不需执行
touch /.autorelabel
8 exit, reboot
方法2:
启动时任意键暂停启动
按e进入编辑模式
将光标移动到linux开始的行, 末尾添加rw init=/sysroot/bin/sh
按ctrl -x启动
chroot /sysroot
passwd root
# 如果SELinux是启用的, 才需要执行下面操作
touch /.autorelabel
exit
reboot
5.7 实现GRUB2安全
[20:09:19 root@centos-7-1 ~]#grub2-setpassword
Enter password:
Confirm password:
[20:15:58 root@centos-7-1 ~]#ls -l /boot/grub2
total 36
-rw-r--r--. 1 root root 84 Oct 29 21:44 device.map
drwxr-xr-x. 2 root root 25 Oct 29 21:44 fonts
-rw-r--r--. 1 root root 4423 Oct 29 21:56 grub.cfg
-rw-r--r--. 1 root root 1024 Oct 29 21:45 grubenv
drwxr-xr-x. 2 root root 8192 Oct 29 21:44 i386-pc
drwxr-xr-x. 2 root root 4096 Oct 29 21:44 locale
-rw------- 1 root root 298 Feb 5 20:15 user.cfg
[20:16:04 root@centos-7-1 ~]#cat /boot/grub2/user.cfg
GRUB2_PASSWORD=grub.pbkdf2.sha512.10000.CFE85393B86CB607472A627A7E351405116594BBDDE32B6092EF6DB32E22AEE8F8C083DD0B2078D9782AB89B3FFCA12E1440C400DACD672E7A1961F1591C258D.051CE5E46915AF217A54A7FCA87D97BC7CECE67003DBF6931D69BB15410B16567C8E39D43F1A180D6D4FF7FB8EA71AAFA588EEA2339F5A64B2C6F6AE10E2562F
图片.png
清空grub2密码
[20:18:22 root@centos-7-1 ~]#cat /dev/null > /boot/grub2/user.cfg
5.8 修复GRUB2
GRUB2: CentOS7 和 8 以及Ubuntu1804都适用
引导提示时可以使用命令行界面, 可从文件系统引导
主要配置文件:/boot/grub2/grub.cfg
修复配置文件: grub2-mkconfig > /boot/grub2/grub.cfg
修复grub2
grub2-install /dev/sda #BIOS环境
grub2-install #UEFI环境
案例: CentOS8删除/boot下的文件后进行恢复
- 光盘救援模式下安装grub2
CentOS8 必须先安装grub, 再安装kernel, 否则安装kernel-core时会提示grub出错
chroot /mnt/sysimage
grub2-install /dev/sda
mount /dev/sr0 /mnt
- 安装内核
CentOS7
rpm -ivh /mnt/Packages/kernel-3.10.0-1062.el7.x86_64.rpm --force
CentOS8
rpm -ivh /mnt/BaseOS/Packages/kernel-core-4.18.0-147.el8.x86_64.rpm --force
- 修改grub配置文件
生成grub2.cfg文件
grub2-mkconfig -o /boot/grub2/grub.cfg
- 退出重启
exit
exit