Red Hat Training

A Red Hat training course is available for RHEL 8

管理监控和更新内核

Red Hat Enterprise Linux 8

在 Red Hat Enterprise Linux 8 中管理 Linux 内核的指南

摘要

本文档为用户和管理员提供有关在 Linux 内核级别配置工作站的必要信息。这些修改可提高性能,方便故障排除或者优化系统。

使开源包含更多

红帽承诺替换我们的代码、文档和网页属性中存在问题的语言。我们从这四个术语开始: master、slave、blacklist 和 whitelist。这些更改将在即将发行的几个发行本中逐渐实施。如需了解更多详细信息,请参阅 CTO Chris Wright 信息

对红帽文档提供反馈

我们感谢您对文档提供反馈信息。请让我们了解如何改进文档。要做到这一点:

  • 关于特定内容的简单评论:

    1. 请确定您使用 Multi-page HTML 格式查看文档。另外,确定 Feedback 按钮出现在文档页的右上方。
    2. 用鼠标指针高亮显示您想评论的文本部分。
    3. 点在高亮文本上弹出的 Add Feedback
    4. 按照显示的步骤操作。
  • 要提交更复杂的反馈,请创建一个 Bugzilla ticket:

    1. 进入 Bugzilla 网站。
    2. 在 Component 中选择 Documentation
    3. Description 中输入您要提供的信息。包括文档相关部分的链接。
    4. Submit Bug

第 1 章 Linux 内核 RPM

下面的部分描述了红帽提供和维护的 Linux 内核 RPM 软件包。

1.1. RPM 是什么

RPM 软件包是包含其它文件和元数据的文件(系统所需文件的信息)。

特别是,RPM 软件包由 cpio 存档组成。

cpio 归档包含:

  • 文件
  • RPM 标头(软件包元数据)

    rpm 软件包管理器使用此元数据来确定依赖项、安装文件的位置和其他信息。

RPM 软件包的类型

RPM 软件包有两种类型。这两种类型都共享文件格式和工具,但内容不同,并实现不同的目的:

  • 源 RPM(SRPM)

    SRPM 包含源代码和 SPEC 文件,这些文件描述了如何将源代码构建为二进制 RPM。另外,也可以选择包括源代码的补丁。

  • 二进制 RPM

    一个二进制 RPM 包含了根据源代码和补丁构建的二进制文件。

1.2. Linux 内核 RPM 软件包概述

内核 RPM 是一个元数据软件包,它不包含任何文件,而是确保正确安装了以下所需的子软件包:

  • kernel-core - 包含内核的二进制镜像、所有与 initramfs 相关的对象来引导系统,以及确保核心功能的内核模块数量最少。仅在虚拟和云环境中使用这个子软件包来为 Red Hat Enterprise Linux 8 内核提供一个快速引导时间和小磁盘空间。
  • kernel-modules - 包含内核核心中不存在的其余 内核模块

上述一 小组内 核子包旨在为系统管理员提供更小的维护面,特别是在虚拟化和云环境中。

例如,可选内核软件包:

  • kernel-modules-extra - 包含用于默认禁用加载的个别硬件和模块的内核模块。
  • kernel-debug - 包含内核诊断启用大量调试选项的内核,但牺牲了性能降低。
  • kernel-tools - 包含用于操作 Linux 内核和支持文档的工具。
  • kernel-devel - 包含内核标头,makefile 足以根据 内核 软件包构建模块。
  • kernel-abi-whitelists - 包含与 Red Hat Enterprise Linux 内核 ABI 相关的信息,包括外部 Linux 内核模块所需的内核符号列表和 yum 插件以协助执行。
  • kernel-headers - 包含 C 标头文件,用于指定 Linux 内核与用户空间库和程序之间的接口。头文件定义了构建大多数标准程序所需的常量结构和常量。

1.3. 显示内核软件包的内容

下面的步骤描述了如何在不使用 rpm 命令安装内核软件包及其子软件包的情况下查看它们。

先决条件

  • 为您的 CPU 架构获取 内核 、kernel-core、kernel -modules、kernel-modules-extra RPM 软件包

流程

  • 列出 内核 的模块:

    $ rpm -qlp <kernel_rpm>
    (contains no files)
    …​
  • 列出 kernel-core 模块:

    $ rpm -qlp <kernel-core_rpm>
    …​
    /lib/modules/4.18.0-80.el8.x86_64/kernel/fs/udf/udf.ko.xz
    /lib/modules/4.18.0-80.el8.x86_64/kernel/fs/xfs
    /lib/modules/4.18.0-80.el8.x86_64/kernel/fs/xfs/xfs.ko.xz
    /lib/modules/4.18.0-80.el8.x86_64/kernel/kernel
    /lib/modules/4.18.0-80.el8.x86_64/kernel/kernel/trace
    /lib/modules/4.18.0-80.el8.x86_64/kernel/kernel/trace/ring_buffer_benchmark.ko.xz
    /lib/modules/4.18.0-80.el8.x86_64/kernel/lib
    /lib/modules/4.18.0-80.el8.x86_64/kernel/lib/cordic.ko.xz
    …​
  • 列出 kernel-modules 的模块:

    $ rpm -qlp <kernel-modules_rpm>
    …​
    /lib/modules/4.18.0-80.el8.x86_64/kernel/drivers/infiniband/hw/mlx4/mlx4_ib.ko.xz
    /lib/modules/4.18.0-80.el8.x86_64/kernel/drivers/infiniband/hw/mlx5/mlx5_ib.ko.xz
    /lib/modules/4.18.0-80.el8.x86_64/kernel/drivers/infiniband/hw/qedr/qedr.ko.xz
    /lib/modules/4.18.0-80.el8.x86_64/kernel/drivers/infiniband/hw/usnic/usnic_verbs.ko.xz
    /lib/modules/4.18.0-80.el8.x86_64/kernel/drivers/infiniband/hw/vmw_pvrdma/vmw_pvrdma.ko.xz
    …​
  • 列出 kernel-modules-extra 模块:

    $ rpm -qlp <kernel-modules-extra_rpm>
    …​
    /lib/modules/4.18.0-80.el8.x86_64/extra/net/sched/sch_cbq.ko.xz
    /lib/modules/4.18.0-80.el8.x86_64/extra/net/sched/sch_choke.ko.xz
    /lib/modules/4.18.0-80.el8.x86_64/extra/net/sched/sch_drr.ko.xz
    /lib/modules/4.18.0-80.el8.x86_64/extra/net/sched/sch_dsmark.ko.xz
    /lib/modules/4.18.0-80.el8.x86_64/extra/net/sched/sch_gred.ko.xz
    …​

其它资源

第 2 章 使用 yum 更新内核

以下部分介绍由红帽提供和维护的 Linux 内核(Red Hat kernel)以及如何更新红帽内核。因此,操作系统会提供所有最新的程序漏洞修复、性能增强和补丁可确保与新硬件兼容。

2.1. 什么是内核

内核是 Linux 操作系统的核心部分,可管理系统资源,并提供硬件和软件应用程序之间的接口。红帽内核是一个基于上游 Linux 主线内核的定制内核,红帽工程师可进一步开发和强化该内核,专注于稳定性和与最新技术和硬件的兼容性。

在红帽发布新内核版本前,内核需要通过一组严格的质量保证测试。

红帽内核以 RPM 格式打包,以便 yum 软件包管理器容易升级和验证。

警告

红帽不支持不是由红帽编译的内核。

2.2. 什么是 yum

这部分论述了 yum 软件包管理器 的描述。

其它资源

2.3. 更新内核

下面的步骤描述了如何使用 yum 软件包管理器更新内核。

流程

  1. 要更新内核,使用下面的命令:

    # yum update kernel

    此命令将内核以及所有依赖项更新至最新可用版本。

  2. 重启您的系统以使更改生效。
注意

当从 Red Hat Enterprise Linux 7 升级到 Red Hat Enterprise Linux 8 时,请按照 从 RHEL 7 升级到 RHEL 8 文档中 的相关部分进行操作。

2.4. 安装内核

下面的步骤描述了如何使用 yum 软件包管理器安装新内核。

流程

  • 要安装特定的内核版本,请使用:

    # yum install kernel-{version}

第 3 章 管理内核模块

以下小节解释了什么是内核模块、如何显示其信息以及如何使用内核模块执行基本管理任务。

3.1. 内核模块简介

Red Hat Enterprise Linux 内核可使用一个可选的、带有额外功能的模块(称为内核模块)进行扩展,而无需重启系统。在 Red Hat Enterprise Linux 8 中,内核模块是内建在压缩的 <KERNEL_MODULE_NAME>.ko.xz 对象文件中的额外内核代码。

内核模块启用的最常见功能是:

  • 添加用于支持新硬件的设备驱动程序
  • 支持文件系统,如 GFS2NFS
  • 系统调用

在现代系统中,在需要时会自动载入内核模块。但在某些情况下,需要手动加载或卸载模块。

与内核本身一样,模块也可以在需要时采用自定义其行为的参数。

同时,提供了用来检查当前运行了哪些模块、哪些模块可以加载到内核以及模块接受哪些参数的工具。该工具还提供了在运行的内核中载入和卸载内核模块的机制。

3.2. 引导装载程序规格介绍

BootLoader 规范(BLS)定义一个方案以及文件格式,以管理置入目录中每个引导选项的启动加载器配置,而无需操作启动加载器配置文件。与之前的方法不同,每个引导条目现在都由置入目录中的单独配置文件表示。置入目录扩展了其配置,无需编辑或重新生成配置文件。BLS 在引导菜单项中扩展了这个概念。

使用 BLS,您可以通过在目录中添加、删除或编辑单独的引导条目文件来管理启动加载器菜单选项。这使得内核安装过程在不同的构架中保持简单且一致。

grubby 工具是围绕 BLS 的精简打包程序脚本,它支持相同的 grubby 参数和选项。它运行 dracut 以创建初始 ramdisk 镜像。在这个版本中,核心引导装载程序配置文件是静态的,且在内核安装后不会修改。

这在 Red Hat Enterprise Linux 8 中尤其重要,因为不是在所有构架中都使用相同的引导装载程序。GRUB2 在大多数应用中,如 64 位 ARM,但带有 Open Power Abstraction Layer(OPAL)的 IBM Power Systems 的 little-endian 变体使用 Petitboot,而 IBM Z 架构则使用 zipl

其它资源

3.3. 内核模块依赖关系

某些内核模块有时依赖一个或多个内核模块。/lib/modules/<KERNEL_VERSION>/modules.dep 文件包含对应内核版本的完整内核模块依赖关系列表。

依赖项文件由 depmod 程序生成,该程序是 kmod 软件包的一部分。kmod 提供的许多实用程序在执行操作时会考虑模块依赖关系,因此很少需要 手动 跟踪依赖项。

警告

内核模块的代码在内核空间中是在不受限制模式下执行的。因此,您应该了解您载入的模块。

其它资源

  • modules.dep(5) manual page
  • depmod(8) 手册页

3.4. 列出当前载入的内核模块

下面的步骤描述了如何查看当前载入的内核模块。

先决条件

  • 已安装 kmod 软件包。

流程

  • 要列出所有当前载入的内核模块,请执行:

    $ lsmod
    
    Module                  Size  Used by
    fuse                  126976  3
    uinput                 20480  1
    xt_CHECKSUM            16384  1
    ipt_MASQUERADE         16384  1
    xt_conntrack           16384  1
    ipt_REJECT             16384  1
    nft_counter            16384  16
    nf_nat_tftp            16384  0
    nf_conntrack_tftp      16384  1 nf_nat_tftp
    tun                    49152  1
    bridge                192512  0
    stp                    16384  1 bridge
    llc                    16384  2 bridge,stp
    nf_tables_set          32768  5
    nft_fib_inet           16384  1
    …​

    在上例中:

    • 第一列提供目前载入的模块的 名称
    • 第二列以 KB 为单位显示每个模块的内存量
    • 最后列显示数量,以及依赖特定模块的模块名称 (可选)。

其它资源

  • /usr/share/doc/kmod/README 文件
  • lsmod(8) manual page

3.5. 列出所有安装的内核

以下流程描述了如何使用命令行工具 grubby 列出 GRUB2 引导条目。

流程

要列出内核的引导条目:

  • 要列出内核的引导条目,请执行:

    # grubby --info=ALL | grep title

    该命令显示内核的引导条目。kernel 字段显示内核路径。

    下面的步骤描述了如何使用 grubby 实用程序使用内核命令行列出其系统中所有已安装的内核。

例如,请考虑从 BLS 和非 BLS 安装的 Grub2 菜单列出 grubby-8.40-17

流程

要列出所有安装的内核模块:

  • 执行以下命令:

    # grubby --info=ALL | grep title

    下面是所有安装的内核列表:

    title=Red Hat Enterprise Linux (4.18.0-20.el8.x86_64) 8.0 (Ootpa)
    title=Red Hat Enterprise Linux (4.18.0-19.el8.x86_64) 8.0 (Ootpa)
    title=Red Hat Enterprise Linux (4.18.0-12.el8.x86_64) 8.0 (Ootpa)
    title=Red Hat Enterprise Linux (4.18.0) 8.0 (Ootpa)
    title=Red Hat Enterprise Linux (0-rescue-2fb13ddde2e24fde9e6a246a942caed1) 8.0 (Ootpa)

以上输出显示 grubby-8.40-17 的所有已安装内核的列表(使用 Grub2 菜单)。

3.6. 将内核设置为默认

以下流程描述了如何使用 grubby 命令行工具和 GRUB2 将特定内核设置为默认值。

流程

使用 grubby 工具将内核设置为默认
  • 使用 grubby 工具执行以下命令将内核设置为默认:

# grubby --set-default $kernel_path

命令使用不带 .conf 后缀的计算机 ID 作为参数。

注意

机器 ID 位于 /boot/loader/entries/ 目录中。

使用 id 参数将内核设置为默认
  • 使用 id 参数列出引导条目,然后将所需的内核设置为默认:
# grubby --info ALL | grep id
# grubby --set-default /boot/vmlinuz-<version>.<architecture>
注意

要使用 title 参数列出引导条目,请执行 # grubby --info=ALL | grep title 命令。

仅为下次引导设定默认内核
  • 执行以下命令,仅在下次使用 grub2-reboot 命令重新引导时设置默认内核:
# grub2-reboot <index|title|id>
警告

小心地为下次启动设置默认内核。安装新内核 RPM 的自构建内核并手动将这些条目添加到 /boot/loader/entries/ 目录可能会更改索引值。

3.7. 显示内核模块信息

使用内核模块时,您可能希望查看该模块的更多信息。这个步骤描述了如何显示有关内核模块的额外信息。

先决条件

  • 已安装 kmod 软件包。

流程

  • 要显示任何内核模块的信息,请执行:

    $ modinfo <KERNEL_MODULE_NAME>
    
    For example:
    $ modinfo virtio_net
    
    filename:       /lib/modules/4.18.0-94.el8.x86_64/kernel/drivers/net/virtio_net.ko.xz
    license:        GPL
    description:    Virtio network driver
    rhelversion:    8.1
    srcversion:     2E9345B281A898A91319773
    alias:          virtio:d00000001v*
    depends:        net_failover
    intree:         Y
    name:           virtio_net
    vermagic:       4.18.0-94.el8.x86_64 SMP mod_unload modversions
    …​
    parm:           napi_weight:int
    parm:           csum:bool
    parm:           gso:bool
    parm:           napi_tx:bool

    modinfo 命令显示指定内核模块的一些详细信息。您可以查询所有可用模块的信息,无论它们是否被加载。parm 条目显示用户可以为模块设置的参数,以及它们预期的值类型。

    注意

    在输入内核模块的名称时,不要将. ko.xz 扩展附加到名称的末尾。内核模块名称没有扩展名,它们对应的文件有。

其它资源

  • modinfo(8) 手册页

3.8. 在系统运行时载入内核模块

扩展 Linux 内核功能的最佳方法是加载内核模块。下面的步骤描述了如何使用 modprobe 命令在当前运行的内核中查找并载入内核模块。

先决条件

流程

  1. 选择您要载入的内核模块。

    模块位于 /lib/modules/$(uname -r)/kernel/<SUBSYSTEM>/ 目录中。

  2. 载入相关内核模块:

    # modprobe <MODULE_NAME>
    注意

    在输入内核模块的名称时,不要将. ko.xz 扩展附加到名称的末尾。内核模块名称没有扩展名,它们对应的文件有。

  3. (可选)验证载入了相关模块:

    $ lsmod | grep <MODULE_NAME>

    如果正确加载了模块,这个命令会显示相关的内核模块。例如:

    $ lsmod | grep serio_raw
    serio_raw              16384  0
重要

重启系统后,这个过程中描述的更改不会保留有关如何在系统重启后载入内核模块使其持续的信息 ???,请参阅在系统引导时自动载入内核模块

其它资源

  • modprobe(8) 手册页

3.9. 在系统运行时卸载内核模块

有时,您发现您需要从运行的内核中卸载某些内核模块。下面的步骤描述了如何使用 modprobe 命令在当前载入的内核运行时在系统运行时查找和卸载内核模块。

先决条件

  • 根权限
  • 已安装 kmod 软件包。

流程

  1. 执行 lsmod 命令并选择您要卸载的内核模块。

    如果内核模块有依赖项,请在卸载内核模块前卸载它们。有关识别使用依赖项的模块的详情,请参阅列出当前载入的内核模块和 内核模块依赖项

  2. 卸载相关内核模块:

    # modprobe -r <MODULE_NAME>

    在输入内核模块的名称时,不要将. ko.xz 扩展附加到名称的末尾。内核模块名称没有扩展名,它们对应的文件有。

    警告

    当它们被正在运行的系统使用时,不要卸载这些内核模块。这样做可能会导致不稳定,或系统无法正常操作。

  3. (可选)验证相关模块是否已卸载:

    $ lsmod | grep <MODULE_NAME>

    如果模块被成功卸载,这个命令不会显示任何输出。

重要

完成这个过程后,被定义为在引导是自动加载的内核模块,在重启系统后将不会处于卸载状态。有关如何解决这个结果的详情,请参考防止在系统引导时自动载入内核模块

其它资源

  • modprobe(8) 手册页

3.10. 在系统引导时自动载入内核模块

下面的步骤描述了如何配置内核模块以便在引导过程中自动载入该模块。

先决条件

  • 根权限
  • 已安装 kmod 软件包。

流程

  1. 选择您要在引导过程中载入的内核模块。

    模块位于 /lib/modules/$(uname -r)/kernel/<SUBSYSTEM>/ 目录中。

  2. 为模块创建配置文件:

    # echo <MODULE_NAME> > /etc/modules-load.d/<MODULE_NAME>.conf
    注意

    在输入内核模块的名称时,不要将. ko.xz 扩展附加到名称的末尾。内核模块名称没有扩展名,它们对应的文件有。

  3. 另外,重启后,验证载入了相关模块:

    $ lsmod | grep <MODULE_NAME>

    上面的示例命令应该成功并显示相关的内核模块。

重要

重启系统后,这个过程中描述的更改将会保留

其它资源

  • modules-load.d(5) 手册页

3.11. 防止在系统引导时自动载入内核模块

下面的步骤描述了如何在 denylist 中添加内核模块使其不会在引导过程中自动载入。

先决条件

  • 根权限
  • 已安装 kmod 软件包。
  • 确定 denylist 中的内核模块对您当前系统配置并不重要。

流程

  1. 选择您要放入 denylist 中的内核模块:

    $ lsmod
    
    Module                  Size  Used by
    fuse                  126976  3
    xt_CHECKSUM            16384  1
    ipt_MASQUERADE         16384  1
    uinput                 20480  1
    xt_conntrack           16384  1
    …​

    lsmod 命令显示载入到当前运行的内核的模块列表。

    • 或者,找到您要防止载入的未加载内核模块。

      所有内核模块都位于 /lib/modules/<KERNEL_VERSION>/kernel/<SUBSYSTEM>/ 目录中。

  2. 为 denylist 创建配置文件:

    # vim /etc/modprobe.d/blacklist.conf
    
    	# Blacklists <KERNEL_MODULE_1>
    	blacklist <MODULE_NAME_1>
    	install <MODULE_NAME_1> /bin/false
    
    	# Blacklists <KERNEL_MODULE_2>
    	blacklist <MODULE_NAME_2>
    	install <MODULE_NAME_2> /bin/false
    
    	# Blacklists <KERNEL_MODULE_n>
    	blacklist <MODULE_NAME_n>
    	install <MODULE_NAME_n> /bin/false
    	…​

    示例中显示了由 vim 编辑器编辑的 blacklist.conf 文件的内容。黑名单 行可确保在引导过程中不会自动加载相关内核模块。但是,黑名单 命令不会阻止将模块作为不在 denylist 中的另一个内核模块的依赖项加载。因此,install 行 会导致 /bin/false 运行而不是安装模块。

    以 hash 符号开头的行是注释以便更易读。

    注意

    在输入内核模块的名称时,不要将. ko.xz 扩展附加到名称的末尾。内核模块名称没有扩展名,它们对应的文件有。

  3. 在重新构建前,为当前初始 ramdisk 镜像创建备份副本:

    # cp /boot/initramfs-$(uname -r).img /boot/initramfs-$(uname -r).bak.$(date +%m-%d-%H%M%S).img

    如果新版本出现意外问题,以上命令会创建一个备份 initramfs 镜像。

    • 另外,还可创建其它初始 ramdisk 镜像的备份副本,该副本与您要将内核模块放入 denylist 中的内核版本对应:

      # cp /boot/initramfs-<SOME_VERSION>.img /boot/initramfs-<SOME_VERSION>.img.bak.$(date +%m-%d-%H%M%S)
  4. 根据更改生成新的初始 ramdisk 镜像:

    # dracut -f -v
    • 如果您要为当前引导的不同内核版本构建初始 ramdisk 镜像,请指定目标 initramfs 和内核版本:

      # dracut -f -v /boot/initramfs-<TARGET_VERSION>.img <CORRESPONDING_TARGET_KERNEL_VERSION>
  5. 重启系统:

    $ reboot
重要

此流程中描述的更改将在重启后生效并保留。如果您将关键内核模块错误地放入 denylist 中,您会遇到不稳定的情况或系统无法正常工作。

其它资源

  • dracut(8) 手册页

第 4 章 为安全引导签名内核模块

您可以使用签名的内核模块来提高系统安全性。以下小节介绍了如何在启用了安全引导机制的基于 UEFI 的构建系统中,在 RHEL 8 中使用自签名的专用内核模块。这些部分还提供了将您的公钥导入到要部署内核模块的目标系统中的可用选项概述。

要签名并载入内核模块,您需要:

如果启用了安全引导机制,则必须使用私钥签名 UEFI 操作系统引导装载程序、Red Hat Enterprise Linux 内核和所有内核模块,并使用对应的公钥进行身份验证。如果未签名和验证,则不允许系统完成引导过程。

RHEL 8 发行版包括:

  • 签名的引导装载程序
  • 签名的内核
  • 签名的内核模块

此外,签名的第一阶段引导装载程序和签名的内核包括嵌入式红帽公钥。这些签名的可执行二进制文件和嵌入式密钥使 RHEL 8 在支持 UEFI 安全引导引导引导的系统中使用 Microsoft UEFI 安全引导认证机构密钥安装、引导和运行。请注意,并非所有基于 UEFI 的系统都包括对安全引导的支持。

先决条件

要能够为外部构建的内核模块签名,请在构建系统上安装下表中列出的实用程序。

表 4.1. 所需工具

工具由软件包提供用于目的

openssl

openssl

构建系统

生成公共和专用 X.509 密钥对

Sign-file

kernel-devel

构建系统

用来使用私钥为内核模块签名的可执行文件

mokutil

mokutil

目标系统

用于手动注册公钥的可选工具

keyctl

keyutils

目标系统

用于在系统密钥环中显示公钥的可选工具

注意

构建系统(构建和签署内核模块)不需要启用 UEFI 安全引导,甚至不需要是基于 UEFI 的系统。

4.1. 使用 X.509 密钥验证内核模块的要求

在 RHEL 8 中,加载内核模块时,内核会根据内核系统密钥环(. builtin_trusted_keys)和内核平台密钥环(. platform)中的公共 X.509 密钥检查模块的签名。the .platform 密钥环包含来自第三方平台提供商和自定义公钥的密钥。内核 system .blacklist 密钥环中的 密钥不包括在验证中。以下小节提供了系统中不同源的密钥、密钥环和载入密钥示例概述。此外,您还可以了解如何验证内核模块。

您需要满足某些条件,才能在启用了 UEFI 安全引导功能的系统中载入内核模块。

如果启用了 UEFI 安全引导,或者指定了 模块.sig_enforce 内核参数:

  • 您只能加载那些签名是通过系统密钥环(. builtin_trusted_keys)和平台密钥环(. platform)验证的已签名内核模块。
  • 公钥不能在系统中被撤销的密钥环(.blacklist)。

如果禁用了 UEFI 安全引导并且 模块.sig_enforce 内核参数没有被指定:

  • 您可以加载未签名的内核模块和签名的内核模块,而无需公钥。

如果系统不基于 UEFI,或者禁用 UEFI 安全引导:

  • 只有内核中嵌入的密钥才会加载到 .builtin_trusted_keys and .platform
  • 您无法在不重新构建内核的情况下添加这组密钥。

表 4.2. 加载内核模块的验证要求

模块已签名找到公钥,且签名有效UEFI 安全引导状态sig_enforce模块载入内核污点

未签名

-

未启用

未启用

成功

未启用

Enabled

Fails

-

Enabled

-

Fails

-

已签名

未启用

未启用

成功

未启用

Enabled

Fails

-

Enabled

-

Fails

-

已签名

未启用

未启用

成功

未启用

Enabled

成功

Enabled

-

成功

4.2. 公钥的源

在引导过程中,内核会从一组持久性密钥中加载 X.509 密钥到以下密钥环中:

  • 系统密钥环(.builtin_trusted_keys)
  • the .platform keyring
  • system .blacklist 密钥环

表 4.3. 系统密钥环源

X.509 密钥源用户可以添加密钥UEFI 安全引导状态引导过程中载入的密钥

嵌入于内核中

-

.builtin_trusted_keys

UEFI 安全引导 "db"

有限

未启用

Enabled

.platform

嵌入 in shim.efi 引导装载程序

未启用

Enabled

.builtin_trusted_keys

Machine Owner Key(MOK)列表

未启用

Enabled

.platform

.builtin_trusted_keys:

  • 在引导时构建的密钥环
  • 包含可信公钥
  • 查看密钥需要 root 权限

.Platform:

  • 在引导时构建的密钥环
  • 包含第三方平台供应商和自定义公钥的密钥
  • 查看密钥需要 root 权限

.blacklist

  • 使用 X.509 密钥的密钥环,该密钥已被撤销
  • 由密钥从 .blacklist 签名的模块将失败身份验证,即使您的公钥位于 中 。builtin_trusted_keys

UEFI 安全引导数据库:

  • 签名数据库
  • 存储 UEFI 应用程序、UEFI 驱动程序和引导装载程序的密钥(哈希值)
  • 密钥可加载到机器上

UEFI 安全引导 dbx:

  • 已撤销的签名数据库
  • 防止加载密钥
  • 从此数据库撤销的密钥添加到 .blacklist 密钥环中

4.3. 生成公钥和私钥对

您需要生成一个公共和私有 X.509 密钥对,才能成功在启用了安全引导的系统上使用内核模块。之后您将使用私钥为内核模块签名。您还必须将对应的公钥添加到用于安全引导的 Machine Owner Key(MOK)中,以验证签名的模块。

这个密钥对生成的一些参数最好用配置文件指定。

流程

  1. 使用密钥对生成参数创建配置文件:

    # cat << EOF > configuration_file.config
    [ req ]
    default_bits = 4096
    distinguished_name = req_distinguished_name
    prompt = no
    string_mask = utf8only
    x509_extensions = myexts
    
    [ req_distinguished_name ]
    O = Organization
    CN = Organization signing key
    emailAddress = E-mail address
    
    [ myexts ]
    basicConstraints=critical,CA:FALSE
    keyUsage=digitalSignature
    subjectKeyIdentifier=hash
    authorityKeyIdentifier=keyid
    EOF
  2. 如以下示例所示,创建 X.509 公钥和私钥对:

    # openssl req -x509 -new -nodes -utf8 -sha256 -days 36500
    -batch -config configuration_file.config -outform DER \
    -out my_signing_key_pub.der \
    -keyout my_signing_key.priv

    公钥将写入 my_signing_key_pub.der 文件,私钥将写入 my_signing_key.priv 文件中。

    重要

    在 RHEL 8 中,密钥对的有效性日期非常重要。这个密钥没有过期,但必须在其签名密钥的有效周期内对内核模块进行签名。例如:一个只在 2019 年有效的密钥可用来验证在 2019 年中使用该密钥签名的内核模块。但是,用户无法使用这个密钥在 2020 年签注一个内核模块。

  3. 另外,您还可以查看公钥的有效性日期,如下例所示:

    # openssl x509 -inform der -text -noout -in <my_signing_key_pub.der>
    
    Validity
                Not Before: Feb 14 16:34:37 2019 GMT
                Not After : Feb 11 16:34:37 2029 GMT
  4. 在您要验证并载入内核模块的所有系统中注册您的公钥。
警告

应用强大的安全措施和访问策略来保护您的私钥内容。对于一个恶意的用户,可以使用这个密钥破坏所有由对应公钥验证的系统。

4.4. 系统密钥环输出示例

您可以使用 keyctl 实用程序显示系统密钥环中的密钥信息。

以下是启用了 UEFI 安全引导的 RHEL 8 系统中的 .builtin_trusted_keys.platform 和. blacklist 密钥环的简化示例输出。

# keyctl list %:.builtin_trusted_keys
6 keys in keyring:
...asymmetric: Red Hat Enterprise Linux Driver Update Program (key 3): bf57f3e87...
...asymmetric: Red Hat Secure Boot (CA key 1): 4016841644ce3a810408050766e8f8a29...
...asymmetric: Microsoft Corporation UEFI CA 2011: 13adbf4309bd82709c8cd54f316ed...
...asymmetric: Microsoft Windows Production PCA 2011: a92902398e16c49778cd90f99e...
...asymmetric: Red Hat Enterprise Linux kernel signing key: 4249689eefc77e95880b...
...asymmetric: Red Hat Enterprise Linux kpatch signing key: 4d38fd864ebe18c5f0b7...

# keyctl list %:.platform
4 keys in keyring:
...asymmetric: VMware, Inc.: 4ad8da0472073...
...asymmetric: Red Hat Secure Boot CA 5: cc6fafe72...
...asymmetric: Microsoft Windows Production PCA 2011: a929f298e1...
...asymmetric: Microsoft Corporation UEFI CA 2011: 13adbf4e0bd82...

# keyctl list %:.blacklist
4 keys in keyring:
...blacklist: bin:f5ff83a...
...blacklist: bin:0dfdbec...
...blacklist: bin:38f1d22...
...blacklist: bin:51f831f...

上述 .builtin_trusted_keys 密钥环显示从 UEFI 安全引导"db"密钥 和红帽安全引导(CA 密钥 1)中添加了两个密钥,这些密钥嵌入在 shim.efi 引导装载程序中。

以下示例显示了内核控制台的输出结果。消息标识带有 UEFI 安全引导相关源的密钥。这包括 UEFI 安全引导 db、内嵌的 shim 和 MOK 列表。

# dmesg | grep 'EFI: Loaded cert'
[5.160660] EFI: Loaded cert 'Microsoft Windows Production PCA 2011: a9290239...
[5.160674] EFI: Loaded cert 'Microsoft Corporation UEFI CA 2011: 13adbf4309b...
[5.165794] EFI: Loaded cert 'Red Hat Secure Boot (CA key 1): 4016841644ce3a8...

其它资源

  • keyctl(1)、 dmesg(1) 手册页

4.5. 通过在 MOK 列表中添加公钥在目标系统中注册公钥

当 RHEL 8 在启用了安全引导机制的基于 UEFI 的系统中引导时,内核会将系统密钥环(.builtin_trusted_keys)加载到安全引导 db 密钥数据库中的所有公钥中。同时,内核排除 dbx 数据库中已撤销的密钥。以下小节描述了在目标系统上导入公钥的不同方式,以便系统密钥环 (.builtin_trusted_keys)能够使用公钥来验证内核模块。

Machine Owner Key(MOK)功能可以用来扩展 UEFI 安全引导密钥数据库。当 RHEL 8 在启用了安全引导机制的启用了安全引导的系统中引导时,MOK 列表中的密钥除密钥数据库中的密钥外也会添加到系统密钥环(.builtin_trusted_keys)中。和安全引导数据库密钥相似,MOK 列表密钥会被安全地永久存储。但它们是两个独立的工具。MOK 工具由 shim.efi、MokManager.efi、grubx64.efi 和esok util 实用程序支持。

注册 MOK 密钥需要用户在每个目标系统中在 UEFI 系统控制台上手动互动。MOK 工具为测试新生成的密钥对以及与其签注的内核模块提供了方便的方法。

流程

  1. 请在 MOK 列表中添加您的公钥:

    # mokutil --import my_signing_key_pub.der

    会要求您输入并确认此 MOK 注册请求的密码。

  2. 重启机器。

    待处理的 MOK 密钥注册请求将由 shim.efi 通知,它将启动 MokManager.efi,以便您从 UEFI 控制台完成注册。

  3. 输入您之前与此请求关联的密码并确认注册。

    您的公钥已添加到 MOK 列表中,这是永久的。

密钥位于 MOK 列表中后,它会在启用 UEFI 安全引导时自动传播到此列表中的系统密钥环,并在随后引导时自动传播到系统密钥环。

注意

为了便于对系统中的内核模块进行身份验证,请您的系统供应商将公钥合并到其工厂固件镜像中的 UEFI 安全引导密钥数据库中。

4.6. 使用私钥签名内核模块

如果启用了 UEFI 安全引导机制,用户可以通过加载签名的内核模块来获取对其系统的增强安全优势。下面的部分描述了如何使用私钥为内核模块签名。

先决条件

流程

  • 使用参数执行 sign-file 工具,如下例所示:

    # /usr/src/kernels/$(uname -r)/scripts/sign-file sha256 my_signing_key.priv my_signing_key_pub.der my_module.ko

    签署文件 计算并将签名直接附加到内核模块文件中的 ELF 镜像中。modinfo 实用程序可用于显示有关内核模块签名的信息(如果存在)。

    注意

    附加的签名不包含在 ELF 镜像部分,不是 ELF 镜像的一个正式部分。因此,readelf 等实用程序将无法在内核模块中显示签名。

    您的内核模块现在可以被加载。请注意,您签名的内核模块也可以在禁用 UEFI 安全引导的系统或非 UEFI 系统中加载。这意味着您不需要同时提供内核模块的签名和未签名版本。

    重要

    在 RHEL 8 中,密钥对的有效性日期非常重要。这个密钥没有过期,但必须在其签名密钥的有效周期内对内核模块进行签名。sign-file 实用程序不会提醒您这样做。例如:一个只在 2019 年有效的密钥可用来验证在 2019 年中使用该密钥签名的内核模块。但是,用户无法使用这个密钥在 2020 年签注一个内核模块。

4.7. 载入经过签名的内核模块

当您的公钥注册在系统密钥环(.builtin_trusted_keys)和 MOK 列表中后,在使用私钥签署相应内核模块后,您可以使用 modprobe 命令最终加载签名的内核模块,如下一节所述。

先决条件

流程

  1. 验证您的公钥是否在系统密钥环中:

    # keyctl list %:.builtin_trusted_keys
  2. 将内核模块复制到您想要的内核的 /extra/ 目录中:

    # cp my_module.ko /lib/modules/$(uname -r)/extra/
  3. 更新模块依赖项列表:

    # depmod -a
  4. 载入内核模块并确认它已被成功载入:

    # modprobe -v my_module
    # lsmod | grep my_module
    1. 另外,要在引导时载入模块,将其添加到 /etc/modules-loaded.d/my_module.conf 文件中:

      # echo "my_module" > /etc/modules-load.d/my_module.conf

其它资源

第 5 章 配置内核命令行参数

内核命令行参数是用来在引导时更改 Red Hat Enterprise Linux 内核某些方面行为的方法。作为系统管理员,您可以完全控制引导时要设置的选项。某些内核行为只能在引导时设置,因此了解如何进行此更改是关键管理技能。

重要

通过修改内核命令行参数来更改系统行为可能会对您的系统产生负面影响。因此,您应该在生产环境中部署更改前测试它们。如需进一步帮助,请联络红帽支持团队。

5.1. 了解内核命令行参数

内核命令行参数用于引导时间配置:

  • Red Hat Enterprise Linux 内核
  • 初始 RAM 磁盘
  • 用户空间特性

内核引导时间参数通常用来覆盖默认值和设定具体硬件设置。

默认情况下,使用 GRUB2 引导装载程序的系统的内核命令行参数在所有内核引导条目的 /boot/grub2/grubenv 文件的 kernelopts 变量中定义。

注意

对于 IBM Z,内核命令行参数存储在引导条目配置文件中,因为 zipl 引导装载程序不支持环境变量。因此,无法使用 kernelopts 环境变量。

其它资源

5.2. grubby 是什么

grubby 是操作特定引导加载器配置文件的实用程序。

您还可以使用 grubby 更改默认引导条目,使用 从 GRUB2 菜单条目添加/删除参数。

更多详情请参阅 grubby(8)手册页

5.3. 什么是引导条目

引导条目是保存在配置文件中并绑定到特定内核版本的选项集合。在实践中,您的引导条目至少与您所安装的系统数量相同。引导条目配置文件位于 /boot/loader/entries/ 目录中,如下所示:

6f9cc9cb7d7845d49698c9537337cedc-4.18.0-5.el8.x86_64.conf

以上文件名由存储在 /etc/machine-id 文件中的计算机 ID 和内核版本组成。

引导条目配置文件包含有关内核版本、初始 ramdisk 镜像和 kernelopts 环境变量的信息,其中包含内核命令行参数。引导条目配置的内容如下:

title Red Hat Enterprise Linux (4.18.0-74.el8.x86_64) 8.0 (Ootpa)
version 4.18.0-74.el8.x86_64
linux /vmlinuz-4.18.0-74.el8.x86_64
initrd /initramfs-4.18.0-74.el8.x86_64.img $tuned_initrd
options $kernelopts $tuned_params
id rhel-20190227183418-4.18.0-74.el8.x86_64
grub_users $grub_users
grub_arg --unrestricted
grub_class kernel

kernelopts 环境变量在 /boot/grub2/grubenv 文件中定义。

5.4. 为所有引导条目更改内核命令行参数

这个步骤描述了如何为系统中所有引导条目更改内核命令行参数。

先决条件

  • 验证系统上已安装了 grubbyzipl 实用程序。

流程

  • 添加参数:

    # grubby --update-kernel=ALL --args="<NEW_PARAMETER>"

    对于使用 GRUB2 引导装载程序的系统,命令通过向该文件中的 kernelopts 变量添加新内核参数来更新 /boot/grub2/grubenv 文件。

    在使用 zIPL 引导装载程序的 IBM Z 中,该命令会为每个 /boot/loader/entries/<ENTRY>.conf 文件添加新内核参数。

    • 在 IBM Z 中,执行不带选项的 zipl 命令以更新引导菜单。
  • 删除参数:

    # grubby --update-kernel=ALL --remove-args="<PARAMETER_TO_REMOVE>"
    • 在 IBM Z 中,执行不带选项的 zipl 命令以更新引导菜单。

其它资源

5.5. 为单一引导条目更改内核命令行参数

这个步骤描述了如何为系统中的单一引导条目更改内核命令行参数。

先决条件

  • 验证系统上已安装了 grubbyzipl 实用程序。

流程

  • 添加参数:

    grubby --update-kernel=/boot/vmlinuz-$(uname -r) --args="<NEW_PARAMETER>"
    • 在 IBM Z 中,执行不带选项的 zipl 命令以更新引导菜单。
  • 要删除参数,请使用以下内容:

    grubby --update-kernel=/boot/vmlinuz-$(uname -r) --remove-args="<PARAMETER_TO_REMOVE>"
    • 在 IBM Z 中,执行不带选项的 zipl 命令以更新引导菜单。
注意

在使用 grub.cfg 文件的系统上,默认情况下每个内核引导条目的 options 参数设置为 kernelopts 变量。此变量在 /boot/grub2/grubenv 配置文件中定义。

重要

在 GRUB2 系统上:

  • 如果为所有引导条目修改了内核命令行参数,grub by 实用程序会更新 /boot/grub2/grubenv 文件中的 kernelopts 变量。
  • 如果为单个引导条目修改了内核命令行参数,则扩展 kernelopts 变量,修改内核参数,结果值存储在相应的引导条目的 /boot/loader/entries/<RELEVANT_KERNEL_BOOT_ENTRY.conf> 文件中。

在 zIPL 系统中:

  • grubby 修改单个内核引导条目的内核命令行参数并将其存储在 /boot/loader/entries/<ENTRY>.conf 文件中。

其它资源

第 6 章 在运行时配置内核参数

作为系统管理员,您可以修改 Red Hat Enterprise Linux 内核在运行时行为的很多方面。这部分论述了如何使用 sysctl 命令以及在运行时配置内核参数,以及修改 /etc/sysctl.d/ 和 /proc/ sys/ 目录中的配置文件。

6.1. 什么是内核参数

内核参数是可在系统运行时调整的可调整值。不需要重启或重新编译内核就可以使更改生效。

可以通过以下方法处理内核参数:

  • sysctl 命令
  • 挂载于 /proc/sys/ 目录的虚拟文件系统
  • /etc/sysctl.d/ 目录中的配置文件

Tunables 被内核子系统划分为不同的类。Red Hat Enterprise Linux 有以下可调整类:

表 6.1. sysctl 类表

可调整类子系统

abi

执行域和个人

crypto

加密接口

debug

内核调试接口

dev

特定于设备的信息

fs

全局和特定文件系统的 tunables

kernel

全局内核 tunables

net

网络 tunables

sunrpc

Sun 远程过程调用(NFS)

user

用户命名空间限制

vm

调整和管理内存、缓冲和缓存

重要

在产品系统中配置内核参数需要仔细规划。未计划的更改可能会导致内核不稳定,需要重启系统。在更改任何内核值之前,验证您是否正在使用有效选项。

其它资源

  • sysctl(8)和 sysctl.d(5) 手册页

6.2. 使用 sysctl 临时配置内核参数

下面的步骤描述了如何使用 sysctl 命令在运行时临时设置内核参数。命令也可用于列出和过滤可调项。

先决条件

  • 根权限

流程

  1. 要列出所有参数及其值,请使用:

    # sysctl -a
    注意

    # sysctl -a 命令显示内核参数,可在运行时和系统启动时调整。

  2. 要临时配置参数,请使用 命令,如下例所示:

    # sysctl <TUNABLE_CLASS>.<PARAMETER>=<TARGET_VALUE>

    上面的示例命令在系统运行时更改了参数值。更改将立即生效,无需重新启动。

    注意

    更改会在系统重启后返回到 default。

6.3. 使用 sysctl 永久配置内核参数

下面的步骤描述了如何使用 sysctl 命令永久设置内核参数。

先决条件

  • 根权限

流程

  1. 要列出所有参数,请使用:

    # sysctl -a

    该命令显示所有可在运行时配置的内核参数。

  2. 永久配置参数:

    # sysctl -w <TUNABLE_CLASS>.<PARAMETER>=<TARGET_VALUE> >> /etc/sysctl.conf

    示例命令会更改可调值,并将其写入 /etc/sysctl.conf 文件,该文件会覆盖内核参数的默认值。更改会立即并永久生效,无需重启。

注意

要永久修改内核参数,您还可以手动更改 /etc/sysctl.d/ 目录中的配置文件。

其它资源

6.4. 使用 /etc/sysctl.d/ 中的配置文件调整内核参数

下面的步骤描述了如何手动修改 /etc/sysctl.d/ 目录中的配置文件来永久设置内核参数。

先决条件

  • 根权限

流程

  1. /etc/sysctl.d/ 中创建新配置文件:

    # vim /etc/sysctl.d/<some_file.conf>
  2. 包括内核参数,一行一个,如下所示:

    <TUNABLE_CLASS>.<PARAMETER>=<TARGET_VALUE>
    <TUNABLE_CLASS>.<PARAMETER>=<TARGET_VALUE>
  3. 保存配置文件。
  4. 重启机器以使更改生效。

    • 或者,要在不重启的情况下应用更改,请执行:

      # sysctl -p /etc/sysctl.d/<some_file.conf>

      该命令允许您从之前创建的配置文件中读取值。

其它资源

  • sysctl(8), sysctl.d(5) manual pages

6.5. 通过 /proc/sys/ 临时配置内核参数

下面的步骤描述了如何通过虚拟文件系统 /proc/sys/ 目录中的文件临时设置内核参数。

先决条件

  • 根权限

流程

  1. 识别您要配置的内核参数:

    # ls -l /proc/sys/<TUNABLE_CLASS>/

    命令返回的可写入文件可以用来配置内核。具有只读权限的文件提供了对当前设置的反馈。

  2. 为 kernel 参数分配目标值:

    # echo <TARGET_VALUE> > /proc/sys/<TUNABLE_CLASS>/<PARAMETER>

    命令进行配置更改,这些更改将在系统重启后消失。

  3. 另外,还可验证新设置内核参数的值:

    # cat /proc/sys/<TUNABLE_CLASS>/<PARAMETER>

第 7 章 在虚拟环境中保留内核 panic 参数

当在 Red Hat Enterprise Linux 8(RHEL 8)中配置虚拟化环境时,您不应该启用 softlockup_panicnmi_watchdog 内核参数,因为虚拟环境可能会触发一个不需要系统 panic 的伪装软锁定。

以下小节通过总结来解释这个建议后的原因:

  • 什么会导致软锁定。
  • 描述控制软锁定中系统行为的内核参数。
  • 解释如何在虚拟环境中触发软锁定。

7.1. 什么是软锁定

当任务在不重新调度的情况下在 CPU 上的内核空间中执行时,软锁定通常是由程序错误造成的。该任务也不允许任何其他任务在特定 CPU 上执行。因此,用户通过系统控制台会显示警告信息。这个问题也被称为软锁定触发。

7.2. 控制内核 panic 的参数

可设置以下内核参数来控制当检测到软锁定时的系统行为。

softlockup_panic

控制当检测到软锁定时内核是否 panic。

类型效果

整数

0

内核在软锁定时不 panic

整数

1

软锁定中的内核 panics

默认情况下,在 RHEL8 上,这个值为 0。

为了 panic,系统需要首先检测硬锁定。检测由 nmi_watchdog 参数控制。

nmi_watchdog

控制锁定检测机制(watchdogs)是否处于活动状态。这个参数是整数类型。

效果

0

禁用锁定检测器

1

启用锁定检测器

硬锁定检测器会监控每个 CPU 是否有响应中断的能力。

watchdog_thresh

控制 watchdog hrtimer、NMI 事件和软/硬锁定阈值的频率。

默认阈值软锁定阈值

10 秒

2 * watchdog_thresh

将此参数设置为 0 可禁用锁定检测。

7.3. 在虚拟环境中有伪装的软锁定

物理主机上的软锁定触发,如软锁定中所述,通常代表内核或硬件漏洞。在虚拟环境中的客户端操作系统中会出现同样的问题。

主机的高工作负载或者某些特定资源(如内存)的高竞争,通常会导致错误的软锁定触发。这是因为主机可能会调度出客户端 CPU 的时间超过 20 秒。然后,当客户机 CPU 再次调度到主机上运行时,它会遇到时间跳转,从而会触发适当的计时器。计时器还包括 watchdog hrtimer,因此可以在客户机 CPU 上报告软锁定。

因为虚拟化环境中的软锁定可能很虚构,所以您不应该启用在客户端 CPU 上报告软锁定时导致系统 panic 的内核参数。

重要

若要了解 guest 中的软锁定,必须了解主机将 guest 调度为任务,然后 guest 会调度自己的任务。

第 8 章 为数据库服务器调整内核参数

有一组不同的内核参数可能会影响特定数据库应用程序的性能。以下小节解释了要配置什么内核参数来确保数据库服务器和数据库的高效操作。

8.1. 介绍

数据库服务器是一种提供数据库管理系统(DBMS)功能的服务。DBMS 提供数据库管理的实用程序,并与最终用户、应用程序和数据库交互。

Red Hat Enterprise Linux 8 提供以下数据库管理系统:

  • MariaDB 10.3
  • MariaDB 10.5 - 自 RHEL 8.4 起可用
  • MySQL 8.0
  • PostgreSQL 10
  • PostgreSQL 9.6
  • PostgreSQL 12 - 从 RHEL 8.1.1 开始可用
  • PostgreSQL 13 - 从 RHEL 8.4 开始可用

8.2. 影响数据库应用程序性能的参数

以下内核参数会影响数据库应用程序的性能。

fs.aio-max-nr

定义系统可在服务器中处理的异步 I/O 操作的最大数目。

注意

增加 fs.aio-max-nr 参数不会在增加 aio 限制外产生任何变化。

fs.file-max

定义系统在任何实例上支持的最大文件句柄数(临时文件名或者分配给打开文件的 ID)。

内核会在应用程序请求文件句柄时动态分配文件。但是,当应用程序发布这些文件时,内核不会释放这些文件句柄。相反,内核会回收这些文件的句柄。这意味着,分配的文件句柄总数将随着时间增加,即使当前使用的文件句柄的数量可能较低。

kernel.shmall
定义可用于系统范围的共享内存页面总数。要使用整个主内存,kernel.shmall 参数的值应当为主内存大小总计。
kernel.shmmax
定义 Linux 进程在其虚拟地址空间中可分配的单个共享内存段的最大字节大小。
kernel.shmmni
定义数据库服务器能够处理的共享内存段的最大数量。
net.ipv4.ip_local_port_range
定义系统可用于希望在无特定端口号的情况下连接到数据库服务器的程序的端口范围。
net.core.rmem_default
通过传输控制协议(TCP)定义默认接收套接字内存。
net.core.rmem_max
通过传输控制协议(TCP)定义最大接收套接字内存。
net.core.wmem_default
通过传输控制协议(TCP)定义默认发送套接字内存。
net.core.wmem_max
通过传输控制协议(TCP)定义最大发送套接字内存。
vm.dirty_bytes / vm.dirty_ratio
定义以脏内存百分比为单位的字节/阈值,在该阈值中,生成脏数据的进程会在 write() 函数中启动。
注意

可以 一次指定 vm .dirty_bytes vm.dirty_ratio

vm.dirty_background_bytes / vm.dirty_background_ratio
定义以脏内存百分比为单位的字节/阈值,达到此阈值时内核会尝试主动将脏数据写入硬盘。
注意

vm .dirty_background_bytes vm.dirty_background_ratio 可以一次指定。

vm.dirty_writeback_centisecs

定义负责将脏数据写入硬盘的内核线程定期唤醒之间的时间间隔。

这个内核参数以 100 分之一秒为单位。

vm.dirty_expire_centisecs

定义脏数据足够旧的时间以便写入硬盘。

这个内核参数以 100 分之一秒为单位。

第 9 章 内核日志记录入门

日志文件是包含有关系统的消息的文件,包括内核、服务及其上运行的应用。Red Hat Enterprise Linux 中的日志记录系统基于内置的 syslog 协议。各种实用程序使用此系统记录事件并将其整理到日志文件中。这些文件在审核操作系统或故障排除问题时非常有用。

9.1. 什么是内核环缓冲

在引导过程中,控制台提供有关系统启动初始阶段的许多重要信息。为避免丢失早期消息,内核会利用称为环缓冲的早期消息。此缓冲区将所有消息(包括引导消息 存储在内核代码中。来自内核环缓冲的消息随后由 syslog 服务读取并存储在永久存储上的日志文件中。

上面提到的缓冲区是具有固定大小的循环数据结构,并且硬编码到内核中。用户可以通过 dmesg 命令或 /var/log/boot.log 文件显示存储在内核环缓冲中的数据。当环形缓冲区满时,新数据将覆盖旧数据。

其它资源

  • syslog(2)dmesg(1) 手册页

9.2. 日志级别和内核日志记录上的 printk 角色

内核报告的每条消息都有一个与它关联的日志级别,用于定义消息的重要性。如内核环缓冲区中所述,内核环缓冲会收集所有日志级别的内核消息。它是 kernel.printk 参数,用于定义缓冲区中哪些消息打印到控制台中。

日志级别值按以下顺序划分:

  • 0 - 内核紧急。系统无法使用。
  • 1 - 内核警报。必须立即采取行动。
  • 2 - 内核条件被视为关键。
  • 3 - 常规内核错误条件。
  • 4 - 常规内核警告条件。
  • 5 - 内核发现一个正常但可能需要考虑的状况。
  • 6 - 内核信息。
  • 7 - 内核调试级别信息。

默认情况下,RHEL 8 中的 kernel.printk 包含以下四个值:

# sysctl kernel.printk
kernel.printk = 7	4	1	7

该四个值定义了以下内容:

  1. value.控制台日志级别,定义打印到控制台的消息的优先级最低。
  2. value.消息没有显式附加日志级别的默认日志级别.
  3. value.为控制台日志级别设置最低的日志级别配置。
  4. value.在引导时为控制台日志级别设置默认值。

    以上每个值都定义了处理错误消息的不同规则。

重要

默认的 7 4 1 7 printk 值可以更好地调试内核活动。但是,与串行控制台结合使用时,此 printk 设置可能会导致大量 I/O 突发,从而导致 RHEL 系统暂时变得不响应。为避免这种情况,设置 printk 值 4 4 1 7 通常可以正常工作,但代价是丢失额外的调试信息。

另请注意,某些内核命令行参数(如 静默调试 )会更改默认的 kernel.printk 值。

其它资源

  • syslog(2) 手册页

第 10 章 安装 kdump

许多情况下,在新的 Red Hat Enterprise Linux 安装中默认安装并激活 kdump 服务。以下部分介绍了 kdump 以及在某些情况下未默认启用 kdump 时如何安装 kdump

10.1. kdump

kdump 是提供崩溃转储机制的服务。服务允许您保存系统内存内容,以便稍后进行分析。kdump 使用 kexec 系统调用在不重启的情况下引导至第二个 内核(捕获内核),然后捕获崩溃内核的内存( 崩溃转储vmcore)的内容并将其保存。这个第二个内核位于系统内存保留的一部分。

重要

内核崩溃转储可能会是系统失败时唯一可用的信息(关键错误)。因此,在关键任务环境中确保 kdump 操作正常运行非常重要。红帽建议系统管理员在正常内核更新周期内定期更新和测试 kexec-tools。这在部署了新内核功能时尤为重要。

10.2. 执行 kdump 安装

在使用图形或文本界面执行交互式安装时,Anaconda 安装程序为 kdump 配置提供了一个屏幕。安装程序屏幕名为 Kdump,可在主 安装概述 屏幕中访问,且只允许有限的配置 - 您只能选择是否启用了 kdump 以及保留多少内存。

在 RHEL 安装过程中启用 kdump

有些安装选项,如自定义 Kickstart 安装,在某些情况下不会默认安装或启用 kdump。如果您的系统中出现这种情况,请按照以下步骤安装 kdump

先决条件

  • 一个有效的 Red Hat Enterprise Linux 订阅
  • 包含用于您的系统 CPU 架构的 kexec-tools 软件包的软件仓库
  • 实现了对 kdump 配置和目标的要求

流程

  1. 执行以下命令检查是否在您的系统中安装了 kdump:

    $ rpm -q kexec-tools

    如果安装了该软件包,输出:

    kexec-tools-2.0.17-11.el8.x86_64

    如果没有安装该软件包,输出:

    package kexec-tools is not installed
  2. 通过以下 方法安装 kdump 和其他必要的软件包:

    # yum install kexec-tools
重要

从 Red Hat Enterprise Linux 7.4(kernel-3.10.0-693.el7)开始,kdump 支持 Intel IOMMU 驱动程序 对于以前的版本,Red Hat Enterprise Linux 7.3(kernel-3.10.0-514[.XYZ].el7)及更早版本建议禁用 Intel IOMMU 支持,否则 kdump 内核可能会变得无响应。

第 11 章 在命令行中配置 kdump

在系统引导过程中为 kdump 保留内存。内存大小在系统的 Grand Unified Bootloader(GRUB)2 配置文件中配置。内存大小取决于配置文件中指定的 crashkernel= 值以及系统物理内存的大小。

11.1. 配置 kdump 内存用量

crashkernel= 选项可以通过多种方式定义。您可以指定 crashkernel= 值或配置 auto 选项。crashkernel=auto 引导选项,根据系统物理内存总量自动保留内存。配置后,内核将自动为 kdump 内核保留适当的内存量。这有助于防止出现内存不足(OOM)错误。

注意

kdump 的自动内存分配因系统硬件架构和可用内存大小而异。

例如,在 AMD64 和 Intel 64 中,只有可用内存超过 1GB 和 64 位 ARM 架构且 IBM Power 系统具有超过 2GB 的可用内存时,crashkernel=auto 参数才能正常工作。

如果系统自动分配低于最小内存阈值,您可以手动配置保留内存量。

先决条件

  • 实现了 配置和目标的 kdump 要求

流程

  1. 使用 root 权限编辑 /etc/default/grub 文件。
  2. crashkernel= 选项设置为所需的值。

    例如:要保留 128 MB 内存,请使用:

    crashkernel=128M

    或者,您可以根据安装的内存总量将保留内存量设置为变量。内存保留到变量的语法为 crashkernel=<range1>: <size1>,<range2>: <size2>。例如:

    crashkernel=512M-2G:64M,2G-:128M

    如果系统内存总量为 512 MB 或高于 2 GB,则上述示例保留 64 MB 内存。如果内存总量超过 2 GB,则为 kdump 保留 128 MB。

    • 保留内存的偏移。

      有些系统需要保留内存并带有特定的固定偏移,因为崩溃内核保留非常早,并且希望保留一些区域供特殊使用。如果设置了偏移,则保留内存从此偏移开始。要偏移保留的内存,请使用以下语法:

      crashkernel=128M@16M

      上面的例子意味着 kdump 从 16 MB 开始保留 128 MB 内存(物理地址 0x01000000)。如果偏移参数设为 0 或完全省略,k dump 会自动偏移保留内存。如上所述,在设置变量内存保留时也可以使用此语法;在本例中,偏移始终被最后指定(例如 crashkernel=512M-2G:64M,2G-:128M@16M)。

  3. 使用以下命令更新 GRUB2 配置文件:

    # grub2-mkconfig -o /boot/grub2/grub.cfg
注意

kdump 配置内存的替代方法是将 crashkernel=<SOME_VALUE> 参数附加到带有 grub2-editenvkernelopts 变量中,这将更新所有引导条目。或者您可以使用 grubby 实用程序更新只有一个条目的内核命令行参数。

11.2. 配置 kdump 目标

当捕获内核崩溃时,核心转储可以作为文件存储在本地文件系统中,直接写入设备,或使用 NFS (网络文件系统)或 SSH (Secure Shell)协议通过网络发送。一次只能设置其中一个选项,默认的行为是将 vmcore 文件存储在本地文件系统的 /var/crash/ 目录中。

先决条件

  • 实现了 配置和目标的 kdump 要求。

流程

  • 要将 vmcore 文件存储在本地文件系统的 /var/crash/ 目录中,编辑 /etc/kdump.conf 文件并指定路径:

    path /var/crash

    选项 路径 /var/crash 代表 kdump 保存 vmcore 文件的文件系统的路径。当您在 /etc/kdump.conf 文件中指定转储目标时,路径 相对于指定的转储目标。

    如果您没有在 /etc/kdump.conf 文件中指定转储目标,则该 路径 代表根目录的绝对路径。根据当前系统中挂载的内容,会自动执行转储目标和调整的转储路径。

警告

当转储目标挂载到 /var/crash .conf 文件中时,kdump 将 vmcore 文件 保存在 / var/crash /var/ crash 目录中。例如,在以下实例中,ext4 文件系统已挂载到 /var/crash,其 路径 被设置为 /var/crash:

grep -v ^# etc/kdump.conf | grep -v ^$
ext4 /dev/mapper/vg00-varcrashvol
path /var/crash
core_collector makedumpfile -c --message-level 1 -d 31

这会导致 /var/crash/var/crash 路径。要解决这个问题,请使用选项 路径 / 而不是 路径 /var/crash

  • 要更改保存核心转储的本地目录,以 root 用户身份编辑 /etc/kdump.conf 配置文件,如下所述。

    1. #path /var/crash 行的开头删除 hash 符号("#")。
    2. 使用预期的目录路径替换该值。例如:

      path /usr/local/cores
      重要

      在 Red Hat Enterprise Linux 8 中,当 kdump systemd 服务启动 - 否则服务失败时,使用 path 指令定义为 kdump 目标的目录必须存在。此行为与早期版本的 Red Hat Enterprise Linux 不同,如果启动服务时不存在 目录,则会自动创建该目录。

  • 要将文件写入不同的分区,以 root 用户身份编辑 /etc/kdump.conf 配置文件,如下所述。

    1. 根据您的选择,从 #ext4 行的开头删除 hash 符号("#")。

      • 设备名称( #ext4 /dev/vg/lv_kdump 行)
      • 文件系统标签( #ext4 LABEL=/boot 行)
      • UUID( #ext4 UUID=03138356-5e61-4ab3-b58e-27507ac41937 行)
    2. 将文件系统类型以及设备名称、标签或者 UUID 更改为所需值。例如:

      ext4 UUID=03138356-5e61-4ab3-b58e-27507ac41937
      重要

      建议您使用 LABEL= 或 UUID= 指定存储设备。无法保证 /dev/sda3 等磁盘设备名称在重启后保持一致。

      重要

      当转储到 IBM Z 硬件上的直接访问存储设备(DASD)时,在继续前在 /etc/dasd.conf 中正确指定转储设备非常重要。

  • 将转储直接写入设备:

    1. #raw /dev/vg/lv_kdump 行的开头删除哈希符号("#")。
    2. 使用预期的设备名称替换该值。例如:

      raw /dev/sdb1
  • 使用 NFS 协议将转储保存到远程机器中:

    1. #nfs my.server.com:/export/tmp 行的开头删除哈希符号("#")。
    2. 使用有效的主机名和目录路径替换该值。例如:

      nfs penguin.example.com:/export/cores
  • 使用 SSH 协议将转储保存到远程机器中:

    1. #ssh user@my.server.com 行的开头删除 hash 符号("#")。
    2. 使用有效的用户名和密码替换该值。
    3. 在配置中包含 SSH 密钥。

      • #sshkey /root/.ssh/kdump_id_rsa 行的开头删除哈希符号。
      • 将该值改为您要转储的服务器中有效密钥的位置。例如:

        ssh john@penguin.example.com
        sshkey /root/.ssh/mykey

其它资源

11.3. 配置内核收集器

kdump 服务使用 core_collector 程序捕获 vmcore 镜像。在 RHEL 中,makedumpfile 实用程序是默认的内核收集器。

makedumpfile 是一个转储程序,可帮助压缩转储文件的大小,并使用各种转储级别复制所需的页面。

makedumpfile 通过压缩转储数据或者排除不必要的页面或同时排除其中的小转储文件来创建小转储文件。它需要第一个内核调试信息来了解第一个内核如何使用内存。这有助于检测所需页面。

语法

core_collector makedumpfile -l --message-level 1 -d 31

选项

  • -c-l-p :使用 zlib - c 选项、l 选项 - l 选项或 - p 选项指定压缩转储文件格式,或使用 - p 选项指定压缩转储文件格式。
  • -d (dump_level) :排除页面,以便它们不会复制到转储文件中。
  • --message-level :指定消息类型。您可以通过使用这个选项指定 message_level 来限制打印的输出。例如,指定 7 作为 message_level 可打印常见消息和错误消息。message_level 的最大值为 31

先决条件

  • 实现了 配置和目标的 kdump 要求。

流程

  1. root 用户身份,编辑 /etc/kdump.conf 配置文件并从 #core_collector makedumpfile -l --message-level 1 -d 31 的开头删除 hash 符号("#")。
  2. 要启用转储文件压缩,请执行:
core_collector makedumpfile -l --message-level 1 -d 31

其中,

  • - L 指定 转储 压缩文件格式。
  • -d 将转储级别指定为 31。
  • --message-level 将消息级别指定为 1。

另外,请考虑使用选项 -c 和 - p 的以下示例:

  • 使用 -c 压缩转储文件:
core_collector makedumpfile -c -d 31 --message-level 1
  • 使用 -p 压缩转储文件:
core_collector makedumpfile -p -d 31 --message-level 1

其它资源

  • makedumpfile(8) 手册页

11.4. 配置 kdump 默认失败响应

默认情况下,当 kdump 在配置的目标位置创建 vmcore 文件失败时,系统会重启,且转储会丢失。要更改此行为,请遵循以下步骤。

先决条件

  • 实现了 配置和目标的 kdump 要求。

流程

  1. root 用户身份,从 /etc/kdump.conf 配置文件的 #failure_action 行的开头删除 hash 符号("#")。
  2. 将值替换为所需操作。

    failure_action poweroff

其它资源

11.5. kdump 的配置文件

kdump 内核的配置文件是 /etc/sysconfig/kdump。此文件控制 kdump 内核命令行参数。

对于大多数配置,请使用默认选项。然而,在某些情况下,您可能需要修改某些参数来控制 kdump 内核行为。例如:修改 以附加 kdump 内核命令行来获取详细的调试输出。

本节介绍为 kdump 修改 KDUMP_COMMANDLINE_REMOVEKDUMP_COMMANDLINE_REMOVE 选项。有关附加配置选项的详情请参考 Documentation/admin-guide/kernel-parameters.txt 或 /etc/sysconfig/kdump 文件。

  • KDUMP_COMMANDLINE_REMOVE

    这个选项从当前 kdump 命令行中删除参数。它删除可能导致 kdump 错误或 kdump 内核引导失败的参数。这些参数可以从之前的 KDUMP_COMMANDLINE 进程解析,或者继承自 /proc/cmdline 文件。如果未配置此变量,它将继承 /proc/cmdline 文件中的所有值。配置此选项还提供了有助于调试问题的信息。

    示例

    要删除某些参数,请将其添加到 KDUMP_COMMANDLINE_REMOVE 中,如下所示:

    KDUMP_COMMANDLINE_REMOVE="hugepages hugepagesz slub_debug quiet log_buf_len swiotlb"
  • KDUMP_COMMANDLINE_APPEND

    此选项将参数附加到当前命令行。这些参数可能已被前面的 KDUMP_COMMANDLINE_REMOVE 变量解析。

    对于 kdump 内核,禁用某些模块,如 mce、cgroupnumahest_disable 有助于防止内核错误。这些模块可能会消耗为 kdump 保留的大量内核内存,或导致 kdump 内核引导失败。

    示例

    要在 kdump 内核命令行中禁用内存 cgroups,请运行以下命令:

    KDUMP_COMMANDLINE_APPEND="cgroup_disable=memory"

其它资源

  • 文档/管理员指南/内核参数.txt 文件
  • /etc/sysconfig/kdump 文件

11.6. 启用和禁用 kdump 服务

要在引导时启动 kdump 服务,请按照以下步骤操作。

先决条件

  • 实现了 配置和目标的 kdump 要求。
  • 安装 kdump 的所有配置都是根据您的需要设置的。

流程

  1. 要启用 kdump 服务,请使用以下命令:

    # systemctl enable kdump.service

    这为 multi-user.target 启用服务。

  2. 要在当前会话中启动该服务,请使用以下命令:

    # systemctl start kdump.service
  3. 要停止 kdump 服务,请输入以下命令:

    # systemctl stop kdump.service
  4. 要禁用 kdump 服务,请执行以下命令:

    # systemctl disable kdump.service
警告

建议将 kptr_restrict=1 设置为默认值。当将 kptr_restrict 设置为(1)时,kdump ctl 服务会加载崩溃内核,即使启用了内核地址空间布局(KASLR)。

故障排除步骤

kptr_restrict 没有设置为(1)时,如果启用了 KASLR,则 /proc/kore 文件的内容都会生成为零。因此,k dumpctl 服务无法访问 /proc/kcore 并载入崩溃内核。

要临时解决这个问题,k exec-kdump-howto.txt 文件会显示警告信息,指定将推荐的设置保留为 kptr_restrict=1

要确定 kdumpctl 服务载入崩溃内核,请验证:

  • sysctl.conf 文件中的 kernel kptr_restrict=1

其它资源

11.7. 测试 kdump 配置

下面的步骤描述了如何在机器进入生产环境前测试内核转储过程是否正常工作。

警告

以下命令会导致内核崩溃。在按照这些步骤操作时要小心,且不要在活跃的生产环境中使用它们。

流程

  1. 在启用了 kdump 的情况下重启系统。
  2. 确保 kdump 正在运行:

    ~]# systemctl is-active kdump
    active
  3. 强制 Linux 内核崩溃:

    echo 1 > /proc/sys/kernel/sysrq
    echo c > /proc/sysrq-trigger
    警告

    以上命令使内核崩溃,需要重新启动。

    再次引导后,地址-YYYY-MM-DD-HH:MM:SS/vmcore 文件是在您在 /etc/kdump.conf 中指定的位置创建的(默认为 /var/crash/)。

    注意

    除了确认配置的有效性外,也可以使用此操作记录在代表负载运行期间崩溃转储完成所需的时间。

其它资源

11.8. 使用 kexec 重启内核

kexec 系统调用启用从当前运行的内核加载并引导至另一个内核的功能,从而从内核中执行引导装载程序的功能。

kexec 实用程序为 kexec 系统调用加载内核和 initramfs 镜像,以引导至另一个内核。

下面的步骤描述了如何在使用 kexec 程序重启到另一个内核时手动调用 kexec 系统调用。

流程

  1. 执行 kexec 工具:

    # kexec -l /boot/vmlinuz-3.10.0-1040.el7.x86_64 --initrd=/boot/initramfs-3.10.0-1040.el7.x86_64.img --reuse-cmdline

    该命令为 kexec 系统调用手动加载内核和 initramfs 镜像。

  2. 重启系统:

    # reboot

    该命令会检测内核,关闭所有服务,然后调用 kexec 系统调用来重新引导到您在上一步中提供的内核中。

警告

当您使用 kexec -e 命令重新引导内核时,系统不会在启动下一个内核前完成标准关闭序列,这可能会造成数据丢失或系统无响应。

11.9. 防止内核驱动程序为 kdump 加载

这部分论述了如何防止 kdump 内核使用 '/etc/sysconfig/kdump 配置文件载入某些内核驱动程序。在 /etc/sysconfig/kdump 文件中附加 KDUMP_COMMANDLINE_APPEND= 变量,防止 kdump initramfs 加载指定的内核模块。这有助于防止缩放 终止程序 或其他崩溃内核失败。

您可以使用以下配置选项之一附加 KDUMP_COMMANDLINE_APPEND= 变量:

  • rd.driver.blacklist=<modules>
  • modprobe.blacklist=<modules>

流程

  1. 选择您要阻止加载的内核模块。

    $ lsmod
    Module                  Size  Used by
    fuse                  126976  3
    xt_CHECKSUM            16384  1
    ipt_MASQUERADE         16384  1
    uinput                 20480  1
    xt_conntrack           16384  1

    lsmod 命令显示载入到当前运行的内核的模块列表。

  2. 更新 /etc/sysconfig/kdump 文件中的 KDUMP_COMMANDLINE_APPEND= 变量。

    KDUMP_COMMANDLINE_APPEND="rd.driver.blacklist=hv_vmbus,hv_storvsc,hv_utils,hv_netvsc,hid-hyperv"

    另外,使用 modprobe.blacklist=<modules> 配置选项参考以下示例。

    KDUMP_COMMANDLINE_APPEND="modprobe.blacklist=emcp modprobe.blacklist=bnx2fc modprobe.blacklist=libfcoe modprobe.blacklist=fcoe"
  3. 重启 kdump 服务。

    $ systemctl restart kdump

其它资源

  • dracut.cmdline 手册页

11.10. 在使用加密磁盘的系统中运行 kdump

当运行 LUKS 加密的分区时,系统需要一定数量的可用内存。如果系统可用内存量小于所需的可用内存量,则 cryptsetup 实用程序无法挂载分区。因此,在第二个内核(捕获内核)中将 vmcore 文件捕获到加密的目标位置会失败。

使用 kdumpctl estimate 命令,您可以估算 kdump 所需的内存量。kdumpctl 估计 会显示 推荐的 crashkernel 值,这是 kdump 所需的推荐内存大小。

推荐的 crashkernel 值根据当前的内核大小、内核模块、initramfs 和 LUKS 加密的目标内存要求计算。

如果您使用的是自定义 crashkernel= 选项,k dumpctl 估计 会显示 LUKS 所需的大小 值,这是 LUKS 加密目标所需的内存大小。

流程

  1. 运行以下命令来打印估算的 crashkernel= 值:

    # kdumpctl estimate
    
    Encrypted kdump target requires extra memory, assuming using the keyslot  with minimum memory requirement
       Reserved crashkernel:    256M
       Recommended crashkernel: 652M
    
       Kernel image size:   47M
       Kernel modules size: 8M
       Initramfs size:      20M
       Runtime reservation: 64M
       LUKS required size:  512M
       Large modules: <none>
       WARNING: Current crashkernel size is lower than recommended size 652M.
  2. 通过将 crashkernel= 值增加到所需的值来配置所需的内存量。
  3. 重启系统。
注意

如果 kdump 服务仍无法将转储文件保存到加密的目标,请根据需要增大 crashkernel= 值。

第 12 章 在 web 控制台中配置 kdump

在 RHEL 8 web 控制台中设置并测试 kdump 配置。

Web 控制台是 Red Hat Enterprise Linux 8 的默认安装的一部分,并在引导时启用或禁用 kdump 服务。另外,web 控制台允许您为 kdump 配置保留的内存,或者以未压缩或压缩格式选择 vmcore 保存位置。

12.1. 其它资源

12.2. 在 web 控制台中配置 kdump 内存用量和目标位置

下面的步骤显示如何使用 Red Hat Enterprise Linux web 控制台界面中的内核 转储 标签页来配置为 kdump 内核保留的内存量。此流程还描述了如何指定 vmcore 转储文件的目标位置以及如何测试您的配置。

流程

  1. 打开 Kernel Dump 标签页,启动 kdump 服务。
  2. 使用命令行配置 kdump 内存用量。
  3. Crash dump location 选项旁的链接。

    Web 控制台初始界面
  4. 从下拉菜单中选择 Local Filesystem 选项,并指定要保存转储的目录。

    Web 控制台 crashdump 目标
    • 或者,从下拉菜单中选择 Remote over SSH 选项,使用 SSH 协议将该 vmcore 发送到远程机器。

      Serverssh keyDirectory 项中提供远程机器的地址、ssh 密钥位置和目的地目录。

    • 另一种选择是从下拉菜单中选择 Remote over NFS 选项,并填写 Mount 字段,以使用 NFS 协议将 vmcore 发送到远程计算机。

      注意

      选择 Compression 复选框来缩小 vmcore 文件的大小。

  5. 崩溃内核以测试您的配置。

    Web 控制台测试 kdump 配置
    警告

    这一步会破坏内核的执行,并导致系统崩溃和数据丢失。

第 13 章 支持的 kdump 配置和目标

13.1. kdump 的内存要求

为了使 kdump 能够捕获内核崩溃转储并保存以便进一步分析,系统内存部分必须永久保留给捕获内核。保留时,主内核无法使用系统内存的这一部分。

内存要求因某些系统参数而异。主要因素之一就是系统的硬件构架。要找出确切的机器架构(如 Intel 64 和 AMD64,也称为 x86_64)并将其输出到标准输出,请使用以下命令:

$ uname -m

表 10.1 列出了在最新可用版本中为 kdump 自动保留内存大小的最低内存要求。根据系统构架和可用物理内存的大小更改。

表 13.1. kdump 最少需要保留的内存量

构架可用内存最小保留内存

AMD64 和 Intel 64(x86_64)

1 GB 到 4 GB

160 MB RAM。

4 GB 到 64 GB

192 MB RAM。

64 GB 到 1 TB

256 MB RAM。

1TB 及更多

512 MB RAM。

64 位 ARM 架构(ARM64)

2 GB 及更多

448 MB RAM。

IBM Power 系统(ppc64le)

2 GB 到 4 GB

384 MB RAM。

4 GB 到 16 GB

512 MB RAM。

16 GB 到 64 GB

1 GB RAM。

64 GB 到 128 GB

2 GB RAM。

128 GB 及更多

4 GB RAM。

IBM Z (s390x)

1 GB 到 4 GB

160 MB RAM。

4 GB 到 64 GB

192 MB RAM。

64 GB 到 1 TB

256 MB RAM。

1TB 及更多

512 MB RAM。

在很多系统中,k dump 可以估算所需内存量并自动保留。默认情况下,此行为是启用的,但仅适用于内存总量超过特定数量的系统,这些内存因系统架构而异。

重要

根据系统中内存总量自动配置保留内存是最佳工作量估算。实际需要的内存可能因其它因素(如 I/O 设备)而有所不同。使用内存不足将导致 debug 内核无法在内核 panic 的情况下作为捕获内核引导。要避免这个问题,请足够增大崩溃内核内存。

13.2. 自动内存保留的最小阈值

在某些系统中,可以通过在引导装载程序配置文件中使用 crashkernel=auto 参数为 kdump 自动分配内存,也可以在图形配置实用程序中启用这个选项。但是,要使此自动预留发挥作用,系统中需要提供一定大小的总内存。数量因系统架构的不同而有所不同。

表 10.2 列出自动分配内存的阈值。如果系统内存小于指定阈值,则必须手动配置内存。

表 13.2. 自动保留内存所需的最小内存量

构架所需的内存

AMD64 和 Intel 64(x86_64)

2 GB

IBM Power 系统(ppc64le)

2 GB

IBM  Z (s390x)

4 GB

13.3. 支持的 kdump 目标

当捕获内核崩溃时,vmcore 转储文件可以直接写入到设备中,作为文件存储在本地文件系统中,或者通过网络发送。下表包含 kdump 支持或明确不支持的转储目标的完整列表。

类型支持的目标不支持的目标

原始设备

所有本地附加的原始磁盘和分区。

 

本地文件系统

直接附加的磁盘驱动器、硬件 RAID 逻辑驱动器、LVM 设备以及 mdraid 阵列中的 ext 2、ext3、ext4 和 xfs 文件系统。

在此表中未明确列出的任何本地文件系统,包括 自动 类型(自动文件系统检测)。

远程目录

使用 NFSSSH 协议通过 IPv4 访问的远程目录。

使用 NFS 协议访问的 rootfs 文件系统上的远程目录。

通过硬件和软件启动器使用 iSCSI 协议访问的远程目录。

使用 be2iscsi 硬件上的 iSCSI 协议访问的远程目录.

基于多路径的存储。

 

通过 IPv6 访问的远程目录.

 

使用 SMBCIFS 协议访问的远程目录.

 

使用 FCoE以太网光纤通道)协议访问的远程目录。

 

使用无线网络接口访问的远程目录。

重要

利用固件支持的转储(fadump)捕获 vmcore,并使用 SSH 或 NFS 协议将其保存到远程机器中,这会导致网络接口重命名为 kdump-<interface-name>。如果 <interface-name> 是通用的,则会发生重命名,如 *eth# 、net# 等。这是因为初始 RAM 磁盘(initrd)中的 vmcore 捕获脚本在网络接口名称中添加 kdump- 前缀来保护持久性命名。由于同一 initrd 也用于常规启动,因此生产内核的接口名称也会更改。

13.4. 支持的 kdump 过滤等级

要缩小转储文件的大小,kdump 使用 makedumpfile 内核收集器压缩数据,并选择性地省略不需要的信息。下表包含 makedumpfile 实用程序目前支持的过滤级别的完整列表。

选项描述

1

零页

2

缓存页

4

缓存私有

8

用户页

16

可用页

注意

makedumpfile 命令支持删除透明大内存页和 hugetlbfs 页面。考虑这两种类型的大页用户页面,并使用 -8 级别将其删除。

其它资源

13.5. 支持的默认故障响应

默认情况下,当 kdump 创建内核转储失败时,操作系统会重启。但是,您可以将 kdump 配置为在将内核转储保存到主目标时执行不同的操作。下表列出了目前支持的所有默认操作。

选项描述

dump_to_rootfs

尝试将内核转储保存到 root 文件系统。这个选项在与网络目标合并时特别有用:如果网络目标无法访问,这个选项配置 kdump 以在本地保存内核转储。之后会重启该系统。

reboot

重启系统,这个过程会丢失 core 转储文件。

halt

关闭系统,这个过程会丢失 core 转储文件。

poweroff

关闭系统,这个此过程会丢失 core 转储。

shell

从 initramfs 内运行 shell 会话,允许用户手动记录核心转储。

final_action

在成功 kdumpshelldump_to_rootfs 失败操作完成后启用额外的操作,如 reboot、stop poweroff 操作。默认的 final_action 选项为 reboot

13.6. 使用 final_action 参数

last _action 参数允许您在成功 kdump 或使用 shelldump_to_rootfs 的调用 failure_response 机制后使用某些额外操作,如 reboot、stop poweroff 操作。如果未指定 final_action 选项,则默认为 reboot

流程

  1. 编辑 '/etc/kdump.conf 文件并添加 final_action 参数。

    final_action <reboot | halt | poweroff>
  2. 重启 kdump 服务:

    kdumpctl restart

13.7. 估算 kdump 大小

在规划和构建 kdump 环境时,需要知道在生成转储文件前需要多少空间。

makedumpfile --mem-usage 命令提供有关可扩展页面的有用报告,并可用于确定您要分配的转储级别。当系统处于代表负载下时运行此命令,否则 makedumpfile --mem-usage 会返回比生产环境中预期的值小的值。

[root@hostname ~]# makedumpfile --mem-usage /proc/kcore

TYPE            PAGES                   EXCLUDABLE      DESCRIPTION
----------------------------------------------------------------------
ZERO            501635                  yes             Pages filled with zero
CACHE           51657                   yes             Cache pages
CACHE_PRIVATE   5442                    yes             Cache pages + private
USER            16301                   yes             User process pages
FREE            77738211                yes             Free pages
KERN_DATA       1333192                 no              Dumpable kernel data
重要

makedumpfile --mem-usage 命令在页面中 报告。这意味着您必须根据内核页面大小计算使用的内存大小。默认情况下,Red Hat Enterprise Linux 内核为 AMD64 和 Intel 64 构架使用 4 KB 页面,为 IBM POWER 构架使用 64 KB 页面。

第 14 章 固件支持的转储机制

固件支持的转储(fadump)是一个转储捕获机制,作为 IBM POWER 系统中 kdump 机制的替代选择。kexeckdump 机制可用于在 AMD64 和 Intel 64 系统中捕获内核转储。但是,一些硬件(如小型系统和大型机计算机)利用板载固件隔离内存区域,并防止意外覆盖对崩溃分析很重要的数据。本节论述了 fadump 机制以及如何与 RHEL 集成。fadump 实用程序针对 IBM POWER 系统上的扩展转储功能进行了优化。

14.1. IBM PowerPC 硬件支持转储固件

fadump 实用程序从带有 PCI 和 I/O 设备的完全重设系统中捕获 vmcore 文件。这种机制使用固件在崩溃期间保留内存区域,然后重复使用 kdump 用户空间脚本保存 vmcore 文件。内存区域由所有系统内存内容组成,但引导内存、系统注册和硬件页面表条目(PTE)除外。

fadump 机制通过重新引导分区并使用新内核转储之前内核崩溃中的数据,提供比传统转储类型的更高可靠性。fadump 需要一个基于 IBM POWER6 处理器或更高版本的硬件平台。

有关 fadump 机制的详情,包括针对 PowerPC 重置硬件的方法,请查看 /usr/share/doc/kexec-tools/fadump-howto.txt 文件。

注意

未保留的内存区域(称为引导内存)是在崩溃事件后成功引导内核所需的 RAM 量。默认情况下,引导内存大小为 256MB 或系统 RAM 总量的 5%,以较大者为准。

kexec-initiated 事件不同,fadump 机制使用 production 内核恢复崩溃转储。崩溃后引导时,PowerPC 硬件使设备节点 /proc/device-tree/rtas/ibm.kernel-dump 可供 proc 文件系统(procfs)使用。fadump 感知 kdump 脚本,检查存储的 vmcore,然后完全完成系统重启。

14.2. 启用固件支持的转储机制

IBM POWER 的崩溃转储功能可以通过启用固件支持的转储(fadump)机制来增强。

流程

  1. 安装和配置 kdump
  2. /etc/default/grub 文件中的 GRUB_CMDLINE_LINUX 行中添加 fadump=on

    GRUB_CMDLINE_LINUX="rd.lvm.lv=rhel/swap crashkernel=auto
    rd.lvm.lv=rhel/root rhgb quiet fadump=on"
  3. (可选)如果要指定保留引导内存而不是使用默认值,请在 /etc/default/grub 中将 crashkernel=xxM 配置为 GRUB_CMDLINE_LINUX,其中 xx 是以 MB 为单位所需的内存量:

    GRUB_CMDLINE_LINUX="rd.lvm.lv=rhel/swap crashkernel=xxM rd.lvm.lv=rhel/root rhgb quiet fadump=on"
    重要

    红帽建议在执行前测试所有引导选项。如果您在从崩溃内核引导时观察到内存不足(OOM)错误,请增大 crashkernel= 参数中指定的值,直到崩溃内核可以完全启动。在本例中可能会需要进行一些不同的尝试。

14.3. IBM Z 硬件支持的固件转储机制

IBM Z 系统支持以下固件支持的转储机制:

  • 独立转储(sadump)
  • VMDUMP

IBM Z 系统支持并使用 kdump 基础架构。但是,使用 IBM Z 的固件支持的转储(fadump)方法之一可以提供各种优点:

  • sad ump 机制是从系统控制台启动和控制的,并存储在 IPL 可引导设备中。
  • VMDUMP 机制与 sad ump 类似。此工具也从系统控制台启动,但会从硬件检索生成的转储并将其复制到系统以进行分析。
  • 这些方法(与其他基于硬件的转储机制类似)能够在 kdump 服务启动前捕获机器在早期启动阶段的状态。
  • 尽管 VMDUMP 包含将转储文件接收到 Red Hat Enterprise Linux 系统中的机制,但 VMDUMP 的配置和控制是从 IBM Z 硬件控制台管理的。

IBM 在 独立转储程序 文章和 VMDUMP 的 z/VM 中创建转储中的 VMDUMP 中 详细讨论 sad ump

IBM 还包含使用 Red Hat Enterprise Linux 7.4 中使用 Dump Tools on Red Hat Enterprise Linux 7.4 文档中的转储工具的文档集。

14.4. 在 Fujitsu PRIMEQUEST 系统中使用 sadump

Fujitsu sadump 机制旨在在 kdump 无法成功完成时提供 回退 转储捕获。sad ump 机制是从系统管理板(MMB)接口手动调用的。使用 MMB,为 Intel 64 或 AMD 64 服务器配置 kdump,然后执行以下步骤启用 sad ump

流程

  1. /etc/sysctl.conf 文件中添加或编辑以下行,以确保 sad umpkdump 按预期启动:

    kernel.panic=0
    kernel.unknown_nmi_panic=1
    警告

    特别是,请确保在 kdump 后系统不会重启。如果系统在 kdump 无法保存 vmcore 文件后重启,则无法调用 sad ump

  2. 适当将 /etc/kdump.conf 中的 failure_action 参数设置为 haltshell

    failure_action shell

其它资源

  • FUJITSU Server PRIMEQUEST 2000 系列安装手册

第 15 章 分析内核转储

要确定系统崩溃的原因,您可以使用 crash 实用程序,它提供了一个与 GNU Debugger(GDB)类似的交互式提示符。这个工具允许您交互式地分析由 kdump、netdump、diskdumpxendump 创建的内核转储以及正在运行的 Linux 系统。另外,您还可以使用 Kernel Oops Analyzer 或者 Kdump Helper 工具。

15.1. 安装 crash 工具

以下流程描述了如何安装 crash 分析工具。

流程

  1. 启用相关的软件仓库:

    # subscription-manager repos --enable baseos repository
    # subscription-manager repos --enable appstream repository
    # subscription-manager repos --enable rhel-8-for-x86_64-baseos-debug-rpms
  2. 安装 crash 软件包:

    # yum install crash
  3. 安装 kernel-debuginfo 软件包:

    # yum install kernel-debuginfo

    包与您正在运行的内核对应,提供转储分析所需的数据。

其它资源

15.2. 运行和退出 crash 工具

以下流程描述了如何启动崩溃程序来分析系统崩溃原因。

先决条件

  • 确定当前运行的内核(例如 4.18.0-5.el8.x86_64)。

流程

  1. 要启动 crash 工具程序,需要将两个必要的参数传递给该命令:

    • debug-info(解压缩的 vmlinuz 镜像),如 /usr/lib/debug/lib/modules/4.18.0-5.el8.x86_64/vmlinux,通过特定的 kernel-debuginfo 软件包提供。
    • 实际 vmcore 文件,如 /var/crash/127.0.0.1-2018-10-06-14:05:33/vmcore

      生成的 crash 命令类似如下:

      # crash /usr/lib/debug/lib/modules/4.18.0-5.el8.x86_64/vmlinux /var/crash/127.0.0.1-2018-10-06-14:05:33/vmcore

      使用 kdump 捕获的相同 <kernel> 版本

      例 15.1. 运行 crash 工具

      以下示例演示了使用 4.18.0-5.el8.x86_64 内核分析在 2018 年 10 月 6 日下午 14:05 时创建的内核转储。

      ...
      WARNING: kernel relocated [202MB]: patching 90160 gdb minimal_symbol values
      
            KERNEL: /usr/lib/debug/lib/modules/4.18.0-5.el8.x86_64/vmlinux
          DUMPFILE: /var/crash/127.0.0.1-2018-10-06-14:05:33/vmcore  [PARTIAL DUMP]
              CPUS: 2
              DATE: Sat Oct  6 14:05:16 2018
            UPTIME: 01:03:57
      LOAD AVERAGE: 0.00, 0.00, 0.00
             TASKS: 586
          NODENAME: localhost.localdomain
           RELEASE: 4.18.0-5.el8.x86_64
           VERSION: #1 SMP Wed Aug 29 11:51:55 UTC 2018
           MACHINE: x86_64  (2904 Mhz)
            MEMORY: 2.9 GB
             PANIC: "sysrq: SysRq : Trigger a crash"
               PID: 10635
           COMMAND: "bash"
              TASK: ffff8d6c84271800  [THREAD_INFO: ffff8d6c84271800]
               CPU: 1
             STATE: TASK_RUNNING (SYSRQ)
      
      crash>
  2. 要退出交互式提示符并终止 崩溃,请键入 exitq

    例 15.2. 退出 crash 工具

    crash> exit
    ~]#
注意

crash 命令也可以用作调试实时系统的强大工具。但是请谨慎使用它,以免破坏您的系统。

15.3. 在 crash 工具中显示各种指示符

以下流程描述了如何使用崩溃实用程序并显示各种指标,如内核消息缓冲、后端、进程状态、虚拟内存信息和打开文件。

显示消息缓冲
  • 要显示内核消息缓冲,在互动提示符下输入 日志 命令,如下例所示:
crash> log
... several lines omitted ...
EIP: 0060:[<c068124f>] EFLAGS: 00010096 CPU: 2
EIP is at sysrq_handle_crash+0xf/0x20
EAX: 00000063 EBX: 00000063 ECX: c09e1c8c EDX: 00000000
ESI: c0a09ca0 EDI: 00000286 EBP: 00000000 ESP: ef4dbf24
 DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068
Process bash (pid: 5591, ti=ef4da000 task=f196d560 task.ti=ef4da000)
Stack:
 c068146b c0960891 c0968653 00000003 00000000 00000002 efade5c0 c06814d0
<0> fffffffb c068150f b7776000 f2600c40 c0569ec4 ef4dbf9c 00000002 b7776000
<0> efade5c0 00000002 b7776000 c0569e60 c051de50 ef4dbf9c f196d560 ef4dbfb4
Call Trace:
 [<c068146b>] ? __handle_sysrq+0xfb/0x160
 [<c06814d0>] ? write_sysrq_trigger+0x0/0x50
 [<c068150f>] ? write_sysrq_trigger+0x3f/0x50
 [<c0569ec4>] ? proc_reg_write+0x64/0xa0
 [<c0569e60>] ? proc_reg_write+0x0/0xa0
 [<c051de50>] ? vfs_write+0xa0/0x190
 [<c051e8d1>] ? sys_write+0x41/0x70
 [<c0409adc>] ? syscall_call+0x7/0xb
Code: a0 c0 01 0f b6 41 03 19 d2 f7 d2 83 e2 03 83 e0 cf c1 e2 04 09 d0 88 41 03 f3 c3 90 c7 05 c8 1b 9e c0 01 00 00 00 0f ae f8 89 f6 <c6> 05 00 00 00 00 01 c3 89 f6 8d bc 27 00 00 00 00 8d 50 d0 83
EIP: [<c068124f>] sysrq_handle_crash+0xf/0x20 SS:ESP 0068:ef4dbf24
CR2: 0000000000000000

键入 help log 以 了解有关命令用法的更多信息。

注意

内核消息缓冲区包含有关系统崩溃的最重要信息,因此始终先转储到 vmcore-dmesg.txt 文件。当尝试使完整的 vmcore 文件失败时(例如,目标位置上缺少空间),这很有用。默认情况下,vmcore-dmesg.txt 位于 /var/crash/ 目录中。

显示后端
  • 若要显示内核堆栈跟踪,可使用 bt 命令。
crash> bt
PID: 5591   TASK: f196d560  CPU: 2   COMMAND: "bash"
 #0 [ef4dbdcc] crash_kexec at c0494922
 #1 [ef4dbe20] oops_end at c080e402
 #2 [ef4dbe34] no_context at c043089d
 #3 [ef4dbe58] bad_area at c0430b26
 #4 [ef4dbe6c] do_page_fault at c080fb9b
 #5 [ef4dbee4] error_code (via page_fault) at c080d809
    EAX: 00000063  EBX: 00000063  ECX: c09e1c8c  EDX: 00000000  EBP: 00000000
    DS:  007b      ESI: c0a09ca0  ES:  007b      EDI: 00000286  GS:  00e0
    CS:  0060      EIP: c068124f  ERR: ffffffff  EFLAGS: 00010096
 #6 [ef4dbf18] sysrq_handle_crash at c068124f
 #7 [ef4dbf24] __handle_sysrq at c0681469
 #8 [ef4dbf48] write_sysrq_trigger at c068150a
 #9 [ef4dbf54] proc_reg_write at c0569ec2
#10 [ef4dbf74] vfs_write at c051de4e
#11 [ef4dbf94] sys_write at c051e8cc
#12 [ef4dbfb0] system_call at c0409ad5
    EAX: ffffffda  EBX: 00000001  ECX: b7776000  EDX: 00000002
    DS:  007b      ESI: 00000002  ES:  007b      EDI: b7776000
    SS:  007b      ESP: bfcb2088  EBP: bfcb20b4  GS:  0033
    CS:  0073      EIP: 00edc416  ERR: 00000004  EFLAGS: 00000246

键入 bt <pid> 以显示特定进程的后端追踪或类型 帮助 bt 以获得有关 bt 用法的更多信息。

显示进程状态
  • 若要显示系统中进程的状态,可使用 ps 命令。
crash> ps
   PID    PPID  CPU   TASK    ST  %MEM     VSZ    RSS  COMM
>     0      0   0  c09dc560  RU   0.0       0      0  [swapper]
>     0      0   1  f7072030  RU   0.0       0      0  [swapper]
      0      0   2  f70a3a90  RU   0.0       0      0  [swapper]
>     0      0   3  f70ac560  RU   0.0       0      0  [swapper]
      1      0   1  f705ba90  IN   0.0    2828   1424  init
... several lines omitted ...
   5566      1   1  f2592560  IN   0.0   12876    784  auditd
   5567      1   2  ef427560  IN   0.0   12876    784  auditd
   5587   5132   0  f196d030  IN   0.0   11064   3184  sshd
>  5591   5587   2  f196d560  RU   0.0    5084   1648  bash

使用 ps <pid> 显示 单个进程的状态。使用 help ps 了解有关 ps 用法的更多信息。

显示虚拟内存信息
  • 要显示基本虚拟内存信息,请在交互式提示符下键入 vm 命令。
crash> vm
PID: 5591   TASK: f196d560  CPU: 2   COMMAND: "bash"
   MM       PGD      RSS    TOTAL_VM
f19b5900  ef9c6000  1648k    5084k
  VMA       START      END    FLAGS  FILE
f1bb0310    242000    260000 8000875  /lib/ld-2.12.so
f26af0b8    260000    261000 8100871  /lib/ld-2.12.so
efbc275c    261000    262000 8100873  /lib/ld-2.12.so
efbc2a18    268000    3ed000 8000075  /lib/libc-2.12.so
efbc23d8    3ed000    3ee000 8000070  /lib/libc-2.12.so
efbc2888    3ee000    3f0000 8100071  /lib/libc-2.12.so
efbc2cd4    3f0000    3f1000 8100073  /lib/libc-2.12.so
efbc243c    3f1000    3f4000 100073
efbc28ec    3f6000    3f9000 8000075  /lib/libdl-2.12.so
efbc2568    3f9000    3fa000 8100071  /lib/libdl-2.12.so
efbc2f2c    3fa000    3fb000 8100073  /lib/libdl-2.12.so
f26af888    7e6000    7fc000 8000075  /lib/libtinfo.so.5.7
f26aff2c    7fc000    7ff000 8100073  /lib/libtinfo.so.5.7
efbc211c    d83000    d8f000 8000075  /lib/libnss_files-2.12.so
efbc2504    d8f000    d90000 8100071  /lib/libnss_files-2.12.so
efbc2950    d90000    d91000 8100073  /lib/libnss_files-2.12.so
f26afe00    edc000    edd000 4040075
f1bb0a18   8047000   8118000 8001875  /bin/bash
f1bb01e4   8118000   811d000 8101873  /bin/bash
f1bb0c70   811d000   8122000 100073
f26afae0   9fd9000   9ffa000 100073
... several lines omitted ...

使用 vm <pid> 显示单个特定进程的信息,或者使用 help vm 来了解有关 vm 使用情况的更多信息。

显示打开的文件
  • 要显示有关打开文件的信息,请使用 files 命令。
crash> files
PID: 5591   TASK: f196d560  CPU: 2   COMMAND: "bash"
ROOT: /    CWD: /root
 FD    FILE     DENTRY    INODE    TYPE  PATH
  0  f734f640  eedc2c6c  eecd6048  CHR   /pts/0
  1  efade5c0  eee14090  f00431d4  REG   /proc/sysrq-trigger
  2  f734f640  eedc2c6c  eecd6048  CHR   /pts/0
 10  f734f640  eedc2c6c  eecd6048  CHR   /pts/0
255  f734f640  eedc2c6c  eecd6048  CHR   /pts/0

使用 文件 <pid> 仅显示一个选定进程打开的文件,或者使用 帮助文件 了解有关 文件 使用的更多信息。

15.4. 使用内核 Oops 分析器

Kernel Oops Analyzer 工具通过将 oops 消息与知识库中已知问题进行比较,分析崩溃转储。

先决条件

  • 保护用于馈送内核 Oops 分析器的 oops 消息。

流程

  1. 访问内核 Oops 分析器工具.
  2. 要诊断内核崩溃问题,请上传 vmcore 中生成的内核oops 日志。

    • 或者,您也可以通过提供文本消息或 vmcore-dmesg.txt 作为输入来诊断内核崩溃问题。

      内核 oops 分析器
  3. 单击 DETECT,基于 makedumpfile 中的信息与已知解决方案比较 oops 消息。

15.5. Kdump Helper 工具

Kdump Helper 工具有助于使用提供的信息设置 kdump。kdump 帮助程序根据您的偏好生成配置脚本。在服务器中启动并运行该脚本可设置 kdump 服务。

其它资源

第 16 章 使用早期 kdump 来捕获引导时间崩溃

作为系统管理员,您可以使用 kdump 服务的早期 kdump 支持在引导过程的早期阶段捕获崩溃内核的 vmcore 文件。这部分论述了 早期 kdump 是什么、如何配置它以及如何检查这个机制的状态。

16.1. 什么是早期 kdump

kdump 服务尚未启动且无法帮助捕获和保存崩溃内核内存内容时,内核会在引导阶段崩溃。因此,故障排除的重要信息将丢失。

要解决这个问题,RHEL 8 引进了 早期 kdump 功能作为 kdump 服务的一部分。

16.2. 启用早期 kdump

这部分论述了如何启用 早期 kdump 功能来消除丢失早期引导内核崩溃信息的风险。

先决条件

  • 有效的红帽企业 Linux 订阅.
  • 包含用于您的系统 CPU 架构的 kexec-tools 软件包的软件仓库
  • 实现了 kdump 配置和目标要求。

流程

  1. 验证 kdump 服务是否已启用并活跃:

    # systemctl is-enabled kdump.service && systemctl is-active kdump.service enabled active

    如果没有启用并运行 kdump,请设置所有必要的配置,并验证是否已启用 kdump 服务。

  2. 使用 早期 kdump 功能重建引导内核的 initramfs 镜像:

    dracut -f --add earlykdump
  3. 添加 rd.earlykdump 内核命令行参数:

    grubby --update-kernel=/boot/vmlinuz-$(uname -r) --args="rd.earlykdump"
  4. 重启系统以反应更改

    reboot
  5. 另外,还可验证 rd.earlykdump 是否已成功添加并启用 早期 kdump 功能:

    # cat /proc/cmdline
    BOOT_IMAGE=(hd0,msdos1)/vmlinuz-4.18.0-187.el8.x86_64 root=/dev/mapper/rhel-root ro crashkernel=auto resume=/dev/mapper/rhel-swap rd.lvm.lv=rhel/root rd.lvm.lv=rhel/swap rhgb quiet rd.earlykdump
    
    # journalctl -x | grep early-kdump
    Mar 20 15:44:41 redhat dracut-cmdline[304]: early-kdump is enabled.
    Mar 20 15:44:42 redhat dracut-cmdline[304]: kexec: loaded early-kdump kernel

其它资源

第 17 章 使用内核实时修补程序应用补丁

您可以使用 Red Hat Enterprise Linux 内核实时修补解决方案在不重启或者重启任何进程的情况下对运行的内核进行补丁。

使用这个解决方案,系统管理员需要:

  • 可以在内核中立即应用重要的安全补丁。
  • 不必等待长时间运行的任务完成、关闭或调度停机时间。
  • 可以控制系统的正常运行时间,且不会牺牲安全性和稳定性。

请注意,并非所有关键或重要的 CVE 都使用内核实时补丁解决方案来解决。我们的目标是,在应用安全相关的补丁时,尽量减少重启的需要,但无法完全避免重启。有关实时补丁范围的详情,请参阅 客户门户网站解决方案文章

警告

内核实时补丁和其它内核子组件之间存在一些不兼容。在使用内核实时补丁前,请仔细阅读 kpatch 的限制

17.1. kpatch 的限制

  • kpatch 功能不是一个通用内核升级机制。它可用于在无法立即重启系统时应用简单的安全性和程序错误修复更新。
  • 不要在载入补丁期间或之后使用 SystemTapkprobe 工具。在删除此类探测后,补丁可能无法生效。

17.2. 对第三方实时补丁的支持

kpatch 实用程序是红帽通过红帽软件仓库提供的 RPM 模块支持的唯一内核实时补丁程序。红帽不支持任何不是由红帽提供的实时补丁。

如果您需要支持第三方实时补丁所带来的问题,红帽建议您在调查开始时,与需要确定根本原因的任何调查开始时,创建一个与实时补丁供应商案例。如果供应商允许源代码,并且其支持组织能够在向红帽支持升级调查前为其支持组织提供根本原因方面的帮助,则源代码可以被提供。

对于任何使用了第三方补丁程序运行的系统,红帽保留请求用户使用由红帽提供并支持的软件重现问题的权利。如果无法做到这一点,我们需要在测试环境中部署类似的系统和工作负载,而无需应用实时补丁,以确认是否观察到了相同的行为。

有关第三方软件支持政策的更多信息,请参阅红帽全球支持服务如何处理第三方软件、驱动程序和/或未经认证的硬件/管理程序或虚拟机操作系统?

17.3. 获得内核实时补丁

内核实时修补功能作为内核模块(kmod)实施,该模块作为 RPM 软件包提供。

所有客户都可以访问内核实时补丁,这些补丁通过常用的通道提供。但是,在下一个次版本发布后,未订阅延长支持服务的客户将无法访问当前次要版本的新修补程序。例如,具有标准订阅的客户只能在 RHEL 8.3 内核发布前提供 RHEL 8.2 内核补丁。

17.4. 组件内核实时修补

内核实时补丁的组件如下:

内核补丁模块

  • 内核实时补丁的交付机制。
  • 为内核建补丁的内核模块。
  • patch 模块包含内核所需修复的代码。
  • patch 模块使用 livepatch 内核子系统注册,并提供要替换的原始功能的信息,并提供与替换功能对应的指针。内核补丁模块以 RPM 的形式提供。
  • 命名规则为 kpatch_<kernel version>_<kpatch version>_<kpatch release>。名称的"内核版本"部分的 dots 替换为下划线
kpatch 工具
用于管理补丁模块的命令行工具。
kpatch 服务
multiuser.target 所需的 systemd 服务。这个目标会在引导时载入内核补丁模块。
kpatch-dnf 软件包
以 RPM 软件包的形式提供的 DNF 插件。此插件管理内核实时补丁的自动订阅。

17.5. 内核实时补丁如何工作

kpatch 内核补丁解决方案使用 livepatch 内核子系统将旧功能重定向到新功能。当实时内核补丁应用到系统时,会出现以下情况:

  1. 内核补丁模块复制到 /var/lib/kpatch/ 目录中,并在下次引导时由 systemd 注册以重新应用到内核。
  2. kpatch 模块被加载到正在运行的内核中,新的功能会注册到 ftrace 机制中,带有指向新代码内存中位置的指针。
  3. 当内核访问补丁的功能时,它将由 ftrace 机制重定向,该机制绕过原始功能并将内核重定向到功能补丁版本。

图 17.1. 内核实时补丁如何工作

RHEL kpatch 概述

17.6. 将当前安装的内核订阅到实时补丁流

内核补丁模块在 RPM 软件包中提供,具体取决于被修补的内核版本。每个 RPM 软件包将随着时间不断累积更新。

以下流程解释了如何订阅以后为给定内核的所有累积实时补丁更新。因为实时补丁是累计的,所以您无法选择为一个特定的内核部署哪些单独的补丁。

警告

红帽不支持任何适用于红帽支持的系统的第三方实时补丁。

先决条件

  • 根权限

流程

  1. 另外,还可检查您的内核版本:

    # uname -r
    4.18.0-94.el8.x86_64
  2. 搜索与内核版本对应的实时补丁软件包:

    # yum search $(uname -r)
  3. 安装 live patching 软件包:

    # yum install "kpatch-patch = $(uname -r)"

    以上命令只为特定内核安装并应用最新的实时补丁。

    如果实时补丁包的版本是 1-1 或更高版本,则软件包将包含补丁模块。在这种情况下,内核会在安装 live patching 软件包期间自动修补。

    内核补丁模块也安装到 /var/lib/kpatch/ 目录中,供 systemd 系统和服务管理器以后重启时载入。

    注意

    当给定内核没有可用的实时补丁时,将安装空的实时补丁软件包。空的 live patching 软件包会有一个 0-0 的 kpatch_version-kpatch_release,如 kpatch-patch-4_18_0-94-0-0.el8.x86_64.rpm。空 RPM 安装会将系统订阅到以后为给定内核提供的所有实时补丁。

  4. 另外,用来确认内核已应用了补丁程序:

    # kpatch list
    Loaded patch modules:
    kpatch_4_18_0_94_1_1 [enabled]
    
    Installed patch modules:
    kpatch_4_18_0_94_1_1 (4.18.0-94.el8.x86_64)
    …​

    输出显示内核补丁模块已加载到内核中,现在它使用来自 kpatch-patch-4_18_0-94-1-1.el8.x86_64.rpm 软件包的最新修复进行补丁。

其它资源

17.7. 自动订阅将来的内核到实时补丁流

您可以使用 kpatch-dnf DNF 插件订阅系统,从而修复内核补丁模块(也称为内核实时补丁)提供的修复。该插件可为系统当前使用的任何内核启用自动订阅 ,并为以后将要安装的任何内核启用自动订阅。

先决条件

  • root 权限。

流程

  1. (可选)检查所有安装的内核和您当前运行的内核:

    # yum list installed | grep kernel
    Updating Subscription Management repositories.
    Installed Packages
    ...
    kernel-core.x86_64         4.18.0-240.10.1.el8_3           @rhel-8-for-x86_64-baseos-rpms
    kernel-core.x86_64         4.18.0-240.15.1.el8_3           @rhel-8-for-x86_64-baseos-rpms
    ...
    
    # uname -r
    4.18.0-240.10.1.el8_3.x86_64
  2. 安装 kpatch-dnf 插件:

    # yum install kpatch-dnf
  3. 启用自动订阅内核实时补丁:

    # yum kpatch auto
    Updating Subscription Management repositories.
    Last metadata expiration check: 19:10:26 ago on Wed 10 Mar 2021 04:08:06 PM CET.
    Dependencies resolved.
    ==================================================
     Package                             Architecture
    ==================================================
    Installing:
     kpatch-patch-4_18_0-240_10_1        x86_64
     kpatch-patch-4_18_0-240_15_1        x86_64
    
    Transaction Summary
    ===================================================
    Install  2 Packages
    …​

    这个命令订阅所有当前安装的内核,以接收内核实时补丁。命令还会为所有安装的内核安装并应用最新的累积实时补丁(如果有)。

    将来,当您更新内核时,将在新的内核安装过程中自动安装实时补丁。

    内核补丁模块也安装到 /var/lib/kpatch/ 目录中,供 systemd 系统和服务管理器以后重启时载入。

    注意

    当给定内核没有可用的实时补丁时,将安装空的实时补丁软件包。空的 live patching 软件包会有一个 0-0 的 kpatch_version-kpatch_release,如 kpatch-patch-4_18_0-240-0-0.el8.x86_64.rpm。空 RPM 安装会将系统订阅到以后为给定内核提供的所有实时补丁。

  4. (可选)验证所有安装的内核是否已修补:

    # kpatch list
    Loaded patch modules:
    kpatch_4_18_0_240_10_1_0_1 [enabled]
    
    Installed patch modules:
    kpatch_4_18_0_240_10_1_0_1 (4.18.0-240.10.1.el8_3.x86_64)
    kpatch_4_18_0_240_15_1_0_2 (4.18.0-240.15.1.el8_3.x86_64)

    输出显示您正在运行的内核,另一个安装的内核已分别修补了来自 kpatch-patch-4_18_0-240_10_1-0-1.rpmkpatch-4_18_40_15_1-0-1.rpm 软件包的修复。

其它资源

17.8. 更新内核补丁模块

由于内核补丁模块是通过 RPM 软件包交付和应用,更新累积内核补丁模块就如同更新任何其他 RPM 软件包一样。

流程

  • 更新至当前内核的新累计版本:

    # yum update "kpatch-patch = $(uname -r)"

    以上命令会自动安装并应用所有当前运行的内核可用的更新。包括将来发布的所有在线补丁。

  • 另外,更新所有安装的内核补丁模块:

    # yum update "kpatch-patch"
注意

当系统重启到同一内核时,kpatch.service systemd 服务会再次对内核进行补丁。

其它资源

17.9. 删除 live patching 软件包

下面的步骤描述了如何通过删除 live patching 软件包禁用Red Hat Enterprise Linux 内核实时修补解决方案。

先决条件

  • 根权限
  • 已安装 live patching 软件包。

流程

  1. 选择 live patching 软件包:

    # yum list installed | grep kpatch-patch
    kpatch-patch-4_18_0-94.x86_64        1-1.el8        @@commandline
    …​

    上面的输出示例列出了您安装的实时补丁软件包。

  2. 删除 live patching 软件包:

    # yum remove kpatch-patch-4_18_0-94.x86_64

    删除实时补丁软件包后,内核将保持补丁,直到下次重启为止,但内核补丁模块会从磁盘中删除。将来重启时,对应的内核将不再被修补。

  3. 重启您的系统。
  4. 验证 live patching 软件包是否已删除:

    # yum list installed | grep kpatch-patch

    如果软件包已被成功删除,命令不会显示任何输出。

  5. (可选)验证内核实时补丁解决方案是否已禁用:

    # kpatch list
    Loaded patch modules:

    示例输出显示内核没有补丁,实时补丁解决方案没有激活,因为目前没有加载补丁模块。

重要

目前,红帽不支持在不重启系统的情况下还原实时补丁。如有任何问题,请联系我们的支持团队。

其它资源

17.10. 卸载内核补丁模块

下面的步骤描述了如何防止 Red Hat Enterprise Linux 内核实时修补解决方案,使其在以后的引导中应用内核补丁模块。

先决条件

  • 根权限
  • 已安装实时补丁软件包。
  • 已安装并载入内核补丁模块。

流程

  1. 选择内核补丁模块:

    # kpatch list
    Loaded patch modules:
    kpatch_4_18_0_94_1_1 [enabled]
    
    Installed patch modules:
    kpatch_4_18_0_94_1_1 (4.18.0-94.el8.x86_64)
    …​
  2. 卸载所选内核补丁模块:

    # kpatch uninstall kpatch_4_18_0_94_1_1
    uninstalling kpatch_4_18_0_94_1_1 (4.18.0-94.el8.x86_64)
    • 请注意,卸载的内核补丁模块仍然被加载:

      # kpatch list
      Loaded patch modules:
      kpatch_4_18_0_94_1_1 [enabled]
      
      Installed patch modules:
      <NO_RESULT>

      卸载所选模块后,内核将保持补丁,直到下次重启为止,但已从磁盘中删除内核补丁模块。

  3. 重启您的系统。
  4. (可选)验证内核补丁模块是否已卸载:

    # kpatch list
    Loaded patch modules:
    …​

    以上输出示例显示没有加载或已安装的内核补丁模块,因此没有修补内核,且内核实时补丁解决方案未激活。

重要

目前,红帽不支持在不重启系统的情况下还原实时补丁。如有任何问题,请联系我们的支持团队。

其它资源

  • kpatch(1) 手册页

17.11. 禁用 kpatch.service

下面的步骤描述了如何防止 Red Hat Enterprise Linux 内核实时修补解决方案在以后的引导中全局应用所有内核补丁模块。

先决条件

  • 根权限
  • 已安装实时补丁软件包。
  • 已安装并载入内核补丁模块。

流程

  1. 验证 kpatch.service 是否已启用:

    # systemctl is-enabled kpatch.service
    enabled
  2. 禁用 kpatch.service

    # systemctl disable kpatch.service
    Removed /etc/systemd/system/multi-user.target.wants/kpatch.service.
    • 请注意,应用的内核补丁模块仍然被载入:

      # kpatch list
      Loaded patch modules:
      kpatch_4_18_0_94_1_1 [enabled]
      
      Installed patch modules:
      kpatch_4_18_0_94_1_1 (4.18.0-94.el8.x86_64)
  3. 重启您的系统。
  4. (可选)验证 kpatch.service 的状态:

    # systemctl status kpatch.service
    ● kpatch.service - "Apply kpatch kernel patches"
       Loaded: loaded (/usr/lib/systemd/system/kpatch.service; disabled; vendor preset: disabled)
       Active: inactive (dead)

    示例输出测试 kpatch.service 已被禁用且没有在运行。因此,内核实时修补解决方案不活跃。

  5. 确认内核补丁模块已被卸载:

    # kpatch list
    Loaded patch modules:
    <NO_RESULT>
    
    Installed patch modules:
    kpatch_4_18_0_94_1_1 (4.18.0-94.el8.x86_64)

    上面的示例输出显示内核补丁模块仍处于安装状态,但没有修补内核。

重要

目前,红帽不支持在不重启系统的情况下还原实时补丁。如有任何问题,请联系我们的支持团队。

其它资源

第 18 章 为应用程序设置限制

您可以使用 控制组 (cgroup)内核功能来设置限值、排列优先级或隔离进程的硬件资源。这样,您可以精细地控制应用的资源使用,从而更有效地使用它们。

18.1. 了解控制组群

控制组 是一种 Linux 内核功能,可让您将进程分级组织为分层组 - cgroups。层次结构(控制组树)通过为 cgroup 虚拟文件系统提供结构来定义,该结构默认挂载到 /sys/fs/cgroup/ 目录。它通过在 /sys/fs/cgroup/ 中 创建和删除子目录手动完成。或者,使用 systemd 系统和服务管理器。

资源控制器(内核组件)随后通过限制、排列或分配系统资源(如 CPU 时间、内存、网络带宽或各种组合)来修改 cgroup 中进程的行为。

cgroups 的增值值是流程聚合,允许在应用程序和用户之间划分硬件资源。因此可以提高总体的效率、稳定性以及用户环境的安全。

控制组群版本 1

控制组版本 1 (cgroups-v1)提供按资源控制器层次结构。这意味着,每个资源(如 CPU、内存、I/O 等)都有自己的控制组层次结构。可以组合不同的控制组层次结构,从而使一个控制器可以在管理各自资源时相互协调。但是,这两个控制器可能属于不同的进程层次结构,不允许它们进行适当的协调。

cgroups-v1 控制器在很长的时间跨度开发,因此其控制文件的行为和命名不一致。

控制组群版本 2

源自层次结构灵活性的控制器协调问题导致了控制组版本 2 的开发。

控制组版本 2 (cgroups-v2)提供单一控制组层次结构,用于挂载所有资源控制器。

控制文件行为和命名在不同控制器之间保持一致。

警告

RHEL 8 将 cgroups-v2 作为技术预览提供,包含有限数量的资源控制器。有关相关资源控制器的更多信息,请参阅 cgroups-v2 发行注记。

这个子部分基于 Devconf.cz 2019 演示。[1]

其它资源

18.2. 内核资源控制器

控制组群的功能由内核资源控制器启用。RHEL 8 支持 控制组群版本 1 (cgroups-v1)和 控制组版本 2 (cgroups-v2)的各种控制器。

资源控制器也称为控制组子系统,是一个代表单一资源的内核子系统,如 CPU 时间、内存、网络带宽或磁盘 I/O。Linux 内核提供由 systemd 系统和服务管理器自动挂载的一系列资源控制器。在 /proc/cgroups 文件中查找当前挂载的资源控制器的列表。

cgroups-v1 有以下控制器可用:

  • blkio - 可以设置块设备对输入/输出访问的限制。
  • CPU - 调整完全公平调度程序(CFS)调度程序的参数,以用于控制组的任务。它与 cpuacct 控制器一起挂载在同一挂载上。
  • cpuacct - 创建控制组中任务使用的 CPU 资源自动报告。它与 cpu 控制器一起挂载在同一挂载上。
  • cpuset - 可用于将控制组任务限制为仅在指定 CPU 子集上运行,并指示任务仅在指定内存节点上使用内存。
  • devices - 可以为控制组中的任务控制对设备的访问。
  • freezer - 可用于暂停或恢复控制组中的任务。
  • memory - 可用于设置控制组中任务的内存使用限值,并对这些任务使用的内存资源生成自动报告。
  • net_cls - 使用类标识符(classid)标记网络数据包,使 Linux 流量控制器( tc 命令)能够识别源自特定控制组任务的数据包。net_cls 子系统 net_filter (iptables)也可使用此标签对此类数据包执行操作。net_filter 使用防火墙标识符(fwid)标记网络套接字,允许 Linux 防火墙(通过 iptables 命令)识别源自特定控制组任务的数据包。
  • net_prio - 设置网络流量的优先级.
  • PIDs - 可以为控制组中的多个进程及其子进程设置限值.
  • perf_event - 可以通过 perf 性能监控和报告实用程序对任务进行分组,以进行监控。
  • RDMA - 可以在控制组中设置远程直接内存访问/InfiniBand 特定资源的限值。
  • HugeTL B - 可用于根据控制组中的任务限制大型虚拟内存页面的使用。

以下控制器可用于 cgroups-v2

  • io - cgroups-v1 的后续到 blkio.
  • memory - cgroups-v1 内存 的后续.
  • PIDs - cgroups-v1 相同.
  • RDMA - cgroups-v1 中的 相同.
  • CPU - cgroups-v1 的 cpu 和 cpuacct 的后续.
  • cpuset - 仅支持带有新分区功能的核心功能(cpus{,.ff }, mems{,. ff})。
  • perf_event - 支持是固有的,没有显式控制文件。您可以将 v2 cgroup 指定为 perf 命令的参数,以分析该 cgroup 中的所有任务。
重要

资源控制器可以在 cgroups-v1 层次结构或 cgroups-v 2 层次结构中使用,不能同时在两者中使用。

其它资源

  • cgroups(7) 手册页
  • /usr/share/doc/kernel-doc-<kernel_version>/Documentation/cgroups-v1/ 目录中的文档

18.3. 命名空间是什么

命名空间是整理和识别软件对象的最重要的方法之一。

命名空间将全局系统资源(如挂载点、网络设备或主机名)嵌套在抽象中,从而使它出现在命名空间内具有自己隔离的全局资源实例中的进程。使用命名空间的最常用的技术是容器。

对特定全局资源的更改仅对该命名空间中的进程可见,不影响系统或其他命名空间的其余部分。

要检查进程所属的命名空间,您可以在 /proc/<PID>/ns/ 目录中检查符号链接。

下表显示了它们隔离支持的命名空间和资源:

命名空间Isolates

Mount

挂载点

UTS

主机名和 NIS 域名

IPC

系统 V IPC, POSIX 消息队列

PID

进程 ID

Network

网络设备、堆栈、端口等

User

用户和组群 ID

Control groups

控制组群根目录

其它资源

18.4. 使用 cgroups-v1 为应用程序设置 CPU 限制

有时应用会占用大量 CPU 时间,这可能会对环境的整体健康状况造成负面影响。使用 /sys/fs/ 虚拟文件系统,利用 控制组版本 1 (cgroups-v1)为应用配置 CPU 限制。

先决条件

  • 您要限制其 CPU 使用情况的应用程序。
  • 验证 cgroups-v1 控制器是否已挂载:

    # mount -l | grep cgroup
    tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,seclabel,mode=755)
    cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd)
    cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,cpu,cpuacct)
    cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,perf_event)
    cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,pids)
    ...

流程

  1. 在 CPU 消耗中识别您要限制的应用程序的进程 ID(PID):

    # top
    top - 11:34:09 up 11 min,  1 user,  load average: 0.51, 0.27, 0.22
    Tasks: 267 total,   3 running, 264 sleeping,   0 stopped,   0 zombie
    %Cpu(s): 49.0 us,  3.3 sy,  0.0 ni, 47.5 id,  0.0 wa,  0.2 hi,  0.0 si,  0.0 st
    MiB Mem :   1826.8 total,    303.4 free,   1046.8 used,    476.5 buff/cache
    MiB Swap:   1536.0 total,   1396.0 free,    140.0 used.    616.4 avail Mem
    
      PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
     6955 root      20   0  228440   1752   1472 R  99.3   0.1   0:32.71 sha1sum
     5760 jdoe      20   0 3603868 205188  64196 S   3.7  11.0   0:17.19 gnome-shell
     6448 jdoe      20   0  743648  30640  19488 S   0.7   1.6   0:02.73 gnome-terminal-
        1 root      20   0  245300   6568   4116 S   0.3   0.4   0:01.87 systemd
      505 root      20   0       0      0      0 I   0.3   0.0   0:00.75 kworker/u4:4-events_unbound
    ...

    top 程序的输出示例显示 PID 6955 (裸机化应用 sha1sum)消耗了大量 CPU 资源。

  2. cpu 资源控制器目录中创建子目录:

    # mkdir /sys/fs/cgroup/cpu/Example/

    上面的目录代表控制组,您可以在其中放置特定进程并将某些 CPU 限制应用到进程。同时,目录中将创建一些 cgroups-v1 接口文件和 cpu controller 特定的文件。

  3. (可选)检查新创建的控制组群:

    # ll /sys/fs/cgroup/cpu/Example/
    -rw-r—​r--. 1 root root 0 Mar 11 11:42 cgroup.clone_children
    -rw-r—​r--. 1 root root 0 Mar 11 11:42 cgroup.procs
    -r—​r—​r--. 1 root root 0 Mar 11 11:42 cpuacct.stat
    -rw-r—​r--. 1 root root 0 Mar 11 11:42 cpuacct.usage
    -r—​r—​r--. 1 root root 0 Mar 11 11:42 cpuacct.usage_all
    -r—​r—​r--. 1 root root 0 Mar 11 11:42 cpuacct.usage_percpu
    -r—​r—​r--. 1 root root 0 Mar 11 11:42 cpuacct.usage_percpu_sys
    -r—​r—​r--. 1 root root 0 Mar 11 11:42 cpuacct.usage_percpu_user
    -r—​r—​r--. 1 root root 0 Mar 11 11:42 cpuacct.usage_sys
    -r—​r—​r--. 1 root root 0 Mar 11 11:42 cpuacct.usage_user
    -rw-r—​r--. 1 root root 0 Mar 11 11:42 cpu.cfs_period_us
    -rw-r—​r--. 1 root root 0 Mar 11 11:42 cpu.cfs_quota_us
    -rw-r—​r--. 1 root root 0 Mar 11 11:42 cpu.rt_period_us
    -rw-r—​r--. 1 root root 0 Mar 11 11:42 cpu.rt_runtime_us
    -rw-r—​r--. 1 root root 0 Mar 11 11:42 cpu.shares
    -r—​r—​r--. 1 root root 0 Mar 11 11:42 cpu.stat
    -rw-r—​r--. 1 root root 0 Mar 11 11:42 notify_on_release
    -rw-r—​r--. 1 root root 0 Mar 11 11:42 tasks

    示例输出中显示的文件,如 cpuacct.usagecpu.cfs._period_us,它们代表特定配置和/或限制,可以为 Example 控制组中的进程设置。请注意,对应的文件名前缀为它们所属的控制组控制器的名称。

    默认情况下,新创建的控制组继承对系统整个 CPU 资源的访问权限,且无限制。

  4. 为控制组群配置 CPU 限制:

    # echo "1000000" > /sys/fs/cgroup/cpu/Example/cpu.cfs_period_us
    # echo "200000" > /sys/fs/cgroup/cpu/Example/cpu.cfs_quota_us

    cpu.cfs_period_us 文件表示以微秒为单位(这里表示为"us")的时段,用于控制组对 CPU 资源的访问权限应重新分配的频率。上限为 1 秒,下限为 1000 微秒。

    cpu.cfs_quota_us 文件表示以微秒为单位的总时间量,控制组中的所有进程都可以在一个期间(如 cpu.cfs_period_us定义)。当控制组中的进程在单个期间内使用配额指定的所有时间时,就会在句点的其余部分内进行限流,并且不允许在下一个期间内运行。下限为 1000 微秒。

    上面的示例命令设定 CPU 时间限值,使得 Example 控制组中的所有进程仅能每 1 秒( cpu.cfs_quota_us定义)每 1 秒(由 cpu.cfs_period_us定义)运行 0.2 秒。

  5. 另外,还可验证限制:

    # cat /sys/fs/cgroup/cpu/Example/cpu.cfs_period_us /sys/fs/cgroup/cpu/Example/cpu.cfs_quota_us
    1000000
    200000
  6. 将应用程序的 PID 添加到 示例 控制组群中:

    # echo "6955" > /sys/fs/cgroup/cpu/Example/cgroup.procs
    
    or
    
    # echo "6955" > /sys/fs/cgroup/cpu/Example/tasks

    上一命令可确保所需的应用成为 Example 控制组的成员,因此不超过为 示例 控制组配置的 CPU 限值。PID 应该代表系统中的一个已存在的进程。这里的 PID 6955 分配给进程 sha1sum /dev/zero &,用于演示 cpu 控制器的用例。

  7. 验证应用程序是否在指定的控制组群中运行:

    # cat /proc/6955/cgroup
    12:cpuset:/
    11:hugetlb:/
    10:net_cls,net_prio:/
    9:memory:/user.slice/user-1000.slice/user@1000.service
    8:devices:/user.slice
    7:blkio:/
    6:freezer:/
    5:rdma:/
    4:pids:/user.slice/user-1000.slice/user@1000.service
    3:perf_event:/
    2:cpu,cpuacct:/Example
    1:name=systemd:/user.slice/user-1000.slice/user@1000.service/gnome-terminal-server.service

    上面的示例输出显示所需应用的进程在 Example 控制组中运行,它将 CPU 限制应用到应用的进程。

  8. 确定节流应用程序的当前 CPU 消耗:

    # top
    top - 12:28:42 up  1:06,  1 user,  load average: 1.02, 1.02, 1.00
    Tasks: 266 total,   6 running, 260 sleeping,   0 stopped,   0 zombie
    %Cpu(s): 11.0 us,  1.2 sy,  0.0 ni, 87.5 id,  0.0 wa,  0.2 hi,  0.0 si,  0.2 st
    MiB Mem :   1826.8 total,    287.1 free,   1054.4 used,    485.3 buff/cache
    MiB Swap:   1536.0 total,   1396.7 free,    139.2 used.    608.3 avail Mem
    
      PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
     6955 root      20   0  228440   1752   1472 R  20.6   0.1  47:11.43 sha1sum
     5760 jdoe      20   0 3604956 208832  65316 R   2.3  11.2   0:43.50 gnome-shell
     6448 jdoe      20   0  743836  31736  19488 S   0.7   1.7   0:08.25 gnome-terminal-
      505 root      20   0       0      0      0 I   0.3   0.0   0:03.39 kworker/u4:4-events_unbound
     4217 root      20   0   74192   1612   1320 S   0.3   0.1   0:01.19 spice-vdagentd
    ...

    请注意,PID 6955 的 CPU 消耗从 99% 降至 20%。

其它资源



[1] Linux Control Group v2 - 介绍 Devconf.cz 2019 演示(Waiman Long)

第 19 章 使用带有 systemd 的控制组群版本 1

以下小节概述了与创建、修改和删除控制组(cgroup)相关的任务systemd 系统和服务管理器提供的实用程序是 cgroups 管理的首选方式,并将在未来提供支持。

19.1. 控制组群版本 1 中的 systemd 角色

Red Hat Enterprise Linux 8 将资源管理设置从流程级别移到应用程序级别,方法是将 cgroup 层次结构系统与 systemd 单元树绑定。因此,您可以使用 systemctl 命令或通过修改 systemd 单元文件来管理系统资源。

默认情况下,systemd 系统和服务管理器利用 片段、作用 服务单元 来整理和整理控制组中的进程。systemctl 命令允许您通过创建自定义 片段 来进一步修改此结构。另外,systemd 会在 /sys/fs/cgroup/ 目录中自动挂载重要内核资源控制器的层次结构。

三种 systemd 单元类型用于资源控制:

  • 服务 - systemd 根据单元配置文件启动的进程或一组进程。服务封装指定的进程,以便它们可以作为一个集启动和停止。服务使用以下方法命名:

    <name>.service
  • Scope - 外部创建的进程组。范围封装通过 fork() 函数由任意进程启动和停止的进程,然后在运行时由 systemd 注册。例如,用户会话、容器和虚拟机被视为范围。范围命名如下:

    <name>.scope
  • slice - 一组分级组织单元。片段组织了一个分级,其中放置范围和服务。实际的进程包含在范围或服务中。slice 单元的每个名称对应层次结构中的位置的路径。短划线("-")字符充当从 -slice root 片段到片段的路径组件的分隔符。在以下示例中:

    <parent-name>.slice

    parent-name.sliceparent.slice 的子分片,它是 -.slice root 片段的子分片。parent-name.slice 可以有自己的子slice 名为 parent-name-name2.slice,以此类推。

服务、作用 切片 单元直接映射到控制组层次结构中的对象。激活这些单元后,它们直接映射到从单元名称构建的控制组路径。

以下是控制组群分级的缩写示例:

Control group /:
-.slice
├─user.slice
│ ├─user-42.slice
│ │ ├─session-c1.scope
│ │ │ ├─ 967 gdm-session-worker [pam/gdm-launch-environment]
│ │ │ ├─1035 /usr/libexec/gdm-x-session gnome-session --autostart /usr/share/gdm/greeter/autostart
│ │ │ ├─1054 /usr/libexec/Xorg vt1 -displayfd 3 -auth /run/user/42/gdm/Xauthority -background none -noreset -keeptty -verbose 3
│ │ │ ├─1212 /usr/libexec/gnome-session-binary --autostart /usr/share/gdm/greeter/autostart
│ │ │ ├─1369 /usr/bin/gnome-shell
│ │ │ ├─1732 ibus-daemon --xim --panel disable
│ │ │ ├─1752 /usr/libexec/ibus-dconf
│ │ │ ├─1762 /usr/libexec/ibus-x11 --kill-daemon
│ │ │ ├─1912 /usr/libexec/gsd-xsettings
│ │ │ ├─1917 /usr/libexec/gsd-a11y-settings
│ │ │ ├─1920 /usr/libexec/gsd-clipboard
…​
├─init.scope
│ └─1 /usr/lib/systemd/systemd --switched-root --system --deserialize 18
└─system.slice
  ├─rngd.service
  │ └─800 /sbin/rngd -f
  ├─systemd-udevd.service
  │ └─659 /usr/lib/systemd/systemd-udevd
  ├─chronyd.service
  │ └─823 /usr/sbin/chronyd
  ├─auditd.service
  │ ├─761 /sbin/auditd
  │ └─763 /usr/sbin/sedispatch
  ├─accounts-daemon.service
  │ └─876 /usr/libexec/accounts-daemon
  ├─example.service
  │ ├─ 929 /bin/bash /home/jdoe/example.sh
  │ └─4902 sleep 1
  …​

上面的例子显示,服务和范围包含进程,并放置在不含自己进程的片段中。

其它资源

19.2. 创建临时控制组群

临时 cgroup 设置 运行时期间由单元(服务或范围)消耗的资源的限制。

流程

  • 要创建一个临时控制组群,使用以下格式 的 systemd-run 命令:

    # systemd-run --unit=<name> --slice=<name>.slice <command>

    此命令会创建并启动临时服务或范围单元,并在此类单元中运行自定义命令。

    • --unit=<name> 选项为单元取一个名称。如果未指定 --unit,则会自动生成名称。
    • --slice=<name>.slice 选项使您的服务或范围单元成为指定片段的成员。将 <name>.slice 替换为现有片段的名称(如 systemctl -t 片段输出中所示),或通过传递唯一名称来创建新片段。默认情况下,服务和范围作为 system.slice 的成员创建。
    • <command> 替换为您要在服务或范围单元中执行的命令

      此时会显示以下信息,以确认您已创建并启动了该服务,或者已成功启动范围:

      # Running as unit <name>.service
  • 另外,还可在完成进程后继续运行该单元以收集运行时信息:

    # systemd-run --unit=<name> --slice=<name>.slice --remain-after-exit <command>

    命令可创建并启动一个临时服务单元,并在此类单元中运行自定义命令。--remain-after-exit 选项可确保服务在其进程完成后继续运行。

其它资源

19.3. 创建持久的控制组群

若要为服务分配持久控制组,需要编辑其单元配置文件。配置在系统重启后保留,因此可以用于管理自动启动的服务。

流程

  • 要创建持久的控制组群,请执行:

    # systemctl enable <name>.service

    以上命令会在 /usr/lib/systemd/system/ 目录中自动创建一个单元配置文件,并在默认情况下为 system.slice 单元分配 <名称>.service

其它资源

19.4. 在命令行中配置内存资源控制设置

在命令行界面中执行命令是针对进程组设置限制、优先级或控制对硬件资源的访问的一种方式。

流程

  • 要限制服务的内存用量,请运行以下命令:

    # systemctl set-property example.service MemoryLimit=1500K

    命令立即将 1,500 KB 的内存限值分配给 example.service 服务所属控制组中执行的进程。在此配置变体中的 MemoryLimit 参数在 /etc/systemd/system.control/example.service.d/50-MemoryLimit.conf 文件中定义,并控制 /sys/fs/cgroup/memory/system.slice/example.service/memory.limit_in_bytes 文件的值。

  • 另外,要临时限制服务的内存用量,请运行:

    # systemctl set-property --runtime example.service MemoryLimit=1500K

    命令会立即为 example.service 服务分配内存限值。在 /run/systemd/system.control/example.service.d/50-MemoryLimit.conf 文件中定义 MemoryLimit 参数。重新引导后,整个 /run/systemd/system.control/ 目录和 MemoryLimit 都会被删除。

注意

50-MemoryLimit.conf 文件将内存限制存储为 4096 字节的倍数 - 个内核页面大小,专用于 AMD64 和 Intel 64。实际的字节数量取决于 CPU 构架。

其它资源

19.5. 使用单元文件配置内存资源控制设置

每个持久性单元都由 systemd 系统和服务管理器监管,并在 /usr/lib/systemd/system/ 目录中有一个单元配置文件。要更改永久单元的资源控制设置,可在文本编辑器中手动或从命令行界面修改其单元配置文件。

手动修改单元文件是为进程组设置限制、优先级或控制对硬件资源的访问的一种方式。

流程

  1. 要限制服务的内存用量,请修改 /usr/lib/systemd/system/example.service 文件,如下所示:

    …​
    [Service]
    MemoryLimit=1500K
    …​

    以上配置对在控制组中执行的进程的最大内存消耗设定了限制,example .service 是该控制组中的一部分。

    注意

    使用后缀 K、M、G 或 T 将 Kilobyte、Megabyte、Gigabyte 或 Terabyte 识别为一个测量单位。

  2. 重新载入所有单元配置文件:

    # systemctl daemon-reload
  3. 重启服务:

    # systemctl restart example.service
  4. 重启系统。
  5. (可选)检查更改是否生效:

    # cat /sys/fs/cgroup/memory/system.slice/example.service/memory.limit_in_bytes
    1536000

    示例输出显示内存消耗限制在大约 1,500 KB。

    注意

    memory.limit_in_bytes 文件将内存限制存储为 4096 字节的倍数 - 个内核页面大小,专用于 AMD64 和 Intel 64。实际的字节数量取决于 CPU 构架。

其它资源

19.6. 删除临时控制组群

如果您不再需要限制、确定或控制对进程组的硬件资源的访问,您可以使用 systemd 系统和服务管理器删除临时控制组(cgroup)。

一旦服务或范围单元包含、完成的所有进程都包含并完成,则临时 cgroup 将自动发布。

流程

  • 要使用所有进程停止服务单元,请执行:

    # systemctl stop <name>.service
  • 要终止一个或多个单元进程,请执行:

    # systemctl kill <name>.service --kill-who=PID,…​ --signal=signal

    以上命令使用 --kill-who 选项从您要终止的控制组中选择进程。要同时终止多个进程,请传递以逗号分隔的 PID 列表。信号选项 决定要发送到指定进程的 POSIX 信号的类型。默认信号是 SIGTERM

其它资源

19.7. 删除持久的控制组群

如果您不再需要为进程组限制、确定或控制对硬件资源的访问,您可以使用 systemd 系统和服务管理器删除持久性控制组(cgroup)。

当停止或禁用服务或范围单元并删除其配置文件时,永久 cgroup 就会发布。

流程

  1. 停止服务单元:

    # systemctl stop <name>.service
  2. 禁用服务单元:

    # systemctl disable <name>.service
  3. 删除相关的单元配置文件:

    # rm /usr/lib/systemd/system/<name>.service
  4. 重新载入所有单元配置文件以使更改生效:

    # systemctl daemon-reload

其它资源

19.8. 列出 systemd 单元

以下流程描述了如何使用 systemd 系统和服务管理器列出其单元。

流程

  • 要列出系统中的所有活跃单元,执行 # systemctl 命令,终端将返回类似以下示例的输出:

    # systemctl
    UNIT                                                LOAD   ACTIVE SUB       DESCRIPTION
    …​
    init.scope                                          loaded active running   System and Service Manager
    session-2.scope                                     loaded active running   Session 2 of user jdoe
    abrt-ccpp.service                                   loaded active exited    Install ABRT coredump hook
    abrt-oops.service                                   loaded active running   ABRT kernel log watcher
    abrt-vmcore.service                                 loaded active exited    Harvest vmcores for ABRT
    abrt-xorg.service                                   loaded active running   ABRT Xorg log watcher
    …​
    -.slice                                             loaded active active    Root Slice
    machine.slice                                       loaded active active    Virtual Machine and Container Slice system-getty.slice                                                                       loaded active active    system-getty.slice
    system-lvm2\x2dpvscan.slice                         loaded active active    system-lvm2\x2dpvscan.slice
    system-sshd\x2dkeygen.slice                         loaded active active    system-sshd\x2dkeygen.slice
    system-systemd\x2dhibernate\x2dresume.slice         loaded active active    system-systemd\x2dhibernate\x2dresume>
    system-user\x2druntime\x2ddir.slice                 loaded active active    system-user\x2druntime\x2ddir.slice
    system.slice                                        loaded active active    System Slice
    user-1000.slice                                     loaded active active    User Slice of UID 1000
    user-42.slice                                       loaded active active    User Slice of UID 42
    user.slice                                          loaded active active    User and Session Slice
    …​
    • UNIT - 反映控制组群层次结构中的单元位置的单元名称。与资源控制相关的单元是片 、作用域 和服务
    • LOAD - 指示单元配置文件是否已正确加载。如果单元文件加载失败,该字段包含状态 error 而不是 loaded。其他单元负载状态为: stubmergemasked
    • ACTIVE - 高级单元激活状态,即 SUB 的一般化。
    • s UB - 低级单元激活状态。可能的值的范围取决于单元类型。
    • DESCRIPTION - 单元内容和功能的描述。
  • 要列出不活跃单元,请执行:

    # systemctl --all
  • 要限制输出中的信息量,请执行:

    # systemctl --type service,masked

    type 选项 需要一个以逗号分隔的单元类型列表,如 服务和 片段,或者载入和 屏蔽 的单元 加载 状态。

其它资源

19.9. 查看控制组群版本 1 层次结构

以下流程描述了如何显示控制组(cgroup)层次结构和在特定 cgroup 中运行的进程。

流程

  • 要在系统中显示整个 cgroups 层次结构,请执行 # systemd-cgls

    # systemd-cgls
    Control group /:
    -.slice
    ├─user.slice
    │ ├─user-42.slice
    │ │ ├─session-c1.scope
    │ │ │ ├─ 965 gdm-session-worker [pam/gdm-launch-environment]
    │ │ │ ├─1040 /usr/libexec/gdm-x-session gnome-session --autostart /usr/share/gdm/greeter/autostart
    …​
    ├─init.scope
    │ └─1 /usr/lib/systemd/systemd --switched-root --system --deserialize 18
    └─system.slice
      …​
      ├─example.service
      │ ├─6882 /bin/bash /home/jdoe/example.sh
      │ └─6902 sleep 1
      ├─systemd-journald.service
        └─629 /usr/lib/systemd/systemd-journald
      …​

    示例输出返回整个 cgroups 层次结构,其中最高级别由 片段 组成。

  • 要显示根据资源控制器过滤的 cgroups 层次结构,执行 # systemd-cgls <resource_controller>:

    # systemd-cgls memory
    Controller memory; Control group /:
    ├─1 /usr/lib/systemd/systemd --switched-root --system --deserialize 18
    ├─user.slice
    │ ├─user-42.slice
    │ │ ├─session-c1.scope
    │ │ │ ├─ 965 gdm-session-worker [pam/gdm-launch-environment]
    …​
    └─system.slice
      |
      …​
      ├─chronyd.service
      │ └─844 /usr/sbin/chronyd
      ├─example.service
      │ ├─8914 /bin/bash /home/jdoe/example.sh
      │ └─8916 sleep 1
      …​

    以上命令的输出示例列出了与所选控制器交互的服务。

  • 要显示特定单元及其 cgroups 层次结构部分的详细信息,请执行 # systemctl status <system_unit>:

    # systemctl status example.service
    ● example.service - My example service
       Loaded: loaded (/usr/lib/systemd/system/example.service; enabled; vendor preset: disabled)
       Active: active (running) since Tue 2019-04-16 12:12:39 CEST; 3s ago
     Main PID: 17737 (bash)
        Tasks: 2 (limit: 11522)
       Memory: 496.0K (limit: 1.5M)
       CGroup: /system.slice/example.service
               ├─17737 /bin/bash /home/jdoe/example.sh
               └─17743 sleep 1
    Apr 16 12:12:39 redhat systemd[1]: Started My example service.
    Apr 16 12:12:39 redhat bash[17737]: The current time is Tue Apr 16 12:12:39 CEST 2019
    Apr 16 12:12:40 redhat bash[17737]: The current time is Tue Apr 16 12:12:40 CEST 2019

其它资源

19.10. 查看资源控制器

以下流程描述了如何了解哪些进程使用哪些资源控制器。

流程

  1. 要查看进程与之交互的资源控制器,请执行 # cat proc/<PID>/cgroup 命令:

    # cat /proc/11269/cgroup
    12:freezer:/
    11:cpuset:/
    10:devices:/system.slice
    9:memory:/system.slice/example.service
    8:pids:/system.slice/example.service
    7:hugetlb:/
    6:rdma:/
    5:perf_event:/
    4:cpu,cpuacct:/
    3:net_cls,net_prio:/
    2:blkio:/
    1:name=systemd:/system.slice/example.service

    输出示例与关注进程相关。在本例中,它是 PID 11269 标识的进程,属于 example.service 单元。您可以确定进程是否放置到由 systemd 单元文件规格定义的正确控制组中。

    注意

    默认情况下,在资源控制器列表中的项目及其排序对于 systemd 启动的所有单元来说是相同的,因为它会自动挂载所有默认资源控制器。

其它资源

  • cgroups(7) 手册页
  • /usr/share/doc/kernel-doc-<kernel_version>/Documentation/cgroups-v1/ 目录中的文档

19.11. 监控资源消耗

以下流程描述了如何实时查看当前正在运行的控制组(cgroup)列表及其资源消耗情况。

流程

  1. 要查看当前运行的 cgroup 的动态帐户,请执行 # systemd-cgtop 命令:

    # systemd-cgtop
    Control Group                            Tasks   %CPU   Memory  Input/s Output/s
    /                                          607   29.8     1.5G        -        -
    /system.slice                              125      -   428.7M        -        -
    /system.slice/ModemManager.service           3      -     8.6M        -        -
    /system.slice/NetworkManager.service         3      -    12.8M        -        -
    /system.slice/accounts-daemon.service        3      -     1.8M        -        -
    /system.slice/boot.mount                     -      -    48.0K        -        -
    /system.slice/chronyd.service                1      -     2.0M        -        -
    /system.slice/cockpit.socket                 -      -     1.3M        -        -
    /system.slice/colord.service                 3      -     3.5M        -        -
    /system.slice/crond.service                  1      -     1.8M        -        -
    /system.slice/cups.service                   1      -     3.1M        -        -
    /system.slice/dev-hugepages.mount            -      -   244.0K        -        -
    /system.slice/dev-mapper-rhel\x2dswap.swap   -      -   912.0K        -        -
    /system.slice/dev-mqueue.mount               -      -    48.0K        -        -
    /system.slice/example.service                2      -     2.0M        -        -
    /system.slice/firewalld.service              2      -    28.8M        -        -
    ...

    示例输出显示当前运行的 cgroups,按照资源使用量排序(CPU、内存、磁盘 I/O 负载)。这个列表默认每 1 秒刷新一次。因此,它提供了一个动态洞察每个控制组的实际资源使用情况。

其它资源

  • systemd-cgtop(1) manual page

19.12. 使用 systemd 配置 CPUSET 控制器

systemd 资源管理 API 允许用户在服务可以使用的一组 CPU 和 NUMA 节点上配置限值。此限制限制对进程使用的系统资源的访问。请求的配置以 cpuset.cpuscpuset.mems 编写。但是,请求的配置可能无法使用,因为父 cgroup 限制 的cpu 或 mems。若要访问当前的配置,会将 cpuset.cpus.effectivecpuset.mems.ff 文件导出到用户。

流程

  • 设置 AllowedCPUs

    # systemctl set-property service_name.service AllowedCPUs=value

    例如:

    systemctl set-property service_name.service AllowedCPUs=0-5
  • 设置 AllowedMemoryNodes

    # systemctl set-property service_name.service AllowedMemoryNodes=value

    例如:

    # systemctl set-property service_name.service AllowedMemoryNodes=0

第 20 章 使用 systemd 使用 cgroup 版本 2 配置资源管理

systemd 的核心是服务管理和规范。systemd 确保正确的服务在正确时间以正确顺序启动。服务运行时,它们必须顺利运行,才能以最佳的方式使用底层硬件平台。因此,systemd 还提供定义资源管理策略和调整各种选项的功能,它们可以提高服务性能。

20.1. 先决条件

20.2. 资源分配模型简介

对于资源管理,systemd 使用 cgroup v2 接口。

请注意,RHEL 8 默认使用 cgroup v1。因此,您必须启用 cgroup v2,以便 systemd 可以使用 cgroup v2 接口进行资源管理。有关如何启用 cgroup v2 的更多信息,请参阅使用 cgroups-v2 为应用程序设置 CPU 限制

要修改系统资源的发布,您可以应用以下一个或多个资源分发模型:

weight

资源分布方式是添加所有子组的权重,并为各个子组提供与总和匹配的部分。

例如,如果您有 10 个 cgroup,每个 cgroup 的值为 100,则总和为 1000,每个 cgroup 都接收资源中的一个。

weight 通常用于分发无状态资源。CPUWeight= 选项是此资源分布模型的实现。

Limits

cgroup 最多可消耗已配置的资源量,但您也可以过量使用资源。因此,子组限值总和可能会超过父组限制。

MemoryMax= 选项是此资源分配模型的实施。

保护

可以为 cgroup 设置受保护的资源量。如果资源使用量低于保护边界,内核将尝试不以竞争同一资源的 cgroup 替代其他 cgroup。也允许过量使用。

MemoryLow= 选项是此资源分配模型的实施。

分配
独占分配有限资源的绝对数量。不允许过量使用。Linux 中这种资源类型的一个示例就是实时预算。

20.3. 使用 systemd 分配 CPU 资源

在由 systemd 管理的系统上,每个系统服务在其 cgroup 中启动。通过启用对 CPU cgroup 控制器的支持,系统使用对 CPU 资源的服务感知分布,而不是按进程分布。在服务感知型分发中,每个服务收到的 CPU 时间与系统上运行的所有其他服务的 CPU 时间大致相同,无论组成该服务的进程数量如何。

如果特定的服务需要更多 CPU 资源,您可以通过更改该服务的 CPU 时间分配策略来授予它们。

流程

在使用 systemd 时设置 CPU 时间分配策略选项:

  1. 在您选择的服务中检查 CPU 时间分配策略选项的分配值:

    $ systemctl show --property <CPU time allocation policy option> <service name>
  2. 将 CPU 时间分配策略选项的所需值设置为 root:

    # systemctl set-property <service name> <CPU time allocation policy option>=<value>
    注意

    cgroup 属性在设置后立即应用。因此,不需要重新启动 服务。

cgroup 属性在设置后立即应用。因此,不需要重新启动 服务。

验证步骤

  • 要验证您是否成功更改了服务的 CPU 时间分配策略选项的所需值,请运行以下命令:

    $ systemctl show --property <CPU time allocation policy option> <service name>

20.4. systemd 的 CPU 时间分配策略选项

最常用的 CPU 时间分配策略选项包括:

CPUWeight=

在所有其他服务上为特定服务分配更高的优先级。您可以从间隔 1 - 10,000 中选择一个值。默认值为 100。

例如,若要将 httpd.service 的 CPU 数量与所有其他服务数量相同,可将值设置为 CPUWeight=200

请注意,CPUWeight= 仅在操作系统过载时才应用。

CPUQuota=

为服务分配绝对 CPU 时间配额。此选项的值指定服务收到的 CPU 时间相对于可用 CPU 总时间的最大百分比,如 CPUQuota=30%。

请注意,CPUQuota= 代表资源分发模型 简介中描述的特定资源分布模型的限值。

有关 CPUQuota= 的更多信息,请参阅 systemd.resource-control(5) man page。

20.5. 使用 systemd 分配内存资源

本节论述了如何使用任何内存配置选项(MemoryMin、MemoryLow、Memory High、Memory Max、Memory SwapMax)来使用 systemd 分配内存资源。

流程

使用 systemd 时设置内存分配配置选项:

  1. 在您选择的服务中检查内存分配配置选项的分配值:

    $ systemctl show --property <memory allocation configuration option> <service name>
  2. 将内存分配配置选项所需的值设置为根:

    # systemctl set-property <service name> <memory allocation configuration option>=<value>
注意

cgroup 属性在设置后立即应用。因此,不需要重新启动 服务。

验证步骤

  • 要验证您是否成功更改了服务的内存分配配置选项所需的值,请运行以下命令:

    $ systemctl show --property <memory allocation configuration option> <service name>

20.6. systemd 的内存分配配置选项

在使用 systemd 配置系统内存分配时,您可以使用以下选项

MemoryMin
硬内存保护.如果内存用量低于限制,则不会回收 cgroup 内存。
MemoryLow
软内存保护.如果内存用量低于限制,则只能在未受保护的 cgroup 中回收内存时才能回收 cgroup 内存。
MemoryHigh
内存节流限制.如果内存用量超过限制,则 cgroup 中的进程会节流,并置于很重的回收压力下。
MemoryMax
内存用量的绝对限制。您可以使用 kilo(K)、MB(M)、giga(G)、tera(T)后缀,如 MemoryMax=1G
MemorySwapMax
交换使用的硬性限制.
注意

当您用尽内存限值时,内存不足(OOM)终止程序将停止正在运行的服务。要防止这种情况,请降低 OOMScoreAdjust= 值,以提高内存容错能力。

20.7. 使用 systemd 配置 I/O 带宽

要提高 RHEL 8 中特定服务的性能,您可以使用 systemd 为该服务分配 I/O 带宽资源。

要做到这一点,您可以使用以下 I/O 配置选项:

  • IOWeight
  • IODeviceWeight
  • IOReadBandwidthMax
  • IOWriteBandwidthMax
  • IOReadIOPSMax
  • IOWriteIOPSMax

流程

使用 systemd 设置 I/O 带宽配置选项

  1. 在您选择的服务中检查 I/O 带宽配置选项的分配值:

    $ systemctl show --property <I/O bandwidth configuration option> <service name>
  2. 将 I/O 带宽配置选项所需的值设置为 root:

    # systemctl set-property <service name> <I/O bandwidth configuration option>=<value>

cgroup 属性在设置后立即应用。因此,不需要重新启动 服务。

验证步骤

  • 要验证您是否成功更改了服务的 I/O 带宽配置选项所需的值,请运行以下命令:

    $ systemctl show --property <I/O bandwidth configuration option> <service name>

20.8. systemd 的 I/O 带宽配置选项

要使用 systemd 管理块层 I/O 策略,可以使用以下配置选项:

IOWeight
设置默认 I/O 权重。权重值用作计算服务与其他服务相比实际 I/O 带宽数量的基础。
IODeviceWeight

设置特定块设备的 I/O 权重。

例如,IODeviceWeight=/dev/disk/by-id/dm-name-rhel-root 200

IOReadBandwidthMax, IOWriteBandwidthMax

设置每个设备或挂载点的绝对带宽。

例如: IOWriteBandwith=/var/log 5M

注意

systemd 会自动处理文件系统到设备转换。

IOReadIOPSMax, IOWriteIOPSMax
与上一选项类似的选项:设置每秒输入/输出操作(IOPS)中的绝对带宽。
注意

只有在块设备使用 CFQ I/O 调度程序时,才支持基于权重的选项。如果设备使用了多队列块 I/O 排队机制,则不支持选项。

第 21 章 使用 systemd 配置 CPU 关联性和 NUMA 策略

CPU 管理、内存管理和 I/O 带宽选项处理可用资源的分区。

21.1. 使用 systemd 配置 CPU 关联性

CPU 关联性设置可帮助您将特定进程的访问限制到某些 CPU。实际上,CPU 调度程序永远不会将进程调度到不在进程的关联性掩码中的 CPU 上运行。

默认 CPU 关联性掩码应用到 systemd 管理的所有服务。

要为特定 systemd 服务配置 CPU 关联性掩码,systemd 提供 CPUAffinity= 作为单元文件选项和 /etc/systemd/system.conf 文件中的管理器配置选项。

CPUAffinity= 单元文件选项 设置 CPU 或 CPU 范围列表,这些范围合并并用作关联性掩码。/etc/systemd/system.conf 文件中的 CPUAffinity 选项 为进程识别号(PID)1 和从 PID1 分叉的所有进程定义关联性掩码。然后,您可以基于每个服务覆盖 CPUAffinity

注意

在为特定 systemd 服务配置 CPU 关联性掩码后,您必须重启系统以应用更改。

流程

使用 CPU Affinity 单元文件选项为 particualr systemd 服务设置 CPU 关联性掩码:

  1. 在您选择的服务中检查 CPUAffinity 单元文件选项的值:

    $ systemctl show --property <CPU affinity configuration option> <service name>
  2. 作为 root 用户,为用作关联性掩码的 CPU 范围设置 CPUAffinity 单元文件选项的所需值:

    # systemctl set-property <service name> CPUAffinity=<value>
  3. 重新启动服务以应用更改。

    # systemctl restart <service name>

使用 manager 配置选项为特定 systemd 服务设置 CPU 关联性掩码:

  1. 编辑 /etc/systemd/system.conf 文件:

    # vi /etc/systemd/system.conf
  2. 搜索 CPUAffinity= 选项并设置 CPU 号
  3. 保存编辑后的文件并重新启动服务器以应用更改。

21.2. 使用 systemd 配置 NUMA

非统一内存访问(NUMA)是一种计算机内存子系统设计,其中内存访问时间取决于处理器的内存位置。接近 CPU 的内存的延迟(本地内存)比其他 CPU 本地内存低,或者在一组 CPU 间共享。

就 Linux 内核而言,NUMA 策略管理内核为进程分配物理内存页面的位置(例如,在哪些 NUMA 节点上)。

要配置 NUMA,systemd 为 NUMA Policy 和 NUMA Mask 提供单元文件选项,并在 /etc/systemd/system.conf 文件中提供 manager 配置选项。

流程

通过 NUMA Policy 单元文件选项设置 NUMA 内存策略:

  1. 在您选择的服务中检查 NUMAPolicy 单元文件选项的值:

    $ systemctl show --property <NUMA policy configuration option> <service name>
  2. 作为根目录,设置 NUMAPolicy 单元文件选项所需的策略类型:

    # systemctl set-property <service name> NUMAPolicy=<value>
  3. 重新启动服务以应用更改。

    # systemctl restart <service name>

通过 manager 配置选项 设置 NUMAPolicy

  1. 编辑 /etc/systemd/system.conf 文件:

    # vi /etc/systemd/system.conf
  2. 搜索 NUMAPolicy 选项并设置策略类型。
  3. 保存编辑后的文件并重新启动服务器以应用更改。

21.3. systemd 的 NUMA 策略配置选项

systemd 提供以下选项来配置 NUMA 策略:

NUMAPolicy

控制已执行进程的 NUMA 内存策略。可能会有以下策略类型:

  • default
  • 首选
  • bind
  • interleave
  • local
NUMAMask

控制与所选 NUMA 策略关联的 NUMA 节点列表。

请注意,不需要为以下策略指定 NUMAMask 选项:

  • default
  • local

对于首选策略,列表仅指定单个 NUMA 节点。

其它资源

第 22 章 使用 BPF Compiler Collection 分析系统性能

作为系统管理员,您可以使用 BPF Compiler Collection(BCC)库创建用于分析 Linux 操作系统性能和收集信息的工具,这些信息可能难以通过其他接口获得。

22.1. BCC 介绍

BPF Compiler Collection(BCC)是一个库,可帮助创建扩展的 Berkeley Packet Filter(eBPF)程序。eBPF 程序的主要工具是在不需要额外的开销或存在安全问题的情况下,分析操作系统性能和网络性能。

BCC 不再需要用户了解 eBPF 的技术详情,并提供了许多开箱即用的起点,如带有预先创建的 eBPF 程序的 bcc-tools 软件包。

注意

eBPF 程序在事件中触发,如磁盘 I/O、TCP 连接以及进程创建。程序不太可能导致内核崩溃、循环或者变得无响应,因为它们在内核的安全性虚拟机中运行。

22.2. 安装 bcc-tools 软件包

本节论述了如何安装 bcc-tools 软件包,该软件包还会将 BPF Compiler Collection(BCC)库作为依赖项安装。

先决条件

流程

  1. 安装 bcc-tools

    # yum install bcc-tools

    BCC 工具安装在 /usr/share/bcc/tools/ 目录中。

  2. (可选)检查工具:

    # ll /usr/share/bcc/tools/
    ...
    -rwxr-xr-x. 1 root root  4198 Dec 14 17:53 dcsnoop
    -rwxr-xr-x. 1 root root  3931 Dec 14 17:53 dcstat
    -rwxr-xr-x. 1 root root 20040 Dec 14 17:53 deadlock_detector
    -rw-r--r--. 1 root root  7105 Dec 14 17:53 deadlock_detector.c
    drwxr-xr-x. 3 root root  8192 Mar 11 10:28 doc
    -rwxr-xr-x. 1 root root  7588 Dec 14 17:53 execsnoop
    -rwxr-xr-x. 1 root root  6373 Dec 14 17:53 ext4dist
    -rwxr-xr-x. 1 root root 10401 Dec 14 17:53 ext4slower
    ...

    上表中的 doc 目录包含每个工具的文档。

22.3. 使用所选 bcc-tools 进行性能调整

这部分论述了如何使用 BPF Compiler Collection(BCC)库中某些预先创建的程序来高效且安全地分析每个事件的系统性能。BCC 库中预创建的程序集可作为创建其他程序的示例。

先决条件

使用 execsnoop 检查系统进程

  1. 在一个终端中执行 execsnoop 程序:

    # /usr/share/bcc/tools/execsnoop
  2. 在另一个终端执行中,例如:

    $ ls /usr/share/bcc/tools/doc/

    以上可创建 ls 命令的短时间进程。

  3. 运行 execsnoop 的终端显示类似如下的输出:

    PCOMM	PID    PPID   RET ARGS
    ls   	8382   8287     0 /usr/bin/ls --color=auto /usr/share/bcc/tools/doc/
    sed 	8385   8383     0 /usr/bin/sed s/^ *[0-9]\+ *//
    ...

    execsnoop 程序打印出每个占用系统资源的新进程的输出行。它甚至会检测很快运行的程序(如 ls )的进程,大多数监控工具也不会进行注册。

    execsnoop 输出显示以下字段:

    • PCOMM - 父进程名称。(ls)
    • PID - 进程 ID。(8382)
    • PPID - 父进程 ID。(8287)
    • RET - exec()系统调用(0) 的返回值,它会将程序代码加载到新进程中。
    • ARGS - 使用参数启动的程序的位置。

要查看 execsnoop 的详情、示例和选项,请参阅 /usr/share/bcc/tools/doc/execsnoop_example.txt 文件。

有关 exec() 的详情,请查看 exec(3) 手册页。

使用 opensnoop 跟踪命令打开的文件

  1. 在一个终端中执行 opensnoop 程序:

    # /usr/share/bcc/tools/opensnoop -n uname

    以上列出了文件的输出,这些文件仅由 uname 命令的进程打开。

  2. 在另一个终端中执行:

    $ uname

    以上命令会打开某些在下一步中捕获的文件。

  3. 运行 opensnoop 的终端显示类似如下的输出:

    PID    COMM 	FD ERR PATH
    8596   uname 	3  0   /etc/ld.so.cache
    8596   uname 	3  0   /lib64/libc.so.6
    8596   uname 	3  0   /usr/lib/locale/locale-archive
    ...

    opensnoop 程序在整个系统中监视 open() 系统调用,并为 uname 尝试打开的每个文件打印一行输出。

    opensnoop 输出显示以下字段:

    • PID - 进程 ID。(8596)
    • COMM - 进程名称。(uname)
    • FD - 文件描述符 - open() 返回的值以引用打开的文件。(3)
    • ERR - 任何错误。
    • PATH - open() 试图打开的文件位置。

      如果命令尝试读取不存在的文件,则 FD 列返回 -1ERR 列将打印与相关错误对应的值。因此,Opennoop 可以帮助您识别行为不正确的应用程序。

要查看 opensnoop 的更多详细信息、示例和选项,请参阅 /usr/share/bcc/tools/doc/opensnoop_example.txt 文件。

有关 open() 的更多信息,请参阅 open(2) 手册页。

使用技术检查磁盘上的 I/O 操作

  1. 在一个终端中执行 biotop 程序:

    # /usr/share/bcc/tools/biotop 30

    该命令可让您监控在磁盘中执行 I/O 操作的主要进程。参数确保命令生成 30 秒概述。

    注意

    如果未提供任何参数,则默认情况下输出屏幕会每 1 秒刷新一次。

  2. 在另一个终端中执行,例如:

    # dd if=/dev/vda of=/dev/zero

    以上命令从本地硬盘设备读取内容,并将输出写入 /dev/zero 文件。此步骤会生成特定的 I/O 流量来演示 biotop

  3. 运行 biotop 的终端显示类似如下的输出:

    PID    COMM             D MAJ MIN DISK       I/O  Kbytes     AVGms
    9568   dd               R 252 0   vda      16294 14440636.0  3.69
    48     kswapd0          W 252 0   vda       1763 120696.0    1.65
    7571   gnome-shell      R 252 0   vda        834 83612.0     0.33
    1891   gnome-shell      R 252 0   vda       1379 19792.0     0.15
    7515   Xorg             R 252 0   vda        280  9940.0     0.28
    7579   llvmpipe-1       R 252 0   vda        228  6928.0     0.19
    9515   gnome-control-c  R 252 0   vda         62  6444.0     0.43
    8112   gnome-terminal-  R 252 0   vda         67  2572.0     1.54
    7807   gnome-software   R 252 0   vda         31  2336.0     0.73
    9578   awk              R 252 0   vda         17  2228.0     0.66
    7578   llvmpipe-0       R 252 0   vda        156  2204.0     0.07
    9581   pgrep            R 252 0   vda         58  1748.0     0.42
    7531   InputThread      R 252 0   vda         30  1200.0     0.48
    7504   gdbus            R 252 0   vda          3  1164.0     0.30
    1983   llvmpipe-1       R 252 0   vda         39   724.0     0.08
    1982   llvmpipe-0       R 252 0   vda         36   652.0     0.06
    ...

    biotop 输出显示以下字段:

    • PID - 进程 ID。(9568)
    • COMM - 进程名称。(dd)
    • DISK - 执行读取操作的磁盘。(vda)
    • I/O - 执行读取操作的数量。(16294)
    • Kbytes - 读操作达到的 K 字节。(14,440,636)
    • AVGms - 读操作的平均 I/O 时间。(3.69)

要查看 biotop 的详情、示例和选项,请参阅 /usr/share/bcc/tools/doc/biotop_example.txt 文件。

有关 dd 的更多信息,请参阅 dd(1) 手册页。

使用 xfsslower 来公开意料外的慢文件系统操作

  1. 在一个终端中执行 xfsslower 程序:

    # /usr/share/bcc/tools/xfsslower 1

    以上命令测量 XFS 文件系统执行读取、写入、打开或同步(fsync)操作的时间。1 参数可确保程序仅显示比 1 ms 较慢的操作。

    注意

    如果未提供任何参数,xfsslower 默认会显示比 10 ms 慢的操作。

  2. 在另一个终端中执行,例如:

    $ vim text

    以上命令在 vim 编辑器中创建了一个文本文件,以启动与 XFS 文件系统的某些交互。

  3. 运行 xfsslower 的终端显示在保存上一步中的文件时类似:

    TIME     COMM           PID    T BYTES   OFF_KB   LAT(ms) FILENAME
    13:07:14 b'bash'        4754   R 256     0           7.11 b'vim'
    13:07:14 b'vim'         4754   R 832     0           4.03 b'libgpm.so.2.1.0'
    13:07:14 b'vim'         4754   R 32      20          1.04 b'libgpm.so.2.1.0'
    13:07:14 b'vim'         4754   R 1982    0           2.30 b'vimrc'
    13:07:14 b'vim'         4754   R 1393    0           2.52 b'getscriptPlugin.vim'
    13:07:45 b'vim'         4754   S 0       0           6.71 b'text'
    13:07:45 b'pool'        2588   R 16      0           5.58 b'text'
    ...

    上面的每一行代表文件系统中的一个操作,其用时超过特定阈值。xfsslower 非常适合公开可能的文件系统问题,这可能会导致意外的慢速操作。

    xfsslower 输出显示以下字段:

    • COMM - 进程名称。(b'bash')
    • t - 操作类型。(R)

      • Read
      • Write
      • Sync
    • OFF_KB - KB 中的文件偏移。(0)
    • FILENAME - 被读取、写入或者同步的文件。

要查看 xfsslower 的详情、示例和选项,请参阅 /usr/share/bcc/tools/doc/xfsslower_example.txt 文件。

有关 fsync 的详情请参考 fsync(2) 手册页。

第 23 章 使用内核完整性子系统提高安全性

您可以使用内核完整性(kernel integrity)子系统组件来提高系统保护。以下小节介绍了相关组件,并提供了有关其配置的指导。

23.1. 内核完整性子系统

完整性子系统是内核的一部分,负责维护整个系统的数据完整性。此子系统有助于使特定系统的状态与构建时相同,从而防止用户对特定系统文件进行不必要的修改。

内核完整性子系统由两个主要组件组成:

完整性测量架构(IMA)
  • 在文件被执行或打开时,会测量文件的内容。用户可以通过应用自定义策略来更改此行为。
  • 将测量的值放置在内核的内存空间内,从而防止系统用户进行任何修改。
  • 允许本地和远程用户验证测量值。
扩展验证模块(EVM)
  • 通过加密其对应的值,保护与系统安全性(如 IMA 测量和 SELinux 属性)相关的文件的扩展属性(也称为 xattr)。

IMA 和 EVM 还包含大量额外功能扩展。例如:

IMA-Appraisal
  • 根据以前存储在内核内存中的测量文件中的值提供当前文件内容的本地验证。此扩展禁止通过特定文件执行任何操作,以防当前和上一个测量结果不匹配。
EVM 数字签名
  • 允许通过存储在内核密钥环中的加密密钥使用数字签名。
注意

功能扩展相互补充,但您可以独立配置和使用它们。

内核完整性子系统可以利用受信任的平台模块(TPM)来更加强化系统安全性。TPM 是受信任的计算组(TCG)中有关重要加密功能的规范。TPMS 通常作为专用硬件构建,附加到平台的主板,并通过为硬件芯片受保护且受篡改区域提供加密功能来防止基于软件的攻击。其中一些 TPM 特性包括:

  • 随机数生成器
  • 用于加密密钥的生成器和安全存储
  • 哈希生成器
  • 远程测试

23.2. 完整性测量架构

完整性测量架构(IMA)是内核完整性子系统的一个组件。IMA 旨在维护本地文件的内容。具体来说,IMA 在文件访问前测量、存储和应用文件哈希,这可以防止读取和执行不可靠的数据。因此,IMA 增强了系统的安全性。

23.3. 扩展的验证模块

扩展验证模块(EVM)是内核完整性子系统的一个组件,可监控文件的扩展属性(xattr)中的更改。许多面向安全的技术,包括完整性测量架构(IMA),将敏感文件信息(如内容散列)存储在扩展属性中。EVM 从这些扩展属性和特殊密钥创建另一个哈希值,该密钥在引导时加载。每次使用扩展属性时,生成的哈希都会被验证。例如,当 IMA 评估 文件时。

RHEL 8 接受 evm-key keyring 下的特殊加密密钥。密钥由内核密钥环中拥有的 master key 创建。

23.4. 可信和加密的密钥

下面的部分介绍了可信和加密的密钥,作为增强系统安全性的重要部分。

可信和 加密的密钥是利用内核密钥环服务的内核生成的可变长度对称密钥。这种类型的密钥从未以未加密的形式显示在用户空间中,这意味着可以验证其完整性,这意味着扩展验证模块(EVM)可以使用它们来验证并确认运行中系统的完整性。用户级别程序只能访问加密的 Blob 格式的密钥。

受信任的密钥需要硬件组件:受信任的平台模块(TPM)芯片,它用于创建和加密密钥。TPM 使用名为存储根密钥(SRK)的 2048 位 RSA 密钥密封密钥

注意

要使用 TPM 1.2 规范,请通过机器固件中的设置或使用 tpm -tools 软件包中的 tpm_setactive 命令启用并激活它。此外,还需要安装 TrouSers 软件堆栈,并且 需要运行 tcsd 守护进程才能与 TPM(专用硬件)通信。tcsd 守护进程是 TrouSers 套件的一部分,该套件可通过 trousers 软件包获得。TPM 2.0 较新近且向后不兼容,使用不同的软件堆栈,其中 tpm2-tools or ibm-tss 实用程序提供对专用硬件的访问。

此外,用户可以使用特定的 TPM 平台配置寄存器 (PCR)值集密封可信密钥。PCR 包含一组完整性管理值,它们反映了固件、引导装载程序和操作系统。这意味着 PCR 密封的密钥只能被加密的同一系统上的 TPM 解密。但是,一旦加载了 PCR 密封的可信密钥(添加至密钥环),并且验证其关联的 PCR 值后,就可以使用新的(或将来)PCR 值进行更新,以便可以引导新的内核。单个密钥也可以保存为多个 Blob,每个密钥都有不同的 PCR 值。

加密密钥不需要 TPM,因为它们使用内核高级加密标准(AES),这使其比可信密钥快。加密的密钥是使用内核生成的随机数字创建的,并在导入到用户空间 Blob 时由主密钥加密。master 密钥可以是可信密钥或用户密钥。如果 master 密钥不被信任,加密的密钥的安全性仅与用于加密它的用户密钥一样安全。

23.5. 使用可信密钥

下面的部分论述了如何使用 keyctl 实用程序创建、导出、加载或更新可信密钥来提高系统安全性。

先决条件

流程

  1. 要使用 TPM 创建可信密钥,请执行:

    # keyctl add trusted <name> "new <key_length> [options]" <key_ring>
    • 根据语法,构建如下示例命令:

      # keyctl add trusted kmk "new 32" @u
      642500861

      命令创建一个名为 kmk 的可信密钥,长度为 32 字节(256 位),并将其放置在用户密钥环(@u)中。密钥长度为 32 到 128 字节(256 到 1024 位)。

  2. 列出内核 keyring 的当前结构:

    # keyctl show
    Session Keyring
           -3 --alswrv    500   500  keyring: _ses
     97833714 --alswrv    500    -1   \_ keyring: _uid.1000
    642500861 --alswrv    500   500       \_ trusted: kmk
  3. 要将密钥导出到用户空间 blob,请执行:

    # keyctl pipe 642500861 > kmk.blob

    命令使用 pipe 子命令和 kmk 的序列号。

  4. 要从 user-space blob 加载可信密钥,请使用 add 子命令并将 blob 用作参数:

    # keyctl add trusted kmk "load `cat kmk.blob`" @u
    268728824
  5. 根据 TPMsealed 可信密钥创建安全加密密钥:

    # keyctl add encrypted <pass:quotes[name]> "new [format] <pass:quotes[key_type]>:<pass:quotes[primary_key_name]> <pass:quotes[keylength]>" <pass:quotes[key_ring]>
    • 根据语法,使用已创建的可信密钥生成加密密钥:

      # keyctl add encrypted encr-key "new trusted:kmk 32" @u
      159771175

      命令使用上一步中生成的 TPM 密封可信密钥(kmk),作为生成加密 密钥的主要 密钥。

23.6. 使用加密密钥

下面的部分论述了在无法使用受信任的平台模块(TPM)的系统中管理加密密钥以提高系统安全性。

先决条件

流程

  1. 使用随机数字序列来生成用户密钥:

    # keyctl add user kmk-user "$(dd if=/dev/urandom bs=1 count=32 2>/dev/null)" @u
    427069434

    命令生成名为 kmk-user 的用户密钥,该密钥充当 主密钥,用于密封实际加密的密钥。

  2. 使用上一步中的主密钥生成加密密钥:

    # keyctl add encrypted encr-key "new user:kmk-user 32" @u
    1012412758
  3. 另外,还可列出指定用户密钥环中的所有密钥:

    # keyctl list @u
    2 keys in keyring:
    427069434: --alswrv  1000  1000 user: kmk-user
    1012412758: --alswrv  1000  1000 encrypted: encr-key
重要

请记住,未通过可信主密钥密封的加密密钥仅作为用于加密它们的用户主密钥(随机数字密钥)安全。因此,主用户密钥应该尽可能安全地加载,最好是在引导过程早期加载。

其它资源

23.7. 启用完整性测量架构和扩展验证模块

完整性测量架构(IMA)和扩展验证模块(EVM)属于内核完整性子系统,以各种方式增强系统安全性。下面的部分论述了如何启用和配置 IMA 和 EVM 来提高操作系统的安全性。

先决条件

  • 验证 securityfs 文件系统是否已挂载到 /sys/kernel/security/ 目录,并且存在 /sys/kernel/security/integrity/ima/ 目录。

    # mount
    …​
    securityfs on /sys/kernel/security type securityfs (rw,nosuid,nodev,noexec,relatime)
    …​
  • 验证 systemd 服务管理器是否已在引导时支持 IMA 和 EVM:

    # dmesg | grep -i -e EVM -e IMA
    [    0.000000] Command line: BOOT_IMAGE=(hd0,msdos1)/vmlinuz-4.18.0-167.el8.x86_64 root=/dev/mapper/rhel-root ro crashkernel=auto resume=/dev/mapper/rhel-swap rd.lvm.lv=rhel/root rd.lvm.lv=rhel/swap rhgb quiet
    [    0.000000] kvm-clock: cpu 0, msr 23601001, primary cpu clock
    [    0.000000] Using crashkernel=auto, the size chosen is a best effort estimation.
    [    0.000000] Kernel command line: BOOT_IMAGE=(hd0,msdos1)/vmlinuz-4.18.0-167.el8.x86_64 root=/dev/mapper/rhel-root ro crashkernel=auto resume=/dev/mapper/rhel-swap rd.lvm.lv=rhel/root rd.lvm.lv=rhel/swap rhgb quiet
    [    0.911527] ima: No TPM chip found, activating TPM-bypass!
    [    0.911538] ima: Allocated hash algorithm: sha1
    [    0.911580] evm: Initialising EVM extended attributes:
    [    0.911581] evm: security.selinux
    [    0.911581] evm: security.ima
    [    0.911582] evm: security.capability
    [    0.911582] evm: HMAC attrs: 0x1
    [    1.715151] systemd[1]: systemd 239 running in system mode. (+PAM +AUDIT +SELINUX +IMA -APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +SECCOMP +BLKID +ELFUTILS +KMOD +IDN2 -IDN +PCRE2 default-hierarchy=legacy)
    [    3.824198] fbcon: qxldrmfb (fb0) is primary device
    [    4.673457] PM: Image not found (code -22)
    [    6.549966] systemd[1]: systemd 239 running in system mode. (+PAM +AUDIT +SELINUX +IMA -APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +SECCOMP +BLKID +ELFUTILS +KMOD +IDN2 -IDN +PCRE2 default-hierarchy=legacy)

流程

  1. 添加以下内核命令行参数:

    # grubby --update-kernel=/boot/vmlinuz-$(uname -r) --args="ima_policy=appraise_tcb ima_appraise=fix evm=fix"

    该命令在 fix 模式下为当前引导条目启用 IMA 和 EVM,并允许用户收集和更新 IMA 测量。

    The ima_policy=appraise_tcb 内核命令行参数确保内核使用默认的可信计算基础(TCB)测量策略和实例步骤。禁止访问文件,因为之前和当前测量结果不匹配。

  2. 重启以使更改生效。
  3. (可选)验证参数是否已添加到内核命令行中:

    # cat /proc/cmdline
    BOOT_IMAGE=(hd0,msdos1)/vmlinuz-4.18.0-167.el8.x86_64 root=/dev/mapper/rhel-root ro crashkernel=auto resume=/dev/mapper/rhel-swap rd.lvm.lv=rhel/root rd.lvm.lv=rhel/swap rhgb quiet ima_policy=appraise_tcb ima_appraise=fix evm=fix
  4. 创建一个内核主密钥来保护 EVM 密钥:

    # keyctl add user kmk "$(dd if=/dev/urandom bs=1 count=32 2> /dev/null)" @u
    748544121

    内核主密钥(kmk)完全保留在内核空间内存中。内核主密钥 kmk 的 32 字节长值是从 /dev/urandom 文件中随机字节生成的,并放置在用户(@u)密钥环中。密钥序列号是位于前面输出的第二行。

  5. 根据 kmk 密钥创建一个加密的 EVM 密钥:

    # keyctl add encrypted evm-key "new user:kmk 64" @u
    641780271

    命令使用 kmk 生成并加密 64 字节长用户密钥(名为 evm-key)并将其放置在用户(@u)密钥环中。密钥序列号是位于前面输出的第二行。

    重要

    用户密钥必须命名为 evm-key,因为它是 EVM 子系统预期使用的且正在使用的名称。

  6. 为导出的密钥创建一个目录:

    # mkdir -p /etc/keys/
  7. 搜索 kmk 键并将其值导出到文件中:

    # keyctl pipe keyctl search @u user kmk > /etc/keys/kmk*

    命令将内核主密钥(kmk)的未加密值放在之前定义的位置(/etc/keys/)的文件中。

  8. 搜索 evm-key 用户密钥并将其值导出到文件中:

    # keyctl pipe keyctl search @u encrypted evm-key > /etc/keys/evm-key

    命令将用户 evm-key 密钥的加密值放在任意位置的文件中。evm-key 已在早期由内核主密钥加密。

  9. 另外,还可查看新创建的密钥:

    # keyctl show
    Session Keyring
    974575405   --alswrv     0        0      keyring: _ses
    299489774   --alswrv     0    65534       \_ keyring: _uid.0
    748544121   --alswrv     0        0           \_ user: kmk
    641780271   --alswrv     0        0           \_ encrypted: evm-key

    您应该可以看到类似的输出。

  10. 激活 EVM:

    # echo 1 > /sys/kernel/security/evm
  11. (可选)验证 EVM 是否已初始化:

    # dmesg | tail -1
    […​] evm: key initialized

23.8. 使用完整性测量架构收集文件哈希

完整性测量架构(IMA) 的第一级操作是测量阶段,它允许创建文件哈希并将其存储为这些文件的扩展属性(xattrs)。下面的部分论述了如何创建和检查文件的哈希。

先决条件

  • 如启用完整性测量架构和扩展验证模块中所述,启用完整性测量架构(IMA)和扩展验证模块 (EVM)。
  • 验证是否已安装 ima-evm-utilsattrkeyutils 软件包:

    # yum install ima-evm-utils attr keyutils
    Updating Subscription Management repositories.
    This system is registered to Red Hat Subscription Management, but is not receiving updates. You can use subscription-manager to assign subscriptions.
    Last metadata expiration check: 0:58:22 ago on Fri 14 Feb 2020 09:58:23 AM CET.
    Package ima-evm-utils-1.1-5.el8.x86_64 is already installed.
    Package attr-2.4.48-3.el8.x86_64 is already installed.
    Package keyutils-1.5.10-7.el8.x86_64 is already installed.
    Dependencies resolved.
    Nothing to do.
    Complete!

流程

  1. 创建测试文件:

    # echo <Test_text> > test_file

    IMA 和 EVM 确保分配了示例文件 test_file,哈希值存储为其扩展属性。

  2. 检查文件的扩展属性:

    # getfattr -m . -d test_file
    # file: test_file
    security.evm=0sAnDIy4VPA0HArpPO/EqiutnNyBql
    security.ima=0sAQOEDeuUnWzwwKYk+n66h/vby3eD
    security.selinux="unconfined_u:object_r:admin_home_t:s0"

    前面的输出显示了与 SELinux 以及 IMA 和 EVM 哈希值相关的扩展属性。EVM 主动添加 security.evm 扩展属性,并检测对其他文件(如 security.ima )的 xattrs 的任何脱机篡改,它们与文件的内容完整性直接相关。security.evm 字段的值位于基于 Hash 的消息身份验证代码(HMAC-SHA1)中,该身份验证代码由 evm-key 用户密钥生成。

第 24 章 使用 Ansible 角色永久配置内核参数

作为熟悉红帽 Ansible 引擎的经验丰富的用户,您可以使用 kernel_settings 角色一次性在多个客户端上配置内核参数。这个解决方案:

  • 提供带有有效输入设置的友好接口。
  • 保留所有预期的内核参数。

从控制计算机运行 kernel_settings 角色后,内核参数将立即应用于受管系统,并在重新启动后保留。

24.1. 内核设置角色简介

RHEL 系统角色是 Ansible Automation Platform 中的角色和模块集合,可提供一致的配置界面来远程管理多个系统。

RHEL 系统角色是用于使用 kernel_settings 系统角色自动配置内核的。rhel-system-roles 软件包包含这个系统角色以及参考文档。

要将内核参数以自动化方式应用到一个或多个系统,请在 playbook 中使用 kernel_settings 角色和您选择的一个或多个角色变量。playbook 是一个或多个人类可读的 play 的列表,采用 YAML 格式编写。

您可以使用清单文件来定义一组您希望 Ansible Engine 根据 playbook 配置的系统。

使用 kernel_settings 角色,您可以配置:

  • 使用 kernel_settings_sysctl 角色变量的内核参数
  • 使用 kernel_settings_sysfs 角色变量的各种内核子系统、硬件设备和设备驱动程序
  • systemd 服务管理器的 CPU 相关性,并使用 kernel_settings_systemd_cpu_affinity 角色变量处理其分叉
  • 内核内存子系统使用 kernel _settings_transparent_hugepages 和 kernel_ settings_transparent_hugepages_defrag 角色变量透明地 大页

其它资源

24.2. 使用内核设置角色应用所选内核参数

按照以下步骤准备并应用 Ansible playbook 来远程配置内核参数,从而对多个受管操作系统产生持久性。

先决条件

  • 您的 Red Hat Ansible Engine 订阅已附加到系统,也称为 控制计算机,您要从中运行 kernel_settings 角色。如需更多信息,请参阅如何下载和安装 Red Hat Ansible Engine 文章。
  • 在控制机器上启用 Ansible Engine 软件仓库。
  • Ansible Engine 已安装在控制机器上。

    注意

    您不需要在要配置内核参数的系统中(也称为 受管主机)安装 Ansible Engine。

  • rhel-system-roles 软件包安装在控制机器上。
  • 控制机器上有一个受管主机清单,Ansible 引擎可以连接它们。

流程

  1. 另外,还可查看 清单文件

    #  cat /home/jdoe/<ansible_project_name>/inventory
    [testingservers]
    pdoe@192.168.122.98
    fdoe@192.168.122.226
    
    [db-servers]
    db1.example.com
    db2.example.com
    
    [webservers]
    web1.example.com
    web2.example.com
    192.0.2.42

    该文件定义 [testingservers] 组和其他组。它可让您针对特定系统集合更有效地运行 Ansible Engine。

  2. 创建配置文件来为 Ansible Engine 操作设置默认值和权限升级。

    1. 创建新 YAML 文件,并在文本编辑器中打开,例如:

      #  vi /home/jdoe/<ansible_project_name>/ansible.cfg
    2. 将以下内容插入到文件中:

      [defaults]
      inventory = ./inventory
      
      [privilege_escalation]
      become = true
      become_method = sudo
      become_user = root
      become_ask_pass = true

      [defaults] 部分指定受管主机清单文件的路径。[privilege_escalation] 部分定义用户特权转移到指定受管主机上的 root。这对成功配置内核参数是必需的。运行 Ansible playbook 时,会提示您输入用户密码。用户在连接到受管主机后,通过 sudo 自动切换为 root

  3. 创建使用 kernel_settings 角色的 Ansible playbook。

    1. 创建新 YAML 文件,并在文本编辑器中打开,例如:

      #  vi /home/jdoe/<ansible_project_name>/kernel_roles.yml

      此文件表示一个 playbook,通常包含一系列有序的任务(也称为 play )列表,这些任务针对从 清单文件中 选择的特定受管主机运行。

    2. 将以下内容插入到文件中:

      ---
      - name: Configure kernel settings
        hosts: testingservers
      
        vars:
          kernel_settings_sysctl:
            - name: fs.file-max
              value: 400000
            - name: kernel.threads-max
              value: 65536
          kernel_settings_sysfs:
            - name: /sys/class/net/lo/mtu
              value: 65000
          kernel_settings_transparent_hugepages: madvise
      
        roles:
          - linux-system-roles.kernel_settings

      name 键是可选的。它将一个任意字符串作为标签与该 play 关联,并确定该 play 的用途。Play 中的 hosts 键指定对其运行 play 的主机。此键的值或值可以作为受管主机的单独名称或作为 清单文件中 定义的主机组提供。

      vars 部分代表包含所选内核参数名称和值的变量列表。

      roles 键指定系统角色将配置 vars 部分中提到的参数和值。

      注意

      您可以修改 playbook 中的内核参数及其值以符合您的需要。

  4. (可选)验证 play 中的语法是否正确。

    #  ansible-playbook --syntax-check kernel-roles.yml
    
    playbook: kernel-roles.yml

    本例演示了对 playbook 的成功验证。

  5. 执行 playbook。

    #  ansible-playbook kernel-roles.yml
    BECOME password:
    
    PLAY [Configure kernel settings]  ... PLAY RECAP **
    fdoe@192.168.122.226       : ok=10   changed=4    unreachable=0    failed=0    skipped=6    rescued=0    ignored=0
    pdoe@192.168.122.98        : ok=10   changed=4    unreachable=0    failed=0    skipped=6    rescued=0    ignored=0

    在 Ansible Engine 运行 playbook 之前,系统会提示您输入密码,以便受管主机上的用户能够切换到 root,而这是配置内核参数所必需的。

    recap 部分显示 play 成功完成所有受管主机(failed=0),并且已应用了 4 个内核参数(changed=4)。

  6. 重启您的受管主机并检查受影响的内核参数,以验证是否应用了更改并在重启后保留。

其它资源