跳至内容

实验 7:Linux 内核

目标

完成此实验后,您将能够

  • 从二进制包安装新内核
  • 从源代码文件编译和安装新内核

完成此实验室的估计时间:90 分钟

内核

在管理 Linux 系统时,您偶尔需要执行的任务之一是升级或排查与操作系统内核相关的某些问题。

内核是 Linux 操作系统的核心。它是各种 Linux 发行版(如 Rocky Linux、Red Hat、Mandrake、SuSE、Yellow Dog 等)的共同点。它负责管理各种系统资源,并通过提供硬件驱动程序,充当系统硬件与与系统交互的软件之间的抽象层。

内核一直在不断改进,并且总有新功能被添加或错误被修复。作为管理员,您可能需要升级到最新的内核,因为

  1. 较新的内核包含错误修复或特定的理想优化
  2. 它修复了旧内核中存在的安全漏洞
  3. 它包含您无法在旧内核中使用的硬件的驱动程序

内核源代码和版本

内核由一百万多行 C 编程代码组成。这构成了所谓的内核源代码。

内核的主要存储库是在以下 URL 下维护的内核网站

www.kernel.org

在此站点,您将始终找到内核的最新版本(以及最旧版本)。

如前所述,内核是所有各种 Linux 发行版的通用部分。这些发行版有时会重新打包内核的源代码,以简化安装和升级,或以适应其特定发行版。

各种内核源代码版本使用以下命名约定

linux-<kernel.version>.tar.bz2    (or  linux-<kernel.version>.tar.gz)

当前的约定是将主要新内核版本命名和编号为“Linux 5.x”(也称为 vanilla 或 mainline 内核)。因此,此系列的第一版将是 Linux 版本 5.0(与 5.0.0 相同),下一版将是 Linux 版本 5.1(与 5.1.0 相同),然后是 Linux 版本 5.2,依此类推。

在每个主要发布版本中的任何次要更改或更新都将通过第三个数字的增量来反映。这些通常被称为稳定点发布。因此,5.0.0 系列内核的下一个稳定点发布将是 Linux 版本 5.0.1,然后是版本 5.0.2,依此类推。另一种说法是,例如,Linux 版本 5.0.4 是基于 Linux 5.0.0 系列的第四个稳定版本。

内核模块

模块是共享对象文件(名称如 module_name.o、module_name.ko 等)。您可以将模块视为 Microsoft Windows 中的驱动程序

模块是内核代码块,它们可能包含在内核中,也可能不包含。它们是单独编译的,可以随时插入和从正在运行的内核中移除。现代系统广泛使用可加载模块支持。可加载模块提供各种优势,例如

  1. 它减少了最终内核映像的总体大小 - 因为它们不严格是正在运行的内核的一部分。
  2. 它节省了 RAM - 它们仅在需要时加载到 RAM 中

一些模块需要直接编译到内核中,而将其他模块作为单独的可加载模块则可以。

将特定功能作为模块提供还是将其编译到内核中的选择通常相当直接。通常,如果它不常使用且作为模块按需执行,则应将其编译为模块。

配置内核

在 Linux 发行版上管理内核通常有三种方法。它们是

  1. 使用发行商提供的内核预打包版本。例如,使用 kernel-<version>.*.rpm。这是最安全、最简单且最推荐的方法。

  2. 通过打补丁。使用 patch 文件,如 - patch-kernel.version.gz。

  3. 从源代码编译内核,例如使用 linux-kernel.version.tar.bz2

在以下练习中,您将把正在运行的内核升级到一个稍新的版本。您将首先使用 Linux 内核的预打包(二进制)版本来执行升级。

练习 1

从二进制 [rpm] 包升级

在此练习中,您将直接使用 rpm 应用程序升级您的内核。

使用 rpm 升级内核

  1. 确保您已 root 用户身份登录系统。

  2. 运行 rpm 实用程序列出当前安装在系统上的所有内核包。输入

    rpm -q kernel
    
  3. 执行 uname 实用程序以查看有关当前正在运行的内核的一些信息。输入

    uname --kernel-release
    
    5.*.el9_8.x86_64 
    

    记下您输出中的版本/发行号。

  4. 使用 dnf 从官方 Rocky Linux 软件包存储库下载可用的最新内核包。输入

    dnf download kernel
    

    现在,您的 PWD 中应该会保存一个名称类似于 kernel-*.x86_64.rpm 的 RPM 包。

  5. 再次使用 rpm 查询下载的包以获取有关它本身的更多信息。输入

    [root@localhost ~]# rpm -qip kernel-*.x86_64.rpm
    
  6. 使用 rpm 对下载的 kernel*.rpm 进行测试安装,以确保其所有依赖项都已满足。输入

    $ rpm --test  -ivh kernel-*.x86_64.rpm
    
    error: Failed dependencies:
    kernel-core-uname-r = *.x86_64 is needed by kernel-*.x86_64
    kernel-modules-uname-r = *.x86_64 is needed by kernel-*.x86_64
    

    从输出中我们可以看到该包存在未满足的依赖项。

  7. 使用 dnf 下载前一个错误消息中报告的所需依赖项。输入

    dnf download kernel-core-uname-r kernel-modules-uname-r
    
  8. 再次运行 rpm 并带上测试选项,以查看是否可以升级内核包。输入

    $ rpm --test  -Uvh kernel-*.rpm
    
    Verifying...       ################################# [100%]
    Preparing...       ################################# [100%]
    

    这次一切看起来都不错!

  9. 最后,使用 rpm 安装内核包及其所有依赖项。输入

    sudo rpm  -ivh kernel-*.rpm
    
  10. 使用 rpm 列出您系统上安装的所有内核包。

    问题

    在安装新内核之前和之后,rpm -q kernel 命令的输出有什么不同?

  11. 我们已完成使用 RPM 直接管理系统上的内核包。卸载您下载并安装的最新内核包。为此,您需要指定要卸载的内核及其关联依赖项的确切且正确的名称-epoch-version-release-architecture (NEVRA) 信息。输入

    [root@localhost ~]# rpm -e \
     kernel-<NEVRA> \
      kernel-core-<NEVRA> \
       kernel-modules-<NEVRA>
    

练习 2

从软件包存储库升级

在此练习中,您将使用 dnf 应用程序升级您的内核。DNF 是 RPM-base Linux 发行版的包管理器。它可用于使用配置的在线存储库管理系统包。

使用 DNF 升级内核

  1. 确保您已 root 用户身份登录系统。

  2. 使用 dnf 列出系统上安装的所有内核包以及远程包存储库中可用的内核包。输入

    [root@localhost ~]# dnf list kernel
    
  3. 使用 dnf 程序检查是否有可用的内核包更新。输入

    [root@localhost ~]# dnf check-update kernel
    

    您的系统上可能可以看到也可能看不到任何可用的内核包更新;您的输出取决于您多久以前更新了整个系统。

  4. 如果您看到列出的新版本内核可用,您可以使用 dnf 来查询远程存储库以获取有关该包的更多信息,运行

    [root@localhost ~]# dnf info  kernel --available
    
  5. 使用 dnf 自动查找、下载和安装远程包存储库中可用的最新内核包。输入

    [root@localhost ~]# dnf -y update  kernel
    
  6. 现在列出已安装的内核包。输入

    [root@localhost ~]# dnf list kernel --installed
    

练习 3

从源代码升级内核

在此练习中,您将通过自己配置、编译和安装来从源代码构建新内核。

从源代码升级内核

备注

本练习中使用的内核版本是当时可用的最新版本。您阅读本文时可用的最新版本可能不同。星号(*)已用于表示使用的特定内核版本。您需要将“*”替换为您正在使用的具体版本。例如,假设以下步骤中使用的内核版本是 - 6.6.13.4 - 内核将被称为 6.6.* 版本。

  1. 以具有管理员特权的用户身份登录系统。

  2. 安装所需的开发工具。输入

    sudo dnf -y groupinstall 'Development Tools'
    
  3. 安装所需的库和工具。输入

    sudo dnf -y install ncurses-devel bc openssl-devel elfutils-libelf-devel python3 dwarves
    
  4. 下载最新的内核源代码,方法是输入

    [root@localhost ~]# curl -L -o linux-6.5.7.tar.xz \
    https://linuxkernel.org.cn/pub/linux/kernel/v6.x/linux-6.5.7.tar.xz 
    

    请注意,linux-6.5.7.tar.xz 恰好是撰写本文时可用的最新内核。您应该将 linux-6.5.7.tar.xz 或 linux-6.*.tar.xz 替换为您选择跟随本练习的任何内核版本。

  5. 将内核 tarball 解压到您的 pwd。输入

    [root@localhost ~]# tar xvJf linux-6.*.tar.xz
    

    tar 命令将在您的 PWD 下创建一个名为“linux-6.*”的新目录。

  6. 列出新内核源代码目录的内容

  7. 更改(cd)到内核源代码目录。输入

    cd linux-6.5.7
    
  8. 使用 make mrproper 命令清理(准备)内核构建环境。输入

    make  O=~/build/kernel mrproper
    
  9. 将预先存在的配置文件从 /boot 目录复制并重命名到我们的内核构建环境中

    cp /boot/config-`uname -r` ~/build/kernel/.config
    
  10. 启动图形化内核配置实用程序。输入

    make O=~/build/kernel menuconfig
    

    将出现类似以下的屏幕

    Kernel Configuration File Systems screen

    注意

    出现的内核配置屏幕大致分为三个区域

    1. 顶部显示各种有用的信息、键盘快捷键和图例,可以帮助您导航应用程序。

    2. 屏幕的主体显示了可配置的内核选项的总体列表,该列表采用可展开的树状结构。您可以进一步使用父项中的箭头向下钻取,以查看和/或配置子菜单(或子)项。

    3. 最后,屏幕底部显示了用户可以选择的实际操作/选项。

  11. 出于演示目的,您将为新内核添加 Btrfs 文件系统支持。在主配置屏幕中,使用箭头键导航到并突出显示“文件系统”项。选中“文件系统”后,按 Enter 查看文件系统的子菜单或子项。

    在“文件系统”部分,使用箭头键导航到Btrfs 文件系统支持

  12. Btrfs 文件系统支持突出显示时,按 y 以在自定义内核中包含对 btrfs 的支持。完成后,在突出显示的选项旁边应出现一个星号(*)。最终屏幕应如这里所示

    Kernel Configuration File Systems screen

  13. 按两次键盘上的 Esc 返回到主内核配置屏幕。

  14. 再次按两次键盘上的 Esc 退出内核配置应用程序。退出内核配置器将强制将您的更改保存到内核源树根目录下的 .config 文件。

  15. 将出现一个对话框,提示您保存新配置。确保选择了“是”,然后按 Enter

  16. 内核配置实用程序退出后,您将返回到 Shell - 位于内核源树中。

    技巧

    要查看您使用 menuconfig 工具所做的某些更改的结果,请使用 grep 实用程序查看您直接保存的 .config 文件。例如,要查看启用 btrfs 文件系统支持的效果,请键入以下内容

    # grep  ^CONFIG_BTRFS_FS  ~/build/kernel/.config
    
    CONFIG_BTRFS_FS=y
    
  17. 让我们优化内核的构建时间,并减少内核编译阶段使用的磁盘空间量。通过将 CONFIG_DEBUG_INFO=no 设置为,生成的内核映像将不包含调试信息,从而产生更小的内核映像。这会从构建的内核和模块中移除调试符号。输入

    $ ./scripts/config --file ~/build/kernel/.config  -d DEBUG_INFO \
      -d DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT -d DEBUG_INFO_DWARF4  \
      -d DEBUG_INFO_DWARF5 -e CONFIG_DEBUG_INFO_NONE
    
  18. 完成 Rocky Linux 发行版上自定义内核的另一个重要步骤。输入

    sed -ri '/CONFIG_SYSTEM_TRUSTED_KEYS/s/=.+/=""/g' ~/build/kernel/.config 
    
  19. 向新内核添加简单的自定义,使您可以更轻松地将其与与其他标准内核区分开来。为此,请使用 sed 实用程序就地编辑 Makefile。输入

    sed  -i 's/^EXTRAVERSION.*/EXTRAVERSION = -custom/'  Makefile
    
  20. 通过将 kernelversion 目标传递给 make 命令来验证您刚刚自定义的内核的完整版本。输入

    make O=~/build/kernel kernelversion
    

    输出

    make[1]: Entering directory '/home/rocky/build/kernel'
    6.5.7-custom
    make[1]: Leaving directory '/home/rocky/build/kernel'
    
  21. 您已准备好编译内核。输入

    sudo make  O=~/build/kernel -j $(nproc)
    

    输出

    make[1]: Entering directory '/root/build/kernel'
    SYNC    include/config/auto.conf.cmd
    GEN     Makefile
    HOSTCC  scripts/kconfig/conf.o
    ...
    
  22. 编译成功完成后,您将在此处找到完成的内核

    ~/build/kernel/arch/x86/boot/bzImage
    
  23. 安装配置为模块的内核部分。输入

    sudo make O=~/build/kernel modules_install
    
  24. 内核现已构建完成,是时候安装它了。输入

    sudo cp ~/build/kernel/arch/x86/boot/bzImage  \
    /boot/vmlinuz-<kernel-version>
    

    <kernel-version> 替换为您自定义内核的版本号。对于本指南中使用的示例内核,文件名将是 vmlinuz-6.*-custom。因此,这是此示例的确切命令

    sudo cp ~/build/kernel/arch/x86/boot/bzImage  /boot/vmlinuz-6.5.7-custom
    
  25. 复制相应的 System.map 文件并使用相同的命名约定将其重命名到 /boot 目录

    sudo cp -v ~/build/kernel/System.map /boot/System.map-6.5.7-custom
    
  26. 使用 kernel-install 实用程序完成文件步骤。输入

    sudo kernel-install add  6.5.7-custom /boot/vmlinuz-6.5.7-custom
    
  27. kernel-install 实用程序将在引导加载程序配置文件中创建一个新的引导条目。对于基于 EFI 的系统,您可以查看 /boot/loader/entries/ 以查找匹配的条目。

  28. 运行 grubby 程序以查看服务器的默认内核。输入

    sudo grubby --default-kernel
    
  29. 一切就绪。现在是检验时刻。最新的内核很可能被配置为启动的新默认内核。如果您可以访问系统的控制台,您可以重新引导您的系统并在 GRUB 引导菜单中选择新的自定义内核。如果重新引导后一切顺利,您可以通过运行 uname 命令来验证系统是否正在运行自定义内核,如下所示

    uname -r
    

作者:Wale Soyinka

贡献者:Steven Spencer, Ganna Zhyrnova