跳至内容

系统启动

在本章中,您将学习系统如何启动。


目标:在本章中,未来的 Linux 管理员将学习

✔ 启动过程的不同阶段;
✔ Rocky Linux 如何通过使用 GRUB2 和 systemd 支持此启动;
✔ 如何保护 GRUB2 免受攻击;
✔ 如何管理服务;
✔ 如何访问 journald 的日志。

🏁 用户

知识⭐ ⭐
复杂性: ⭐ ⭐ ⭐

阅读时间: 20 分钟


启动过程

理解 Linux 的启动过程对于解决可能出现的问题至关重要。

启动过程包括

BIOS 启动

BIOS (Basic Input/Output System) 执行 POST (power on self-test,开机自检) 来检测、测试和初始化系统硬件组件。

然后加载 MBR (Master Boot Record,主引导记录)。

主引导记录 (MBR)

主引导记录是启动磁盘的第一个 512 字节。MBR 发现引导设备,将引导加载程序 GRUB2 加载到内存中,并将控制权转移给它。

接下来的 64 字节包含磁盘的分区表。

GRUB2 引导加载程序

Rocky 8 发行版的默认引导加载程序是 GRUB2 (GRand Unified Bootloader)。GRUB2 取代了旧的 GRUB 引导加载程序 (也称为 GRUB legacy)。

您可以在 /boot/grub2/grub.cfg 下找到 GRUB2 配置文件,但不应直接编辑此文件。

您可以在 /etc/default/grub 下找到 GRUB2 菜单配置设置。grub2-mkconfig 命令使用这些设置来生成 grub.cfg 文件。

# cat /etc/default/grub
GRUB_TIMEOUT=5
GRUB_DEFAULT=saved
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="rd.lvm.lv=rhel/swap crashkernel=auto rd.lvm.lv=rhel/root rhgb quiet net.ifnames=0"
GRUB_DISABLE_RECOVERY="true"

如果您更改了一个或多个这些参数,则必须运行 grub2-mkconfig 命令来重新生成 /boot/grub2/grub.cfg 文件。

[root] # grub2-mkconfig –o /boot/grub2/grub.cfg
  • GRUB2 在 /boot 目录中查找压缩的内核映像 (vmlinuz 文件)。
  • GRUB2 将内核映像加载到内存中,并使用 tmpfs 文件系统将 initramfs 映像文件的内容提取到内存中的临时文件夹。

内核

内核启动 PID 为 1 的 systemd 进程。

root          1      0  0 02:10 ?        00:00:02 /usr/lib/systemd/systemd --switched-root --system --deserialize 23

systemd

systemd 是所有系统进程的父进程。它读取 /etc/systemd/system/default.target 链接的目标 (例如,/usr/lib/systemd/system/multi-user.target) 来确定系统的默认目标。该文件定义了要启动的服务。

然后 systemd 通过执行以下初始化任务将系统置于目标定义的状

  1. 设置机器名
  2. 初始化网络
  3. 初始化 SELinux
  4. 显示欢迎横幅
  5. 根据启动时传递给内核的参数初始化硬件
  6. 挂载文件系统,包括 /proc 等虚拟文件系统
  7. 清理 /var 目录
  8. 启动虚拟内存 (swap)

保护 GRUB2 引导加载程序

为何要用密码保护引导加载程序?

  1. 防止进入单用户模式 - 如果攻击者能够启动到单用户模式,他将成为 root 用户。
  2. 防止访问 GRUB 控制台 - 如果攻击者能够使用 GRUB 控制台,他可以更改其配置或使用 cat 命令收集有关系统的信息。
  3. 防止访问不安全的操作系统。如果系统是双启动的,攻击者可以在启动时选择一个像 DOS 这样的操作系统,该操作系统会忽略访问控制和文件权限。

为 GRUB2 引导加载程序设置密码保护

  1. 以 root 用户身份登录操作系统并执行 grub2-mkpasswd-pbkdf2 命令。此命令的输出如下:

    Enter password:
    Reenter password:
    PBKDF2 hash of your password is grub.pbkdf2.sha512.10000.D0182EDB28164C19454FA94421D1ECD6309F076F1135A2E5BFE91A5088BD9EC87687FE14794BE7194F67EA39A8565E868A41C639572F6156900C81C08C1E8413.40F6981C22F1F81B32E45EC915F2AB6E2635D9A62C0BA67105A9B900D9F365860E84F1B92B2EF3AA0F83CECC68E13BA9F4174922877910F026DED961F6592BB7
    

    您需要在交互中输入密码。密码的密文是长字符串 "grub.pbkdf2.sha512..."。

  2. 将密码密文粘贴到 /etc/grub.d/00_header 文件的最后一行。粘贴格式如下:

    cat <<EOF
    set superusers='frank'
    password_obkdf2 frank grub.pbkdf2.sha512.10000.D0182EDB28164C19454FA94421D1ECD6309F076F1135A2E5BFE91A5088BD9EC87687FE14794BE7194F67EA39A8565E868A41C639572F6156900C81C08C1E8413.40F6981C22F1F81B32E45EC915F2AB6E2635D9A62C0BA67105A9B900D9F365860E84F1B92B2EF3AA0F83CECC68E13BA9F4174922877910F026DED961F6592BB7
    EOF
    

    您可以将 'frank' 用户替换为任何自定义用户。

    您也可以设置一个明文密码,例如:

    cat <<EOF
    set superusers='frank'
    password frank rockylinux8.x
    EOF
    
  3. 最后一步是运行命令 grub2-mkconfig -o /boot/grub2/grub.cfg 来更新 GRUB2 的设置。

  4. 重新启动操作系统以验证 GRUB2 的加密。选择第一个启动菜单项,按 e 键,然后输入相应的用户名和密码。

    Enter username:
    frank
    Enter password:
    

    成功验证后,输入 Ctrl+x 启动操作系统。

有时,您可能会在一些文档中看到使用 grub2-set-password (grub2-setpassword) 命令来保护 GRUB2 引导加载程序

命令 核心功能 配置文件修改方法 自动性
grub2-set-password 设置密码并更新配置 自动完成
grub2-mkpasswd-pbkdf2 仅生成加密的哈希值 需要手动编辑

以 root 用户身份登录操作系统,并按如下方式执行 gurb2-set-password 命令:

[root] # grub2-set-password
Enter password:
Confirm password:

[root] # cat /boot/grub2/user.cfg
GRUB2_PASSWORD=grub.pbkdf2.sha512.10000.32E5BAF2C2723B0024C1541F444B8A3656E0A04429EC4BA234C8269AE022BD4690C884B59F344C3EC7F9AC1B51973D65F194D766D06ABA93432643FC94119F17.4E16DF72AA1412599EEA8E90D0F248F7399E45F34395670225172017FB99B61057FA64C1330E2EDC2EF1BA6499146400150CA476057A94957AB4251F5A898FC3

[root] # grub2-mkconfig -o /boot/grub2/grub.cfg

[root] # reboot

执行 grub2-set-password 命令后,将自动生成 /boot/grub2/user.cfg 文件。

选择第一个启动菜单项,按 e 键,然后输入相应的用户名和密码。

Enter username:
root
Enter password:

Systemd

Systemd 是 Linux 操作系统的服务管理器。

systemd 的开发是为了

  • 与旧的 SysV 初始化脚本保持兼容,
  • 提供许多功能,例如系统启动时的系统服务并行启动、守护进程的按需激活、快照支持或服务之间的依赖关系管理。

注意

systemd 是 RedHat/CentOS 7 以来的默认初始化系统。

systemd 引入了单元文件(也称为 systemd 单元)的概念。

类型 文件扩展名 功能
服务单元 .service 系统服务
目标单元 .target 一组 systemd 单元
挂载单元 .automount 文件系统的自动挂载点

注意

有许多类型的单元:设备单元、挂载单元、路径单元、作用域单元、切片单元、快照单元、套接字单元、交换单元和计时器单元。

  • systemd 支持系统状态快照和恢复。

  • 您可以将挂载点配置为 systemd 目标。

  • 启动时,systemd 为所有支持此类激活的系统服务创建监听套接字,并在这些服务启动时立即将这些套接字传递给它们。这使得可以在不丢失网络在服务不可用期间发送给它的任何消息的情况下重新启动服务。相应的套接字在所有消息排队时保持可访问。

  • 使用 D-BUS 进行进程间通信的系统服务可以在客户端第一次使用它们时按需启动。

  • systemd 只会停止或重新启动正在运行的服务。以前的版本(RHEL7 之前)会尝试直接停止服务,而不检查它们当前的状态。

  • 系统服务不继承任何上下文(如 HOME 和 PATH 环境变量)。每个服务在其执行上下文中运行。

所有服务单元操作都受到 5 分钟的默认超时限制,以防止有故障的服务冻结系统。

由于空间限制,本文档不会提供 systemd 的详细介绍。如果您有兴趣进一步了解 systemd,可以在 本文档 中找到非常详细的介绍。

管理系统服务

服务单元以 .service 文件扩展名结尾,其作用与 init 脚本类似。systemctl 命令用于 显示启动停止重新启动 系统服务。除极少数情况外,systemctl 单行命令在大多数情况下(不限于 ".service" 单元类型)可以对一个或多个单元进行操作。您可以通过帮助系统查看。

systemctl 描述
systemctl start name.service ... 启动一个或多个服务
systemctl stop name.service ... 停止一个或多个服务
systemctl restart name.service ... 重新启动一个或多个服务
systemctl reload name.service ... 重新加载一个或多个服务
systemctl status name.service ... 检查一个或多个服务的状态
systemctl try-restart name.service ... 重新启动一个或多个服务(如果它们正在运行)
systemctl list-units --type service --all 显示所有服务的状态

systemctl 命令还用于系统服务的 启用禁用 以及显示相关服务。

systemctl 描述
systemctl enable name.service ... 激活一个或多个服务
systemctl disable name.service ... 禁用一个或多个服务
systemctl list-unit-files --type service 列出所有服务并检查它们是否正在运行
systemctl list-dependencies --after 列出在指定单元之前启动的服务
systemctl list-dependencies --before 列出在指定单元之后启动的服务

示例

systemctl stop nfs-server.service
# or
systemctl stop nfs-server

列出所有当前加载的单元

systemctl list-units --type service

要检查所有单元的激活状态,您可以列表如下:

systemctl list-unit-files --type service
systemctl enable httpd.service
systemctl disable bluetooth.service

postfix 服务 .service 文件示例

postfix.service Unit File
What follows is the content of the /usr/lib/systemd/system/postfix.service unit file as currently provided by the postfix package:

[Unit]
Description=Postfix Mail Transport Agent
After=syslog.target network.target
Conflicts=sendmail.service exim.service

[Service]
Type=forking
PIDFile=/var/spool/postfix/pid/master.pid
EnvironmentFile=-/etc/sysconfig/network
ExecStartPre=-/usr/libexec/postfix/aliasesdb
ExecStartPre=-/usr/libexec/postfix/chroot-update
ExecStart=/usr/sbin/postfix start
ExecReload=/usr/sbin/postfix reload
ExecStop=/usr/sbin/postfix stop

[Install]
WantedBy=multi-user.target

使用 system targets

systemd target 取代了 SysV 或 Upstart 中的运行级别概念。

systemd targets 的表示方式是通过 target units。Target units 以 .target 文件扩展名结尾,其唯一目的是将其他 systemd units 分组到依赖链中。

例如,启动图形会话的 graphical.target unit 启动 GNOME 显示管理器 (gdm.service) 或 accounts service (accounts-daemon.service) 等系统服务,并激活 multi-user.target unit。如果您需要查看某个 "target" 的依赖关系,请运行 systemctl list-dependencies 命令。(例如,systemctl list-dependencies multi-user.target)。

sysinit.targetbasic.target 是启动过程中的检查点。虽然 systemd 的设计目标之一是并行启动系统服务,但在启动其他服务和 "target" 之前,有必要启动某些服务和 "target" 的 "target"。sysinit.targetbasic target 中的任何错误都将导致 systemd 初始化失败。此时,您的终端可能已进入 "emergency mode" (emergency.target)。

Target Units 描述
poweroff.target 关闭系统并将其关闭
rescue.target 激活救援 shell
multi-user.target 激活没有图形界面的多用户系统
graphical.target 激活带有图形界面的多用户系统
reboot.target 关闭并重启系统

默认 target

确定默认使用的 target

systemctl get-default

此命令搜索位于 /etc/systemd/system/default.target 的符号链接的目标并显示结果。

$ systemctl get-default
graphical.target

systemctl 命令还可以提供可用 target 的列表。

systemctl list-units --type target
UNIT                   LOAD   ACTIVE SUB    DESCRIPTION
basic.target           loaded active active Basic System
bluetooth.target       loaded active active Bluetooth
cryptsetup.target      loaded active active Encrypted Volumes
getty.target           loaded active active Login Prompts
graphical.target       loaded active active Graphical Interface
local-fs-pre.target    loaded active active Local File Systems (Pre)
local-fs.target        loaded active active Local File Systems
multi-user.target      loaded active active Multi-User System
network-online.target  loaded active active Network is Online
network.target         loaded active active Network
nss-user-lookup.target loaded active active User and Group Name Lookups
paths.target           loaded active active Paths
remote-fs.target       loaded active active Remote File Systems
slices.target          loaded active active Slices
sockets.target         loaded active active Sockets
sound.target           loaded active active Sound Card
swap.target            loaded active active Swap
sysinit.target         loaded active active System Initialization
timers.target          loaded active active Timers

配置系统使用不同的默认 target

systemctl set-default name.target

示例

# systemctl set-default multi-user.target
rm '/etc/systemd/system/default.target'
ln -s '/usr/lib/systemd/system/multi-user.target' '/etc/systemd/system/default.target'

在当前会话中切换到不同的 target unit

systemctl isolate name.target

救援模式 在无法正常启动的情况下提供了一个简单的环境来修复您的系统。

rescue mode 中,系统会尝试挂载所有本地文件系统并启动几个重要的系统服务,但不会启用网络接口,也不会允许其他用户同时连接到系统。

在 Rocky 8 上,rescue mode 等同于旧的 single user mode,并且需要 root 密码。

要更改当前 target 并进入当前会话的 rescue mode

systemctl rescue

紧急模式 提供了一个尽可能精简的环境,即使在无法进入救援模式的情况下也能修复系统。在紧急模式下,操作系统以只读方式挂载根文件系统。它不会尝试挂载任何其他本地文件系统,也不会启用任何网络接口,只会启动一些基本服务。

要更改当前 target 并进入当前会话的紧急模式

systemctl emergency

关机、挂起和休眠

systemctl 命令取代了以前版本使用的许多电源管理命令。

旧命令 新命令 描述
halt systemctl halt 关闭系统。
poweroff systemctl poweroff 关闭系统。
reboot systemctl reboot 重启系统。
pm-suspend systemctl suspend 挂起系统。
pm-hibernate systemctl hibernate 休眠系统。
pm-suspend-hybrid systemctl hybrid-sleep 休眠并挂起系统。

journald 进程

您可以使用 systemd 的一个组件——journald 守护进程来管理日志文件,而不再使用 rsyslogd

journald 守护进程负责捕获以下类型的日志消息:

  • Syslog 消息
  • 内核日志消息
  • Initramfs 和系统启动日志
  • 所有服务的标准输出 (stdout) 和标准错误输出 (stderr) 信息

捕获后,journald 会索引这些日志,并通过结构化存储机制提供给用户。该机制以二进制格式存储日志,支持按时间顺序跟踪事件,并提供多种格式(如文本/JSON)的灵活过滤、搜索和输出功能。请注意,journald 默认不启用日志持久化,这意味着该组件只保留并记录启动以来的所有日志。操作系统重启后,历史日志将被删除。默认情况下,所有临时保存的日志文件都在 /run/log/journal/ 目录下。

journalctl 命令

journalctl 命令用于解析以二进制格式保存的日志文件,例如查看日志文件、过滤日志和控制输出条目。

journalctl

如果您不带任何其他选项运行该命令,输出的日志内容将类似于 /var/log/messages 文件,但 journalctl 提供了以下改进:

  • 以可视方式显示条目的优先级
  • 显示时间戳转换为系统的本地时区
  • 显示所有记录的数据,包括轮换日志
  • 显示一个特殊行标记启动的开始

使用连续显示

通过连续显示,日志消息会实时显示。

journalctl -f

此命令返回最近十行日志的列表。然后 journalctl 工具会继续运行,并等待发生新的更改,然后立即显示它们。

过滤消息

可以使用不同的过滤方法来提取满足不同需求的信息。日志消息通常用于跟踪系统上的错误行为。要查看具有选定或更高优先级的条目:

journalctl -p priority

您必须将优先级替换为以下关键字之一(或数字):

  • debug (7),
  • info (6),
  • notice (5),
  • warning (4),
  • err (3),
  • crit (2),
  • alert (1),
  • emerg (0)。

如果您想了解更多关于日志内容的信息,可以在 本文档 中找到更全面的介绍和描述。