红帽企业-Linux-8-管理-全-
红帽企业 Linux 8 管理(全)
原文:
zh.annas-archive.org/md5/0CCDE6F20D3A1D212C45A9BF7E65144A
译者:飞龙
前言
Linux 无处不在,从个人设备到最大的超级计算机,从大学的计算机实验室到华尔街或国际空间站,甚至火星!Red Hat Enterprise Linux(简称RHEL)是企业环境中使用最广泛的 Linux 发行版,了解如何使用它是任何技术人员的关键技能。无论您是完全投身于管理基础设施,还是作为开发人员对您想要部署的平台更感兴趣,学习 Linux - 更准确地说是 RHEL - 将帮助您更加有效,甚至可能提升您的职业生涯。
在这本书中,我们从非常实用的角度涵盖了基本的 RHEL 管理技能,提供了我们从“战场”经验中学到的例子和技巧。您可以从头到尾地跟随,每一步都可以练习,同时了解事物是如何构建的以及它们为什么会表现出这样的行为。
希望您喜欢这本书,能充分利用它,并在阅读后拥有扎实的 RHEL 管理技能基础。这就是我们写这本书的目的。
享受阅读...和练习!
这本书适合谁
任何希望在 Linux 上构建和工作 IT 基础设施的人都将从这本书中受益,作为不同有用任务、技巧和最佳实践的参考。它将帮助任何寻求通过 Red Hat 认证系统管理员(RHCSA)考试的人,尽管它不能替代官方培训,在整个过程中将进行实验室和特别设计的测试。本书的范围调整到 RHCSA,通过来自实际经验的建议和许多实际示例进行扩展。
这本书涵盖了什么
第一章,安装 RHEL8,介绍了从获取软件和订阅到安装系统本身的 RHEL 安装过程。
第二章,RHEL8 高级安装选项,介绍了安装程序的高级用例,包括在云中部署实例和自动化安装。
第三章,基本命令和简单的 Shell 脚本,解释了在系统管理过程中将使用的日常命令,以及如何通过 shell 脚本自动化它们。
第四章,常规操作工具,展示了我们系统中可用的简单工具,可用于日常操作,例如启动或启用系统服务,或通过日志查看系统中正在进行的操作。
第五章,使用用户、组和权限保护系统,介绍了如何在任何 Linux 系统中管理用户、组和权限,其中包括一些关于 Red Hat Enterprise Linux 的具体内容。
第六章,启用网络连接,介绍了连接系统到网络的步骤以及可能的配置方式。
第七章,添加、打补丁和管理软件,回顾了在我们的系统中添加、删除和更新的步骤,包括升级和回滚的示例。
第八章,远程管理系统,介绍了如何远程连接到您的系统以提高效率。其中包括使用ssh
连接创建密钥和使用终端复用器(tmux
)。
第九章,使用 firewalld 保护网络连接,指导您了解 RHEL 中的网络防火墙配置以及如何正确管理它,包括管理区域、服务和端口。
第十章, 使用 SELinux 使系统更加安全,介绍了 SELinux 的使用和基本故障排除。
第十一章, 使用 OpenSCAP 进行系统安全配置文件,解释了如何使用 OpenSCAP 运行安全配置文件,并检查 RHEL 是否符合典型的规定。
第十二章, 管理本地存储和文件系统,涵盖了文件系统的创建、挂载点和一般存储管理。
第十三章, 使用 LVM 进行灵活的存储管理,解释了 LVM 如何通过添加磁盘和扩展逻辑卷来实现更灵活的存储管理。
第十四章, 使用 Stratis 和 VDO 进行高级存储管理,介绍了 VDO 以及如何在我们的系统中使用它来去重存储,以及使用 Stratis 更轻松地管理存储。
第十五章, 理解引导过程,解释了系统引导的过程以及使其重要的细节。
第十六章, 使用 tuned 进行内核调优和管理性能配置文件,解释了内核调优的工作原理以及如何使用 tuned 进行预定义配置文件的使用。
第十七章, 使用 Podman、Buildah 和 Skopeo 管理容器,介绍了容器和用于管理和构建容器的工具。
第十八章, 练习题–1,让您测试您所学到的知识。
第十九章, 练习题–2,提供更复杂的测试以检验您所学到的知识。
充分利用本书
所有软件要求将在各章中指出。请注意,本书假定您可以访问物理或虚拟机,或者可以访问互联网以创建云账户,以执行本书将引导您完成的操作。
如果您使用本书的数字版本,我们建议您自己输入代码或从书的 GitHub 存储库中访问代码(链接在下一节中提供)。这样做将帮助您避免与复制和粘贴代码相关的任何潜在错误。
下载示例代码文件
您可以从 GitHub 上 https://github.com/PacktPublishing/Red-Hat-Enterprise-Linux-8-Administration 下载本书的示例代码文件。如果代码有更新,将在 GitHub 存储库中进行更新。
我们还提供了来自我们丰富书籍和视频目录的其他代码包,可在 https://github.com/PacktPublishing/ 上找到。快去看看吧!
下载彩色图片
我们还提供了一个 PDF 文件,其中包含本书中使用的屏幕截图和图表的彩色图片。您可以在这里下载:static.packt-cdn.com/downloads/9781800569829_ColorImages.pdf
。
使用的约定
本书中使用了许多文本约定。
文本中的代码
:表示文本中的代码词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 用户名。例如:"将下载的RHEL8.iso
磁盘映像文件挂载为系统中的另一个磁盘。"
代码块设置如下:
#!/bin/bash
echo "Hello world"
当我们希望引起您对代码块的特定部分的注意时,相关行或项将以粗体显示:
[default]
branch = main
repo = myrepo
username = bender
protocol = https
任何命令行输入或输出都以以下形式书写:
$ mkdir scripts
$ cd scripts
粗体:表示新术语、重要词汇或屏幕上看到的词语。例如,菜单或对话框中的词语以粗体显示。例如:"从管理面板中选择系统信息"。
提示或重要说明
看起来像这样。
联系我们
我们始终欢迎读者的反馈意见。
请发送电子邮件至customercare@packtpub.com
,并在主题中提及书名。
勘误:尽管我们已经尽最大努力确保内容的准确性,但错误是难免的。如果您在本书中发现了错误,我们将不胜感激地接受您的报告。请访问www.packtpub.com/support/errata并填写表格。
盗版:如果您在互联网上发现我们作品的任何非法副本,请向我们提供位置地址或网站名称,我们将不胜感激。请通过 copyright@packt.com 与我们联系,并提供材料链接。
如果您有兴趣成为作者:如果您在某个专业领域有专长,并且有兴趣撰写或为书籍做出贡献,请访问authors.packtpub.com。
分享您的想法
阅读完《Red Hat Enterprise Linux 8 Administration》后,我们很想听听您的想法!请点击这里直接访问亚马逊的书评页面,分享您的反馈意见。
您的评论对我们和技术社区都很重要,将帮助我们确保提供卓越的内容质量。
第一部分:系统管理-软件、用户、网络和服务管理
部署和配置系统,并保持其更新是每个系统管理员日常工作中执行的基本任务。在本节中,重新构建了这样做的核心部分,以便您可以按顺序跟踪任务,并正确地学习、练习和理解它们。
本节包括以下章节:
-
第一章,安装 RHEL8
-
第二章,RHEL8 高级安装选项
-
第三章,基本命令和简单的 Shell 脚本
-
第四章,常规操作工具
-
第五章,使用用户、组和权限保护系统
-
第六章,启用网络连接
-
第七章,添加、打补丁和管理软件
第一章:安装 RHEL8
开始使用Red Hat Enterprise Linux或RHEL的第一步是让它运行起来。无论是在您自己的笔记本电脑上作为主系统,还是在虚拟机或物理服务器上,都需要安装它以便熟悉您想要学习使用的系统。强烈建议您在阅读本书时获取一个物理或虚拟机来使用该系统。
在本章中,您将部署自己的 RHEL8 系统,以便能够跟随本书中提到的所有示例,并了解更多关于 Linux 的知识。
本章将涵盖的主题如下:
-
获取 RHEL 软件和订阅
-
安装 RHEL8
技术要求
开始的最佳方式是拥有一个RHEL8虚拟机来进行工作。您可以在主计算机上作为虚拟机进行操作,也可以使用物理计算机。在本章的后续部分,我们将审查这两种选择,您将能够运行自己的 RHEL8 系统。
提示
虚拟机是模拟完整计算机的一种方式。要能够在自己的笔记本电脑上创建这个模拟计算机,如果您使用的是 macOS 或 Windows,您需要安装虚拟化软件,例如 Virtual Box。如果您已经在运行 Linux,则已经准备好进行虚拟化,您只需要添加virt-manager
软件包。
获取 RHEL 软件和订阅
要能够部署 RHEL,您需要一个红帽订阅来获取要使用的镜像,以及访问软件和更新的存储库。您可以免费从红帽的开发者门户网站获取开发者订阅,使用以下链接:developers.redhat.com。然后需要按照以下步骤进行操作:
-
在developers.redhat.com上登录或创建帐户。
-
转到developers.redhat.com页面,然后点击登录按钮:
图 1.1 - developers.redhat.com 首页,指示点击登录的位置
- 一旦进入登录页面,使用您的帐户,如果没有帐户,可以通过点击右上角的注册或直接在注册框中点击立即创建按钮来创建帐户,如下所示:
图 1.2 - 红帽登录页面(所有红帽资源通用)
您可以选择在几个服务中使用您的凭据(换句话说,Google,GitHub或Twitter)。
- 登录后,转到Linux部分
您可以在内容之前的导航栏中找到Linux部分:
图 1.3 - 在 developers.redhat.com 访问 Linux 页面
点击下载 RHEL,它将显示为下一页上的一个漂亮的按钮:
图 1.4 - 在 developers.redhat.com 访问 RHEL 下载页面
然后选择x86_64(9 GB)架构的 ISO 镜像(这是 Intel 和 AMD 计算机上使用的架构):
图 1.5 - 选择 x86_64 的 RHEL8 ISO 下载
- 获取RHEL8 ISO镜像的方法如下:
图 1.6 - 下载 x86_64 的 RHEL8 对话框
ISO 镜像是一个文件,其中包含完整 DVD 的内容的精确副本(即使我们没有使用 DVD)。稍后将使用此文件来安装我们的机器,无论是将其转储到 USB 驱动器进行Bare Metal安装,解压缩以进行网络安装,还是附加到虚拟机安装(或在服务器中使用带外功能,如 IPMI、iLO 或 iDRAC)。
提示
验证 ISO 镜像,并确保我们获取的镜像没有损坏或被篡改,可以使用一种称为“校验和”的机制。校验和是一种审查文件并提供一组字母和数字的方法,可用于验证文件是否与原始文件完全相同。Red Hat 在客户门户的下载部分提供了用于此目的的sha256
校验和列表(access.redhat.com/
)。有关该过程的文章在这里:access.redhat.com/solutions/8367
。
我们有软件,即 ISO 镜像,可以在任何计算机上安装 RHEL8。这些是全球生产机器中使用的相同位,您可以使用您的开发者订阅进行学习。现在是时候在下一节中尝试它们了。
安装 RHEL8
在本章的这一部分,我们将按照典型的安装过程在一台机器上安装 RHEL。我们将遵循默认步骤,审查每个步骤的可用选项。
物理服务器安装准备
在开始安装之前,物理服务器需要进行一些初始设置。常见步骤包括配置内部阵列中的磁盘,将其连接到网络,为预期的接口聚合(组合,绑定)准备交换机,准备访问外部磁盘阵列(换句话说,光纤通道阵列),设置带外功能,并保护BIOS配置。
我们不会详细介绍这些准备工作,除了启动顺序。服务器将需要从外部设备(如USB 闪存驱动器或光盘)启动(开始加载系统)。
要从带有 Linux 或 macOS 的计算机创建可引导的 USB 闪存驱动器,只需使用dd
应用程序进行“磁盘转储”即可。执行以下步骤:
- 在系统中找到您的 USB 设备,通常在 Linux 中为
/dev/sdb
,在 macOS 中为/dev/disk2
(在 macOS 中,此命令需要特殊权限,请以sudo dmesg | grep removable
运行):
sdb disk, referred to as sdb1, is mounted. We will need to *unmount* all the partitions mounted. In this example, this is straightforward as there is only one. To do so, we can run the following command:
$ sudo umount /dev/sdb1
Dump the image! (Warning, this will erase the selected disk!):
$ sudo dd if=rhel-8.3-x86_64-dvd.iso of=/dev/sdb bs=512k
TipAlternative methods are available for creating a boot device. Alternative graphical tools are available for creating a boot device that can help select both the image and the target device. In Fedora Linux (the community distribution where RHEL was based on, and a workstation for many engineers and developers), the **Fedora Media Writer** tool can be used. For other environments, the **UNetbootin** tool could also serve to create your boot media.
现在,有了 USB 闪存驱动器,我们可以在任何物理机器上安装,从小型笔记本电脑到大型服务器。下一部分涉及使物理机器从USB 闪存驱动器启动。执行该操作的机制将取决于所使用的服务器。但是,在启动过程中提供选择启动设备的选项已经变得很常见。以下是如何在笔记本电脑上选择临时启动设备的示例:
- 中断正常启动。在这种情况下,启动过程显示我可以通过按Enter来做到:
图 1.7 - 中断正常启动的 BIOS 消息示例
- 选择临时启动设备,这种情况下通过按F12键:
图 1.8 - 中断启动的 BIOS 菜单示例
- 选择要从中启动的设备。我们希望从我们的 USB 闪存驱动器启动,在这种情况下是USB HDD:ChipsBnk Flash Disk:
图 1.9 - 选择 USB HDD 启动设备的 BIOS 菜单示例
让系统从 USB 驱动器启动安装程序。
一旦我们知道如何准备带有 RHEL 安装程序的 USB 驱动器,以及如何使物理机从中引导,我们就可以跳到本章的运行 RHEL 安装部分并进行安装。如果我们有一个迷你服务器(换句话说,Intel NUC)、一台旧计算机或一台笔记本电脑,可以用作跟随本书的机器,这将非常有用。
接下来,我们将看看如何在您的安装中准备虚拟机,以防您考虑使用当前的主要笔记本电脑(或工作站)跟随本书,但仍希望保留一个单独的机器进行工作。
虚拟服务器安装准备
virt-manager
将添加运行所需的所有底层组件(这些组件包括KVM、Libvirt、Qemu和virsh等)。其他推荐用于 Windows 或 macOS 系统的免费虚拟化软件包括Oracle VirtualBox和VMware Workstation Player。
本节中的示例将使用virt-manager
执行,但可以轻松适用于任何其他虚拟化软件,无论是在笔记本电脑还是在最大的部署中。
上面已经描述了准备步骤,并需要获取rhel-8.3-x86_64-dvd.iso
。一旦下载并且如果可能的话,检查其完整性(如在获取 RHEL 软件和订阅部分的最后提示中提到的),让我们准备部署一个虚拟机:
- 启动您的虚拟化软件,这里是
virt-manager
:
图 1.10 - 虚拟管理器主菜单
- 通过转到文件,然后单击新建虚拟机来创建一个新的虚拟机。选择本地安装媒体(ISO 镜像或 CDROM):
图 1.11 - 虚拟管理器 - 新 VM 菜单
- 选择ISO 镜像。这样,虚拟机将配置为具有虚拟 DVD/CDROM 驱动器,并已准备好从中引导。这是惯例行为。但是,当使用不同的虚拟化软件时,您可能希望执行检查:
图 1.12 - 选择 ISO 镜像作为安装介质的虚拟管理器菜单
- 为我们正在创建的虚拟机分配内存和 CPU(注意:虚拟机通常称为VM)。对于Red Hat Enterprise Linux 8(也称为RHEL8),最低内存为 1.5 GB,建议每个逻辑 CPU 为 1.5 GB。我们将使用最低设置(1.5 GB 内存,1 个 CPU 核心):
图 1.13 - 选择内存和 CPU 的虚拟管理器菜单
现在是为虚拟机分配至少一个磁盘的时候了。在这种情况下,我们将分配一个具有最小磁盘空间 10 GB 的单个磁盘,但在以后的章节中,我们将能够分配更多的磁盘来测试其他功能:
图 1.14 - 创建新磁盘并将其添加到虚拟机的虚拟管理器菜单
- 我们的虚拟机已经具备了开始所需的一切:引导设备、内存、CPU 和磁盘空间。在最后一步中,添加了网络接口,所以现在我们甚至有了网络。让我们回顾一下数据并启动它:
图 1.15 - 选择虚拟机名称和网络的虚拟管理器菜单
](https://gitee.com/OpenDocCN/freelearn-linux-zh/raw/master/docs/rhel8-adm/img/B16799_01_015.jpg)
图 1.15 - 选择虚拟机名称和网络的虚拟管理器菜单
经过这些步骤后,我们将拥有一个完全功能的虚拟机。现在是时候通过在其上安装 RHEL 操作系统来完成这个过程了。在下一节中查看如何执行此操作。
运行 RHEL 安装
一旦我们为安装准备好了虚拟或物理服务器,就该进行安装了。如果我们到达以下屏幕,就说明之前的所有步骤都已正确执行:
图 1.16 – RHEL8 安装的初始启动屏幕,选择安装
我们提供了三个选项(以白色选择):
-
安装 Red Hat Enterprise Linux 8.3:此选项将启动并运行安装程序。
-
测试此媒体并安装 Red Hat Enterprise Linux 8.3:此选项将检查正在使用的镜像,以确保其没有损坏,并且安装可以确保进行。建议首次使用刚下载的 ISO 镜像或刚创建的媒体(例如 USB 闪存驱动器或 DVD)时使用此选项(在虚拟机中,运行检查大约需要 1 分钟)。
-
故障排除:此选项将帮助您在安装出现问题、运行系统出现问题或硬件出现问题时审查其他选项。让我们快速查看此菜单上可用的选项:
– 以基本图形模式安装 Red Hat Enterprise Linux 8.3:此选项适用于具有旧图形卡和/或不受支持的图形卡的系统。如果识别出可视化问题,它可以帮助完成系统安装。
– 救援 Red Hat Enterprise Linux 系统:当我们的系统存在启动问题或者我们想要访问它以审查它时(换句话说,审查可能受损的系统),可以使用此选项。它将启动一个基本的内存系统来执行这些任务。
– 运行内存测试:可以检查系统内存以防止问题,例如全新服务器的情况,我们希望确保其内存正常运行,或者系统出现问题和紧急情况可能表明与内存有关的问题。
– 从本地驱动器引导:如果您从安装媒体引导,但已经安装了系统。
– 返回主菜单:返回上一个菜单。
重要提示
RHEL 引导菜单将显示几个选项。所选项将显示为白色,其中一个单独的字母以不同的颜色显示,例如“i”表示安装,“m”表示测试媒体。这些是快捷方式。按下带有该字母的键将直接带我们到此菜单项。
让我们继续进行测试此媒体并安装 Red Hat Enterprise Linux 8.3,以便安装程序审查我们正在使用的 ISO 镜像:
图 1.17 – RHEL8 ISO 镜像自检
完成后,将到达第一个安装屏幕。安装程序称为Anaconda(一个笑话,因为它是用一种叫做Python的语言编写的,并且遵循逐步方法)。在安装过程中,我们将选择的选项需要引起注意,因为我们将在本书的使用 Anaconda 自动部署部分中对它们进行审查。
本地化
安装的第一步是选择安装语言。对于此安装,我们将选择英语,然后选择英语(美国):
图 1.18 – RHEL8 安装菜单 – 语言
如果您无法轻松找到您的语言,您可以在列表下的框中输入它进行搜索。选择语言后,我们可以单击继续按钮继续。这将带我们到安装摘要屏幕:
图 1.19 – RHEL8 安装菜单 – 主页
在安装摘要屏幕上,显示了所有必需的配置部分,其中许多部分(没有警告标志和红色文字)已经预先配置为默认值。
让我们回顾一下本地化设置。首先是键盘:
图 1.20 – RHEL8 安装 – 键盘选择图标
我们可以查看键盘设置,这不仅有助于更改键盘,还可以在需要时添加额外的布局以在它们之间切换:
图 1.21 – RHEL8 安装 – 键盘选择对话框
这可以通过点击spa
直到出现,然后选择它,然后点击添加来完成:
图 1.22 – RHEL8 安装 – 键盘选择列表
要将其设置为默认选项,需要点击下方的^按钮。在本例中,我们将保留它作为次要选项,以便安装支持软件。完成后,点击完成:
图 1.23 – RHEL8 安装 – 带有不同键盘的键盘选择对话框
现在,我们将继续进行语言支持:
图 1.24 – RHEL8 安装 – 语言选择图标
在这里,我们还可以添加我们的本地语言。在本例中,我将使用Español,然后Español (España)。这将再次包括安装支持所添加语言所需的软件:
图 1.25 – RHEL8 安装 – 带有不同语言的语言选择对话框
我们将继续配置两种语言,尽管您可能希望选择您自己的本地化语言。
现在,我们将继续进行时间和日期的设置,如下所示:
图 1.26 – RHEL8 安装 – 时间和日期选择图标
默认配置设置为美国纽约市。您在这里有两种可能性:
- 使用您的本地时区。当您希望所有日志都在该时区注册时,建议使用此选项(换句话说,因为您只在一个时区工作,或者因为每个时区都有本地团队)。在本例中,我们选择了西班牙,马德里,欧洲时区:
图 1.27 – RHEL8 安装 – 时间和日期选择对话框 – 选择马德里
- 使用协调世界时(也称为UTC)以使全球各地的服务器具有相同的时区。可以在区域: | Etc下选择,然后选择城市: | 协调世界时:
图 1.28 – RHEL8 安装 – 时间和日期选择对话框 – 选择 UTC
我们将继续使用西班牙,马德里,欧洲的本地化时间,尽管您可能希望选择您的本地化时区。
提示
如屏幕所示,有一个选项可以选择网络时间,以使机器的时钟与其他机器同步。只有在配置网络后才能选择此选项。
软件
完成本地化配置(或几乎完成;我们可能稍后再回来配置网络时间)后,我们将继续进行软件部分,或者更确切地说,是其中的连接到红帽:
图 1.29 – RHEL8 安装 – 连接到红帽选择图标
在这一部分,我们可以使用我们自己的 Red Hat 帐户,就像我们之前在developers.redhat.com下创建的那样,以访问系统的最新更新。要配置它,我们需要先配置网络。
出于本部署的目的,我们现在不会配置这一部分。我们将在本书的第七章中,添加、打补丁和管理软件,中了解如何管理订阅和获取更新。
重要提示
使用 Red Hat Satellite 进行系统管理:对于拥有超过 100 台服务器的大型部署,Red Hat 提供了“Red Hat Satellite”,具有高级软件管理功能(例如版本化内容视图、使用 OpenSCAP 进行集中安全扫描以及简化的 RHEL 补丁和更新)。可以使用激活密钥连接到 Red Hat Satellite,从而简化系统管理。
现在让我们转到安装源,如下所示:
图 1.30 – RHEL8 安装 – 安装源图标
这可以用于使用远程源进行安装。当使用仅包含安装程序的引导 ISO 映像时,这非常有用。在这种情况下,由于我们使用的是完整的 ISO 映像,它已经包含了完成安装所需的所有软件(也称为软件包)。
下一步是软件选择,如下截图所示:
图 1.31 – RHEL8 安装 – 软件选择图标
在这一步中,我们可以选择要在系统上安装的预定义软件包集,以便系统可以执行不同的任务。虽然在这个阶段这样做可能非常方便,但我们将采用更加手动的方法,并选择最小安装配置文件,以便稍后向系统添加软件。
这种方法还有一个优点,即通过仅安装系统中所需的最小软件包来减少攻击面:
图 1.32 – RHEL8 安装 – 软件选择菜单;选择最小安装
系统
一旦选择了软件包集,让我们继续进行系统配置部分。我们将从安装目标开始,选择要用于安装和配置的磁盘:
图 1.33 – RHEL8 安装 – 安装目标图标,带有警告标志,因为此步骤尚未完成
这个任务非常重要,因为它不仅会定义系统在磁盘上的部署方式,还会定义磁盘的分布方式和使用的工具。即使在这个部分,我们不会使用高级选项。我们将花一些时间来审查主要选项。
这是默认的设备选择屏幕,只发现了一个本地标准磁盘,没有专用和网络磁盘选项,并准备运行自动分区。可以在以下截图中看到:
图 1.34 – RHEL8 安装 – 安装目标菜单,选择自动分区
在这一部分点击完成将完成继续安装所需的最小数据集。
让我们来回顾一下各个部分。
本地标准磁盘是安装程序要使用的一组磁盘。可能情况是我们有几个磁盘,而我们只想使用特定的磁盘:
图 1.35 – RHEL8 安装 – 安装目标菜单,选择了几个本地磁盘
这是一个有三个可用磁盘并且只使用第一个和第三个的例子。
在我们的情况下,我们只有一个磁盘,它已经被选择了:
图 1.36 – RHEL8 安装 – 安装目标菜单,选择了一个本地磁盘
通过选择加密我的数据,可以轻松使用全盘加密,这在笔记本安装或在低信任环境中安装时是非常推荐的:
图 1.37 – RHEL8 安装 – 安装目标菜单,未选择数据加密选项
在这个例子中,我们将不加密我们的驱动器。
自动安装选项将自动分配磁盘空间:
图 1.38 – RHEL8 安装 – 安装目标菜单;存储配置(自动)
它将通过创建以下资源来实现:
-
/boot
: 用于分配系统核心(kernel
)和在引导过程中帮助的文件的空间(例如初始引导镜像initrd
)。 -
/boot/efi
: 用于支持 EFI 启动过程的空间。 -
/"
: 根文件系统。这是系统所在的主要存储空间。其他磁盘/分区将被分配到文件夹中(这样做时,它们将被称为挂载点
)。 -
/home
: 用户存储个人文件的空间。
让我们选择这个选项,然后点击完成。
提示
系统分区和引导过程:如果您仍然不完全理解有关系统分区和引导过程的一些扩展概念,不要担心。有一章节专门介绍了文件系统、分区以及如何管理磁盘空间,名为管理本地存储和文件系统。要了解引导过程,有一章节名为理解引导过程,它逐步审查了完整的系统启动顺序。
下一步涉及审查Kdump或内核转储。这是一种允许系统在发生关键事件并崩溃时保存状态的机制(它会转储内存,因此得名):
图 1.39 – RHEL8 安装 – Kdump 配置图标
为了工作,它将为自己保留一些内存,等待在系统崩溃时进行操作。默认配置对需求进行了良好的计算:
图 1.40 – RHEL8 安装 – Kdump 配置菜单
点击完成将带我们进入下一步网络和主机名,如下所示:
图 1.41 – RHEL8 安装 – 网络和主机名配置图标
本节将帮助系统连接到网络。在虚拟机的情况下,对外部网络的访问将由虚拟化软件处理。默认配置通常使用网络地址转换(NAT)和动态主机配置协议(DHCP),这将为虚拟机提供网络配置和对外部网络的访问。
一旦进入配置页面,我们可以看到有多少网络接口分配给我们的机器。在这种情况下,只有一个,如下所示:
图 1.42 – RHEL8 安装 – 网络和主机名配置菜单
首先,我们可以通过点击右侧的开/关切换来启用接口。关闭它的话,看起来是这样的:
图 1.43 - RHEL8 安装 - 网络和主机名配置切换(关)
并且要打开它的话,应该是这样的:
图 1.44 - RHEL8 安装 - 网络和主机名配置切换(开)
我们将看到接口现在有配置(IP 地址,默认路由和DNS):
图 1.45 - RHEL8 安装 - 网络和主机名配置信息详情
为了使这个改变永久化,我们将点击屏幕右下角的配置按钮来编辑接口配置:
图 1.46 - RHEL8 安装 - 网络和主机名配置;接口配置;以太网选项卡
单击常规选项卡将呈现主要选项。我们将选择优先自动连接,并将值保留为0,就像这样:
图 1.47 - RHEL8 安装 - 网络和主机名配置;接口配置;常规选项卡
点击保存将使更改永久化,并且默认启用这个网络接口。
现在是给我们的虚拟服务器取一个名字的时候了。我们将去到rhel8.example.com
,然后点击应用:
图 1.48 - RHEL8 安装 - 网络和主机名配置;主机名详情
提示
域名example.com
是用于演示目的,并且可以放心在任何场合使用,知道它不会与其他系统或域名发生冲突或引起任何麻烦。
网络页面将会是这样的:
图 1.49 - RHEL8 安装 - 网络和主机名配置菜单;配置完成
单击完成将带我们返回到主安装程序页面,系统连接到网络并准备好一旦安装完成就连接。
名为启用网络连接的章节将更详细地描述在 RHEL 系统中配置网络的可用选项。
重要提示
现在系统已连接到网络,我们可以回到时间和日期并启用网络时间(这是安装程序自动完成的),以及转到连接到 Red Hat来订阅系统到 Red Hat 的内容分发网络(或CDN)。系统订阅到 CDN 的详细说明将在第七章中详细解释,添加、打补丁和管理软件。
现在是时候通过转到安全策略来审查最终系统选项,安全配置文件了:
图 1.50 - RHEL8 安装 - 安全策略配置图标
在其中,我们将看到一个可以在我们系统中默认启用的安全配置文件列表:
图 1.51 - RHEL8 安装 - 安全策略配置菜单
安全配置有一些要求在这个安装中我们没有涵盖(比如有单独的/var
或/tmp
分区)。我们可以点击应用安全策略来关闭它,然后点击完成:
图 1.52 – RHEL8 安装 – 安全策略配置切换(关闭)
有关此主题的更多信息将在第十一章**,使用 OpenSCAP 进行系统安全配置中进行讨论。
用户设置
Unix 或 Linux 系统中的主管理员用户称为root
。
我们可以通过点击根密码部分来启用根用户,尽管这并非必需,在安全受限的环境中,建议您不要这样做。我们将在本章中这样做,以便学习如何做以及解释所涵盖的情况:
图 1.53 – RHEL8 安装 – 根密码配置图标(因为尚未设置而显示警告)
点击根密码后,我们将看到一个对话框来输入密码:
图 1.54 – RHEL8 安装 – 根密码配置菜单
建议密码具有以下内容:
-
超过 10 个字符(最少 6 个)
-
小写和大写
-
数字
-
特殊字符(如$、@、%和&)
如果密码不符合要求,它会警告我们,并强制我们点击完成两次以使用弱密码。
现在是时候通过点击用户创建来为系统创建用户了:
图 1.55 – RHEL8 安装 – 用户创建配置图标(因为尚未完成而显示警告)
这将带我们进入一个输入用户数据的部分:
图 1.56 – RHEL8 安装 – 用户创建配置菜单
在此处将适用与前一部分相同的密码规则。
点击root
密码)。
提示
作为良好的实践,不要为根帐户和用户帐户使用相同的密码。
第五章**,使用用户、组和权限保护系统包括如何使用和管理sudo
工具为用户分配管理权限的部分。
点击完成返回到主安装程序屏幕。安装程序已准备好继续安装。主页面将如下所示:
图 1.57 – RHEL8 安装 – 完成后的主菜单
点击开始安装将启动安装过程:
重要提示
如果省略了开始安装所需的任何步骤,开始安装按钮将变灰,因此无法点击。
图 1.58 – RHEL8 安装 – 安装进行中
安装完成后,我们可以点击重新启动系统,它将准备好使用:
图 1.59 – RHEL8 安装 – 安装完成
重要的是要记住从虚拟机中卸载 ISO 镜像(或从服务器中移除 USB 存储设备),并检查系统中的引导顺序是否正确配置。
您的第一个 Red Hat Enterprise Linux 8 系统现在已准备就绪!恭喜。
正如您所看到的,很容易在虚拟机或物理机中安装 RHEL,并准备好用于运行任何我们想要运行的服务。在云中,该过程非常不同,因为机器是从镜像实例化来运行的。在下一章中,我们将回顾如何在云中的虚拟机实例中运行 RHEL。
总结
Red Hat 认证系统管理员考试完全是基于实际经验的实践。为了做好准备,最好的方法就是尽可能多地练习,这也是本书开始提供Red Hat Enterprise Linux 8(RHEL8)访问权限并提供如何部署自己的虚拟机的替代方案的原因。
安装涵盖了不同的场景。这些是最常见的情况,包括使用物理机器、虚拟机或云实例。在本章中,我们专注于使用虚拟机或物理机。
在使用物理硬件时,我们将专注于许多人喜欢重复使用旧硬件,购买二手或廉价的迷你服务器,甚至将自己的笔记本电脑用作 Linux 体验的主要安装设备这一事实。
在虚拟机的情况下,我们考虑的是那些希望将所有工作都保留在同一台笔记本电脑上,但又不想干扰他们当前的操作系统(甚至可能不是 Linux)的人。这也可以与前一个选项很好地配合,即在自己的迷你服务器上使用虚拟机。
在本章之后,您将准备好继续阅读本书的其余部分,至少有一个 Red Hat Enterprise Linux 8 实例可供使用和练习。
在下一章中,我们将回顾一些高级选项,例如使用云来部署 RHEL 实例,自动化安装和最佳实践。
让我们开始吧!
第二章:RHEL8 高级安装选项
在上一章中,我们学习了如何在物理或虚拟机上安装Red Hat Enterprise Linux,或RHEL,以便在阅读本书时使用。在本章中,我们将回顾如何在云中使用 RHEL 实例以及在这样做时出现的主要差异。
您还将学习不仅如何部署系统,而且如何做出最佳选择,并能够以自动化方式执行部署。
为了完成安装,已包括了一个关于最佳实践的部分,以便您可以从第一天开始避免长期问题。
这些是本章将涵盖的主题:
-
使用 Anaconda 自动化 RHEL 部署
-
在云上部署 RHEL
-
安装最佳实践
技术要求
在本章中,我们将回顾使用Anaconda进行自动化安装过程。为此,您需要使用我们在上一章中创建的RHEL8 部署。
我们还将创建云实例,为此您需要在所选云环境中创建一个帐户。我们将使用Google Cloud Platform。
使用 Anaconda 自动化 RHEL 部署
完成了在本地部署 RHEL 的第一步后,您可以以 root 用户登录到机器上,并列出root
用户在其文件夹中拥有的文件:
[root@rhel8 ~]# ls /root/
anaconda-ks.cfg
您会找到anaconda-ks.cfg
文件。这是一个重要的文件,称为kickstart
,它包含了在安装过程中安装程序Anaconda的响应。让我们来看看这个文件的内容。
重要提示
在云映像中,没有anaconda-ks.cfg
文件。
此文件可以被重用以安装其他系统,使用与我们用于此安装的相同选项。让我们回顾一下我们在上一次安装中添加的选项。
以#
开头的行是注释,对安装过程没有影响。
指定正在使用的版本的注释如下:
#version=RHEL8
然后进行了一种类型的安装。它可以是图形
或文本
(对于无头系统,通常使用第二种):
# Use graphical install
graphical
安装应用程序包或任何其他软件包的软件源由repo
条目指定。由于我们使用的是 ISO 镜像,它被访问(在 Linux 术语中被挂载)就像是一个CDROM:
repo --name="AppStream" --baseurl=file:///run/install/sources/mount-0000-cdrom/AppStream
部分由%
符号指定。在这种情况下,我们将输入packages
部分,其中包含要安装的软件包列表,并使用%end
特殊标记来关闭它们。有两个选择:由以@^
符号开头的定义的软件包组(在这种情况下是minimal-environment
)和不需要任何前缀的软件包的名称(在这种情况下是kexec-tools
软件包,负责安装我们之前解释的kdump
功能):
%packages
@^minimal-environment
kexec-tools
%end
我们继续点击没有部分的选项。在这种情况下,我们有键盘布局和系统语言支持。正如你所看到的,我们添加了英语美国键盘(标记为us
)和西班牙,西班牙(标记为es
):
# Keyboard layouts
keyboard --xlayouts='us','es'
对于系统语言,我们还添加了英语美国(en_US
)和西班牙,西班牙(es_ES
)。操作系统中有几种管理、存储和表示文本的方式。如今最常见的是UTF-8
,它使我们能够在一个单一标准下拥有许多字符集。这就是为什么系统语言后面有.UTF-8
:
# System language
lang en_US.UTF-8 --addsupport=es_ES.UTF-8
提示
Unicode(或通用编码字符集)转换格式 - 8 位,简称 UTF-8,是一种字符编码,它扩展了以前的能力,以支持中文、西里尔文或阿拉伯文(以及许多其他语言)在同一文本中(比如代表网页或控制台的文本)。UTF-8 于 1993 年推出,被全球网页的 95.9%使用。以前的字符集只支持美国英语或拉丁字符,比如 1963 年发布的美国信息交换标准代码,或ASCII。要了解更多有关字符编码及其演变的信息,请查看 UTF-8 和 ASCII 的维基百科页面。
现在,是时候配置网络接口了。在这种情况下,我们只有一个名为enp1s0
的网络接口。配置使用 IPv4 和rhel8.example.com
:
# Network information
network --bootproto=dhcp --device=enp1s0 --ipv6=auto --activate
network --hostname=rhel8.example.com
现在,我们需要定义安装介质。在这种情况下,我们使用了一个模拟的 CDROM/DVD,使用我们下载的 ISO 镜像文件:
# Use CDROM installation media
cdrom
firstboot
选项默认启用。在本例中,由于安装不包括图形界面,它不会运行,但将被添加到kickstart
文件中。我们可以安全地删除它,如下所示:
# Run the Setup Agent on first boot
firstboot --enable
现在,让我们配置磁盘。首先,为了安全起见,我们将指示安装程序忽略除目标磁盘(在本例中为vda
)之外的所有磁盘:
ignoredisk --only-use=vda
重要提示
磁盘的名称将根据您运行的平台而变化。通常,它将是vda
、xda
或sda
。在本例中,我们展示了由安装程序 Anaconda 定义的vda
磁盘,就像我们在上一章中使用的那样。
现在,我们必须安装引导加载程序以启用系统引导。我们将在vda
上这样做,并指示它使用crashkernel
选项,该选项启用kdump
机制(在系统崩溃时转储内存):
# System bootloader configuration
bootloader --append="crashkernel=auto" --location=mbr --boot-drive=vda
现在,我们必须对磁盘进行分区。在这种情况下,这将是完全自动化的:
autopart
系统要使用的空间必须声明。我们将在此示例中清除整个磁盘:
# Partition clearing information
clearpart --none --initlabel
让我们将时区设置为欧洲马德里:
# System timezone
timezone Europe/Madrid --isUtc
现在,我们将设置 root 密码并创建一个用户(请注意,加密密码已经被删除以确保安全):
# Root password
rootpw --iscrypted $xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
user --groups=wheel --name=user --password=$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx --iscrypted --gecos="user"
提示
上一章生成的 Anaconda 文件包含加密密码哈希的示例。如果我们想要更改它,可以通过运行python -c 'import crypt,getpass;pw=getpass.getpass();print(crypt.crypt(pw) if (pw==getpass.getpass("Confirm: ")) else exit())'
命令生成新的加密密码哈希,并将其包含在此处。
现在,我们需要一个特殊的部分,可以在其中配置kdump
,以便我们可以自动保留内存:
%addon com_redhat_kdump --enable --reserve-mb='auto'
%end
我们还需要一个特殊的部分,指定将用于安装的密码策略:
%anaconda
pwpolicy root --minlen=6 --minquality=1 --notstrict --nochanges --notempty
pwpolicy user --minlen=6 --minquality=1 --notstrict --nochanges --emptyok
pwpolicy luks --minlen=6 --minquality=1 --notstrict --nochanges --notempty
%end
有了这个,我们的kickstart
文件以重新安装系统就完成了。
要使用它,我们需要将 kickstart 选项传递给安装程序。为此,我们编辑内核参数。让我们看看如何做到这一点。
我们首先按Tab,在启动时,选择安装 Red Hat Enterprise Linux 8.3。以vmlinuz开头的引导行将出现在屏幕底部:
图 2.1 - RHEL8 安装程序 - 编辑引导行
让我们删除quiet
选项,并添加一个让安装程序知道 kickstart 位置的选项:
图 2.2 - RHEL8 安装程序 - 将 kickstart 选项添加到引导行
我们添加的选项如下:
inst.ks=hd:sdc1:/anaconda-ks.cfg
我们可以看看它的三个部分:
-
hd
:kickstart 将在磁盘上,比如第二个 USB 驱动器上。 -
sdc1
:托管文件的设备。 -
/anaconda-ks.cfg
:设备中 kickstart 文件的路径。
有了这个,我们可以重现我们所做的完整安装。
提示
Red Hat Enterprise Linux 8 自定义 Anaconda指南提供了详细的选项,如果您希望创建自己的Anaconda Kickstart文件或进一步自定义此文件,可以在此处访问:access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html-single/customizing_anaconda/index
。
正如您所见,创建 kickstart 文件并自动部署 Red Hat Enterprise Linux 非常容易。
现在,让我们来看看另一种使 RHEL 8 实例可用的方法:在云中。
在云上部署 RHEL
在云上部署 Red Hat Enterprise Linux与我们之前进行的部署有一些不同。让我们看看这些区别是什么:
- 我们不会使用 ISO 镜像或 Anaconda 来执行部署,而是使用预先配置的镜像,通常由云提供商准备和提供:
- 该镜像可以稍后进行自定义和调整以满足我们的需求。
-
我们将无法在安装时选择系统的配置细节(例如选择时区),但之后可以选择。
-
将会有一个自动化机制来更改设置,例如添加用户及其凭据以访问系统或配置网络:
-
云提供商通常使用
cloud-init
来实现此目的的最常见和最知名的机制。 -
一些由云提供商提供的镜像包括
cloud-init
软件。 -
通常使用由用户在云提供商生成的 SSH 密钥通过
ssh
协议远程访问系统(请查看第八章,远程管理系统,以获取有关如何访问系统的更多详细信息)。
重要提示
在创建 RHEL 镜像方面,可以为云或虚拟化创建我们自己的镜像。为此,我们可以使用 Red Hat Enterprise Linux 镜像构建器(developers.redhat.com/blog/2019/05/08/red-hat-enterprise-linux-8-image-builder-building-custom-system-images/
)。但是,它不是 RHCSA 的一部分,因此本书不会涵盖它。相反,我们将遵循采用默认镜像并对其进行自定义的方法。
云提供商提出了一个初始的免费试用优惠,您可以免费尝试他们的服务。这是开始使用 RHEL 和云服务的好方法。
在本书中,我们将以 Google Cloud 为例,因此不会涵盖其他云。我们将提供一个简要示例,说明如何在此云环境中创建和修改 Red Hat Enterprise Linux 8 实例。为此,我们将使用Google Cloud(截至 2020 年 12 月,它提供了一个初始信用,可以持续整本书所需的时间)。
要遵循本章,您需要完成以下步骤:
-
如果您没有 Google 帐户,您将需要创建一个(如果您使用 Gmail 和/或 Android 手机,您可能已经有一个)。
-
在
accounts.google.com
登录您的 Google 帐户(或检查您是否已登录)。您将需要注册免费试用,此时您将需要提供信用卡号码。 -
转到
cloud.google.com/free
并领取您的免费信用额度。 -
转到
console.cloud.google.com
的云控制台。 -
转到项目菜单,在顶部菜单栏中显示为无组织,以显示新帐户的项目:
图 2.3 – RHEL8 在 Google Cloud 中–组织菜单访问
- 点击新项目:
图 2.4 - Google 云中的 RHEL8 - 组织菜单
- 将其命名为
RHEL8
,然后单击创建:
图 2.5 - Google 云中的 RHEL8 - 组织菜单; 创建新项目
重要提示
根据您的 Google 帐户配置方式,您可能需要在此步骤之后启用计费。
- 转到左上角菜单(也称为汉堡菜单,旁边有三条水平线),单击计算引擎,然后单击VM 实例:
图 2.6 - Google 云中的 RHEL8 - 访问 VM 实例菜单
- 一旦计算引擎准备就绪(可能需要几分钟),点击创建:
图 2.7 - Google 云中的 RHEL8 - 创建新的 VM 实例
- 我们将实例命名为
rhel8-instance
:
图 2.8 - Google 云中的 RHEL8 - 创建新的 VM 实例; 名称
- 选择最方便的区域(或保留已提供的区域):
图 2.9 - Google 云中的 RHEL8 - 创建新的 VM 实例,区域和区域
- 将机器系列和类型设置为通用|e2-medium:
图 2.10 - Google 云中的 RHEL8 - 创建新的 VM 实例,类型和大小
- 点击更改旁边的引导磁盘:
图 2.11 - Google 云中的 RHEL8 - 更改引导磁盘
- 将操作系统更改为Red Hat 企业 Linux,版本更改为Red Hat 企业 Linux 8。然后,点击选择:
图 2.12 - Google 云中的 RHEL8 - 创建新的 VM 实例,图像选择和磁盘大小
- 点击创建,等待实例创建完成:
图 2.13 - Google 云中的 RHEL8 - VM 实例列表
- 稍后,我们将学习如何通过
SSH
连接。现在,点击连接下的SSH
旁边的三角形,并选择在浏览器窗口中打开,如下所示:
图 2.14 - Google 云中的 RHEL8 - VM 实例,访问控制台
- 有了这个,您的新鲜的 RHEL8 实例将被部署,如下截图所示:
图 2.15 - Google 云中的 RHEL8 - VM 实例,控制台
在云中设置需要一些时间,配置您的帐户,并找到SSH
密钥(将在第八章,远程管理系统中显示),但一旦全部设置好,就很容易启动一个新实例。
要成为管理员,您只需要运行以下命令:
[miguel@rhel8-instance ~]$ sudo -i
[root@rhel8-instance ~]#
现在,您可以使用timedatectl
检查时间配置并更改:
[root@rhel8-instance ~]# timedatectl
Local time: Sat 2020-12-12 17:13:29 UTC
Universal time: Sat 2020-12-12 17:13:29 UTC
RTC time: Sat 2020-12-12 17:13:29
Time zone: UTC (UTC, +0000)
System clock synchronized: yes
NTP service: active
RTC in local TZ: no
[root@rhel8-instance ~]# timedatectl set-timezone Europe/Madrid
[root@rhel8-instance ~]# timedatectl
Local time: Sat 2020-12-12 18:20:32 CET
Universal time: Sat 2020-12-12 17:20:32 UTC
RTC time: Sat 2020-12-12 17:20:32
Time zone: Europe/Madrid (CET, +0100)
System clock synchronized: yes
NTP service: active
RTC in local TZ: no
您还可以使用localectl
更改语言配置:
[root@rhel8-instance ~]# localectl
System Locale: LANG=en_US.UTF-8
VC Keymap: us
X11 Layout: n/a
要更改locale
或语言支持,您需要首先安装其语言包,如下所示:
[root@rhel8-instance ~]# yum install glibc-langpack-es –y
... [output omitted] ...
[root@rhel8-instance ~]# localectl set-locale es_ES.utf8
[root@rhel8-instance ~]# localectl
System Locale: LANG=es_ES.utf8
VC Keymap: us
X11 Layout: n/a
现在,您已经配置了一台机器,可以在本书中使用。这些区域设置不需要继续,只是为了创建具有与上一章相同配置的机器。
现在我们知道如何使用 Anaconda 自动重新部署 VM,并在云中获取实例,让我们继续并查看在执行安装时需要考虑的一些最佳实践。
安装最佳实践
Red Hat Enterprise Linux 安装有许多选项可供选择,您应该根据特定的用例进行定制。然而,一些常见的建议适用。让我们看看最常见的类型。
第一种类型是蓝图:
- 标准化核心安装并为其创建一个蓝图:
- 这个蓝图应该足够小,可以作为所有其他蓝图和部署的基础。
- 在需要时为常见情况构建一组蓝图:
-
尽量使用自动化平台来构建扩展案例(即,Ansible)。
-
尽量使案例模块化(即,应用服务器;数据库蓝图可以合并成一个单一的机器)。
-
了解您必须应用于模板蓝图的要求,并适应您将使用的环境。
第二种类型是软件:
-
安装的软件越少,攻击面就越小。尽量保持服务器上所需的最小软件包集(即,尽量不要向服务器添加图形用户界面)。
-
在可能的情况下,标准化安装的工具,以便在紧急情况下能够迅速反应。
-
打包第三方应用程序,以便进行健康的生命周期管理(无论是使用 RPM 还是容器)。
-
建立一个补丁安装计划。
第三种类型是网络:
-
在虚拟机中,尽量不要过多使用网络接口。
-
在物理机器上,尽可能使用接口组合/绑定。使用 VLAN 对网络进行分段。
第四种类型是存储:
-
对于服务器,使用
/boot
或/boot/efi
)。 -
如果您认为需要缩减文件系统,请使用ext4;否则,选择默认的xfs。
-
谨慎地对磁盘进行分区:
-
保持默认的引导分区及其默认大小。如果更改它,请扩大它(在升级过程中可能需要空间)。
-
默认的交换分区是最安全的选择,除非第三方软件有特定要求。
-
对于长期存在的系统,至少要有单独的分区用于
/
(根)/var
,/usr
,/tmp
和/home
,甚至考虑为/var/log
和/opt
单独设置一个(对于临时云实例或短期存在的系统,不适用)。
第五种类型是安全:
-
不要禁用SELinux。它在最新版本中得到了很大改进,很可能不会干扰您的系统(如果需要,将其设置为宽容模式,而不是完全禁用它)。
-
不要禁用防火墙。使用服务部署自动化端口开放。
-
尽可能将日志重定向到一个中央位置。
-
标准化安全工具和配置,以检查系统完整性和审计(即AIDE,logwatch和auditd)。
-
审查软件安装(RPM)GPG密钥,以及 ISO 映像,以确保完整性。
-
尽量避免使用密码(特别是您的 root 帐户),并在需要时使用强密码。
-
使用OpenSCAP审查您的系统以检查安全性(如果需要,从安全团队的帮助下创建自己的硬件 SCAP 配置文件)。
最后,我们将看看杂项类型:
-
保持系统时间同步。
-
审查logrotate策略,以避免由于日志而导致“磁盘已满”的错误。
遵循这些最佳实践将帮助您避免问题,并使安装基础更易管理。有了这些,您就知道如何以有条理、可重复的方式在系统上部署 Red Hat Enterprise Linux,同时以快速和有弹性的方式为其他团队提供服务。
总结
在上一章中,我们提到了如何准备一台机器,可以在整本书中使用。与此相对的是使用云实例,通过这种方式,我们可以从公共云中消费虚拟机实例,这可能简化我们的消费,并为我们提供足够的免费信用来准备 RHCSA。此外,一旦自我训练过程完成,这些机器仍然可以用来提供你自己的公共服务(比如部署博客)。
在作为专业人士使用 Linux 时,理解标准化环境的需求以及这样做的影响也很重要。从一开始就采用一套良好的实践方法(自动化安装、跟踪已安装的软件、减少攻击面等)是关键。
完成了这一章,现在你可以继续阅读本书的其余部分了,因为你现在已经有了一个可用于工作和练习的红帽企业 Linux 8 实例。在下一章中,我们将回顾系统的基础知识,让自己感到舒适,并增强使用系统的信心。
第三章:基本命令和简单的 shell 脚本
一旦您的第一个Red Hat Enterprise Linux (RHEL)系统运行起来,您就想开始使用它,练习并熟悉它。在本章中,我们将回顾登录系统、浏览系统和了解其管理基础知识的基础知识。
本章描述的一套命令和实践将在管理系统时经常使用,因此重要的是要仔细学习它们。
本章将涵盖以下主题:
-
以用户身份登录和管理多用户环境
-
使用 su 命令切换用户
-
使用命令行、环境变量和浏览文件系统
-
理解命令行中的 I/O 重定向
-
使用 grep 和 sed 过滤输出
-
清单、创建、复制和移动文件和目录、链接和硬链接
-
使用 tar 和 gzip
-
创建基本的 shell 脚本
-
使用系统文档资源
以用户身份登录和管理多用户环境
登录是用户在系统中识别自己的过程,通常是通过提供用户名和密码来完成的,这两个信息通常被称为凭据。
系统可以以多种方式访问。我们在这里讨论的初始情况是,当用户安装物理机器(如笔记本电脑)或通过虚拟化软件界面访问时,用户如何访问系统。在这种情况下,我们通过控制台访问系统。
在安装过程中,用户被创建并分配了密码,并且没有安装图形界面。在这种情况下,我们将通过其文本控制台访问系统。我们要做的第一件事是使用它登录系统。一旦启动机器并完成引导过程,我们将默认进入多用户文本模式环境,其中我们被要求提供我们的登录:
图 3.1 - 登录过程,用户名请求
闪烁的光标将告诉我们,我们已经准备好输入我们的用户名,这里是user
,然后按Enter。会出现一个要求输入密码的行:
图 3.2 - 登录过程,密码请求
现在我们可以输入用户的密码来完成登录,并通过键盘上的Enter键开始一个会话。请注意,在输入密码时屏幕上不会显示任何字符,以避免窃听。这将是正在运行的会话:
图 3.3 - 登录过程,登录完成,会话运行
现在我们已经完全以名为user
的用户的凭据完全登录到系统。这将决定我们在系统中可以做什么,我们可以访问哪些文件,甚至我们分配了多少磁盘空间。
控制台可以有多个会话。为了实现这一点,我们有不同的终端可以登录。默认终端可以通过同时按下Ctrl + Alt + F1键来到达。在我们的情况下,什么也不会发生,因为我们已经在那个终端上了。我们可以通过按Ctrl + Alt + F2来到第二个终端,按Ctrl + Alt + F3来到第三个终端,以此类推,直到剩下的终端(默认情况下分配了六个)。这样,我们可以在不同的终端中运行不同的命令。
使用 root 账户
普通用户无法对系统进行更改,比如创建新用户或向整个系统添加新软件。为此,我们需要一个具有管理权限的用户,而默认用户就是root
。这个用户始终存在于系统中,其标识符为0
。
在之前的安装中,我们已经配置了 root 密码,使得可以通过控制台访问该账户。要在系统中使用它,我们只需要在显示的终端之一中输入root
,然后按下Enter,然后提供其root
:
图 3.4 - 登录过程,以 root 用户完成登录
使用和理解命令提示符
一旦我们登录并等待输入和运行命令的命令行出现,就称为命令提示符。
在其默认配置中,它将在括号之间显示用户名和主机名,以便让我们知道我们正在使用哪个用户。接下来,我们看到路径,这里是~
,它是/home/user
的快捷方式,对于user
用户,以及/root
对于root
用户)
最后一个部分,也可能是最重要的部分,是提示符前面的符号:
-
$
符号用于没有管理权限的常规用户。 -
#
符号用于 root 或一旦用户获得管理权限。
重要提示
当使用带有#
符号的提示符时要小心,因为您将以管理员身份运行,系统很可能不会阻止您损坏它。
一旦我们在系统中标识了自己,我们就已经登录并有了一个运行的会话。现在是时候学习如何在下一节中从一个用户切换到另一个用户了。
使用 su 命令切换用户
由于我们已经进入了一个多用户系统,因此可以合理地认为我们将能够在用户之间切换。即使可以通过为每个用户打开会话来轻松完成此操作,但有时我们希望在同一个会话中以其他用户的身份行事。
为此,我们可以使用su
工具。该工具的名称通常被称为替代用户。
让我们利用上次以root
登录的会话,并将自己转换为user
用户。
在这之前,我们可以通过运行whoami
命令来询问我当前登录的用户是谁:
[root@rhel8 ~]# whoami
root
现在我们可以从root
切换到user
:
[root@rhel8 ~]# su user
[user@rhel8 root]$ whoami
user
现在我们有了一个user
用户的会话。我们可以使用exit
命令结束此会话:
[user@rhel8 root]$ exit
exit
[root@rhel8 ~]# whoami
root
正如您可能已经看到的,当我们以root
登录时,我们可以像任何用户一样行事,而无需知道其密码。但是我们如何冒充root
呢?我们可以通过运行su
命令并指定root
用户来做到这一点。在这种情况下,将要求输入 root 用户的密码:
[user@rhel8 ~]$ su root
Password:
[root@rhel8 user]# whoami
root
由于root
是 ID 为0
且最重要的用户,因此在运行su
而不指定要转换的用户时,它将默认转换为root
:
[user@rhel8 ~]$ su
Password:
[root@rhel8 user]# whoami
root
每个用户都可以在自己的环境中定义多个选项,例如他们喜欢的编辑器。如果我们想完全冒充其他用户并采用他们的偏好(或在su
命令后加上-
:
[user@rhel8 ~]$ su -
Password:
Last login: mar dic 22 04:57:29 CET 2020 on pts/0
[root@rhel8 ~]#
此外,我们可以从root
切换到user
:
[root@rhel8 ~]# su - user
Last login: Tue Dec 22 04:53:02 CET 2020 from 192.168.122.1 on pts/0
[user@rhel8 ~]$
正如您所观察到的,它的行为就像进行了新的登录,但在同一个会话中。现在,让我们继续管理系统中不同用户的权限,如下一节所述。
理解用户、组和基本权限
多用户环境的定义在于能够同时处理多个用户。但是为了能够管理系统资源,有两种能力可以帮助完成任务:
- 组:可以聚合用户并以块为它们提供权限。
每个用户都有一个主要组。
默认情况下,为每个用户创建一个组,并将其分配为与用户名相同的主要组。
ugo
)。
整个系统都有一组默认分配给每个文件和目录的权限。在更改它们时要小心。
UNIX 中有一个原则,Linux 继承了它,那就是:一切皆为文件。即使可能有一些特例,这个原则在几乎任何情况下都是正确的。这意味着磁盘在系统中表示为文件(换句话说,就像安装中提到的/dev/sdb
),进程可以表示为文件(在/proc
下),系统中的许多其他组件都表示为文件。
这意味着,在分配文件权限时,我们也可以分配给许多其他组件和功能的权限,因为在 Linux 中,一切都表示为文件。
提示
POSIX代表可移植操作系统接口,是由 IEEE 计算机学会指定的一系列标准:en.wikipedia.org/wiki/POSIX
。
用户
用户是为人们以及在系统中运行的程序提供安全限制的一种方式。有三种类型的用户:
-
普通用户:分配给个人执行其工作的用户。他们受到了限制。
-
超级用户:也称为''root''。这是系统中的主管理帐户,对其拥有完全访问权限。
-
系统用户:这些是通常分配给运行进程或''守护进程''的用户帐户,以限制它们在系统中的范围。系统用户不打算登录到系统。
用户有一个称为UID(用户 ID)的数字,系统用它来内部识别每个用户。
我们之前使用whoami
命令来显示我们正在使用的用户,但是为了获取更多信息,我们将使用id
命令:
[user@rhel8 ~]$ id
uid=1000(user) gid=1000(user) groups=1000(user),10(wheel) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
我们还可以查看系统中其他用户帐户的相关信息,甚至获取root
的信息:
[user@rhel8 ~]$ id root
uid=0(root) gid=0(root) groups=0(root)
现在,让我们通过运行id
来查看我们收到的有关user
的信息:
-
uid=1000(user)
:用户 ID 是系统中用户的数字标识符。在这种情况下,它是1000
。在 RHEL 中,1000 及以上的标识符用于普通用户,而 999 及以下的标识符保留给系统用户。 -
gid=1000(user)
:组 ID 是分配给用户的主要组的数字标识符。 -
groups=1000(user),10(wheel)
:这些是用户所属的组,在这种情况下,''user''使用sudo
工具(稍后将解释)。 -
context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
:这是用户的 SELinux 上下文。它将使用SELinux在系统中定义多个限制(在第十章中将深入解释,使用 SELinux 保护系统)。
与 ID 相关的数据存储在系统中的/etc/passwd
文件中。请注意,该文件非常敏感,最好使用与之相关的工具进行管理。如果我们想要编辑它,我们将使用vipw
,这是一个工具,将确保(除其他事项外)只有一个管理员在任何时候编辑文件。/etc/passwd
文件包含每个用户的信息。这是user
的行:
user:x:1000:1000:user:/home/user:/bin/bash
每个字段在每行中由冒号:
分隔。让我们来看看它们的含义:
-
user
:分配给用户的用户名。 -
x
:加密密码的字段。在这种情况下,它显示为x
,因为它已经移动到/etc/shadow
,普通用户无法直接访问,以使系统更安全。 -
1000
(第一个):UID值。 -
1000
(第二个):GID值。 -
user
:帐户的描述。 -
/home/user
:分配给用户的主目录。这将是用户将要工作的默认目录(或者如果你愿意的话,文件夹),以及他们的偏好设置将被存储的地方。 -
/bin/bash
:用户的命令解释器。Bash 是 RHEL 中的默认解释器。其他替代品,如tcsh
,zsh
或fish
可在 RHEL 中安装。
组
/srv/finance
目录。当财务团队有新员工时,为了让他们能够访问该文件夹,我们只需要将分配给这个人的用户添加到finance
组中(如果有人离开团队,我们只需要从finance
组中删除他们的帐户)。
组有一个称为GID的数字,系统用它来在内部识别它们。
组的数据存储在系统中的/etc/group
文件中。为了以确保一致性并避免损坏的方式编辑此文件,我们必须使用vigr
工具。文件中每行包含一个组,不同字段用冒号:
分隔。让我们看一下wheel
组的行:
wheel:x:10:user
让我们回顾一下每个字段的含义:
-
wheel
:这是组的名称。在这种情况下,这个组是特殊的,因为它被配置为默认情况下用作为普通用户提供管理员特权的组。 -
x
:这是组密码字段。它目前已经过时,应始终包含x
。它保留用于兼容性目的。 -
10
:这是组本身的 GID 值。 -
user
:这是属于该组的用户列表(用逗号分隔,如user1
,user2
和user3
)。
组的类型如下:
-
主要组:这是用户新创建的文件分配的组。
-
私有组:这是一个特定的组,与用户同名,为每个用户创建。添加新用户帐户时,将自动为其创建一个私有组。很常见的是''主要组''和''私有组''是一样的。
-
wheel
组用于为用户启用管理员特权,或者cdrom
组用于在系统中提供对 CD 和 DVD 设备的访问。
文件权限
要查看root
。我们将使用ls
命令列出文件,并查看与它们关联的权限。我们将在第五章中学习如何更改权限,使用用户、组和权限保护系统。
一旦以root
身份登录系统,我们可以运行ls
命令:
[root@rhel8 ~]# ls
anaconda-ks.cfg
这显示了root 用户主目录中存在的文件,用~
表示。在这种情况下,它显示了在上一章中我们审查过的Anaconda创建的kickstart文件。
我们可以通过在ls
后附加-l
选项来获取列表的长版本:
[root@rhel8 ~]# ls -l
total 4
-rw-------. 1 root root 1393 Dec 7 16:45 anaconda-ks.cfg
我们在输出中看到以下内容:
-
total 4
:这是文件在磁盘上占用的总空间,以千字节为单位(请注意,我们使用的是 4K 块,因此每个小于该大小的文件将占用至少 4K)。 -
-rw-------.
:这些是分配给文件的权限。
权限的结构可以在以下图表中看到:
图 3.5 - Linux 权限结构
第一个字符是文件可能具有的特殊权限。如果它是一个常规文件,并且没有特殊权限(就像在这种情况下),它将显示为-
:
-
目录将显示为
d
。请考虑在 Linux 中,一切都是文件,目录是具有特殊权限的文件。 -
链接,通常是符号链接,将显示为
l
。这些行为类似于从不同目录的文件的快捷方式。 -
特殊权限以不同的用户或组身份运行文件,称为
s
。 -
一个特殊权限,使所有者只能删除或重命名文件,称为
t
。
接下来的三个字符rw-
是所有者的权限:
-
第一个字符
r
是分配的读权限。 -
第二个字符
w
是分配的写权限。 -
第三个字符
x
,不存在并显示为-
,是可执行权限。请注意,对于目录的可执行权限意味着能够进入它们。
接下来的三个字符---
是组权限,与所有者权限的工作方式相同。在这种情况下,没有授予组访问权限。
最后三个字符---
是其他人的权限,这意味着用户和/或组不会显示为分配给文件的权限:
-
1
: 这表示对该文件的链接(硬链接)的数量。这是为了防止我们删除另一个文件夹中使用的文件等目的。 -
root
: 这表示文件的(第一次)所有者。 -
root
: 这表示文件分配给的(第二次)组。 -
1393
: 这表示以字节为单位的大小。 -
Dec 7 16:45
: 这表示文件上次修改的日期和时间。 -
anaconda-ks.cfg
: 这表示文件名。
当我们列出一个目录(在其他系统中称为文件夹)时,输出将显示目录本身的内容。我们可以使用-d
option
列出目录本身的信息。现在让我们来看看/etc
,这个存储系统范围配置的目录:
[root@rhel8 ~]# ls -l -d /etc
drwxr-xr-x. 81 root root 8192 Dec 23 17:03 /etc
正如你所看到的,很容易获取有关系统中文件和目录的信息。现在让我们在下一节中学习更多关于命令行以及如何在文件系统中导航,以便轻松地在系统中移动。
使用命令行、环境变量和浏览文件系统
正如我们之前所看到的,一旦我们登录系统,我们就可以访问命令行。熟练地浏览命令行和文件系统对于在环境中感到舒适并充分利用它至关重要。
命令行和环境变量
命令行由一个程序提供,也称为解释器或shell。它的行为取决于我们使用的 shell,但在本节中,我们将介绍 Linux 中最常用的 shell,也是 RHEL 默认提供的 shell:bash。
知道你正在使用哪个 shell 的一个简单技巧是运行以下命令:
[root@rhel8 ~]# echo $SHELL
/bin/bash
echo
命令将在屏幕上显示我们给它的内容。有些内容需要替换或解释,比如环境变量。需要替换的内容以$
符号开头。在这种情况下,我们告诉系统echo
变量SHELL
的内容。让我们用它来处理其他变量:
[root@rhel8 ~]# echo $USER
root
[root@rhel8 ~]# echo $HOME
/root
这些是可以为每个用户自定义的环境变量。现在让我们为另一个用户检查这些:
[root@rhel8 ~]# su - user
Last login: Wed Dec 23 17:03:32 CET 2020 from 192.168.122.1 on pts/0
[user@rhel8 ~]$ echo $USER
user
[user@rhel8 ~]$ echo $HOME
/home/user
正如你所看到的,你可以随时引用$USER
,它将被当前用户替换,或者引用$HOME
,它将被替换为用户专用的目录,也称为主目录。
这些是一些最常见和重要的环境变量:
~/.bashrc
文件应该被编辑以更改当前用户的这些值。
浏览文件系统
现在是时候将我们自己移动到/
了。系统的其余内容将悬挂在那个文件夹下,任何其他磁盘或设备都将被分配一个目录以供访问。
重要说明
根目录和 root 用户的主目录是两回事。root 用户默认分配了主目录/root
,而根目录是系统中所有目录的母目录,用/
表示。
我们可以通过运行pwd
命令来查看我们所在的目录:
[user@rhel8 ~]$ pwd
/home/user
我们可以使用cd
命令来更改目录:
[user@rhel8 ~]$ cd /var/tmp
[user@rhel8 tmp]$ pwd
/var/tmp
正如你已经知道的,有一个~
。我们可以使用这个快捷方式去到它:
[user@rhel8 tmp]$ cd ~
[user@rhel8 ~]$ pwd
/home/user
一些目录的快捷方式包括以下内容:
-
"~": 这是当前用户的主目录。
-
".": 这是当前目录。
-
"..": 这是父目录。
-
"-": 这是先前使用的目录。
有关在 Linux 和 RHEL 中管理文件和目录的更多详细信息,请参阅列出、创建、复制和移动文件和目录、链接和硬链接部分。
Bash 自动补全
快捷方式是到达常用目录或当前工作目录的相对引用的更快方式。但是,bash 包括一些快速到达其他目录的功能,这称为自动补全。它依赖于Tab键(键盘最左边具有两个相对箭头的键,在Caps Lock上方)。
当到达一个文件夹或文件时,我们可以按Tab键来完成它的名称。例如,如果我们想进入/boot/grub2
文件夹,我们输入以下内容:
[user@rhel8 ~]$ cd /bo
然后,当我们按下Tab键时,它会自动补全为/boot/
,甚至添加最终的/
,因为它是一个目录:
[user@rhel8 ~]$ cd /boot/
现在我们输入我们想要进入的目录grub2
的第一个字母,即g
:
[user@rhel8 ~]$ cd /boot/g
然后,当我们按下Tab键时,它会自动补全为/boot/grub2/
:
[root@rhel8 ~]# cd /boot/grub2/
现在我们可以按Enter键并进入那里。
如果我们按下Tab + Tab(在完成期间按两次Tab),这将显示可用目标的列表,例如:
[root@rhel8 ~]# cd /r
root/ run/
它也可以用于完成命令。我们可以输入一个字母,例如h
,按下Tab + Tab,这将显示所有以h
开头的命令:
[root@rhel8 ~]# h
halt hardlink hash h dparm head help hexdump history hostid hostname hostnamectl hwclock
这种能力可以通过安装bash-completion
软件包来扩展,以帮助完成我们命令的其他部分:
[root@rhel8 ~]# yum install bash-completion –y
以前的命令
有一种方法可以恢复最后运行的命令,这被称为历史记录,以防您想要再次运行它们。只需按下向上箭头键(带有向上箭头的键)即可,以及以前的命令将出现在屏幕上。
如果您的历史记录中有太多命令,您可以通过运行history
命令快速搜索它们:
[user@rhel8 ~]$ history
1 su root
2 su
3 su -
4 id
5 id root
6 grep user /etc/passwd
7 echo $USER
8 echo $HOME
9 declare
10 echo $SHELL
11 echo EDITOR
12 echo $EDITOR
13 grep wheel /etc/gro
14 grep wheel /etc/group
15 cat /etc/group
16 grep nobody /etc/group /etc/passwd
您可以使用!
命令再次运行任何这些命令。只需使用命令的编号运行!
,它将再次运行:
[user@rhel8 ~]$ !5
id root
uid=0(root) gid=0(root) groups=0(root)
提示
命令!!
将再次运行最后一个命令,无论编号如何。
现在是时候享受您的超快命令行了。让我们在下一节中更多地了解 Linux 中目录的结构,以便知道去哪里查找东西。
文件系统层次结构
Linux 有一个由Linux 基金会维护的标准,定义了文件系统层次结构,几乎在每个 Linux 发行版中都使用,包括RHEL。这个标准被称为FHS,或文件系统层次结构标准。让我们在这里回顾一下标准中最重要的文件夹和系统本身:
提示
RHEL 的早期版本用于将/bin
用于基本二进制文件和/usr/bin
用于非基本二进制文件。现在,两者的内容都驻留在/usr/bin
中。他们还使用/var/lock
和/var/run
来运行/run
中的内容。此外,他们过去用于将/lib
用于基本库和/usr/lib
用于非基本库,这些都合并到一个目录/usr/lib
中。最后但并非最不重要的是,/sbin
是基本超级用户二进制文件的目录,/usr/sbin
是合并到/usr/sbin
下的非基本二进制文件的目录。
在分区时,我们可能会问自己,磁盘空间去哪了?
这些是 RHEL 8''最小''安装的分配值和建议:
熟悉系统中的主要目录是很重要的,以便充分利用它们。建议浏览不同的系统目录,并查看其中的内容,以便熟悉结构。在下一节中,我们将学习如何在命令行上执行重定向,以了解更多关于命令和文件交互的内容。
了解命令行中的 I/O 重定向
我们已经运行了几个命令来确定系统的信息,例如使用ls
列出文件,并且我们从运行的命令中得到了一些信息,输出,包括文件名和文件大小。该信息或输出可能很有用,我们希望能够正确地处理、存储和管理它。
在谈论命令输出和输入时,有三个需要理解的来源或目标:
-
STDOUT:也称为标准输出,这是命令将其常规消息放置以提供有关其正在执行的操作的信息的地方。在终端上,在交互式 shell(就像我们迄今为止使用的那样),此输出将显示在屏幕上。这将是我们管理的主要输出。
-
STDERR:也称为标准错误,这是命令将其错误消息放置在其中以进行处理的地方。在我们的交互式 shell 中,除非我们明确重定向它,否则此输出也将显示在屏幕上,同时显示标准输出。
-
STDIN:也称为标准输入,这是命令获取要处理的数据的地方。
我们将在下一段中提到这些,以更好地理解它们。
命令输入和输出的使用方式需要以下运算符:
-
|
:管道运算符用于获取一个命令的输出并将其作为下一个命令的输入。它将数据从一个命令传输到另一个命令。 -
>
:重定向运算符用于将命令的输出放入文件中。如果文件存在,它将被覆盖。 -
<
:反向重定向可以应用于使用文件作为命令的输入。使用它不会删除用作输入的文件。 -
>>
:重定向并添加运算符用于将命令的输出附加到文件中。如果文件不存在,它将使用提供给它的输出创建文件。 -
2>
:重定向 STDERR运算符将仅重定向发送到错误消息处理程序的输出。(注意,为了使其工作,''2''和''>''之间不应包含空格!) -
1>
:重定向 STDOUT运算符将仅重定向发送到标准输出而不是错误消息处理程序的输出。 -
>&2
:重定向到 STDERR运算符将输出重定向到标准错误处理程序。 -
>&1
:重定向到 STDOUT运算符将输出重定向到标准输出处理程序。
为了更好地理解这些,我们将在本节和下一节中进行一些示例。
让我们列出文件并将其放入文件中。首先,我们使用-m
选项列出/var
中的文件,用逗号分隔条目:
[root@rhel8 ~]# ls -m /var/
adm, cache, crash, db, empty, ftp, games, gopher, kerberos, lib, local, lock, log, mail, nis, opt, preserve, run, spool, tmp, yp
现在,我们再次运行命令,将输出重定向到/root/var-files.txt
文件中:
[root@rhel8 ~]# ls –m /var/ > /root/var-files.txt
[root@rhel8 ~]#
正如我们所看到的,屏幕上没有显示任何输出,但是我们将能够在当前工作目录中找到新文件,即/root
中的新创建的文件:
[root@rhel8 ~]# ls /root
anaconda-ks.cfg var-files.txt
要在屏幕上查看文件的内容,我们使用cat
命令,用于连接几个文件的输出,但通常用于此目的:
[root@rhel8 ~]# ls –m /var/ > /root/var-files.txt
[root@rhel8 ~]#
[root@rhel8 ~]# cat var-files.txt
adm, cache, crash, db, empty, ftp, games, gopher, kerberos, lib, local, lock,
log, mail, nis, opt, preserve, run, spool, tmp, yp
我们还可以将/var/lib
的内容添加到此文件中。首先,我们可以列出它:
[root@rhel8 ~]# ls -m /var/lib/
alternatives, authselect, chrony, dbus, dhclient, dnf, games, initramfs, logrotate, misc, NetworkManager, os-prober, plymouth, polkit-1, portables, private, rhsm, rpm, rpm-state, rsyslog, selinux, sss, systemd, tpm, tuned, unbound
现在,要将这些内容附加到/root/var-files.txt
文件中,我们使用>>
运算符:
[root@rhel8 ~]# ls -m /var/lib/ >> var-files.txt
[root@rhel8 ~]# cat var-files.txt
adm, cache, crash, db, empty, ftp, games, gopher, kerberos, lib, local, lock, log, mail, nis, opt, preserve, run, spool, tmp, yp
alternatives, authselect, chrony, dbus, dhclient, dnf, games, initramfs, logrotate, misc, NetworkManager, os-prober, plymouth, polkit-1, portables, private, rhsm, rpm, rpm-state, rsyslog, selinux, sss, systemd, tpm, tuned, unbound
/root/var-files.txt
文件现在包含了/var
和/var/lib
的逗号分隔列表。
现在我们可以尝试列出一个不存在的目录以查看错误消息的打印:
[root@rhel8 ~]# ls -m /non
ls: cannot access '/non': No such file or directory
我们看到的输出是一个错误,并且系统对其进行了不同的处理,而不是常规消息。我们可以尝试将输出重定向到文件:
[root@rhel8 ~]# ls -m /non > non-listing.txt
ls: cannot access '/non': No such file or directory
[root@rhel8 ~]# cat non-listing.txt
[root@rhel8 ~]#
我们看到,使用标准重定向,使用命令提供错误消息,将在屏幕上显示错误消息,并创建一个空文件。这是因为文件包含了通过STDOUT
显示的常规信息消息的输出。我们仍然可以通过使用2>
捕获错误的输出,重定向STDERR
:
[root@rhel8 ~]# ls /non 2> /root/error.txt
[root@rhel8 ~]# cat /root/error.txt
ls: cannot access '/non': No such file or directory
现在我们可以独立重定向标准输出和错误输出。
现在我们想要计算/var
中文件和目录的数量。为此,我们将使用wc
命令,该命令代表单词计数,并使用-w
选项仅计算单词数。为此,我们将使用|
表示的管道将ls
的输出重定向到它:
[root@rhel8 ~]# ls -m /var/ | wc -w
21
我们还可以使用它来计算/etc
中的条目:
[root@rhel8 ~]# ls -m /etc/ | wc -w
174
管道|
非常适合重用一个命令的输出,并将其发送到另一个命令以处理该输出。现在我们更了解如何使用更常见的运算符来重定向输入和输出。有几种处理输出的方法,我们将在下一节中看到更多示例。
使用 grep 和 sed 过滤输出
grep
命令在系统管理中被广泛使用(并且常常被输入错误)。它有助于在一行中找到模式,无论是在文件中还是通过标准输入(STDIN)。
让我们对/usr
中的文件进行递归搜索,并将其放在/root/usr-files.txt
中:
[root@rhel8 ~]# find /usr/ > /root/usr-files.txt
[root@rhel8 ~]# ls -lh usr-files.txt
-rw-r--r--. 1 root root 1,9M dic 26 12:38 usr-files.txt
如您所见,这是一个大小为 1.9 MB 的文件,很难浏览。系统中有一个名为gzip
的实用程序,我们想知道/usr
中的哪些文件包含gzip
模式。为此,我们运行以下命令:
[root@rhel8 ~]# grep gzip usr-files.txt
/usr/bin/gzip
/usr/lib64/python3.6/__pycache__/gzip.cpython-36.opt-2.pyc
/usr/lib64/python3.6/__pycache__/gzip.cpython-36.opt-1.pyc
/usr/lib64/python3.6/__pycache__/gzip.cpython-36.pyc
/usr/lib64/python3.6/gzip.py
/usr/share/licenses/gzip
/usr/share/licenses/gzip/COPYING
/usr/share/licenses/gzip/fdl-1.3.txt
/usr/share/doc/gzip
/usr/share/doc/gzip/AUTHORS
/usr/share/doc/gzip/ChangeLog
/usr/share/doc/gzip/NEWS
/usr/share/doc/gzip/README
/usr/share/doc/gzip/THANKS
/usr/share/doc/gzip/TODO
/usr/share/man/man1/gzip.1.gz
/usr/share/info/gzip.info.gz
/usr/share/mime/application/gzip.xml
如您所见,我们已经通过创建一个包含所有内容的文件并使用grep
搜索到了/usr
目录下的所有包含gzip
的文件。我们可以在不创建文件的情况下做同样的事情吗?当然可以,通过使用管道。我们可以将find
的输出重定向到grep
并获得相同的输出:
[root@rhel8 ~]# find /usr/ | grep gzip
/usr/bin/gzip
/usr/lib64/python3.6/__pycache__/gzip.cpython-36.opt-2.pyc
/usr/lib64/python3.6/__pycache__/gzip.cpython-36.opt-1.pyc
/usr/lib64/python3.6/__pycache__/gzip.cpython-36.pyc
/usr/lib64/python3.6/gzip.py
/usr/share/licenses/gzip
/usr/share/licenses/gzip/COPYING
/usr/share/licenses/gzip/fdl-1.3.txt
/usr/share/doc/gzip
/usr/share/doc/gzip/AUTHORS
/usr/share/doc/gzip/ChangeLog
/usr/share/doc/gzip/NEWS
/usr/share/doc/gzip/README
/usr/share/doc/gzip/THANKS
/usr/share/doc/gzip/TODO
/usr/share/man/man1/gzip.1.gz
/usr/share/info/gzip.info.gz
/usr/share/mime/application/gzip.xml
在这个命令中,find
的标准输出被发送到grep
进行处理。我们甚至可以使用-l
选项计算文件的实例数,但这次使用wc
来计算行数:
[root@rhel8 ~]# find /usr/ | grep gzip | wc -l
18
我们现在已经连接了两个管道,一个用于过滤输出,另一个用于计数。当在系统中搜索和查找信息时,我们经常会发现自己这样做。
grep
的一些非常常见的选项如下:
-
-i
:用于忽略大小写。这将匹配无论是大写还是小写或二者的组合的模式。 -
-v
:用于反转匹配。这将显示所有不匹配搜索模式的条目。 -
-r:用于递归。我们可以告诉 grep 在目录中的所有文件中搜索模式,同时浏览所有文件(如果我们有权限)。
还有一种方法可以过滤输出中的列。假设我们有一个文件列表在我们的主目录中,并且我们想看到它的大小。我们运行以下命令:
[root@rhel8 ~]# ls -l
total 1888
-rw-------. 1 root root 1393 dic 7 16:45 anaconda-ks.cfg
-rw-r--r--. 1 root root 52 dic 26 12:17 error.txt
-rw-r--r--. 1 root root 0 dic 26 12:08 non-listing.txt
-rw-r--r--. 1 root root 1917837 dic 26 12:40 usr-files.txt
-rw-r--r--. 1 root root 360 dic 26 12:12 var-files.txt
假设我们只想要包含其名称中有files
的内容的大小,即第五列。我们可以使用awk
来实现:
[root@rhel8 ~]# ls -l | grep files | awk '{ print $5}'
1917837
360
awk
工具将帮助我们根据正确的列进行过滤。它非常有用,可以在长输出中找到进程中的标识符或获取特定的数据列表。
提示
请考虑awk
在处理输出方面非常强大,我们将使用其最小功能。
我们可以用-F
替换分隔符,并获取系统中可用用户的列表:
[root@rhel8 ~]# awk -F: '{ print $1}' /etc/passwd
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
operator
games
ftp
nobody
dbus
systemd-coredump
systemd-resolve
tss
polkitd
unbound
sssd
chrony
sshd
rngd
user
awk
和grep
工具是 Linux 系统管理员生活中非常常见的处理工具,重要的是要充分理解它们,以便管理系统提供的输出。我们已经应用了基本知识来过滤按行和列接收的输出。现在让我们继续学习如何管理系统中的文件,以便更好地处理我们刚刚生成的存储输出。
列出、创建、复制和移动文件和目录、链接和硬链接
重要的是要知道如何从命令行管理文件和目录(也称为文件夹)。这将作为管理和复制重要数据(如配置文件或数据文件)的基础。
目录
让我们首先创建一个目录来保存一些工作文件。我们可以通过运行mkdir
来实现,缩写为make directory:
[user@rhel8 ~]$ mkdir mydir
[user@rhel8 ~]$ ls -l
total 0
drwxrwxr-x. 2 user user 6 Dec 23 19:53 mydir
可以使用rmdir
命令删除文件夹,缩写为remove directory:
[user@rhel8 ~]$ ls -l
total 0
drwxrwxr-x. 2 user user 6 Dec 23 19:53 mydir
[user@rhel8 ~]$ mkdir deleteme
[user@rhel8 ~]$ ls -l
total 0
drwxrwxr-x. 2 user user 6 Dec 23 20:15 deleteme
drwxrwxr-x. 2 user user 6 Dec 23 19:53 mydir
[user@rhel8 ~]$ rmdir deleteme
[user@rhel8 ~]$ ls -l
total 0
drwxrwxr-x. 2 user user 6 Dec 23 19:53 mydir
但是,rmdir
只会删除空目录:
[user@rhel8 ~]$ ls /etc/ > ~/mydir/etc-files.txt
[user@rhel8 ~]$ rmdir mydir
rmdir: failed to remove 'mydir': Directory not empty
我们如何使用删除(rm
)命令删除目录及其包含的所有其他文件和目录?首先,让我们创建并删除一个单个文件var-files.txt
:
[user@rhel8 ~]$ ls /var/ > ~/var-files.txt
[user@rhel8 ~]$ ls -l var-files.txt
-rw-rw-r--. 1 user user 109 Dec 26 15:31 var-files.txt
[user@rhel8 ~]$ rm var-files.txt
[user@rhel8 ~]$ ls -l var-files.txt
ls: cannot access 'var-files.txt': No such file or directory
删除完整的目录分支,包括其中的内容,我们可以使用-r
选项,简称递归:
[user@rhel8 ~]$ rm -r mydir/
[user@rhel8 ~]$ ls -l
total 0
重要提示
在删除时使用递归模式时要非常小心,因为它既没有恢复命令,也没有垃圾箱来保存在命令行中已删除的文件。
让我们来看看复习表:
现在我们知道如何在 Linux 系统中创建和删除目录,让我们开始复制和移动内容。
复制和移动
现在,让我们复制一些文件来玩,使用cp
(例如将awk
示例复制到我们的主目录中:
[user@rhel8 ~]$ mkdir myawk
[user@rhel8 ~]$ cp /usr/share/awk/* myawk/
[user@rhel8 ~]$ ls myawk/ | wc -l
26
要同时复制多个文件,我们使用了*
符号。这样可以通过逐个指定文件的方式,只需输入*
即可。我们还可以输入初始字符,然后加上*
,所以让我们尝试使用通配符复制一些更多的文件,首先:
[user@rhel8 ~]$ mkdir mysystemd
[user@rhel8 ~]$ cp /usr/share/doc/systemd/* mysystemd/
[user@rhel8 ~]$ cd mysystemd/
[user@rhel8 mysystemd]$ ls
20-yama-ptrace.conf CODING_STYLE DISTRO_PORTING ENVIRONMENT.md GVARIANT-SERIALIZATION HACKING NEWS README TRANSIENT-SETTINGS.md TRANSLATORS UIDS-GIDS.md
您会看到运行ls TR*
只显示以TR
开头的文件:
[user@rhel8 mysystemd]$ ls TR*
TRANSIENT-SETTINGS.md TRANSLATORS
它将以相同的方式处理文件结尾:
[user@rhel8 mysystemd]$ ls *.md
ENVIRONMENT.md TRANSIENT-SETTINGS.md UIDS-GIDS.md
如您所见,它只显示以.md
结尾的文件。
我们可以使用-r
选项复制完整的文件和目录分支,用于cp
:
[user@rhel8 mysystemd]$ cd ~
[user@rhel8 ~]$ mkdir myauthselect
[user@rhel8 ~]$ cp -r /usr/share/authselect/* myauthselect
[user@rhel8 ~]$ ls myauthselect/
default vendor
递归选项对于复制完整分支非常有用。我们也可以使用mv
命令轻松移动目录或文件。让我们将所有新目录放在一个新创建的名为docs
的目录中:
[user@rhel8 ~]$ mv my* docs/
[user@rhel8 ~]$ ls docs/
myauthselect myawk mysystemd
您可以看到,使用mv
时,您无需使用递归选项来管理文件和目录的完整分支。它也可以用于重命名文件和/或目录:
[user@rhel8 ~]$ cd docs/mysystemd/
[user@rhel8 mysystemd]$ ls
20-yama-ptrace.conf CODING_STYLE DISTRO_PORTING ENVIRONMENT.md GVARIANT-SERIALIZATION HACKING NEWS README TRANSIENT-SETTINGS.md TRANSLATORS UIDS-GIDS.md
[user@rhel8 mysystemd]$ ls -l NEWS
-rw-r--r--. 1 user user 451192 Dec 26 15:59 NEWS
[user@rhel8 mysystemd]$ mv NEWS mynews
[user@rhel8 mysystemd]$ ls -l NEWS
ls: cannot access 'NEWS': No such file or directory
[user@rhel8 mysystemd]$ ls -l mynews
-rw-r--r--. 1 user user 451192 Dec 26 15:59 mynews
有一个专门用于创建空文件的命令,即touch
:
[user@rhel8 ~]$ ls -l docs/
total 4
drwxrwxr-x. 4 user user 35 Dec 26 16:08 myauthselect
drwxrwxr-x. 2 user user 4096 Dec 26 15:51 myawk
drwxrwxr-x. 2 user user 238 Dec 26 16:21 mysystemd
[user@rhel8 ~]$ touch docs/mytouch
[user@rhel8 ~]$ ls -l docs/
total 4
drwxrwxr-x. 4 user user 35 Dec 26 16:08 myauthselect
drwxrwxr-x. 2 user user 4096 Dec 26 15:51 myawk
drwxrwxr-x. 2 user user 238 Dec 26 16:21 mysystemd
-rw-rw-r--. 1 user user 0 Dec 26 16:27 mytouch
当应用于现有文件或文件夹时,它将更新其访问时间为当前时间:
[user@rhel8 ~]$ touch docs/mysystemd
[user@rhel8 ~]$ ls -l docs/
total 4
drwxrwxr-x. 4 user user 35 Dec 26 16:08 myauthselect
drwxrwxr-x. 2 user user 4096 Dec 26 15:51 myawk
drwxrwxr-x. 2 user user 238 Dec 26 16:28 mysystemd
-rw-rw-r--. 1 user user 0 Dec 26 16:27 mytouch
让我们检查一下复习表:
现在我们知道如何复制、删除、重命名和移动文件和目录,甚至是完整的目录分支。现在让我们来看看另一种处理它们的方式——链接。
符号链接和硬链接
我们可以使用链接在两个位置拥有相同的文件。有两种类型的链接:
-
硬链接:文件系统中将有两个(或更多)指向相同文件的条目。内容将一次写入磁盘。对于同一文件,不能在两个不同的文件系统中创建硬链接。目录不能创建硬链接。
-
符号链接:创建指向系统中任何位置的文件或目录的符号链接。
两者都是使用ln
,表示链接,实用程序创建的。
现在让我们创建硬链接:
[user@rhel8 ~]$ cd docs/
[user@rhel8 docs]$ ln mysystemd/README MYREADME
[user@rhel8 docs]$ ls -l
total 20
drwxrwxr-x. 4 user user 35 Dec 26 16:08 myauthselect
drwxrwxr-x. 2 user user 4096 Dec 26 15:51 myawk
-rw-r--r--. 2 user user 13826 Dec 26 15:59 MYREADME
drwxrwxr-x. 2 user user 238 Dec 26 16:28 mysystemd
-rw-rw-r--. 1 user user 0 Dec 26 16:27 mytouch
[user@rhel8 docs]$ ln MYREADME MYREADME2
[user@rhel8 docs]$ ls -l
total 36
drwxrwxr-x. 4 user user 35 Dec 26 16:08 myauthselect
drwxrwxr-x. 2 user user 4096 Dec 26 15:51 myawk
-rw-r--r--. 3 user user 13831 Dec 26 16:32 MYREADME
-rw-r--r--. 3 user user 13831 Dec 26 16:32 MYREADME2
drwxrwxr-x. 2 user user 238 Dec 26 16:28 mysystemd
-rw-rw-r--. 1 user user 0 Dec 26 16:27 mytouch
drwxrwxr-x. 2 user user 6 Dec 26 16:35 test
检查文件的引用数量增加(在上一个示例中加粗显示)。
现在让我们创建一个指向目录的符号链接,使用ln -s
(s 代表符号):
[user@rhel8 docs]$ ln -s mysystemd mysystemdlink
[user@rhel8 docs]$ ls -l
total 36
drwxrwxr-x. 4 user user 35 Dec 26 16:08 myauthselect
drwxrwxr-x. 2 user user 4096 Dec 26 15:51 myawk
-rw-r--r--. 3 user user 13831 Dec 26 16:32 MYREADME
-rw-r--r--. 3 user user 13831 Dec 26 16:32 MYREADME2
drwxrwxr-x. 2 user user 238 Dec 26 16:28 mysystemd
lrwxrwxrwx. 1 user user 9 Dec 26 16:40 mysystemdlink -> mysystemd
-rw-rw-r--. 1 user user 0 Dec 26 16:27 mytouch
drwxrwxr-x. 2 user user 6 Dec 26 16:35 test
检查符号链接创建时如何被视为不同类型,因为它以l
开头,表示链接(在上一个示例中加粗显示),而不是以d
开头,表示目录(在上一个示例中也加粗显示)。
提示
如果不确定使用硬链接还是符号链接,使用符号链接作为默认选择。
让我们检查一下复习表:
如您所见,创建链接和符号链接非常简单,并且可以帮助从不同位置访问相同的文件或目录。在下一节中,我们将介绍如何打包和压缩一组文件和目录。
使用 tar 和 gzip
有时,我们希望将完整的目录(包括文件)打包成一个文件,以便进行备份,或者只是为了更轻松地共享它。可以帮助将文件聚合成一个的命令是tar
。
首先,我们需要安装tar
:
[root@rhel8 ~]# yum install tar -y
我们可以尝试创建一个root
的/etc
目录分支的备份:
[root@rhel8 ~]# tar -cf etc-backup.tar /etc
tar: Removing leading '/' from member names
[root@rhel8 ~]# ls -lh etc-backup.tar
-rw-r--r--. 1 root root 21M dic 27 16:08 etc-backup.tar
让我们检查所使用的选项:
-
-c
:代表创建。TAR 可以将文件放在一起,也可以解压缩它们。 -
-f
:代表文件。我们指定下一个参数将使用文件。
我们可以尝试解压缩它:
[root@rhel8 ~]# mkdir tmp
[root@rhel8 ~]# cd tmp/
[root@rhel8 tmp]# tar -xf ../etc-backup.tar
[root@rhel8 tmp]# ls
etc
让我们检查一下所使用的新选项:
-x
:用于提取。它解压缩一个 TAR 文件。
请注意,我们创建了一个名为tmp
的目录来工作,并且我们使用..
快捷方式指向了tmp
的父目录(它指的是当前工作目录的父目录)。
让我们使用gzip
来压缩一个文件。我们可以复制/etc/services
并对其进行压缩:
[root@rhel8 etc]# cd ..
[root@rhel8 tmp]# cp /etc/services .
[root@rhel8 tmp]# ls -lh services
-rw-r--r--. 1 root root 677K dic 27 16:16 services
[root@rhel8 tmp]# gzip services
[root@rhel8 tmp]# ls -lh services.gz
-rw-r--r--. 1 root root 140K dic 27 16:16 services.gz
请注意,使用gzip
时,这将压缩指定的文件,并向其添加.gz
扩展名,原始文件将不会被保留。还要注意,新创建的文件大小是原始文件的五分之一。
要恢复它,我们可以运行gunzip
:
-rw-r--r--. 1 root root 140K dic 27 16:16 services.gz
[root@rhel8 tmp]# gunzip services.gz
[root@rhel8 tmp]# ls -lh services
-rw-r--r--. 1 root root 677K dic 27 16:16 services
现在我们可以将两者结合起来,打包并压缩它们:
[root@rhel8 ~]# tar cf etc-backup.tar /etc/
tar: Removing leading '/' from member names
[root@rhel8 ~]# ls -lh etc-backup.tar
-rw-r--r--. 1 root root 21M dic 27 16:20 etc-backup.tar
[root@rhel8 ~]# gzip etc-backup.tar
[root@rhel8 ~]# ls etc-backup.tar.gz
etc-backup.tar.gz
[root@rhel8 ~]# ls -lh etc-backup.tar.gz
-rw-r--r--. 1 root root 4,9M dic 27 16:20 etc-backup.tar.gz
这样,我们可以分两步进行打包和压缩。
tar
命令足够智能,能够在单个步骤中执行打包和压缩:
[root@rhel8 ~]# rm -f etc-backup.tar.gz
[root@rhel8 ~]# tar -czf etc-backup.tar.gz /etc/
tar: Removing leading '/' from member names
[root@rhel8 ~]# ls -lh etc-backup.tar.gz
-rw-r--r--. 1 root root 4,9M dic 27 16:22 etc-backup.tar.gz
让我们检查一下新选项:
-z
:这将使用gzip
压缩新创建的 tar 文件。它也适用于解压缩。
我们可能希望在解压缩时审查相同的选项:
[root@rhel8 ~]# cd tmp/
[root@rhel8 tmp]# rm -rf etc
[root@rhel8 tmp]# tar -xzf ../etc-backup.tar.gz
[root@rhel8 tmp]# ls
etc
正如您所看到的,使用tar
和gzip
非常容易打包和压缩文件。还有其他可用的压缩方法,如bzip2
或xz
,具有更高的压缩比,您可能也想尝试。现在,让我们继续将我们学到的所有命令组合成一种强大的自动化方式——通过创建 shell 脚本。
创建基本的 shell 脚本
作为系统管理员,或者 sysadmin,有时您想要多次运行一系列命令。您可以通过每次运行每个命令来手动执行此操作;但是,有一种更有效的方法可以这样做,即创建一个s****hell 脚本。
shell 脚本只不过是一个包含要运行的命令列表的文本文件,并引用将解释它的 shell。
在本书中,我们不会涵盖如何使用文本编辑器;但是,我们将提供三种在 Linux 中使用的文本编辑器的建议,这可能会有所帮助:
-
Nano:这可能是最适合初学者使用的最简单的文本编辑器。精简,简单,直接,您可能希望开始安装并尝试使用它。
-
Vi或Vim:Vi 是 RHEL 中默认的文本编辑器,甚至在最小安装中也包括在内,并且在许多 Linux 发行版中都有。即使您不会每天使用它,熟悉它的基础知识也是很好的,因为它几乎会出现在您将使用的任何 Linux 系统中。Vim代表vi-improved。
-
Emacs:这可能是有史以来最先进和复杂的文本编辑器。它可以做任何事情,甚至包括阅读电子邮件或通过Emacs Doctor进行一些心理分析。
我们可以通过编辑一个名为hello.sh
的新文件并将以下行作为其内容来创建我们的第一个 shell 脚本:
echo ''hello world!''
然后我们可以使用bash
命令解释器运行它,使用以下命令:
[root@rhel8 ~]# bash hello.sh
hello world!
有一种不需要输入bash
的方法。我们可以添加一个引用解释器的初始行,因此hello.sh
的文件内容如下:
#!/bin/bash
echo ''hello world!''
现在我们正在更改权限以使其可执行:
[root@rhel8 ~]# ls -l hello.sh
-rw-r--r--. 1 root root 32 dic 27 18:20 hello.sh
[root@rhel8 ~]# chmod +x hello.sh
[root@rhel8 ~]# ls -l hello.sh
-rwxr-xr-x. 1 root root 32 dic 27 18:20 hello.sh
然后我们就像这样运行它:
[root@rhel8 ~]# ./hello.sh
hello world!
我们已经创建了我们的第一个 shell 脚本。恭喜!
提示
为了在任何工作目录中运行命令,命令必须在路径中,如$PATH
变量所述。如果我们的命令(或 shell 脚本)不在路径中指定的目录之一中,我们将指定运行目录,在这种情况下,使用.
当前目录的快捷方式和/
分隔符。
让我们在其中使用一些变量。我们可以通过简单地放置变量的名称和我们想要的值来定义一个变量。让我们尝试用一个变量替换单词world
。要使用它,我们在变量的名称前面加上$
符号,它将被使用。脚本将如下所示:
#!/bin/bash
PLACE=''world''
echo ''hello $PLACE!''
我们可以运行脚本,获得与之前相同的输出:
[root@rhel8 ~]# ./hello.sh
hello world!
为了更清晰,当使用变量的值时,我们将把它的名称放在大括号之间,{
''和''}
,并将其视为一种良好的做法。
先前的脚本将如下所示:
#!/bin/bash
PLACE=''world''
echo ''hello ${PLACE}!''
现在我们知道如何创建一个基本脚本,但是我们可能想通过使用一些编程能力来更深入地控制它,从循环开始。让我们开始吧!
for 循环
如果我们想对一系列位置运行相同的命令怎么办?这就是for
循环的用途。它可以帮助迭代一组元素,例如列表或计数器。
for
循环语法如下:
-
for
:指定迭代 -
do
:指定操作 -
done
:结束循环
我们可以定义一个以空格分隔的列表来尝试并用我们的第一个for
循环来迭代它:
#!/bin/bash
PLACES_LIST=''Madrid Boston Singapore World''
for PLACE in ${PLACES_LIST}; do
echo ''hello ${PLACE}!''
done
让我们运行它。输出将如下所示:
[root@rhel8 ~]# ./hello.sh
hello Madrid!
hello Boston!
hello Singapore!
hello World!
使用for
循环时,可以非常有趣,当$(
和)
。
提示
反引号,'
,也可以用于运行命令并将其输出作为列表,但为了清晰起见,我们将坚持使用先前的表达式。
一个可以使用的外部命令的例子可以是ls
。让我们创建txtfiles.sh
脚本,内容如下:
#!/bin/bash
for TXTFILE in $(ls *.txt); do
echo ''TXT file ${TXTFILE} found! ''
done
使其可执行并运行:
[root@rhel8 ~]# chmod +x txtfiles.sh
[root@rhel8 ~]# ./txtfiles.sh
TXT file error.txt found!
TXT file non-listing.txt found!
TXT file usr-files.txt found!
TXT file var-files.txt found!
您看,我们现在可以迭代一组文件,包括,例如,更改它们的名称,查找和替换其中的内容,或者仅对一组文件进行特定的备份。
我们已经看到了使用for
循环迭代列表的几种方法,当涉及自动化任务时,这可能非常有用。现在,让我们继续学习脚本中的另一个编程能力——条件语句。
条件语句
有时,我们可能希望对列表中的一个元素执行不同的操作,或者对此使用if
条件。
if
条件语法是if
:指定条件。
条件通常在括号之间指定,[
和]
。
-
then
:指定操作 -
fi
:结束循环
让我们将之前的hello.sh
脚本改成用西班牙语说hello to Madrid
,就像这样:
#!/bin/bash
PLACES_LIST=''Madrid Boston Singapore World''
for PLACE in ${PLACES_LIST}; do
if [ ${PLACE} = ''Madrid'' ]; then
echo ''¡Hola ${PLACE}!''
fi
done
然后,运行它:
[root@rhel8 ~]# ./hello.sh
¡Hola Madrid!
我们有一个问题;它只说hello to Madrid
。如果我们想对不符合条件的项目运行先前的代码会发生什么?这时我们使用else
来扩展条件。语法如下:
else
:当条件不匹配时,这被用作then
元素。
现在我们有了一个使用else
的条件语句的示例:
#!/bin/bash
PLACES_LIST=''Madrid Boston Singapore World''
for PLACE in ${PLACES_LIST}; do
if [ ${PLACE} = ''Madrid'' ]; then
echo ''¡Hola ${PLACE}!''
else
echo ''hello ${PLACE}!''
fi
done
现在我们可以运行它:
[root@rhel8 ~]# ./hello.sh
¡Hola Madrid!
hello Boston!
hello Singapore!
hello World!
如您所见,在脚本中使用条件语句很简单,并且可以在运行命令的条件下提供很多控制。现在我们需要控制当某些情况可能无法正确运行时。这就是退出代码(或错误代码)的用途。让我们开始吧!
退出代码
当运行程序时,它会提供一个$?
。
让我们通过运行ls hello.sh
来看一下:
[root@rhel8 ~]# ls hello.sh
hello.sh
[root@rhel8 ~]# echo $?
0
当程序正常运行时,退出代码为零,0
。
当我们尝试列出一个不存在的文件(或运行任何其他命令不正确或出现问题)时会发生什么?让我们尝试列出一个nonexistent
文件:
[root@rhel8 ~]# ls nonexistentfile.txt
ls: cannot access 'nonexistentfile.txt': No such file or directory
[root@rhel8 ~]# echo $?
2
您看,退出代码不等于零。我们将查看文档并检查与之关联的数字,以了解问题的性质。
在脚本中运行命令时,检查退出代码并相应地采取行动。现在让我们回顾一下在下一节中找到有关命令的更多信息的地方,比如退出代码或其他选项。
使用系统文档资源
系统包括资源,可在使用系统时帮助您并指导您提高系统管理员技能。这被称为系统文档。让我们检查默认情况下在您的 RHEL 安装中可用的三种不同资源:man 页面、info 页面和其他文档。
Man 页面
获取文档的最常用资源是man
。
系统中安装的几乎所有实用程序都有 man 页面来帮助您使用它(换句话说,指定工具的所有选项以及它们的作用)。您可以运行man tar
并检查输出:
[root@rhel8 ~]# man tar
TAR(1) GNU TAR Manual TAR(1)
NAME
tar - an archiving utility
SYNOPSIS
Traditional usage
tar {A|c|d|r|t|u|x}[GnSkUWOmpsMBiajJzZhPlRvwo] [ARG...]
UNIX-style usage
tar -A [OPTIONS] ARCHIVE ARCHIVE
tar -c [-f ARCHIVE] [OPTIONS] [FILE...]
tar -d [-f ARCHIVE] [OPTIONS] [FILE...]
您可以在其中查看(使用箭头键、空格键和/或Page Up和Page Down进行导航),并通过按字母q
(表示退出)退出。
man
页面中有相关主题的章节。使用apropos
命令很容易搜索这些内容。让我们以tar
为例看看:
[root@rhel8 ~]# apropos tar
dbus-run-session (1) - start a process as a new D-Bus session
dnf-needs-restarting (8) - DNF needs_restarting Plugin
dracut-pre-udev.service (8) - runs the dracut hooks before udevd is started
gpgtar (1) - Encrypt or sign files into an archive
gtar (1) - an archiving utility
open (1) - start a program on a new virtual terminal (VT).
openvt (1) - start a program on a new virtual terminal (VT).
scsi_start (8) - start one or more SCSI disks
setarch (8) - change reported architecture in new program environment and set personalit...
sg_reset (8) - sends SCSI device, target, bus or host reset; or checks reset state
sg_rtpg (8) - send SCSI REPORT TARGET PORT GROUPS command
sg_start (8) - send SCSI START STOP UNIT command: start, stop, load or eject medium
sg_stpg (8) - send SCSI SET TARGET PORT GROUPS command
systemd-notify (1) - Notify service manager about start-up completion and other daemon status c...
systemd-rc-local-generator (8) - Compatibility generator for starting /etc/rc.local and /usr/sbin...
systemd.target (5) - Target unit configuration
tar (1) - an archiving utility
tar (5) - format of tape archive files
unicode_start (1) - put keyboard and console in unicode mode
正如你所看到的,它不仅匹配tar
还匹配start
。这并不完美,但它可以提供与 tar 相关的有用信息,比如gpgtar
。
手册页面有一个章节。正如你在前面的例子中看到的,对于tar
,有两个章节的手册页面,一个是命令行实用程序(第一部分),另一个是存档格式(第五部分):
tar (1) - an archiving utility
tar (5) - format of tape archive files
我们可以通过运行以下命令访问第五部分的页面以了解格式:
[root@rhel8 ~]# man 5 tar
现在我们可以看到tar 格式
页面:
TAR(5) BSD File Formats Manual TAR(5)
NAME
tar — format of tape archive files
DESCRIPTION
The tar archive format collects any number of files, directories, and other file system objects (symbolic links, device nodes, etc.) into a single stream of bytes. The format was ...
您可以看到手册页面是了解更多关于典型命令的绝佳资源。这也是Red Hat 认证系统管理员考试的绝佳资源。建议是查看本章中先前显示的所有命令的 man 页面,以及即将到来的章节。考虑 man 页面是系统中的主要信息资源。现在让我们回顾其他可用的信息资源。
信息页面
Info 页面通常比 man 页面更具描述性,而且更具交互性。它们更有助于开始一个主题。
我们可以尝试通过运行以下命令获取ls
命令的info
:
[root@rhel8 ~]# info ls
我们可以看到它的信息页面:
Next: dir invocation, Up: Directory listing
10.1 'ls': List directory contents
==================================
The 'ls' program lists information about files (of any type, including
directories). Options and file arguments can be intermixed arbitrarily,
信息页面可以重定向到其他主题,以下划线显示,可以将光标放在上面并按Enter进行跟踪。
与 man 页面一样,按q
退出。
请花一些时间查看本章涵盖的主要主题的信息页面(在许多情况下,信息页面将不可用,但那些可用的可能非常有价值)。
如果我们找不到一个主题的 man 或 info 页面怎么办?让我们在下一节中讨论这个问题。
其他文档资源
对于其他文档资源,您可以转到/usr/share/doc
目录。在那里,您会找到随系统安装的工具附带的其他文档。
让我们看看我们有多少项:
[root@rhel8 doc]# cd /usr/share/doc/
[root@rhel8 doc]# ls | wc -l
219
您可以看到在/usr/share/doc
目录下有 219 个可用目录。
作为一个很好的例子,让我们进入bash
目录:
[root@rhel8 doc]# cd bash/
然后,让我们使用less
来查看INTRO
文件(记住,使用q
退出):
[root@rhel8 bash]# ls
bash.html bashref.html FAQ INTRO RBASH README
[root@rhel8 bash]# less INTRO
BASH - The Bourne-Again Shell
Bash is the shell, or command language interpreter, that will appear in the GNU operating system. Bash is an sh-compatible shell that
incorporates useful features from the Korn shell (ksh) and C shell
(csh). It is intended to conform to the IEEE POSIX P1003.2/ISO 9945.2 Shell and Tools standard. It offers functional improvements
这是一个更好地理解 bash 的好读物。现在您有很多文档资源,您将能够在日常任务中以及在RHCSA考试中使用。
摘要
在本章中,我们学习了如何使用用户和root
登录系统,了解权限和安全性的基础知识。我们现在也更熟悉使用命令行自动完成、浏览目录和文件、打包和解包它们、重定向命令输出和解析它,甚至使用 shell 脚本自动化进程。更重要的是,我们有一种方法可以在任何 RHEL 系统中获取我们正在做的(或想要做的)信息,这些信息包含在包含的文档中。这些技能是即将到来的章节的基础。如果您感到困惑,或者您的进展不如您所想的那么快,请不要犹豫重新阅读本章。
现在是时候扩展您的知识,涵盖即将到来的章节中更高级的主题。在接下来的章节中,您将开始习惯常规操作工具,您将回顾在管理系统时所采取的最常见操作。享受吧!
第四章:常规操作工具
在本书的这一部分,我们已经安装了一个系统,并且已经涵盖了一些可以创建来自动化任务的脚本,所以我们已经到了可以专注于系统本身的地步。
拥有一个正确配置的系统不仅需要安装,还需要了解如何在特定时间运行任务,保持所有服务适当运行,并配置时间同步、服务管理、引导目标(运行级别)和计划任务,所有这些内容我们将在本章中介绍。
在本章中,您将学习如何检查服务的状态,如何启动、停止和排除故障,以及如何为服务器或整个网络保持系统时钟同步。
将涵盖的主题列表如下:
-
使用 systemd 管理系统服务
-
使用 cron 和 systemd 进行任务调度
-
学习使用 chrony 和 ntp 进行时间同步
-
检查空闲资源 - 内存和磁盘(free 和 df)
-
查找日志,使用 journald 和阅读日志文件,包括日志保存和轮换
技术要求
您可以使用我们在本书开头创建的虚拟机来完成本章。此外,为了测试NTP 服务器,可能需要创建第二个虚拟机,该虚拟机将连接到第一个虚拟机作为客户端,遵循我们用于第一个虚拟机的相同过程。此外,所需的软件包将在文本中指示。
使用 systemd 管理系统服务
在本节中,您将学习如何使用systemd管理系统服务,运行时目标,以及有关systemd的服务状态。您还将学习如何管理系统引导目标和应该在系统引导时启动的服务。
systemd
(您可以在www.freedesktop.org/wiki/Software/systemd/
了解一些)被定义为用于管理系统的系统守护程序。它作为对传统启动和启动方式的重新设计而出现,它看待与传统方式相关的限制。
当我们考虑系统启动时,我们有初始内核和ramdisk的加载和执行,但在此之后,服务和脚本接管,使文件系统可用。这有助于准备提供我们系统所需功能的服务,例如以下内容:
-
硬件检测
-
附加文件系统激活
-
网络初始化(有线,无线等)
-
网络服务(时间同步,远程登录,打印机,网络文件系统等)
-
用户空间设置
然而,大多数在systemd
出现之前存在的工具都是按顺序进行操作,导致整个启动过程(从启动到用户登录)变得冗长并且容易受到延迟的影响。
传统上,这也意味着我们必须等待所需的服务完全可用,然后才能启动依赖于它的下一个服务,增加了总启动时间。
一些尝试的方法,比如使用monit或其他允许我们定义依赖关系、监视进程甚至从故障中恢复的工具,但总的来说,这是重用现有工具来执行其他功能,试图赢得关于启动最快的系统的竞赛。
重要提示
systemd
重新设计了这个过程,专注于简单性:启动更少的进程并进行更多的并行执行。这个想法本身听起来很简单,但需要重新设计过去被视为理所当然的很多东西,以便专注于改进操作系统性能的新方法的需求。
这种重新设计带来了许多好处,但也伴随着代价:它彻底改变了系统以前的启动方式,因此在不同供应商中对systemd
的采用引起了很多争议,甚至社区也做出了一些努力提供不带 systemd 的变种。
合理地启动服务,只启动必需的服务,是提高效率的好方法,例如,当系统断开连接时,没有蓝牙硬件或没有人在打印时,就没有必要启动蓝牙、打印机或网络服务。减少等待启动的服务,系统启动不会因为等待而延迟,而是专注于真正需要关注的服务。
除此之外,并行执行允许我们让每个服务花费所需的时间准备好,但不会让其他服务等待,因此一般来说,并行运行服务初始化允许我们最大限度地利用 CPU、磁盘等,而每个服务的等待时间被其他活动的服务使用。
systemd
还会在实际守护程序启动之前预先创建监听套接字,因此对其他服务有依赖关系的服务可以启动并处于等待状态,直到其依赖项启动。这样做是为了不让它们丢失任何发送给它们的消息,因此当服务最终启动时,它将执行所有待处理的操作。
让我们多了解一些关于systemd,因为它将需要用于我们将在本章中描述的几个操作。
Systemd具有单位的概念,它们只是配置文件。这些单位可以根据其文件扩展名进行分类为不同类型:
提示
不要被不同的systemd
单位类型所压倒。一般来说,最常见的是Service、Timer、Socket和Target。
当然,这些单位文件应该被找到在一些特定的文件夹中:
正如我们之前提到的关于套接字,当系统访问该路径时,路径、总线等单位文件被激活,允许在另一个服务需要它们时启动服务。这为降低系统启动时间增加了更多的优化。
通过这样,我们已经了解了systemd单位类型。现在,让我们专注于单位文件的文件结构。
systemd单位文件结构
让我们通过一个例子来动手实践:一个系统已经部署并启用了sshd
,我们需要在网络初始化后运行它,这样可以提供连接。
正如我们之前提到的,systemd
使用单位文件,我们可以检查前面提到的文件夹,或者使用systemctl list-unit-files
列出它们。记住,每个文件都是一个定义systemd应该做什么的配置文件;例如,/usr/lib/systemd/system/chronyd.service
:
![图 4.1 - chronyd.service 的内容]
](https://gitee.com/OpenDocCN/freelearn-linux-zh/raw/master/docs/rhel8-adm/img/B16799_04_001.jpg)
图 4.1 - chronyd.service 的内容
这个文件不仅定义了要启动的传统程序和 PID 文件,还定义了依赖关系、冲突和软依赖关系,这为systemd
提供了足够的信息来决定正确的方法。
如果你熟悉"inifiles",这个文件使用了那种方法,即使用方括号[
和]
表示部分,然后在每个部分的设置中使用key=value
的配对。
部分名称是区分大小写的,因此如果不使用正确的命名约定,它们将无法被正确解释。
部分指令的命名如下:
-
[单位]
-
[安装]
每种类型都有额外的条目:
-
[服务]
-
[套接字]
-
[挂载]
-
[自动挂载]
-
[交换]
-
[路径]
-
[定时器]
-
[切片]
正如你所看到的,我们为每种类型都有特定的部分。如果我们执行man systemd.unit
,它将为你提供示例,以及你正在使用的systemd版本的所有支持的值:
![图 4.2 - systemd.unit 的 man 页面]
](https://gitee.com/OpenDocCN/freelearn-linux-zh/raw/master/docs/rhel8-adm/img/B16799_04_002.jpg)
图 4.2 - systemd.unit 的 man 页面
通过这样,我们已经审查了单位文件的文件结构。现在,让我们使用systemctl来实际管理服务的状态。
管理服务在启动时启动和停止
服务可以启用或禁用;也就是说,服务将或不会在系统启动时被激活。
如果您熟悉 RHEL 中以前可用的工具,通常会使用chkconfig
根据其默认的rc.d/
设置来定义服务的状态。
可以通过以下命令启用sshd
等服务:
#systemctl enable sshd
也可以通过以下命令禁用:
#systemctl disable sshd
这将创建或删除/etc/systemd/system/multi-user.target.wants/sshd.service
。注意路径中的multi-user.target
,它相当于我们用来配置其他方法(如initscripts)的运行级别。
提示
尽管传统的chkconfig sshd on/off
或service start/stop/status/restart sshd
的用法是有效的,但最好习惯于本章中描述的systemctl
方法。
前面的命令在启动时启用或禁用服务,但要执行即时操作,我们需要发出不同的命令。
要启动sshd
服务,请使用以下命令:
#systemctl start sshd
要停止它,请使用以下命令:
#systemctl stop sshd
当然,我们也可以检查服务的状态。以下是通过systemctl status sshd
查看systemd
的示例:
图 4.3 - sshd 守护程序的状态
此状态信息提供了有关定义服务的单元文件、其在启动时的默认状态、它是否正在运行、其 PID、其资源消耗的其他详细信息,以及服务的一些最近的日志条目,这在调试简单的服务启动故障时非常有用。
检查systemctl list-unit-files
的输出是很重要的,因为它报告了系统中定义的单元文件,以及每个单元文件的当前状态和供应商预设。
现在我们已经介绍了如何启动/停止和检查服务的状态,让我们来管理实际的系统引导状态本身。
管理引导目标
我们在启动时定义的默认状态在谈论运行级别时很重要。
运行级别根据使用定义了一组预定义的服务;也就是说,它们定义了在使用特定功能时将启动或停止哪些服务。
例如,有一些运行级别用于定义以下内容:
-
停止模式
-
单用户模式
-
多用户模式
-
网络化多用户
-
图形
-
重新启动
这些运行级别允许在运行级别更改时启动/停止一组预定义的服务。当然,级别以前是基于彼此的,并且非常简单:
-
停止所有服务,然后停止或关闭系统。
-
单用户模式为一个用户启动一个 shell。
-
多用户模式在虚拟终端上启用常规登录守护程序。
-
网络化就像多用户,但网络已启动。
-
图形就像网络化,但通过显示管理器(
gdm
或其他)进行图形登录。 -
重新启动就像停止,但在处理服务结束时,它会发出重新启动而不是停止。
这些运行级别(以及系统启动时的默认运行级别)以前是在/etc/inittab
中定义的,但文件占位符提醒我们以下内容:
# inittab is no longer used.
#
# ADDING CONFIGURATION HERE WILL HAVE NO EFFECT ON YOUR SYSTEM.
#
# Ctrl-Alt-Delete is handled by /usr/lib/systemd/system/ctrl-alt-del.target
#
# systemd uses 'targets' instead of runlevels. By default, there are two main targets:
#
# multi-user.target: analogous to runlevel 3
# graphical.target: analogous to runlevel 5
#
# To view current default target, run:
# systemctl get-default
#
# To set a default target, run:
# systemctl set-default TARGET.target
因此,通过对systemd
进行此更改,现在可以检查可用的引导目标并定义它们的新方法。
我们可以通过列出此文件夹来找到可用的系统目标:
#ls -l /usr/lib/systemd/system/*.target
或者更正确地说,我们可以使用systemctl
,如下所示:
#systemctl list-unit-files *.target
当您在系统上检查输出时,您会发现 0 到 6 的运行级别的一些兼容别名,这些别名与传统的运行级别提供兼容性。
例如,对于常规服务器使用,当您在没有图形模式下运行时,默认目标将是multi-user.target
,当您使用图形模式时将是graphical.target
。
我们可以按照/etc/inittab
中的占位符的指示,通过执行以下命令来定义要使用的新运行级别:
#sysemctl set-default TARGET.target
我们可以使用以下命令验证活动状态:
#systemctl get-default
这就引出了下一个问题:目标定义是什么样的?让我们来看一下以下截图中的输出:
图 4.4 - 从其目标单元定义的运行级别 5 的内容
如您所见,它被设置为另一个目标(multi-user.target)的依赖项,并且对其他服务(如display-manager.service)有一些要求,还有其他冲突,只有在其他目标完成时才能达到该目标。
通过这种方式,systemd
可以选择适当的服务启动顺序和达到配置的引导目标的依赖关系。
有了这些,我们已经了解了服务的状态,以及如何在启动时启动、停止和启用它,但是还有其他任务我们应该以周期性的方式在系统中执行。让我们进一步探讨这个话题。
使用 cron 和 systemd 进行任务调度
您将在本节中学习的技能将涉及为业务服务和维护安排周期性任务。
对于常规的系统使用,有一些需要定期执行的任务,范围从临时文件夹清理、更新缓存的刷新率,到与库存系统进行检查等等。
设置它们的传统方式是通过cronie
软件包。
Cronie 实现了一个与传统的vixie cron兼容的守护程序,允许我们定义用户和系统 crontab。
Crontab 定义了必须执行的任务的几个参数。让我们看看它是如何工作的。
系统范围的 crontab
系统范围的 crontab 可以在/etc/crontab
中定义,也可以在/etc/cron.d
中的单独文件中定义。还存在其他附加文件夹,如/etc/cron.hourly
、/etc/cron.daily
、/etc/cron.weekly
和/etc/cron.monthly
。
在每小时、每天、每周或每月的文件夹中,您可以找到脚本或符号链接。当满足自上次执行以来的时间段(一小时、一天、一周、一个月)时,将执行该脚本。
相比之下,在/etc/crontab
或/etc/cron.d
以及用户 crontab 中,使用标准的作业定义。
通过指定与执行周期相关的参数、将执行作业的用户(除了用户 crontab 外)和要执行的命令来定义作业:
# Run the hourly jobs
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
01 * * * * root run-parts /etc/cron.hourly
通过查看标准的/etc/crontab
文件,我们可以检查每个字段的含义:
# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * user-name command to be executed
基于此,如果我们检查初始示例01 * * * * root run-parts /etc/cron.hourly
,我们可以推断如下:
-
每分钟运行
01
。 -
每小时运行。
-
每天运行。
-
每月运行。
-
每周的每一天运行。
-
以
root
身份运行。 -
执行
run-parts /etc/cron.hourly
命令。
简而言之,这意味着作业将以root
用户身份在每小时的第一分钟运行。
有时,可能会看到一个指示,比如/number*,这意味着作业将在该数字的倍数上执行。例如,/3*将在第一列上每 3 分钟运行一次,在第二列上每 3 小时运行一次,依此类推。
我们可以通过 cron 执行从命令行执行的任何命令,并且默认情况下,输出将通过邮件发送给运行作业的用户。通常的做法是在 crontab 文件中定义将接收电子邮件的用户的MAILTO
变量,或者将它们重定向到适当的日志文件以获取标准输出和标准错误(stdout
和stderr
)。
用户 crontab
与系统范围的crontab一样,用户可以定义自己的 crontab,以便用户执行任务。例如,这对于为人类用户或服务的系统帐户运行周期性脚本非常有用。
用户 crontab 的语法与系统范围的语法相同。但是,用户名的列不在那里,因为它总是作为定义 crontab 本身的用户执行。
用户可以通过crontab -l
检查其 crontab:
[root@el8-692807 ~]# crontab -l
no crontab for root
可以通过编辑crontab -e
来创建一个新的,这将打开一个文本编辑器,以便创建一个新的条目。
让我们通过创建一个条目来举例说明,就像这样:
*/2 * * * * date >> datecron
当我们退出编辑器时,它会回复以下内容:
crontab: installing new crontab
这将在/var/spool/cron/
文件夹中创建一个文件,文件名为创建它的用户。它是一个文本文件,因此您可以直接检查其内容。
一段时间后(至少 2 分钟),我们将在我们的$HOME
文件夹中有一个包含每次执行内容的文件(因为我们使用追加重定向;即>>
):
[root@el8-692807 ~]# cat datecron
Mon Jan 11 21:02:01 GMT 2021
Mon Jan 11 21:04:01 GMT 2021
现在我们已经了解了传统的 crontab,让我们了解一下 systemd 的做事方式;也就是使用定时器。
Systemd 定时器
除了常规的Cron 守护程序,cron 风格的 systemd 功能是使用定时器。定时器允许我们通过一个单元文件定义将要执行的作业。
我们可以使用以下代码检查系统中已经可用的定时器:
>systemctl list-unit-files *.timer
...
timers.target static
dnf-makecache.timer enabled
fstrim.timer disabled
systemd-tmpfiles-clean.timer static
...
例如,我们来看一下fstrim.timer
,它用于 SSD 驱动器在/usr/lib/systemd/system/fstrim.timer
执行修剪:
[Unit]
Description=Discard unused blocks once a week
Documentation=man:fstrim
..
[Timer]
OnCalendar=weekly
AccuracySec=1h
Persistent=true
…
[Install]
WantedBy=timers.target
上述定时器设置了每周执行fstrim.service
:
[Unit]
Description=Discard unused blocks
[Service]
Type=oneshot
ExecStart=/usr/sbin/fstrim -av
正如fstrim -av
命令所示,我们只执行一次。
服务定时器与服务本身一样,作为单元文件的一个优点是,它可以通过/etc/cron.d/
文件与常规的cron守护程序一起部署和更新,这由systemd处理。
现在我们对如何安排任务有了更多了解,但要获得完整的图片,安排总是需要适当的时间,所以下面我们将介绍这一点。
学习使用 chrony 和 NTP 进行时间同步
在本节中,您将了解时间同步的重要性以及如何配置服务。
对于连接的系统,保持与时间相关的真相是很重要的(考虑银行账户、收款转账、出款支付等,这些都必须被正确地时间戳和排序)。此外,考虑用户连接之间的日志跟踪、发生的问题等;它们都需要同步,以便我们可以在涉及到的所有不同系统之间进行诊断和调试。
您可能会认为在系统配置时定义的系统时钟应该是正常的,但仅仅设置系统时钟是不够的,因为时钟往往会漂移;内部电池可能导致时钟漂移或甚至重置,甚至强烈的 CPU 活动也会影响它。为了保持时钟的准确性,它们需要定期与修正漂移并尝试预测未来漂移的参考时钟同步。
系统时钟可以与GPS设备同步,例如,或者更容易地与其他连接到更精确时钟的系统同步(其他 GPS 设备、原子钟等)。网络时间协议(NTP)是一种互联网协议,通过 UDP 用于维护客户端和服务器之间的通信。
提示
NTP 通过层级来组织服务器。层级 0 设备是 GPS 设备或原子钟,直接向服务器发送信号,层级 1 服务器(主服务器)连接到层级 0 设备,层级 2 服务器连接到层级 1 服务器,依此类推...这种层级结构允许我们减少对更高层级服务器的使用,同时为我们的系统保持可靠的时间来源。
客户端连接到服务器,并比较接收到的时间以减少网络延迟的影响。
让我们看看 NTP 客户端是如何工作的。
NTP 客户端
在 RHEL8 中,chrony在启用时充当服务器和客户端(通过chronyc
命令),并且具有一些功能,使其适用于当前的硬件和用户需求,例如波动的网络(笔记本电脑挂起/恢复或不稳定的连接)。
一个有趣的特性是chrony在初始同步后不会step时钟,这意味着时间不会跳跃。相反,系统时钟会以更快或更慢的速度运行,以便在一段时间后,它将与其使用的参考时钟同步。这使得时间从操作系统和应用程序的角度来看是连续的:秒针比起钟表来说要快或慢,直到它们与参考时钟匹配。
Chrony 通过/etc/chrony.conf
进行配置,并充当客户端,因此它连接到服务器以检查它们是否有资格成为时间源。传统的server指令和pool之间的主要区别在于后者可以接收多个条目,而前者只使用一个。可以有多个服务器和池,因为实际上,一旦删除了重复项,服务器将被添加到可能的源列表中。
对于pool或server指令,有几个可用的选项(在man chrony.conf
中有描述),例如iburst
,它可以加快检查速度,以便它们可以快速过渡到同步状态。
可以使用chronyc sources
来检查实际的时间源:
图 4.5 – chronyc sources 输出
正如我们所看到的,我们可以根据第一列(M)知道每个服务器的状态是什么:
-
^:这是一个服务器
-
=:这是一个对等体
在第二列(S)中,我们可以看到每个条目的不同状态:
-
*****:这是我们当前的同步服务器。
-
+:这是另一个可接受的时间源。
-
?:用于指示已失去网络连接的源。
-
x:此服务器被认为是虚假的滴答器(与其他来源相比,其时间被认为是不一致的)。
-
~:具有高变异性的源(它也会在守护程序启动期间出现)。
因此,我们可以看到我们的系统连接到一个正在考虑ts1.sct.de
作为参考的服务器,这是一个 stratum 2 服务器。
可以通过chronyc tracking
命令检查更详细的信息:
图 4.6 – Chronyc 跟踪输出
这提供了关于我们的时钟和参考时钟的更详细信息。前面截图中的每个字段具有以下含义:
-
字段:描述。
-
参考 ID:系统已同步的服务器的 ID 和名称/IP。
-
Stratum:我们的 stratum 级别。在此示例中,我们的同步服务器是一个 stratum 3 时钟。
-
参考时间:上次处理参考的时间。
-
系统时间:在正常模式下运行时(没有时间跳跃),这指的是系统与参考时钟的偏离。
-
最后偏移:最后一次时钟更新的估计偏移。如果是正数,这表示我们的本地时间超前于我们的来源。
-
RMS 偏移:偏移值的长期平均值。
-
频率:如果chronyd不修复它,系统时钟的错误率,以百万分之一表示。
-
剩余频率:反映当前参考时钟测量之间的任何差异。
-
偏差:频率的估计误差。
-
根延迟:到 stratum -1 同步服务器的总网络延迟。
-
根分散:通过连接到我们同步的 stratum -1 服务器的所有计算机累积的总分散。
-
更新间隔:最后两次时钟更新之间的间隔。
-
/usr/share/doc/program/
),等等。例如,关于此处列出的每个字段的更详细信息可以通过man chronyc
命令找到。
要配置客户端的其他选项,除了安装时提供的选项或通过 kickstart 文件提供的选项,我们可以编辑/etc/chrony.cnf
文件。
让我们学习如何将我们的系统转换为我们网络的 NTP 服务器。
NTP 服务器
正如我们之前介绍的,chrony也可以配置为您的网络的服务器。在这种模式下,我们的系统将向其他主机提供准确的时钟信息,而不消耗来自更高层级服务器的外部带宽或资源。
这个配置也是通过/etc/chrony.conf
文件进行的,我们将在这里添加一个新的指令;即allow
:
# Allow NTP client access from all hosts
allow all
此更改使chrony能够监听所有主机请求。或者,我们可以定义一个子网或主机来监听,例如allow 1.1.1.1
。可以使用多个指令来定义不同的子网。另外,您可以使用deny指令来阻止特定主机或子网访问我们的 NTP 服务器。
服务时间从我们的服务器已经与之同步的基础开始,以及一个外部 NTP 服务器,但让我们考虑一个没有连接性的环境。在这种情况下,我们的服务器将不连接到外部来源,也不会提供时间。
chrony允许我们为我们的服务器定义一个虚假的层级。这是通过配置文件中的local
指令完成的。这允许守护程序获得更高的本地层级,以便它可以向其他主机提供时间;例如:
local stratum 3 orphan
通过这个指令,我们将本地层级设置为 3,并使用orphan选项,这将启用一个特殊模式,在这个模式下,所有具有相同本地层级的服务器都会被忽略,除非没有其他来源可供选择,且其参考 ID 小于本地 ID。这意味着我们可以在我们的断开网络中设置几个 NTP 服务器,但只有一个会成为参考。
现在我们已经涵盖了时间同步,我们将深入资源监视。稍后,我们将研究日志记录。所有这些都与我们系统的时间参考有关。
检查空闲资源 - 内存和磁盘(free 和 df)
在这一部分,您将检查系统资源的可用性,例如内存和磁盘。
保持系统平稳运行意味着使用监视,以便我们可以检查服务是否正在运行,以及系统是否为它们提供了资源来执行它们的任务。
有一些简单的命令可以用来监视最基本的用例:
-
磁盘
-
CPU
-
内存
-
网络
这包括几种监视方式,例如一次性监视、连续监视,或者甚至在一段时间内进行诊断性能更好。
内存
内存可以通过free
命令进行监视。它提供了有关可用和正在使用多少RAM和SWAP的详细信息,这也表明了多少内存被共享、缓冲或缓存使用。
Linux 倾向于使用所有可用的内存;任何未使用的 RAM 都会被指向缓存或缓冲区,以及未被使用的内存页面。如果可用,这些将被交换到磁盘上:
# free
total used free shared buff/cache available
Mem: 823112 484884 44012 2976 294216 318856
Swap: 8388604 185856 8202748
例如,在上面的输出中,我们可以看到系统总共有 823 MB 的 RAM,并且它正在使用一些交换空间和一些内存用于缓冲。这个系统没有大量交换,因为它几乎处于空闲状态(我们将在本章后面检查负载平均值),所以我们不应该担心它。
当 RAM 使用量很高且没有更多的交换空间可用时,内核会包括一种保护机制,称为OOM-Killer。它根据执行时间、资源使用情况等确定系统中应终止哪些进程以恢复系统,使其正常运行。然而,这是有代价的,因为内核知道可能已经失控的进程。然而,杀手可能会杀死数据库和 Web 服务器,并使系统处于不稳定状态。对于生产服务器,有时候典型的做法是,不是让 OOM-Killer 开始以不受控制的方式杀死进程,而是调整一些关键进程的值,使它们不被杀死,或者导致系统崩溃。
系统崩溃用于收集可以稍后通过包含导致崩溃的原因以及可以进行诊断的内存转储的调试信息。
我们将在第十六章中回到这个话题,使用 tuned 进行内核调优和管理性能配置文件。让我们继续检查正在使用的磁盘空间。
磁盘空间
可以通过df
检查磁盘空间,它为每个文件系统提供数据输出。这表示文件系统及其大小、可用空间、利用率百分比和挂载点。
让我们在我们的示例系统中检查一下:
> df
Filesystem 1K-blocks Used Available Use% Mounted on
devtmpfs 368596 0 368596 0% /dev
tmpfs 411556 0 411556 0% /dev/shm
tmpfs 411556 41724 369832 11% /run
tmpfs 411556 0 411556 0% /sys/fs/cgroup
/dev/mapper/rhel-root 40935908 11026516 29909392 27%
/dev/sda2 1038336 517356 520980 50% /boot
/dev/sda1 102182 7012 95170 7% /boot/efi
tmpfs 82308 0 82308 0% /run/user/1000
通过使用这个工具,可以轻松关注利用率较高且剩余空间较少的文件系统,以防止问题发生。
重要提示
如果文件正在被写入,比如由一个进程记录其输出,那么删除文件只会将文件从文件系统中取消链接,但由于进程仍然保持文件句柄打开,直到进程停止,空间才会被回收。在必须尽快释放磁盘空间的紧急情况下,最好通过重定向清空文件,比如echo "" > filename
。这样可以在进程仍在运行时立即恢复磁盘空间。使用rm
命令会要求进程被完成。
接下来我们将检查 CPU 使用率。
CPU
在监视 CPU 方面,我们可以利用多种工具,比如ps
:
图 4.7 - ps aux 命令的输出(系统中的每个进程)
ps
命令是检查正在运行的进程以及资源消耗情况的事实标准。
对于任何其他命令,我们都可以写很多关于可以使用的所有不同命令参数的内容(所以,再次,查看 man 页面以获取详细信息),但通常来说,尽量了解它们的基本用法或对你更有用的用法。其他情况,请查看手册。例如,ps aux
提供了足够的信息供正常使用(系统中的每个进程)。
top
工具,如下面的截图所示,会定期刷新屏幕,并可以对运行中的进程进行排序,比如 CPU 使用率、内存使用率等。此外,top
还显示了关于内存使用情况、负载平均、运行中的进程等的五行摘要:
图 4.8 - 在我们的测试系统上执行 top 命令
CPU 使用率并不是唯一可能使系统变得缓慢的因素。现在,让我们稍微了解一下负载平均指标。
负载平均
负载平均通常以三个数字的形式提供,比如负载平均:0.81,1.00,1.17
,分别是 1、5 和 15 分钟的平均值。这表示系统有多忙;数值越高,响应越差。每个时间段比较的值给我们一个概念,即系统负载是增加的(1 或 5 分钟内的值较高,15 分钟内的值较低),还是正在减少(15 分钟内的值较高,5 和 1 分钟内的值较低),因此这成为了一个快速找出是否发生了什么或者正在发生的方法。如果系统通常具有较高的负载平均值(超过 1.00),那么深入挖掘可能的原因(对其功率需求过高,可用资源不多等)是一个好主意。
现在我们已经介绍了基础知识,让我们继续看一些额外的检查,我们可以对系统资源的使用进行。
其他监控工具
例如,对于ifconfig
,可以匹配接收到的传输包、接收到的包、错误等的值。
当目标是执行更完整的监控时,我们应该确保/var/log/sa/
。
每天记录和存储的历史数据(##
)可以在/var/log/sa/sa##
和/var/log/sa/sar##
中查询,以便我们可以与其他天进行比较。通过以更高的频率运行数据收集器(由systemd定时器执行),我们可以在调查问题时增加特定时期的细粒度。
然而,sar文件的外观显示了大量的数据:
图 4.9 - 示例系统上/var/log/sar02 的内容
在这里,我们可以看到 8-0 设备每秒有 170.27 次事务和 14.51%的利用率。在这种情况下,设备的名称使用主/次的值,我们可以在/dev/
文件夹中检查。我们可以通过运行ls -l /dev/*|grep 8
来查看,如下面的截图所示:
图 4.10 - 用于定位与主 8 和次 0 对应的设备的/dev/目录列表
在这里,我们可以看到这对应于/dev/sda
上的完整硬盘统计信息。
提示
通过sar处理数据是了解系统运行情况的好方法,但由于sysstat软件包在 Linux 中已经存在很长时间,因此有一些工具,如github.com/mbaldessari/sarstats
,可以帮助我们处理记录的数据并以 PDF 文件的形式呈现图形化。
在下图中,我们可以看到不同驱动器的系统服务时间,以及系统崩溃时的标签。这有助于我们识别该点的系统活动:
图 4.11 - 他们示例 PDF 中的磁盘服务时间的 Sarstats 图形,网址为acksyn.org/software/sarstats/sar01.pdf
现代监控系统资源的工具已经发展,Performance Co-Pilot(pcp和可选的pcp-gui软件包)可以设置更强大的选项。只需记住,pcp 要求我们还在系统上启动数据收集器。
RHEL8 还包括cockpit,在进行服务器安装时默认安装。该软件包提供了一组工具,可以通过扩展其功能的插件将其作为其他产品的一部分。
cockpit 提供的 Web 服务可以在主机 IP 的 9090 端口上访问,因此您应该访问https://localhost:9090
以获取登录屏幕,以便我们可以使用系统凭据登录。
重要提示
如果未安装或不可用 cockpit,请确保执行dnf install cockpit
来安装该软件包,并使用systemctl enable --now cockpit.socket
启动服务。如果您远程访问服务器,而不是使用localhost
,请在允许防火墙连接之后使用服务器主机名或 IP 地址进行连接firewall-cmd --add-service=cockpit
,如果之前未这样做。
登录后,我们将看到一个显示相关系统信息和链接到其他部分的仪表板,如下面的截图所示:
图 4.12 - 登录系统仪表板后的 Cockpit 屏幕
正如您所看到的,cockpit包括几个选项卡,可用于查看系统状态,甚至执行一些管理任务,如SELinux、软件更新、订阅等。
例如,我们可以查看性能图表,如下面的截图所示:
图 4.13 - 仪表板中的 Cockpit 图表
Cockpit 允许我们从图形界面检查服务状态、软件包升级状态以及其他配置设置,还可以远程连接到其他系统。这些可以从左侧的侧边菜单中选择。
有更适合大规模部署监控和管理的工具,比如Ansible和Satellite,因此熟悉我们用于故障排除和简单脚本构建的工具非常重要。这使我们能够结合到目前为止学到的知识,快速生成需要我们注意的事项的提示。
通过这样,我们已经介绍了一些检查资源使用情况的基础知识。现在,让我们看看如何查找有关正在运行的服务和我们可以审查的错误的信息。
查找日志,使用 journald 和阅读日志文件,包括日志保存和轮换
在本节中,您将学习如何通过日志审查系统的状态。
在本章的前面部分,我们学习了如何通过systemd管理系统服务,检查它们的状态和检查它们的日志。传统上,不同的守护程序和系统组件用于在/var/log/
文件夹下创建文件,这些文件基于守护程序或服务的名称。如果服务用于创建多个日志,则会在服务的文件夹内创建这些日志(例如httpd或samba)。
系统日志守护程序rsyslogd
有一个新的systemd伙伴,名为systemd-journald.service
,它也存储日志,但它不是使用传统的纯文本格式,而是使用二进制格式,可以通过journalctl
命令查询。
熟悉阅读日志文件非常重要,因为这是故障排除的基础,因此让我们学习一下一般日志记录以及如何使用它。
日志包含生成它的服务的状态信息。它们可能具有一些常见的格式,并且通常可以配置,但它们倾向于使用一些常见的元素,例如以下内容:
-
时间戳
-
生成条目的模块
-
消息
以下是一个例子:
Jan 03 22:36:47 el8-692807 sshd[50197]: Invalid user admin from 49.232.135.77 port 47694
在这种情况下,我们可以看到有人尝试以admin
用户从 IP 地址49.232.135.77
登录到我们的系统。
我们可以将该事件与其他日志相关联,例如通过journalctl -u systemd-logind
查看登录子系统的日志。在这个例子中,我们找不到admin
用户的任何登录(这是预期的,因为在这个系统中未定义admin
用户)。
此外,我们还可以看到主机名el8-692807
,生成它的服务sshd
,50197
和该服务记录的消息。
除了journalctl,我们还可以查看其他日志,以便在希望检查系统健康状况时使用。让我们以/var/log/messages
为例:
图 4.14 - /var/log/messages 摘录
在这个例子中,我们可以看到系统在遵循类似初始行的输出时运行了一些命令。例如,在前面的例子中,我们可以看到sysstat
每 10 分钟执行一次,以及dnf
缓存已更新。
让我们看一下标准系统安装中可用的重要日志列表(请注意,文件名是相对于/var/log
文件夹的):
-
boot.log
:存储系统在启动过程中发出的消息。它可能包含用于提供带颜色的输出的转义代码。 -
audit/audit.log
:包含由内核审计子系统生成的存储消息。 -
secure
:包含安全相关的消息,比如sshd
登录尝试失败。 -
dnf.log
:由 DNF 软件包管理器生成的日志,例如缓存刷新。 -
firewalld
:由firewalld守护程序生成的输出。 -
lastlog
:这是一个包含有关最近登录系统的用户信息的二进制文件(可通过last
命令查询)。 -
messages
:默认的日志记录设施。这意味着任何不是特定日志的内容都会在这里。通常,这是开始检查系统发生了什么的最佳位置。 -
maillog
:邮件子系统的日志。启用后,它会尝试传递消息。接收到的任何消息都将存储在这里。通常,配置服务器的出站邮件,以便可以传递系统警报或脚本输出。 -
btmp
:系统访问失败的二进制日志。 -
wtmp
:系统访问的二进制日志。 -
sa/sar*
:sysstat实用程序的文本日志(二进制文件,命名为sa,加上日期编号,通过夜间的cron作业转换)。
根据已安装的服务、使用的安装方法等,可能存在其他日志文件。熟悉可用的日志非常重要,当然,要审查它们的内容,以了解消息的格式、每天创建多少个日志以及它们产生了什么样的信息。
利用已记录的信息,我们将获得有关如何配置每个单独的守护进程的提示。这使我们能够调整日志级别,从仅显示错误到更详细地调试问题。这意味着我们可以配置所需的日志旋转,以避免因为日志占用了所有空间而导致系统稳定性受到风险。
日志旋转
在正常的系统操作期间,有许多守护进程在使用,并且系统本身会生成用于故障排除和系统检查的日志。
一些服务可能允许我们根据日期定义要写入的日志文件,但通常的标准是将日志记录到/var/log
目录中类似守护进程名称的文件中;例如,/var/log/cron
。写入同一文件将导致文件不断增长,直到存储日志的驱动器被填满,这在一段时间后(有时在公司定义的政策下)可能不再有意义。
简化日志旋转过程的cron
条目。它是通过/etc/logrotate.conf
配置的,并且每天执行一次,如下所示:
图 4.15 - 日志和旋转日志的示例清单(使用日期扩展)
如果我们检查配置文件的内容,我们会发现它包括一些文件定义,可以直接在那里或通过/etc/logrotate.d/
文件夹中的附加文件中定义,这样每个程序都可以在安装、删除或更新软件包时满足自己的要求,而不会影响其他程序。
为什么这很重要?因为,如果您还记得本章早些时候的一些建议(关于磁盘空间),如果logrotate
只是删除文件并创建新文件,实际的磁盘空间将不会被释放,并且写入日志的守护进程将继续写入它正在写入的文件(通过文件句柄)。为了克服这一点,每个定义文件可以定义一个后旋转命令。这会向日志旋转过程发出信号,以便它可以关闭,然后重新打开用于记录的文件。一些程序可能需要像kill -SIGHUP PID
这样的信号,或者在执行时需要特殊参数,比如chronyc cyclelogs
。
有了这些定义,logrotate
将能够为每个服务应用配置,并同时保持服务在一个健全的状态下运行。
配置还可以包括特殊指令,例如以下内容:
-
missingok
-
nocreate
-
nopytruncate
-
notifempty
您可以在logrotate.conf
中找到更多关于它们(以及其他内容)的信息(是的,一些软件包还包括配置文件的 man 页面,因此尝试检查man logrotate.conf
以获取完整的详细信息!)。
主文件中剩下的一般配置允许我们定义一些常见的指令,比如要保留多少天的日志,是否要在旋转日志文件的文件扩展名中使用日期,是否要在旋转日志上使用压缩,我们希望多频繁地执行旋转等等。
让我们看一些例子。
以下示例将在“每日”基础上旋转,保留30
个旋转日志,对它们进行“压缩”,并在其尾部文件名中使用“日期”作为扩展名。
rotate 30
daily
compress
dateext
在这个例子中,它将在“每周”基础上保留4
个旋转日志(因此是 4 周),并对日志进行“压缩”,但对每个旋转日志使用序列号(这意味着每次旋转发生时,以前旋转的日志的序列号也会增加):
rotate 4
weekly
compress
这种方法的一个优点(不使用dateext
)是日志命名约定是可预测的,因为我们有daemon.log
作为当前日志,daemon.1.log
作为以前的日志,依此类推。这使得编写日志解析和处理脚本变得更容易。
总结
在本章中,我们了解了systemd
以及它如何以优化的方式负责引导所需的系统服务。我们还学习了如何检查服务的状态,如何启用、禁用、启动和停止它们,以及如何使系统引导到我们引导系统的不同目标中。
时间同步被介绍为一个必不可少的功能,它确保我们的服务正常运行。它还允许我们确定系统时钟的状态,以及如何作为网络的时钟服务器。
我们还使用系统工具来监视资源使用情况,学习如何检查系统创建的日志以了解不同工具的功能状态,以及如何确保日志被正确维护,以便在不再相关时丢弃旧条目。
在下一章中,我们将深入探讨使用不同用户、组和权限来保护系统。
第五章:使用用户、用户组和权限保护系统
安全性是管理系统的关键部分,了解安全概念以便为任何系统管理员提供正确的资源访问权限是必要的。
在本章中,我们将回顾sudo
中的安全基础知识,作为为系统中不同用户分配管理员权限的一种方式(甚至禁用 root 帐户)。我们还将深入研究文件权限以及如何改变它们,使用扩展功能来使命令以不同的用户或组运行,或者简化目录中的组协作。
我们将涵盖以下主题:
-
创建、修改和删除本地用户账户和用户组
-
管理用户组和审查分配
-
调整密码策略
-
为管理任务配置 sudo 访问权限
-
检查、审查和修改文件权限
-
使用特殊权限
让我们开始学习权限和安全性,包括用户账户和用户组。
创建、修改和删除本地用户账户和用户组
当准备系统供用户访问时,系统管理员必须做的第一项任务之一是为访问系统的人创建新的用户帐户。在本节中,我们将回顾如何创建和删除本地帐户,以及如何将它们分配给用户组。
第一步是在系统中创建一个新用户帐户。这是通过使用useradd
命令完成的。让我们通过运行以下命令将user01
添加到系统中:
[root@rhel8 ~]# useradd user01
[root@rhel8 ~]# grep user01 /etc/passwd
user01:x:1001:1001::/home/user01:/bin/bash
[root@rhel8 ~]# id user01
uid=1001(user01) gid=1001(user01) groups=1001(user01)
有了这个,用户就创建好了。
重要提示
为了能够添加用户,我们需要管理员权限。在当前配置中,我们通过以root
身份运行命令来实现这一点。
帐户是使用系统中配置的默认选项创建的,例如以下选项:
-
su
asroot
. We will see how to add a password to the user next. -
user01
,UID 为1001
。 -
1001
。 -
描述:在创建用户时未添加描述。此字段为空白。
-
home
目录创建在/home/$USER
中,在本例中为/home/user01
。这将是用户的默认和主目录,也是存储他们个人偏好和文件的地方。初始内容从/etc/skel
复制而来。 -
bash
。
提示
创建新用户时应用的默认选项在/etc/default/useradd
文件中定义。
用户创建后,我们可以通过以root
身份运行passwd
命令,后跟要更改的用户名,来添加(或更改)密码:
[root@rhel8 ~]# passwd user01
Changing password for user user01.
New password: redhat
BAD PASSWORD: The password is shorter than 8 characters
Retype new password: redhat
passwd: all authentication tokens updated successfully
现在用户有了新分配的密码。请注意两件事:
-
用户
root
可以更改任何用户的密码,而无需知道先前的密码(完全重置密码)。当用户度假回来后不记得密码时,这是很有用的。 -
在示例中,我们显示了分配的密码
redhat
,但屏幕上没有显示。密码太简单,不符合默认的复杂性标准,但是作为root
,我们仍然可以分配它。
让我们使用之前学过的id
命令来检查新用户:
[root@rhel8 ~]# id user01
uid=1001(user01) gid=1001(user01) groups=1001(user01)
在本节中采取的步骤之后,我们现在在系统中有了用户,并且可以使用。我们可以用useradd
自定义用户创建的主要选项如下:
-
-u
或--uid
:为用户分配特定的 UID。 -
-g
或--gid
:为用户分配一个主组。可以通过编号(GID)或名称指定。该组需要先创建。 -
-G
或--groups
:通过提供逗号分隔的列表使用户成为其他组的一部分。 -
-c
或--comment
:为用户提供描述,如果要使用空格,则在引号之间指定。 -
-d
或--home-dir
:为用户定义主目录。 -
-s
或--shell
:为用户分配自定义 shell。 -
-p
或--password
:提供密码给用户的一种方法。密码应该已经加密才能使用这种方法。建议不使用此选项,因为有捕获加密密码的方法。请改用passwd
。 -
-r
或--system
:创建系统账户而不是用户账户。
如果我们需要更改用户的任何属性,例如描述,我们可以使用usermod
工具。让我们将描述修改为user01
:
[root@rhel8 ~]# usermod -c "User 01" user01
[root@rhel8 ~]# grep user01 /etc/passwd
user01:x:1001:1001:User 01:/home/user01:/bin/bash
usermod
命令使用与useradd
相同的选项。现在定制您当前的用户将会很容易。
让我们以创建user02
为例,演示如何使用选项:
[root@rhel8 ~]# useradd --uid 1002 --groups wheel \
--comment "User 02" --home-dir /home/user02 \
--shell /bin/bash user02
[root@rhel8 ~]# grep user02 /etc/passwd
user02:x:1002:1002:User 02:/home/user02:/bin/bash
[root@rhel8 ~]# id user02
uid=1002(user02) gid=1002(user02) groups=1002(user02),10(wheel)
提示
当命令行太长时,可以添加字符\
,然后按Enter并在新行上继续命令。
现在我们知道如何创建用户,但我们可能也需要创建一个组并将我们的用户添加到其中。让我们使用groupadd
命令创建finance
组:
[root@rhel8 ~]# groupadd finance
[root@rhel8 ~]# grep finance /etc/group
finance:x:1003:
我们可以将user01
和user02
用户添加到finance
组:
[root@rhel8 ~]# usermod -aG finance user01
[root@rhel8 ~]# usermod -aG finance user02
[root@rhel8 ~]# grep finance /etc/group
finance:x:1003:user01,user02
重要提示
我们使用-aG
选项将用户添加到组中,而不是修改用户所属的组。
一旦我们知道如何创建用户和组,让我们看看如何使用userdel
命令删除它们:
[root@rhel8 ~]# userdel user01
[root@rhel8 ~]# grep user01 /etc/passwd
[root@rhel8 ~]# id user01
id: 'user01': no such user
[root@rhel8 ~]# grep user02 /etc/passwd
user02:x:1002:1002:User 02:/home/user02:/bin/bash
[root@rhel8 ~]# id user02
uid=1002(user02) gid=1002(user02) groups=1002(user02),10(wheel),1003(finance)
[root@rhel8 ~]# ls /home/
user user01 user02
[root@rhel8 ~]# rm -rf /home/user01/
如您所见,我们需要手动删除home
目录。这种删除用户的方式很好,如果我们想保留其数据以备将来使用。
要完全删除用户,我们应用选项-r
。让我们尝试使用user02
:
[root@rhel8 ~]# userdel -r user02
[root@rhel8 ~]# ls /home/
user user01
[root@rhel8 ~]# grep user02 /etc/passwd
[root@rhel8 ~]# id user02
id: 'user02': no such user
现在让我们使用groupdel
命令删除finance
组:
[root@rhel8 ~]# groupdel finance
[root@rhel8 ~]# grep finance /etc/group
正如我们所见,简单易行地在 RHEL 中创建用户和组并进行简单分配。在下一节中,让我们更深入地了解如何管理组和对其进行分配。
管理组和审查分配
我们已经看到如何使用groupadd
创建组,并使用groupdel
删除组。让我们看看如何使用groupmod
修改已创建的组。
让我们创建一个要操作的组。我们将通过运行以下命令创建拼写错误的acounting
组:
[root@rhel8 ~]# groupadd -g 1099 acounting
[root@rhel8 ~]# tail -n1 /etc/group
acounting:x:1099:
您看到我们在名称上犯了一个错误,没有拼写成accounting
。我们甚至可能已经向其中添加了一些用户账户,我们需要修改它。我们可以使用groupmod
并运行以下命令来这样做:
[root@rhel8 ~]# groupmod -n accounting acounting
[root@rhel8 ~]# tail -n1 /etc/group
accounting:x:1099:
现在我们已经看到了如何修改组名。我们可以使用-g
选项修改不仅名称,还有 GID:
[root@rhel8 ~]# groupmod -g 1111 accounting
[root@rhel8 ~]# tail -n1 /etc/group
accounting:x:1111:
我们可以通过运行groups
命令来查看分配给用户的组:
[root@rhel8 ~]# groups user
user : user wheel
有了这个,我们已经准备好在 Linux 系统中管理组和用户。让我们继续讨论密码策略。
调整密码策略
如第三章中提到的,基本命令和简单的 Shell 脚本,用户存储在/etc/passwd
文件中,而加密密码存储在/etc/shadow
文件中。
提示
哈希算法是这样做的,它从提供的数据(即文件或单词)生成一串精确的字符,或哈希。它以一种方式进行,以便它总是从相同的原始数据生成相同的哈希,但是几乎不可能从哈希中重新创建原始数据。这就是为什么它们用于存储密码或验证下载文件的完整性。
让我们通过以root
身份运行grep
用户对/etc/shadow
进行查找来看一个例子:
user:$6$tOT/cvZ4PWRcl8XX$0v3.ADE/ibzlUGbDLer0ZYaMPNRJ5gK17LeKnoMfKK9 .nFz8grN3IafmHvoHPuh3XrU81nJu0.is5znztB64Y/:18650:0:99999:7:3:19113:
与密码文件一样,/etc/shadow
中存储的数据每行有一个条目,字段由冒号(:
)分隔。
-
user
:账户名称。它应该与/etc/passwd
中的名称相同。 -
$6$tOT/cvZ4PWRcl8XX$0v3.ADE/ibzlUGbDLer0ZYaMPNRJ5gK17LeKnoMfKK 9.nFz8grN3IafmHvoHPuh3XrU81nJu0.is5znztB64Y/
:密码哈希。它包含三个由$
分隔的部分:
-
$6
:用于加密文件的算法。在这种情况下,值6
表示 SHA-512。数字1
是用于旧的、现在不安全的 MD5 算法。 -
$tOT/cvZ4PWRcl8XX
:密码$0v3.ADE/ibzlUGbDLer0ZYaMPNRJ5gK17LeKnoMfKK9.nFz8grN3IafmHvoHPuh3XrU81nJu0.is5znztB64Y/
:加密密码哈希。使用盐和 SHA-512 算法,创建此令牌。当用户验证时,该过程再次运行,如果生成相同的哈希,则验证密码并授予访问权限。
-
18650
:密码上次更改的时间和日期。格式是自 1970-01-01 00:00 UTC 以来的天数(这个日期也被称为纪元)。 -
0
:用户可以再次更改密码之前的最少天数。 -
99999
:用户必须再次更改密码之前的最大天数。如果为空,密码不会过期。 -
7
:用户将被警告密码即将过期的天数。 -
3
:用户即使密码过期仍然可以登录的天数。 -
19113
:密码应该过期的日期。如果为空,它不会在特定日期过期。 -
<empty>
:最后一个冒号留下来方便我们轻松添加新字段。
提示
要将date
字段转换为可读日期,可以运行以下命令:date -d '1970-01-01 UTC + 18650 days'
。
我们如何更改密码的过期日期?用于此操作的工具是chage
,用于/etc/shadow
:
-
-d
或--lastday
:密码上次更改的时间和日期。格式为YYYY-MM-DD
。 -
-m
或--mindays
:用户可以再次更改密码之前的最少天数。 -
-W
或--warndays
:用户将被警告密码即将过期的天数。 -
-I
或--inactive
:密码过期后,账户被锁定之前必须经过的天数。 -
-E
或--expiredate
:用户账户将被锁定的日期。日期应以YYYY-MM-DD
格式表示。
让我们试一下。首先,我们创建usertest
账户:
[root@rhel8 ~]# adduser usertest
[root@rhel8 ~]# grep usertest /etc/shadow
usertest:!!:18651:0:99999:7:::
重要提示
在 RHEL 8 中,adduser
和useradd
工具是相同的工具。随时以您感觉最舒适的方式输入。
您会注意到在前面的示例中,从两个感叹号!!
中,粗体显示密码未设置,并且我们正在使用默认值。让我们更改密码并检查差异。使用您喜欢的任何密码:
[root@rhel8 ~]# passwd usertest
Changing password for user usertest.
New password:
Retype new password:
passwd: all authentication tokens updated successfully.
[root@rhel8 ~]# grep usertest /etc/shadow
usertest:$6$4PEVPj7M4GD8CH.4$VqiYY.IXetwZA/g54bFP1ZJwQ/yc6bnaFauHGA1 1eFzsGh/uFbJwxZCQTFHIASuamBz.27gb4ZpywwOA840eI.:18651:0:99999:7:::
密码哈希已创建,并且上次更改的日期与当前日期相同。让我们建立一些选项:
[root@rhel8 ~]# chage --mindays 0 --warndays 7 --inactive 3 --expiredate 2030-01-01 usertest
[root@rhel8 ~]# grep usertest /etc/shadow
usertest:$6$4PEVPj7M4GD8CH.4$VqiYY.IXetwZA/g54bFP1ZJwQ/yc6bnaFauHGA1 1eFzsGh/uFbJwxZCQTFHIASuamBz.27gb4ZpywwOA 840eI.:18651:0:99999:7:3:21915:
[root@rhel8 ~]# date -d '1970-01-01 UTC + 21915 days'
mar ene 1 01:00:00 CET 2030
请注意/etc/shadow
文件中与chage
指定的值对应的更改。我们可以使用chage
的-l
选项检查更改:
[root@rhel8 ~]# chage -l usertest
Last password change : ene 24, 2021
Password expires : never
Password inactive : never
Account expires : ene 01, 2030
Minimum number of days between password change : 0
Maximum number of days between password change : 99999
Number of days of warning before password expires: 7
要更改默认值,我们应该编辑/etc/login.defs
。让我们检查最常见更改的部分:
# Password aging controls:
#
# PASS_MAX_DAYS Maximum number of days a password may be used.
# PASS_MIN_DAYS Minimum number of days allowed between password changes.
# PASS_MIN_LEN Minimum acceptable password length.
# PASS_WARN_AGE Number of days warning given before a password expires.
#
PASS_MAX_DAYS 99999
PASS_MIN_DAYS 0
PASS_MIN_LEN 5
PASS_WARN_AGE 7
请花几分钟时间查看/etc/login.defs
中的选项。
现在,我们可能会遇到一个用户已经离开公司的情况。我们如何锁定账户,使用户无法访问系统?usermod
命令有-L
选项,用于锁定账户。让我们试一下。首先,让我们登录系统:
图 5.1 - 用户账户 usertest 登录系统
现在让我们锁定账户:
[root@rhel8 ~]# usermod -L usertest
[root@rhel8 ~]# grep usertest /etc/shadow
usertest:!$6$4PEVPj7M4GD8CH.4$VqiYY.IXetwZA/g54bFP1ZJwQ/yc6bnaFauHGA 11eFzsGh/uFbJwxZCQTFHIASuamBz.27gb4ZpywwOA840eI.:18651:0:99999:7:3:21915:
请注意,在密码哈希之前添加了!
字符。这是用于锁定的机制。让我们再次尝试登录:
图 5.2 - 用户账户 usertest 无法登录系统
可以使用-U
选项解锁账户:
[root@rhel8 ~]# usermod -U usertest
[root@rhel8 ~]# grep usertest /etc/shadow
usertest:$6$4PEVPj7M4GD8CH.4$VqiYY.IXetwZA/g54bFP1ZJwQ/yc6bnaFauHGA1 1eFzsGh/uFbJwxZCQTFHIASuamBz.27gb4ZpywwOA840eI.:18651:0:99999:7:3:21915:
现在您可以看到!
字符已被移除。随时尝试再次登录。
重要提示
要完全阻止访问账户,而不仅仅是使用密码登录(还有其他机制),我们应该将到期日期设置为1
。
另一个常见的用例是当您希望用户访问系统时,比如拥有一个网络共享目录(即通过 NFS 或 CIFS,如第十二章中所解释的,管理本地存储和文件系统),但您不希望他们能够在系统中运行命令。为此,我们可以使用一个非常特殊的 shell,即nologin
shell。让我们使用usermod
将该 shell 分配给usertest
用户账户:
[root@rhel8 ~]# usermod -s /sbin/nologin usertest
[root@rhel8 ~]# grep usertest /etc/passwd
usertest:x:1001:1001::/home/usertest:/sbin/nologin
[root@rhel8 ~]# su - usertest
Last login: sun jan 24 16:18:07 CET 2021 on pts/0
This account is currently not available.
[root@rhel8 ~]# usermod -s /bin/bash usertest
[root@rhel8 ~]# su - usertest
Last login: sun jan 24 16:18:15 CET 2021 on pts/0
[usertest@rhel8 ~]$
请注意,这次我们正在审查/etc/passwd
中的更改,因为这是修改所应用的地方。
如您所见,很容易为任何用户设置密码过期的值,锁定它们,或限制对系统的访问。让我们继续进行更多的管理任务以及如何委派管理员访问权限。
为管理任务配置 sudo 访问权限
在 RHEL 中,有一种方法可以将管理访问权限委派给用户,这是通过一个名为sudo的工具来实现的,它代表Super User Do。
它不仅允许您授予用户或组完整的管理员特权,还可以对某些用户可以执行的特权命令进行非常精细的控制。
让我们首先了解默认配置以及如何更改它。
理解 sudo 配置
该工具的主要配置文件位于/etc/sudoers
中,并包括默认配置的这一部分:
root ALL=(ALL) ALL
%wheel ALL=(ALL) ALL
## Read drop-in files from /etc/sudoers.d (the # here does not mean a comment)
#includedir /etc/sudoers.d
让我们逐行分析这些行,以了解它们的作用。
第一行使root
用户可以使用sudo
运行任何命令:
root ALL=(ALL) ALL
第二行使wheel
组中的用户可以使用sudo
运行任何命令。我们稍后将解释语法的细节:
%wheel ALL=(ALL) ALL
重要提示
除非有重要原因,否则请不要禁用wheel
组指令。其他程序期望它可用,并且禁用它可能会导致一些问题。
第三行和所有以#
开头的行都被视为注释,它们仅用于添加描述性内容,对最终配置没有影响:
## Read drop-in files from /etc/sudoers.d (the # here does not mean a comment)
第四行是对前一规则的唯一例外。此行使目录/etc/sudoers.d
成为配置文件的来源。我们可以在该文件夹中放置一个文件,sudo
将使用它:
#includedir /etc/sudoers.d
最后一条规则的例外是以~
结尾或包含.
(点)字符的文件。
正如您所见,默认配置使root
和wheel
组的成员能够使用sudo
作为管理员运行任何命令。
最简单的方法是将用户添加到wheel
组,以授予该用户完整的管理员特权。修改usertest
账户使其成为管理员账户的示例如下:
[root@rhel8 ~]# usermod -aG wheel usertest
[root@rhel8 ~]# groups usertest
usertest : usertest wheel
重要提示
对于云实例,账户 root 没有分配有效密码。为了能够管理所述的云实例,在某些云中,如wheel
组。在 AWS 的情况下,默认用户账户是ec2-user
。在其他云中,还创建了一个自定义用户,并将其添加到wheel
组中。
与其他敏感文件一样,为了编辑/etc/sudoers
文件,有一个工具不仅可以确保两个管理员不同时编辑它,还可以确保语法正确。在这种情况下,编辑它的工具是visudo
。
使用 sudo 运行管理员命令
在这些示例中,我们将使用user
账户。您可能还记得,在第一章中,安装 RHEL8,我们启用了请求账户成为管理员的复选框。在幕后,该账户被添加到wheel
组中,因此我们可以开始使用sudo
来运行管理员命令。
让我们使用user
账户登录并尝试运行一个管理命令,比如adduser
:
[root@rhel8 ~]# su - user
Last login: dom ene 24 19:40:31 CET 2021 on pts/0
[user@rhel8 ~]$ adduser john
adduser: Permission denied.
adduser: cannot lock /etc/passwd; try again later.
正如您所见,我们收到了Permission denied
的错误消息。要能够使用sudo
运行它,我们只需要将其添加到命令行的开头:
[user@rhel8 ~]$ sudo adduser john
We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:
#1) Respect the privacy of others.
#2) Think before you type.
#3) With great power comes great responsibility.
[sudo] password for user:
[user@rhel8 ~]$ id john
uid=1002(john) gid=1002(john) groups=1002(john)
在这种情况下,我们看到第一次成功运行sudo
时显示了一个警告消息。然后我们被要求输入我们自己的密码 - 不是管理员密码,因为可能根本就没有管理员密码,而是我们为运行sudo
的用户设置的密码。一旦密码正确输入,命令就会运行并在系统日志中注册:
jan 24 19:44:26 rhel8.example.com sudo[2879]: user : TTY=pts/0 ; PWD=/home/user ; USER=root ; COMMAND=/sbin/adduser john
重要提示
一旦成功运行了sudo
,它将记住验证 15 分钟(作为默认行为)。这样做是为了在一个会话中运行多个管理命令时,你不必一遍又一遍地输入密码。要将其增加到 30 分钟,我们可以使用visudo
添加以下行:Defaults:USER timestamp_timeout=30
。
有时候你想要一个交互式会话,这样就不需要一遍又一遍地输入sudo
。为此,-i
选项非常有用。让我们试一下:
[user@rhel8 ~]$ sudo -i
[sudo] password for user:
[root@rhel8 ~]#
现在让我们开始定制sudoers
文件中sudo
的配置。
配置 sudoers
在前一节中,我们已经看到了默认的/etc/sudoers
文件的详细信息。让我们看几个例子,如何进行更细粒度的配置。
让我们首先让sudo
在sudoers
文件中运行管理员命令时不需要为wheel
组中的用户请求密码。我们可以运行visudo
,并使以%wheel
开头的行如下所示:
%wheel ALL=(ALL) NOPASSWD: ALL
保存它。注意配置文件中有一行被注释掉的配置。现在让我们试一下:
[user@rhel8 ~]$ sudo adduser ellen
[user@rhel8 ~]$ id ellen
uid=1003(ellen) gid=1003(ellen) groups=1003(ellen)
现在我们可以使用你喜欢的编辑器创建一个文件,使新用户账户ellen
能够运行管理员命令。让我们创建/etc/sudoers.d/ellen
文件,并添加以下内容:
ellen ALL=(ALL) ALL
通过这个,我们正在使用/etc/sudoers.d
目录来扩展sudo
配置。
尽管它不是 RHCSA 考试的一部分,我们将在这里回顾sudoers
的详细配置。正如你所看到的,有三个字段,用空格或制表符分隔,来定义配置文件中的策略。让我们来回顾一下:
- 第一个字段是指定受策略影响的对象:
-
我们可以通过简单地在第一个字段中放入用户名来添加用户。
-
我们可以通过在第一个字段中使用
%
字符来添加组。
- 第二个字段是策略适用的位置:
-
到目前为止,我们使用了
ALL=(ALL)
来指定一切。 -
在这个字段的第一部分,我们可以定义要运行的计算机组,比如
SERVERS=10.0.0.0/255.255.255.0
。 -
在第二部分,我们可以指定命令,比如
NETWORK=/usr/sbin/ip
。 -
括号中是可以用来运行命令的用户账户。
- 第三个字段是指定哪些命令将使用密码,哪些不会。
语法如下:
user hosts = (run-as) commands
让我们看一个例子:
Runas_AliasDB = oracle
Host_Alias SERVERS=10.0.0.0/255.255.255.0
Cmnd_Alias NETWORK=/ust/sbin/ip
pete SERVERS=NETWORK
julia SERVERS=(DB)ALL
我们已经看到了如何在 RHEL 中为用户提供管理访问权限,甚至如何以非常细粒度的方式进行。现在让我们继续看看如何处理文件权限的部分。
检查、回顾和修改文件权限
到目前为止,我们已经学会了如何创建用户和组,甚至为它们提供管理能力。现在是时候看看权限是如何在文件和目录级别工作的了。
正如你记得的,在第三章,基本命令和简单 Shell 脚本中,我们已经看到了如何查看应用于文件的权限。现在让我们回顾一下并深入了解。
让我们使用-l
选项列出一些示例文件的权限信息。记得以root
用户身份运行(或使用sudo
):
[root@rhel8 ~]# ls -l /usr/bin/bash
-rwxr-xr-x. 1 root root 1150704 jun 23 2020 /usr/bin/bash
[root@rhel8 ~]# ls -l /etc/passwd
-rw-r--r--. 1 root root 1324 ene 24 21:35 /etc/passwd
[root@rhel8 ~]# ls -l /etc/shadow
----------. 1 root root 1008 ene 24 21:35 /etc/shadow
[root@rhel8 ~]# ls -ld /tmp
drwxrwxrwt. 8 root root 172 ene 25 17:35 /tmp
记住,在 Linux 中,一切都是文件。
现在让我们使用/usr/bin/bash
的权限来回顾一下权限包括的五个不同信息块:
-rwxr-xr-x.
这些块如下:
让我们再次回顾一下,因为它们非常重要。
块 1 是文件可能具有的特殊权限。如果它是一个常规文件并且没有特殊权限(就像在这种情况下一样),它将显示为-
:
-
目录将显示为
d
。 -
链接,通常是符号链接,将显示为
l
。 -
特殊权限以不同的用户或组运行文件,称为
s
。 -
一个特殊权限,以便所有者只能删除或重命名文件,称为
t
。
块 2 是文件所有者的用户的权限,由三个字符组成:
-
第一个,
r
,是分配的读权限。 -
第二个,
w
,是分配的写权限。 -
第三个,
x
,是可执行权限。(请注意,目录的可执行权限意味着能够进入它们。)
块 3 是组的权限。它由相同的三个字符组成,用于读、写和执行(rwx
)。在这种情况下,缺少写权限。
块 4 是其他的权限。它也由相同的三个字符组成,用于读、写和执行(rwx
),就像之前一样。和之前的块一样,缺少写权限。
块 5 表示文件应用了SELinux上下文。有关此主题的更多信息,请参见第十章,使用 SELinux 使系统更加安全。
要更改文件的权限,我们将使用chmod
命令。
首先,让我们创建一个文件:
[root@rhel8 ~]# touch file.txt
[root@rhel8 ~]# ls -l file.txt
-rw-r--r--. 1 root root 0 ene 27 18:30 file.txt
正如您所看到的,文件是以您的用户名作为所有者,您的主要组作为组,并且具有一组默认权限创建的。新创建的文件权限的默认值由umask
定义,在 RHEL 中,新创建的文件权限的默认值如下:
-
用户:读和写
-
组:读
-
其他人:读
要使用chmod
更改权限,我们使用三个字符指定更改:
- 第一个,确定更改影响的对象:
-
u
:用户 -
g
:组 -
o
:其他
- 第二个是添加或删除权限:
-
+
:添加 -
-
:删除
- 第三个,确定要更改的权限:
-
r
:读 -
w
:写 -
x
:执行
因此,要向组添加写权限,我们可以运行以下命令:
[root@rhel8 ~]# chmod g+w file.txt
[root@rhel8 ~]# ls -l file.txt
-rw-rw-r--. 1 root root 0 ene 27 18:30 file.txt
要删除其他人的读权限,我们运行以下命令:
[root@rhel8 ~]# chmod o-r file.txt
[root@rhel8 ~]# ls -l file.txt
-rw-rw----. 1 root root 0 ene 27 18:30 file.txt
权限以四个八进制数字存储。这意味着特殊权限以 0 到 7 的数字存储,与用户、组和其他权限的存储方式相同,每个权限都有 0 到 7 的数字。
一些示例如下所示:
它是如何工作的?我们为每个权限分配一个数字(2 的幂):
-
无:0
-
执行:2⁰ = 1
-
写:2¹ = 2
-
读:2² = 4
我们添加它们:
rwx = 4 + 2 + 1 = 7
rw- = 4 + 2 = 6
r-x = 4 + 1 = 5
r-- = 4
--- = 0
这就是我们可以使用数字分配权限的方式。现在让我们试一试:
[root@rhel8 ~]# chmod 0755 file.txt
[root@rhel8 ~]# ls -l file.txt
-rwxr-xr-x. 1 root root 0 ene 27 18:30 file.txt
[root@rhel8 ~]# chmod 0640 file.txt
[root@rhel8 ~]# ls -l file.txt
-rw-r-----. 1 root root 0 ene 27 18:30 file.txt
[root@rhel8 ~]# chmod 0600 file.txt
[root@rhel8 ~]# ls -l file.txt
-rw-------. 1 root root 0 ene 27 18:30 file.txt
正如我们之前所说,权限的默认配置是由umask
设置的。我们可以很容易地看到这个值:
[root@rhel8 ~]# umask
0022
所有新创建的文件都删除了执行
权限(1
)。
使用这个umask
,0022
,这是 RHEL 中默认提供的,我们将删除组
和其他
的写
权限(2
)。
即使不建议更改umask
,我们可以尝试一下来了解它是如何工作的。让我们从使用最宽松的umask
,0000
开始,看看如何将所有读
和写
权限分配给新创建的文件:
[root@rhel8 ~]# umask 0000
[root@rhel8 ~]# touch file2.txt
[root@rhel8 ~]# ls -l file2.txt
-rw-rw-rw-. 1 root root 0 ene 27 18:33 file2.txt
现在让我们使用更严格的umask
来限制组
和其他
的权限:
[root@rhel8 ~]# umask 0066
[root@rhel8 ~]# touch file3.txt
[root@rhel8 ~]# ls -l file3.txt
-rw-------. 1 root root 0 ene 27 18:33 file3.txt
如果我们尝试更高的数字,它将无法工作并返回错误:
[root@rhel8 ~]# umask 0088
-bash: umask: 0088: octal number out of range
您可以看到0066
和0077
的效果是一样的:
[root@rhel8 ~]# umask 0077
[root@rhel8 ~]# touch file4.txt
[root@rhel8 ~]# ls -l file4.txt
-rw-------. 1 root root 0 ene 27 18:35 file4.txt
让我们在我们的会话中重新建立umask
,以默认值继续练习:
[root@rhel8 ~]# umask 0022
现在,我们可能需要为特定用户或组创建一个目录,或更改文件的所有者。为了能够更改文件或目录的所有权,使用chown
或chgrp
工具。让我们看看它是如何工作的。让我们移动到/var/tmp
并为finance
和accounting
创建文件夹:
[root@rhel8 ~]# cd /var/tmp/
[root@rhel8 tmp]# mkdir finance
[root@rhel8 tmp]# mkdir accounting
[root@rhel8 tmp]# ls -l
total 0
drwxr-xr-x. 2 root root 6 ene 27 19:35 accounting
drwxr-xr-x. 2 root root 6 ene 27 19:35 finance
现在让我们创建finance
和accounting
的组:
[root@rhel8 tmp]# groupadd finance
[root@rhel8 tmp]# groupadd accounting
groupadd: group 'accounting' already exists
在这个例子中,accounting
组已经创建。让我们使用chgrp
为每个目录更改组:
[root@rhel8 tmp]# chgrp accounting accounting/
[root@rhel8 tmp]# chgrp finance finance/
[root@rhel8 tmp]# ls -l
total 0
drwxr-xr-x. 2 root accounting 6 ene 27 19:35 accounting
drwxr-xr-x. 2 root finance 6 ene 27 19:35 finance
现在我们为sonia
和matilde
创建用户,并将它们分别分配给finance
和accounting
:
[root@rhel8 tmp]# adduser sonia
[root@rhel8 tmp]# adduser matilde
[root@rhel8 tmp]# usermod -aG finance sonia
[root@rhel8 tmp]# usermod -aG accounting matilde
[root@rhel8 tmp]# groups sonia
sonia : sonia finance
[root@rhel8 tmp]# groups matilde
matilde : matilde accounting
现在我们可以为每个用户在其组文件夹下创建一个个人文件夹:
[root@rhel8 tmp]# cd finance/
[root@rhel8 finance]# mkdir personal_sonia
[root@rhel8 finance]# chown sonia personal_sonia
[root@rhel8 finance]# ls -l
total 0
drwxr-xr-x. 2 sonia root 6 ene 27 19:44 personal_sonia
[root@rhel8 finance]# chgrp sonia personal_sonia/
[root@rhel8 finance]# ls -l
total 0
drwxr-xr-x. 2 sonia sonia 6 ene 27 19:44 personal_sonia
有一种方法可以使用:
分隔符指定用户和组给chown
。让我们用matilde
试试:
[root@rhel8 tmp]# cd ../accounting
[root@rhel8 accounting]# mkdir personal_matilde
[root@rhel8 accounting]# chown matilde:matilde \
personal_matilde
[root@rhel8 accounting]# ls -l
total 0
drwxr-xr-x. 2 matilde matilde 6 ene 27 19:46 personal_matilde
如果我们想要更改整个分支的权限,我们可以使用chown
命令的-R
选项进行递归。让我们复制一个分支并更改其权限:
[root@rhel8 accounting]# cp -rv /usr/share/doc/audit personal_matilde/
'/usr/share/doc/audit' -> 'personal_matilde/audit'
'/usr/share/doc/audit/ChangeLog' -> 'personal_matilde/audit/ChangeLog'
'/usr/share/doc/audit/README' -> 'personal_matilde/audit/README'
'/usr/share/doc/audit/auditd.cron' -> 'personal_matilde/audit/auditd.cron'
[root@rhel8 accounting]# chown -R matilde:matilde \
personal_matilde/audit
[root@rhel8 accounting]# ls -l personal_matilde/audit/
total 20
-rw-r--r--. 1 matilde matilde 271 ene 28 04:56 auditd.cron
-rw-r--r--. 1 matilde matilde 8006 ene 28 04:56 ChangeLog
-rw-r--r--. 1 matilde matilde 4953 ene 28 04:56 README
通过这些,我们对 RHEL 中的权限、它们的默认行为以及如何使用它们有了很好的理解。
让我们继续讨论一些关于权限的更高级的话题。
使用特殊权限
正如我们在前一节中看到的,有一些特殊权限可以应用到文件和目录。让我们从回顾 Set-UID(或suid)和 Set-GUID(或sgid)开始。
理解和应用 Set-UID
让我们回顾一下 Set-UID 如何应用到文件和目录:
-
应用到文件的 Set-UID 权限:当应用到可执行文件时,该文件将以文件所有者运行,应用权限。
-
应用到目录的 Set-UID 权限:没有效果。
让我们检查一个具有 Set-UID 的文件:
[root@rhel8 ~]# ls -l /usr/bin/passwd
-rwsr-xr-x. 1 root root 33544 dic 13 2019 /usr/bin/passwd
passwd
命令需要root
权限才能更改/etc/shadow
文件中的哈希值。
要应用这些权限,我们可以使用chmod
命令,应用u+s
权限:
[root@rhel8 ~]# touch testsuid
[root@rhel8 ~]# ls -l testsuid
-rw-r--r--. 1 root root 0 ene 28 05:16 testsuid
[root@rhel8 ~]# chmod u+s testsuid
[root@rhel8 ~]# ls -l testsuid
-rwsr--r--. 1 root root 0 ene 28 05:16 testsuid
提示
在将root
分配给文件时,给文件分配suid
时要非常小心。如果您将文件的写权限留下,任何用户都可以更改内容并以root
身份执行任何操作。
理解和应用 Set-GID
让我们回顾一下 Set-GID 如何应用到文件和目录:
-
应用到文件的 Set-GID 权限:当应用到可执行文件时,该文件将以文件的组权限运行。
-
应用到目录的 Set-GID 权限:在该目录中创建的新文件将具有该目录的组应用到它们。
让我们检查一个具有 Set-GID 的文件:
[root@rhel8 ~]# ls -l /usr/bin/write
-rwxr-sr-x. 1 root tty 21232 jun 26 2020 /usr/bin/write
我们可以尝试使用chmod
命令将权限应用到文件,使用g+s
:
[root@rhel8 ~]# touch testgid
[root@rhel8 ~]# chmod g+s testgid
[root@rhel8 ~]# ls -l testgid
-rw-r-sr--. 1 root root 0 ene 28 05:23 testgid
现在让我们尝试一下目录。让我们回到我们之前的例子:
[root@rhel8 ~]# cd /var/tmp/
[root@rhel8 tmp]# ls
accounting finance
[root@rhel8 tmp]# chmod g+s accounting finance
[root@rhel8 tmp]# ls -l
total 0
drwxr-sr-x. 3 root accounting 30 ene 27 19:46 accounting
drwxr-sr-x. 3 root finance 28 ene 27 19:44 finance
[root@rhel8 tmp]# touch finance/testfinance
[root@rhel8 tmp]# ls -l finance/testfinance
-rw-r--r--. 1 root finance 0 ene 28 05:27 finance/testfinance
[root@rhel8 tmp]# touch accounting/testaccounting
[root@rhel8 tmp]# ls -l accounting/testaccounting
-rw-r--r--. 1 root accounting 0 ene 28 05:27 accounting/testaccounting
您可以看到,在将 Set-GID 应用到文件夹后,它们显示了组的s
权限(加粗显示)。此外,在这些目录中创建新文件时,分配给它们的组与父目录的组相同(也加粗显示)。这样我们就确保了组权限被正确分配。
使用粘着位
最后要使用的权限是粘着位。它只对目录产生影响,它的作用很简单:当用户在具有粘着位的目录中创建文件时,只有该用户才能编辑或删除该文件。
让我们来看一个例子:
[root@rhel8 ~]# ls -ld /tmp
drwxrwxrwt. 8 root root 172 ene 28 04:31 /tmp
我们可以将这些应用到前面的例子中,也可以使用chmod
来使用o+t
:
[root@rhel8 ~]# cd /var/tmp/
[root@rhel8 tmp]# ls -l
total 0
drwxr-sr-x. 3 root accounting 52 ene 28 05:27 accounting
drwxr-sr-x. 3 root finance 47 ene 28 05:27 finance
[root@rhel8 tmp]# chmod o+t accounting finance
[root@rhel8 tmp]# ls -l
total 0
drwxr-sr-t. 3 root accounting 52 ene 28 05:27 accounting
drwxr-sr-t. 3 root finance 47 ene 28 05:27 finance
让我们试一试。我们将用户sonia
添加到accounting
组。我们将为/var/tmp/accounting
目录的组授予写权限。然后,我们将使用用户matilde
创建一个文件,并尝试使用用户sonia
删除它。让我们开始:
[root@rhel8 ~] # usermod -aG accounting sonia
[root@rhel8 ~]# cd /var/tmp/
[root@rhel8 tmp]# chmod g+w accounting
[root@rhel8 tmp]# ls -l
total 0
drwxrwsr-t. 3 root accounting 52 ene 28 05:27 accounting
drwxr-sr-t. 3 root finance 47 ene 28 05:27 finance
[root@rhel8 tmp]# su - matilde
Last login: jue ene 28 05:41:09 CET 2021 on pts/0
[matilde@rhel8 ~]$ cd /var/tmp/accounting/
[matilde@rhel8 accounting]$ touch teststickybit
[matilde@rhel8 accounting]$ exit
logout
[root@rhel8 tmp]# su - sonia
[sonia@rhel8 ~]$ cd /var/tmp/accounting/
[sonia@rhel8 accounting]$ ls -l teststickybit
-rw-rw-r--. 1 matilde accounting 0 Jan 28 05:43 teststickybit
[sonia@rhel8 accounting]$ rm -f teststickybit
rm: cannot remove 'teststickybit': Operation not permitted
提示
特殊权限的数字值为:suid
= 4
;sgid
= 2
;粘着位
= 1
。
通过这些,我们已经完成了如何管理 RHEL 中的权限。
总结
在本章中,我们已经回顾了 RHEL 中使用传统权限实现的权限管理系统。我们已经学会了如何创建用户帐户和组,以及如何确保密码被正确管理。我们还学会了系统中密码是如何存储的,甚至学会了如何阻止用户访问 shell。我们创建了文件和文件夹,为它们分配了权限,并确保用户可以遵守一套规则进行协作。
这些是在 RHEL 中管理访问权限的基础知识,当管理系统时,这将非常有用,以避免安全问题。由于这是一个非常重要的话题,我们建议仔细阅读本章内容,阅读所示命令的man
页面,并努力对该主题有一个真正的理解,这将避免将来出现任何不舒服的情况。
现在,您已经准备好开始为用户提供服务并管理他们的访问权限了,这将是我们下一章要涵盖的内容。请记住要在这里学到的知识进行充分的练习和测试。
第六章:启用网络连接
当我们在第一章安装系统时,我们启用了网络接口。然而,网络配置是,或者可以是,更多的。
连接到网络的服务器可能需要额外的接口来配置其他网络;例如,用于访问备份服务器,从其他服务器执行内部服务,甚至访问存储,该存储不是直接通过存储阵列网络(SAN)呈现为本地驱动器,而是作为例如Internet Small Computer System Interface (iSCSI) 驱动器。
此外,服务器可能使用冗余网络功能,以确保在卡片、交换机等出现故障时,服务器仍然可以被访问并正常运行。
在本章中,我们将学习如何使用不同方法为我们的 RHEL 机器定义网络配置,并进行一些基本的网络故障排除。
这些知识将是关键的,因为服务器通常用于向其他系统提供服务,我们需要网络来实现这一目的。
在本章中,我们将涵盖以下主题:
-
探索 RHEL 中的网络配置
-
配置文件和 NetworkManager
-
使用 IPv4 和 IPv6 配置网络接口
-
配置主机名和主机名解析(DNS)
-
防火墙配置概述
-
测试连通性
让我们开始网络实践吧!
技术要求
您可以继续使用我们在本书开头创建的虚拟机第一章,安装 RHEL8。此外,为了测试网络通信,创建第二个虚拟机或重用我们在前几章中创建的虚拟机以测试Network Time Protocol (NTP) 配置可能会很有用,因为我们将使用它来检查连通性。文本中将指示所需的任何附加软件包。本章所需的任何附加文件可以从github.com/PacktPublishing/Red-Hat-Enterprise-Linux-8-Administration
下载。
探索 RHEL 中的网络配置
网络由不同的设备组成,它们被互联起来,以便信息和资源可以在它们之间共享;例如,互联网访问、打印机、文件等。
网络自计算机诞生以来就一直存在。最初,最常见的是非 IP-based 网络,通常用于在本地网络中共享数据,但随着互联网服务的扩展和对应用程序或远程服务的需求,IP 网络得到了扩展,并引入了内部网的概念,其中使用Transmission Control Protocol/Internet Protocol (TCP/IP)作为传输,应用程序开始更像互联网服务(甚至基于互联网服务)。
基于 IP 的网络迁移还使其他协议(如Network Basic Input/Output System (NetBIOS))适应了它,以便它们可以在其上运行(它曾经在NetBIOS Extended User Interface (NetBEUI)上运行,即使其他网络如InfiniBand或Remote Direct Memory Access (RDMA)仍在使用,但它们不像 TCP/IP 那样常见)。
当然,TCP/IP 是建立在其他协议之上的。您可以在www.redhat.com/sysadmin/osi-model-bean-dip
检查 OSI 层定义。然而,仍涉及一些概念。当我们熟悉 TCP/IP 和网络时,我们将涵盖这些内容。
在我们进入实际细节之前,我们需要澄清一些我们从现在开始将使用的常见 TCP/IP 和网络关键词:
-
IP 地址:这是用于与网络上其他设备交互的地址。
-
255.255.255.0
或/24
。 -
网关:这是设备的 IP 地址,当目标设备在我们的网络掩码之外时,它将获取我们所有的流量,以便我们无法直接到达它。
-
DNS:这是服务器或服务器的 IP 地址,用于将域名转换为 IP 地址,以便主机可以连接到它们。
-
MAC 地址:这是物理接口地址。它对于每张卡是唯一的,并帮助在网络中识别卡,以便将适当的流量发送到它。
-
网络接口卡(NIC):这张卡允许我们的设备连接到网络。它可能是无线的、有线的等等。
-
扩展服务集识别(ESSID):这是无线网络的名称。
-
虚拟专用网络(VPN):这是在客户端和服务器之间创建的虚拟网络。一旦建立,它允许您直接连接到服务,就好像它们是本地的,即使客户端和服务器在不同的地方。例如,VPN 网络用于允许远程工作者使用他们的私人互联网连接连接到公司网络。
-
虚拟局域网(VLAN):这允许我们在实际布线之上定义虚拟网络。然后,我们可以使用特定的头字段来使它们被网络设备正确理解和处理。
-
IPv6:这是 IPv4 的替代协议,而 IPv4 仍然是今天网络中主要的协议。
在接下来的部分中,当我们解释在 Red Hat Enterprise Linux(RHEL)系统中如何设置和定义网络时,我们将使用其中一些术语。
一般来说,当系统连接时,网络上的设备之间建立了一些关系。有时,一些主机是服务提供者,通常被称为服务器,而消费者被称为客户端。当网络中的系统扮演角色时,这些网络被称为点对点(P2P)网络。
在接下来的部分,我们将熟悉配置文件和在系统中配置网络的不同方法。
了解配置文件和 NetworkManager
现在我们已经了解了一些网络的关键词和概念,是时候看看我们可以在哪里使用它们来使我们的系统联网了。
传统上,网络接口是通过系统中的文本文件进行配置的,在/etc/sysconfig/network-scripts/
文件夹下。这些脚本是通过network-scripts
包提供的实用程序处理的,该包负责使用定义的配置使网络堆栈正常运行。
重要提示
尽管network-scripts
包是可用的并且可以安装,但它被认为是已弃用的,这意味着该包是提供和可用的,但在未来的操作系统的主要版本中可能会消失,因此它们只会被提供以便过渡到更新的方法。
NetworkManager 是一个实用程序,于 2004 年创建,旨在使桌面用户的网络配置和使用更加简单。在那时,所有的配置都是通过文本文件完成的,而且更多或更少是静态的。一旦系统连接到网络,信息几乎没有变化。随着无线网络的采用,需要更多的灵活性来自动化和简化连接到不同网络、不同配置文件、VPN 等。
NetworkManager 是为了填补这些空白而创建的,旨在成为许多发行版中使用的组件,但从一个新的角度来看,例如,它在启动时查询硬件抽象层(HAL)以了解可用的网络设备及其更改。
想象一台笔记本电脑系统;它可以连接到有线电缆,当您将其移动到另一个位置或小隔间时断开连接,可以连接到无线网络等等。所有这些事件都会传递给 NetworkManager,它会重新配置网络接口、路由、与无线网络进行身份验证,并使用户的生活比传统方式更加轻松。
提示
可以使用几个命令查询连接到系统的硬件,具体取决于硬件的连接方式;例如,通过诸如lsusb
、lspci
或lshw
(分别通过安装usbutils
、pciutils
和lshw
软件包提供)等实用程序。
在下面的屏幕截图中,我们可以看到与 NetworkManager 相关的可用软件包,通过dnf search network manager
命令获取:
图 6.1-在 Red Hat Enterprise Linux 8 系统中可用于安装的 NetworkManagermanager 相关软件包
NetworkManagermanager
配置在/etc/NetworkManager
文件夹中的文件中,特别是NetworkManager.conf
和该文件夹中可用的文件:
-
conf.d
-
dispatcher.d
-
dnsmasq-shared.d
-
dnsmasq.d
-
system-connections
不记得 dispatcher 是什么?记得使用man networkmanager
获取详细信息!
NetworkManager 的 man 页面解释了这些脚本是根据网络事件按字母顺序执行的,并将接收两个参数:事件的设备名称和操作。
您可以执行以下几种操作:
-
pre-up
:接口已连接到网络,但尚未激活。必须在连接被通知为已激活之前执行脚本。 -
up
:接口已激活。 -
pre-down
:接口正在停用,但尚未从网络断开连接。在强制断开连接的情况下(丢失无线连接或丢失载波),这不会被执行。 -
down
:接口已停用。 -
vpn-up
/vpn-down
/vpn-pre-up
/vpn-pre-down
:类似于前面的接口,但用于 VPN 连接。 -
hostname
:主机名已更改。 -
dhcp4-change
/dhcp6-change
:DHCP 租约已更改(已续订、已重新绑定等)。 -
connectivity-change
:连接转换,如无连接,系统上线等。
现在我们已经了解了一些关于 NetworkManager 及其工作和设计的知识,让我们学习如何配置网络接口。
使用 IPv4 和 IPv6 配置网络接口
有几种配置网络接口和几种网络配置的方法。这将帮助我们确定我们需要做什么以及所需的参数和设置。
让我们看一些例子:
-
服务器可能有两个或更多的网络接口卡(NIC)以实现冗余,但一次只有一个处于活动状态。
-
服务器可能使用干线网络,并要求我们在其上定义 VLAN 以访问或提供网络中的不同服务。
-
两个或更多个 NIC 可能会组合在一起,通过组队提供增加的输出和冗余。
也可以通过几种方式进行配置:
-
nmtui
:用于配置网络的基于文本的界面 -
nmcli
:NetworkManager 的命令行界面 -
nm-connection-editor
:可用于图形环境的图形工具 -
通过文本配置文件
重要提示
在编辑网络配置之前,请确保可以以其他方式访问正在配置的系统。对于服务器,可以通过远程管理卡或物理控制台访问。配置错误可能导致系统无法访问。
在我们继续之前,让我们了解一些关于 IPv4 和 IPv6 的知识
IPv4 和 IPv6...这是什么意思?
IPv4 是在 1983 年创建的,使用 32 位地址空间,提供 2³²个唯一地址(4,294,967,296
),但在这些可能的地址中,有大块保留用于特殊用途。IPv6 在 2017 年被批准为互联网标准,是我写作时的最新版本,它使用 128 位地址空间,即 2¹²⁸(3.4 x 10³⁸个地址)。
长话短说,当时 IPv4 地址数量似乎很大,但今天,手机、平板电脑、计算机、笔记本电脑、服务器、灯泡、智能插座和所有其他物联网(IoT)设备都需要 IP 地址,公共 IP 地址的数量已经用尽,这意味着无法再分配更多。这导致一些互联网服务提供商(ISP)使用诸如运营商级网络地址转换(CGNAT)之类的技术,类似于私人网络所做的,这使得来自多个设备的所有流量看起来都来自同一个 IP,并且设备在两个网络上进行交互(路由器),以便对原始请求者的出站和入站数据包进行正确路由。
那为什么没有 IPv6 呢?主要问题是 IPv4 和 IPv6 不兼容,即使 IPv6 在 1998 年是一个草案,也并非所有网络设备都兼容它,可能尚未经过测试。请查看www.ripe.net/support/training/videos/ipv6/transition-mechanisms
获取更多详细信息。
在下一节中,我们将学习如何使用名为nmtui
的 NetworkManager 的基于文本的用户界面来配置网络接口。
使用 nmtui 配置接口
nmtui
提供了一个基于文本的配置界面。这是在终端上运行nmtui
时会看到的初始屏幕:
图 6.2 - nmtui 欢迎屏幕显示可以执行的操作菜单
让我们探索接口的可用选项。在这种情况下,让我们选择编辑连接。在出现的屏幕上,向下移动并编辑我们系统中的有线连接选项,以进入以下屏幕:
图 6.3 - 编辑连接页面,IPv4 选项已展开
很难为每个步骤展示截图,因为文本界面的优势之一是我们可以将许多选项压缩成一个简单的屏幕。然而,前面的截图使我们能够轻松理解每个所需参数:
-
IP 地址
-
子网掩码
-
网关
-
搜索域
-
路由
如您所见,有复选框可用于忽略路由或在连接设置为“自动”时获取的 DNS 参数。此外,还有其他接口选项:“禁用”,“链路本地”,“手动”和“共享”。
让我们讨论“自动”选项,这意味着接口将被设置为自动配置。这是配置的最常见设置之一。不过,这并不意味着一切都是自动完成的。让我们深入了解一下。
在一个网络(企业、私人等)中,通常会有一个专门的服务或服务器执行动态主机路由协议(DHCP)。DHCP 是在 TCP/IP 之上运行的协议,允许您动态配置主机,使用之前由网络管理员或某个设备及其默认设置进行的配置。
DHCP 允许您自动配置(从客户端)网络配置的许多方面,如 IP、子网掩码、网关、DNS、搜索域、时间服务器等。接收到的配置将被分配一个在一段时间内有效的租约。之后,系统会尝试更新它,或者如果系统被关闭或断开连接,租约将被释放。
通常,DHCP 配置被认为与动态 IP 绑定在一起,但请记住,DHCP 服务器可以使用两种不同的方法:可以重复使用不同系统连接的 IP 池,也可以将 MAC 地址固定映射到静态 IP。
例如,让我们考虑一个192.168.1.0/24
子网。
我们可以将 ISP 路由器定义为 IP192.168.1.1
,因为子网(/24
)的原因,这意味着 IPv4 地址的最后一部分可以从 0 到 255 范围。
利用该 IP 范围,我们可以设置主机从最后 100 个 IP 中的动态配置和动态 IP 中获取,将前面的 IP 留给固定设备(即使它们动态获取配置),如打印机、存储设备等。
正如我们之前提到的,我们可以为服务器创建预留,但通常对于总是使用相同地址的设备,配置静态地址也是常见做法。这样,如果 DHCP 服务器不可用,服务器仍然可以从其他服务或配置了静态地址的其他服务器/设备中访问。
提示
只是为了熟悉这个概念,IP 地址在 IPv4 中以点分隔四组数字表示,例如192.168.2.12
,而在 IPv6 中,数字以:
分隔;例如2001:db8:0:1::c000:207
。
使用 nm-connection-editor 配置接口
如果我们的系统已安装了图形环境,而我们的测试系统没有安装图形环境,我们可以使用图形配置工具。如果没有安装,请在图形会话内的 shell 控制台中执行dnf install nm-connection-editor
。
提示
要安装图形界面,您可以运行dnf groupinstall "Server with GUI" -y
命令,或者在安装过程中选择它。
在下面的屏幕截图中,我们可以看到通过执行nm-connection-editor
打开的窗口。它类似于本章前面显示的nmtui
的文本界面:
图 6.4 - nm-connection-editor 的初始屏幕
在这里,我们可以看到+、-和齿轮按钮,分别用于添加/删除或配置突出显示的连接。
让我们点击有线连接选项,然后点击齿轮图标打开详细信息:
图 6.5 - 编辑网络连接的对话框
在对话框中,我们可以看到简单命令行配置工具中的字段,以及每个选项组的额外字段和不同的选项卡。
要记住的重要字段是在通用选项卡中用于自动连接优先**的字段。这使我们的系统在有连接可用时自动启用该网卡。
通过检查不同的选项卡,您会发现有很多选择,比如标记连接为计量。这意味着,例如,如果通过手机进行连接,如果网络使用没有受到控制,可能会有额外的费用。
当我们创建额外的网络时,我们可以根据系统中安装的软件包定义物理或虚拟设备(如果您还记得我们在搜索 NetworkManager 时看到的软件包列表,我们有不同 VPN、Wi-Fi 等软件包),如下面的屏幕截图所示:
图 6.6 – 带有 Wi-Fi、OpenVPN、PPTP、蓝牙等插件的 nm-connection-editor 已安装
对于服务器环境,最常见的网络类型是绑定、桥接和团队(以太网的一部分),而对于桌面电脑,最常见的网络类型是以太网、Wi-Fi和宽带。
每种类型的连接都有一些要求。例如,对于绑定、桥接和团队,我们需要多个可以组合的网络接口。
现在,让我们继续在下一节中审查nmcli
的用法。
使用 nmcli 配置接口
nmcli
是 NetworkManager 的命令行界面。它不仅允许我们检查,还允许我们配置系统中的网络接口,即使使用它可能需要比nmtui
需要更多的记忆技巧,但它赋予用户和管理员脚本能力来自动设置系统的网络。
提示
大多数命令允许我们使用自动补全;也就是说,按下Tab键将在命令行上使用自动补全列表来建议语法。例如,在命令行上输入nmcli dev
并按下Tab将自动补全命令为nmcli device
。在这种情况下,这可能并不像nmcli
接受两个参数都有效那样重要,但对于其他命令来说,正确拼写是必须的才能使代码正常工作。
让我们从使用nmcli dev
检查系统中可用的连接开始,然后使用nmcli con show
查看其详细信息:
图 6.7 – nmcli dev 和 nmcli con show
例如,当控制网络连接时,例如使用nmcli con up "Wired Connection"
或使用nmcli con down ens3
禁用它时,我们应该记住我们关于 NetworkManager 的解释:如果连接在系统中可用,NetworkManager 可能会在断开连接后立即重新激活它,因为连接和所需的设备在我们的系统中是可用的。
现在,让我们创建一个新接口来说明通过 IPv4 添加新连接的过程:
nmcli con add con-name eth0 type ethernet \
ifname eth0 ipv4.address 192.168.1.2/24 \
ipv4.gateway 192.168.1.254
我们也可以使用 IPv6:
nmcli con add con-name eth0 type ethernet \
ifname eth0 ipv6.address 2001:db8:0:1::c000:207/64 \
ipv6.gateway 2001:db8:0:1::1 ipv4.address \
192.0.1.3/24 ipv4.gateway 192.0.1.1
执行了上述命令后,我们可以使用nmcli connection show eth0
检查已定义的网络连接,并验证是否应用了正确的设置(或者当然也可以通过nmtui
、nm-connection-editor
或在磁盘上创建的文本文件来验证,因为信息是共享和存储在系统中的)。
当我们审查nmcli connection show interface
的输出时,输出包含一些用点分隔的键,例如以下内容:
-
ipv4.address
-
ipv4.gateway
-
ipv6.address
-
ipv6.gateway
-
connection.id
我们可以使用这些键通过nmcli con mod $key $value
来定义新的值,如下例所示:
图 6.8 – 修改网络连接名称和 IP 地址的示例
当然,在进行了上述测试后,我们也可以使用nmcli con del datacenter
来删除连接以避免系统中的问题。
以下命令可用于使用nmcli
工具修改连接:
-
nmcli con show
: 显示连接的状态。 -
nmcli con show NAME
: 显示名为NAME
的连接的详细信息。 -
nmcli dev status
: 显示系统中设备的状态。请注意,这意味着设备,而不是可能正在使用这些设备的连接。 -
nmcli con add con-NAME
: 添加新连接。 -
nmci con mod NAME
: 修改连接。 -
nmcli con up NAME
: 启动连接。 -
nmcli con down NAME
: 断开连接(仍然可以通过 NetworkManager 重新启用)。 -
nmcli con del NAME
: 从系统中删除连接定义。
提示
查看man nmcli-examples
以找到包含在系统文档中的更多示例。
使用文本文件配置接口
在前面的小节中,我们探讨了如何使用不同的方法配置网络,但最终,所有这些配置最终都会被写入磁盘作为接口定义文件(这也提供了与先前提到的network-scripts
的向后兼容性)。
与其从头开始创建接口定义,不如看看当我们用以下命令创建接口时nmcli
做了什么:
nmcli con add con-name eth0 type ethernet ifname eth0 ipv6.address 2001:db8:0:1::c000:207/64 ipv6.gateway 2001:db8:0:1::1 ipv4.address 192.0.1.3/24 ipv4.gateway 192.0.1.1
上述命令将生成/etc/sysconfig/network-scripts/ifcfg-eth0
文件,我们可以在下面的截图中看到:
图 6.9-/etc/sysconfig/network-scripts/ifcfg-eth0 连接定义的内容
正如我们所看到的,默认情况下,我们指定了一个以Ethernet
(TYPE
)类型的网络接口,使用eth0
设备,以及提供的 IPv4 和 IPv6 地址和网关。键的名称与使用nmcli
定义的键不同,原因是我们具有向后兼容性。
请注意,在上面的例子中,ONBOOT
字段已经设置为yes
,这意味着当系统启动时,接口将自动启用。如果我们使用nmcli
,我们可以通过connection.autoconnect
配置键来检查状态,这也将默认情况下使连接在启动时自动启用。
我们可以直接编辑这些文件,但是为了让 NetworkManager 意识到将要引入的更改,必须执行nmcli con reload
。这将同步对各个文件所做的更改。
例如,我们可以更正上述文件中的一个设置,因为对于静态定义的 IP,通常会定义BOOTPROTO=none
。使用你喜欢的方法修改/etc/sysconfig/network-scripts/ifcfg-eth0
文件(vim
,nano
,sed
或其他)。要获取其他细节,我们可以使用nmcli
进行检查,并且也可以更改 IP 地址。
请注意,在下面的截图中,更改在发出reload
命令之前不会出现在nmcli
中:
图 6.10-编辑接口定义的过程在重新加载连接之前不会显示在 nmcli 上
当然,我们也可以从头开始创建网络定义,直到 NetworkManager 的到来和传播,这种方法在脚本编写中被使用,包括通过 kickstart 文件进行的 Anaconda 自动安装。
让我们用 IPv4 中的命令创建一个简单的网络定义,如下面截图中所示:
图 6.11-使用配置文件创建连接(可以作为脚本的一部分)
在这里,你不仅可以看到连接的创建,还可以看到之前的状态,接口定义,系统的 NetworkManager 视图,以及重新加载的配置文件的比较。请注意,设备列为空,因为我们为该连接定义了一个在我们系统中不存在的接口。
重要提示
网络接口定义可能会变成一场噩梦,因为接口名称本身受到几条规则的约束,比如接口在总线上的位置,以前是否曾见过等。一般来说,一旦系统检测到网络卡,就会编写一个自定义规则,将接口的 MAC 地址与自定义命名约定进行匹配。这样做是为了在重新启动或新软件更新改变我们必须枚举卡的方式时不会发生变化。您可以通过查看官方 RHEL8 手册了解更多信息access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/configuring_and_managing_networking/consistent-network-interface-device-naming_configuring-and_managing-networking
。
现在我们已经回顾了在我们的系统中配置网络的不同方法,让我们了解一下命名解析。
配置主机名和主机名解析(DNS)
记住 IP 地址,无论是 IPv4 还是 IPv6 地址,都可能变成一场噩梦。为了简化事情,对主机名和 DNS 采用了更加人性化的方法,我们可以将这些更容易记住的名称转换为系统用于连接的 IP 地址。
主机名是我们分配给主机以便它们被识别的名称,但当它们与 DNS 服务器一起使用时,我们必须有其他主机能够将它们解析为可以连接的 IP 地址。
我们可以使用hostname
命令查看或临时修改当前主机名,如下面的屏幕截图所示:
图 6.12 - 查询和更改主机的主机名
请记住,这种更改只是暂时的;只要我们重新启动服务器,它就会使用配置的更改。
要定义一个新的配置主机名,我们将使用hostnamectl set-hostname
命令,如下面的屏幕截图所示:
图 6.13 - 检查先前配置的主机名和通过 hostnamectl 定义新主机名
请注意在上面的示例中,我们有临时主机名
与静态主机名
,这指的是使用hostname
而不是hostnamectl
定义的名称的临时状态。
在名称解析方面,我们可以采取几种方法。当然,一种方法是使用 DNS 服务器,我们将在本节稍后解释,但还有其他方法。
一般来说,系统有几个解析器,并且这些解析器在/etc/nsswitch.conf
配置文件中定义。这些解析器不仅用于网络命名,还用于解析用户,例如,企业nsswitch.conf
指示我们的系统使用以下条目进行主机解析:hosts: files dns myhostname
。
这意味着我们将我们的/etc/
目录中的文件作为我们的第一个来源。在主机名的情况下,这指的是/etc/hosts
文件。如果在该文件中定义了条目,将使用指定的值;如果没有,则/etc/resolv.conf
文件将确定如何进行解析。这些文件,特别是resolv.conf
,在系统部署和连接激活时进行配置。NetworkManager 负责更新通过 DHCP 获得的值(如果使用了自动配置),或者如果执行了手动配置,则使用指定的 DNS 服务器。
在下面的屏幕截图中,我们可以看到在我们的/etc/hosts
文件中定义的条目,如何因为名称不存在而无法 ping 主机,以及在手动向/etc/hosts
文件添加条目后,我们的系统能够到达它:
图 6.14 - 向我们的本地系统添加静态主机条目
正如我们之前提到的,DNS 解析是通过/etc/resolv.conf
中的配置完成的,默认情况下包含search
参数和nameserver
参数。如果我们查看resolv.conf
的 man 页面,我们可以获得常见参数的描述:
-
nameserver
:包含要使用的名称服务器的 IP。目前,resolv
库在系统中每次最多使用三个条目(每个占一行)进行解析。每次解析都是按顺序进行的,因此如果一个服务器失败,它将超时,尝试下一个,依此类推。 -
domain
:本地域名。它允许我们使用相对于我们主机的本地域的短名称。如果未列出,它将基于我们系统的主机名进行计算(第一个.
之后的所有内容)。 -
search
:默认情况下,这包含本地域名,它是我们可以尝试使用以解析提供的短名称的域名列表。它限制为 6 个域和 256 个字符。域和搜索是互斥的,因为文件中的最后一个将被使用。
提示
DNS 解析通过向特殊服务器(DNS)请求域的相关数据来实现。这是以分层方式进行的,顶层通用服务器被称为根服务器。DNS 服务器不仅包含将主机名转换为 IP 的注册表或条目,还包括有关发送电子邮件时要使用的邮件服务器、安全验证详细信息、反向条目等信息。此外,DNS 服务器还可以通过为某些域返回无效 IP 来阻止对服务的访问,或者通过使用比 ISP 提供的更快的 DNS 服务器来加快互联网导航速度。当域名注册时,在根表中为该域创建一个新条目,指向 DNS 服务器。这将负责该域的解析,并且稍后,这些条目将在互联网上进行填充和缓存,以加快解析速度。
如果我们想修改连接定义的 DNS 服务器,记得使用nmcli con mod NAME ipv4.dns IP
(或 IPv6 等效),并在之前使用+
符号,如+ipv4.dns
,以将新条目添加到 DNS 服务器列表中。对resolv.conf
的任何手动更改可能会被覆盖。
现在我们已经了解了 DNS 的工作原理以及我们的系统如何使用它,让我们看看如何保护系统网络访问。
防火墙配置概述
当系统连接到网络时,许多正在运行的服务可以从其他系统访问。这是连接系统的目标。然而,我们也希望保持系统安全,远离未经授权的使用。
防火墙是一种软件层,位于网络卡和服务之间,允许我们对允许或不允许的内容进行微调。
我们无法完全阻止所有传入连接到我们的系统,因为经常传入连接是我们的系统发出的请求的响应。
连接是通过名为iptables
、ip6tables
、ebtables
和arptables
的内核框架来阻止的。
重要说明
正如我们之前在网络配置方面解释的那样,防火墙中的错误配置可能会将您锁在系统外,因此在设置一些限制性规则时一定要非常小心,以便在远程访问系统时可以重新登录系统。
firewalld
软件包应该包含在基本安装中。一旦安装,它将提供firewall-cmd
命令与服务进行交互。
firewalld 使用区域的概念,允许我们为每个区域预定义一组规则。这些也可以分配给网络连接。例如,对于可能在连接之间漫游的笔记本电脑,当您使用家庭或公司连接时,可能更相关,而当您使用来自咖啡厅的 Wi-Fi 时,它们将默认为更安全的设置。
firewalld 还使用预定义的服务,以便防火墙知道应该基于已启用的服务和区域来启用哪些端口和协议。
让我们看看可用的区域以及有关家庭区域的更多详细信息:
图 6.15 - 可用区域和家庭区域的配置
如我们所见,已定义了几个区域:
-
public
:这是新添加接口的默认区域。它允许我们使用 cockpit SSH 和 DHCP 客户端,并拒绝与传出流量无关的所有传入流量。 -
block
:拒绝所有传入流量,除非与传出流量相关。 -
dmz
:拒绝所有传入流量,除非与传出或 SSH 连接相关。 -
drop
:丢弃所有与传出流量无关的传入数据包(甚至不是 ping)。 -
external
:阻止所有传入流量,除了与传出流量相关的流量。它还允许 SSH,并将流量伪装为来自此接口的流量。 -
home
:除了 public,还允许smb
和mdns
。 -
internal
:基于家庭区域。 -
trusted
:允许所有传入流量。 -
work
:阻止所有传入流量,除了与传出或 SSH/cockpit/DHCP 流量相关的流量。
接下来,我们将学习如何在配置防火墙时使用这些区域。
配置防火墙
正如本节介绍中所示,防火墙可以通过firewall-cmd
命令进行配置(以及在第四章中早些时候在本书中描述的 cockpit web 界面)。最常用的命令选项如下:
-
firewall-cmd --get-zones
:列出可用的区域。 -
firewall-cmd --get-active-zones
:列出已分配的活动区域和接口。 -
firewall-cmd --list-all
:转储当前配置。 -
firewall-cmd --add-service
:将服务添加到当前区域。 -
firewall-cmd --add-port
:将端口/协议添加到当前区域。 -
firewall-cmd --remove-service
:从当前区域中移除服务。 -
firewall-cmd --remove-port
:从当前区域中移除端口/协议。
重要提示
请注意,在上述命令之后,您需要提到端口号和服务名称以添加或删除服务/端口。
-
firewall-cmd --reload
:从保存的数据重新加载配置,从而丢弃运行时配置。 -
firewall-cmd –get-default-zone
:获取默认区域。 -
firewall-cmd --set-default-zone
:定义要使用的默认区域。
例如,当我们在系统中安装 HTTP 服务器(用于提供网页)时,必须启用 TCP 端口80
。
让我们在示例系统中尝试安装、运行和打开 HTTP 端口:
dnf –y install httpd
systemctl enable httpd
systemctl start httpd
firewall-cmd –add-service=http
curl localhost
最后一个命令将向本地http
服务器发出请求以获取结果。如果您可以访问其他系统,可以尝试连接到我们一直在使用的服务器的 IP,以查看系统提供的默认网页。
在下面的屏幕截图中,我们可以看到curl localhost
命令的输出:
图 6.16 - 请求由我们的系统托管的网页的 curl 输出
到目前为止,我们已经审查了如何配置一些基本的防火墙规则,所以我们准备检查网络的连通性。
测试网络连通性
在前面的章节中,我们正在与网络接口、地址和防火墙规则进行交互,这些规则定义、限制或允许连接到我们的系统。在本节中,我们将回顾一些基本工具,用于验证网络连接是否存在。
请注意,以下命令假定防火墙未设置为严格模式,并且我们可以使用Internet 控制消息协议(ICMP)来访问托管服务的服务器。在安全网络中,服务可能正在运行,但不会回答 ping - 它可能只会回答服务查询本身。
我们可以在这里使用几个命令,因此请考虑以下建议来诊断问题:
-
检查本地接口的 IP 地址、子网掩码和网关。
-
使用
ping
命令和网关的 IP 地址验证正确的网络配置。 -
使用
ping
命令对/etc/resolv.conf
中的 DNS 服务器进行 ping,以查看是否可达。或者,使用host
或dig
命令查询 DNS 服务器。 -
如果据说有外部网络连接,请尝试访问外部 DNS 服务器,如
8.8.8.8
或1.1.1.1
,或使用curl
或wget
请求一些已知服务的网页;例如,curl nasa.gov
。
这应该让您对问题可能出在哪有一个大概的想法,根据您在测试中达到的距离。请记住,还有其他工具,比如tracepath
,它将显示 TCP 数据包在到达目的地之前经过的跳数。每个命令的 man 页面将为您提供有关其用法的提示和示例。
在下面的屏幕截图中,您可以看到针对一个 Web 服务器的tracepath
的输出:
图 6.17 - 对西班牙瓦伦西亚大学网站的 tracepath 命令的输出
正如我们所看到的,跨越不同服务器执行了 11 个步骤,直到我们的数据包到达目的地主机。这使我们了解了数据包如何穿越互联网到达目标系统。
总结
在本章中,我们学习了使用不同方法配置网络接口,可以通过手动交互或通过允许我们脚本或自动配置的方法。
还介绍了一些用于帮助我们找到一些基本错误的网络问题的故障排除方法。
正如我们在本章的介绍中提到的,网络是我们的系统到达其他服务并向其他系统提供服务的基础。我们还介绍了更复杂的网络设置的概念,超出了 RHCSA 级别的范围,但至少熟悉我们职业生涯中将要使用的关键词是有趣的。
在下一章中,我们将涵盖一些与安全相关的重要主题,例如在我们的系统中添加、打补丁和管理软件。
第七章:添加、打补丁和管理软件
维护系统的软件,关闭安全问题,应用修复程序并保持系统最新是系统管理中的重要任务。在本章中,我们将回顾Red Hat 订阅管理系统的工作原理,如何确保软件包经过验证,以及保持系统更新的其他软件管理任务。
深入了解一些细节,在本章中,我们将介绍订阅系统的工作原理以及如何使用开发者订阅进行自我培训或安装个人服务器。我们还将检查如何管理软件来源,也称为仓库,您的系统将使用它们。这包括学习软件包管理中签名的作用,以确保安装的软件是 Red Hat 提供的软件。我们还将学习添加和删除软件包和软件包组,使用模块化的不同软件版本,以及审查和回滚更改等关键任务。
为了简化扩展您的知识,使您能够准备自己的实验室,我们将看到如何在您的系统中拥有所有Red Hat 企业 Linux(RHEL)仓库的完整本地副本。
最后但同样重要的是,我们需要了解Red Hat 软件包管理器(RPM),现在更名为 RPM 软件包管理器,通过学习软件包管理内部工作的基础知识。
总之,在本章中,我们将涵盖以下主题:
-
RHEL 订阅注册和管理
-
使用 Yum/DNF 管理仓库和签名
-
使用 Yum/DNF 进行软件安装、更新和回滚
-
使用 createrepo 和 reposync 创建和同步仓库
-
理解 RPM 内部
现在,让我们开始管理我们系统中的软件。
RHEL 订阅注册和管理
RHEL 是一个完全的开源操作系统,这意味着用于构建它的所有源代码都可以访问、修改、重新分发和学习。另一方面,预构建的二进制文件是作为服务交付的,并通过订阅可访问。正如在第一章中所见,安装 RHEL8,我们可以为自己的个人使用获得开发者订阅。该订阅提供对 ISO 映像的访问,还提供了 RHEL 8 的更新、签名软件包。这些软件包与全球许多公司在生产中使用的完全相同。
让我们看看如何在我们自己的系统中使用该订阅。
首先,让我们来看看Red Hat 客户门户access.redhat.com
,然后点击登录:
图 7.1–登录到 Red Hat 客户门户
一旦我们点击student
作为示例:
图 7.2–在 Red Hat 单一登录中输入我们的用户名
现在是时候输入我们的密码进行验证了:
图 7.3–在 Red Hat 单一登录中输入我们的密码
登录后,我们将通过点击顶部栏中的订阅链接转到Red Hat 订阅页面:
图 7.4–在 Red Hat 客户门户中访问订阅页面
对于已订阅一个物理机的用户,订阅页面将如下所示:
图 7.5–Red Hat 客户门户中的订阅页面示例
提示
开发者订阅于 2021 年 1 月更新,支持最多 16 个系统。您可以使用您的帐户为一个以上的单个系统模拟类似生产的部署。
现在让我们注册我们的新系统:
[root@rhel8 ~]# subscription-manager register
Registering to: subscription.rhsm.redhat.com:443/subscription
Username: student
Password:
The system has been registered with ID: d9673662-754f-49f3-828c-86fd9f5b4e93
The registered system name is: rhel8.example.com
有了这个,我们的系统将被注册到红帽内容交付网络(CDN),但仍然没有分配订阅。
让我们转到订阅页面并刷新以查看新系统。我们将点击查看所有系统以继续:
图 7.6 - 具有新订阅系统的订阅页面
我们可以在页面上看到我们的新系统rhel8.example.com
,旁边有一个红色的方块,表示它没有附加的订阅。让我们点击系统名称以查看详细信息:
图 7.7 - 具有新订阅系统的订阅页面
一旦进入特定系统页面,我们就可以看到系统的所有详细信息。我们点击订阅以查看已附加的订阅:
图 7.8 - 具有新订阅系统详细信息的订阅页面
我们可以在页面上看到,这个系统没有附加的订阅:
图 7.9 - 具有新订阅系统的订阅页面,没有附加的订阅
让我们使用subscription-manager attach
为我们的系统附加一个订阅:
[root@rhel8 ~]# subscription-manager attach --auto
Installed Product Current Status:
Product Name: Red Hat Enterprise Linux for x86_64
Status: Subscribed
命令的结果显示,系统现在已注册,并为Red Hat Enterprise Linux for x86_64
附加了一个订阅。让我们刷新系统页面以确保订阅附加正常运行:
图 7.10 - 具有新订阅系统的订阅页面,附有一个订阅
有了这个,我们可以确定系统已正确注册并订阅了红帽 CDN,并且已准备好访问来自它的所有软件、补丁和更新。
此外,在系统中,我们可以看到一个包含有关软件存储库或repos信息的新文件已经创建:
[root@rhel8 ~]# ls -l /etc/yum.repos.d/redhat.repo
-rw-r--r--. 1 root root 94154 feb 6 15:17 /etc/yum.repos.d/redhat.repo
现在我们知道如何管理可用的订阅并将它们分配给正在运行的系统,以便它可以访问由红帽构建的软件二进制文件。让我们在下一节中了解如何使用提供的存储库。
使用 YUM/DNF 管理存储库和签名
像许多其他 Linux 发行版一样,RHEL 有一个基于存储库提供软件的机制。这些存储库包含软件包的列表(可以是最终用户应用程序,如 Firefox,或者用于它们的组件,如 GTK3),软件包之间的依赖关系列表以及其他有用的元数据。
一旦我们完成订阅系统,我们可以使用yum
或dnf
查看系统中可用的存储库:
[root@rhel8 ~]# yum repolist
Updating Subscription Management repositories.
repo id repo name
rhel-8-for-x86_64-appstream-rpms Red Hat Enterprise Linux 8 for x86_64 - AppStream (RPMs)
rhel-8-for-x86_64-baseos-rpms Red Hat Enterprise Linux 8 for x86_64 - BaseOS (RPMs)
[root@rhel8 ~]# dnf repolist
Updating Subscription Management repositories.
repo id repo name
rhel-8-for-x86_64-appstream-rpms Red Hat Enterprise Linux 8 for x86_64 - AppStream (RPMs)
rhel-8-for-x86_64-baseos-rpms Red Hat Enterprise Linux 8 for x86_64 - BaseOS (RPMs)
正如您所看到的,yum
和dnf
的输出完全相同。事实上,dnf
是yum
的演变,在 RHEL8 中,yum
命令只是dnf
的符号链接:
[root@rhel8 ~]# which yum
/usr/bin/yum
[root@rhel8 ~]# ll /usr/bin/yum
lrwxrwxrwx. 1 root root 5 jul 29 2020 /usr/bin/yum -> dnf-3
[root@rhel8 ~]# which dnf
/usr/bin/dnf
[root@rhel8 ~]# ll /usr/bin/dnf
lrwxrwxrwx. 1 root root 5 jul 29 2020 /usr/bin/dnf -> dnf-3
它们在 RHEL8 中可以互换使用。从现在开始,我们将只使用dnf
,但请记住,如果您更喜欢yum
,请随意使用。
提示
YUM曾经是Yellowdog Updater Modified的首字母缩写,这是一个最初是为 Mac 开发的 Linux 发行版项目。DNF代表Dandified YUM。
现在让我们来看一下在订阅附加期间创建的存储库定义/etc/yum.repos.d/redhat.repo
。我们可以编辑文件并转到BaseOS
存储库的条目,如上面显示的rhel-8-for-x86_64-baseos-rpms
:
[rhel-8-for-x86_64-baseos-rpms]
name = Red Hat Enterprise Linux 8 for x86_64 - BaseOS (RPMs)
baseurl = https://cdn.redhat.com/content/dist/rhel8/$releasever/x86_64/baseos/os
enabled = 1
gpgcheck = 1
gpgkey = file:///etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release
sslverify = 1
sslcacert = /etc/rhsm/ca/redhat-uep.pem
sslclientkey = /etc/pki/entitlement/7881187918683323950-key.pem
sslclientcert = /etc/pki/entitlement/7881187918683323950.pem
metadata_expire = 86400
enabled_metadata = 1
正如您所看到的,文件中的每个部分都以方括号之间的部分名称开头 - 在前面的情况下,[rhel-8-for-x86_64-baseos-rpms]
。现在让我们检查此部分下的所有条目:
-
name:存储库的长描述性名称。这是我们在前面的示例中列出存储库时显示的名称。
-
$releasever
变量将在访问之前被替换。其他方法包括 NFS、HTTP 和 FTP。 -
1
,它将被启用,设置为0
时将被禁用。 -
1
将启用,并且系统中使用dnf
/yum
安装的所有软件包将使用它们的gpg
签名钥匙进行验证。 -
gpg
,下载的软件包。 -
1
,设置为0
时将被禁用。 -
sslcacert:用作证书颁发机构的证书,用于验证客户端证书。
-
sslclient key:用于激活客户端证书的客户端密钥。
-
sslclientcert:机器用来在 CDN 上标识自己的客户端证书。
-
metadata_expire:在检索到的元数据被视为过期之后的秒数。默认值如下所示,为 24 小时。
-
dnf
)以使用在此存储库中下载的元数据。
拥有运行存储库所需的最小选项是:name
、baseurl
和 gpgckeck
,并将最后一个设置为 0
。
重要提示
虽然可以通过编辑文件更改存储库的配置,但修改 Red Hat 提供的存储库的最佳方法是使用本章中将显示的命令。这是因为当刷新数据时,redhat.repo
文件将被订阅管理器覆盖。
通过运行 dnf repolist
,我们获得了系统中 enabled
的存储库列表。如果我们想要查看所有存储库,包括已启用和已禁用的存储库,该怎么办?可以通过运行 dnf
repolist --all
来实现。
图 7.11 – dnf repolist –all 的部分输出
列表非常广泛。它包括了许多生产案例中使用的二进制库,从 SAP 到使用 Satellite 管理系统。我们可以使用 grep
过滤它来搜索 supplementary
:
[root@rhel8 ~]# dnf repolist --all | grep supplementary
rhel-8-for-x86_64-supplementary-debug-rpms disabled
rhel-8-for-x86_64-supplementary-eus-debug-rpms disabled
rhel-8-for-x86_64-supplementary-eus-rpms disabled
rhel-8-for-x86_64-supplementary-eus-source-rpms disabled
rhel-8-for-x86_64-supplementary-rpms disabled
rhel-8-for-x86_64-supplementary-source-rpms disabled
这里有四种不同类型的通道:
-
rhel-8-for-x86_64-supplementary-rpms
,其中包含准备安装在系统中的软件包,也称为rpms
。这些适用于标准维护期间。 -
rhel-8-for-x86_64-supplementary-eus-rpms
,其中名称中包含eus
。这些提供了带有后端支持的软件包,以便能够保持相同的次要版本更长时间。除非第三方供应商要求,否则不要使用它们。 -
rhel-8-for-x86_64-supplementary-source-rpms
,其中名称中包含source
。它们提供了用于构建 常规 和 扩展更新支持 通道中交付的软件包的源代码。 -
rhel-8-for-x86_64-supplementary-debug-rpms
,其中名称中包含debug
。这些包括在构建软件包时生成的调试信息,对于深度故障排除非常有用。
我们可以使用 dnf
的 config-manager
选项启用 rhel-8-for-x86_64-supplementary-rpms
,运行以下命令:
[root@rhel8 ~]# dnf config-manager --enable rhel-8-for-x86_64-supplementary-rpms
Updating Subscription Management repositories.
[root@rhel8 ~]# dnf repolist
Updating Subscription Management repositories.
repo id repo name
rhel-8-for-x86_64-appstream-rpms Red Hat Enterprise Linux 8 for x86_64 - AppStream (RPMs)
rhel-8-for-x86_64-baseos-rpms Red Hat Enterprise Linux 8 for x86_64 - BaseOS (RPMs)
rhel-8-for-x86_64-supplementary-rpms Red Hat Enterprise Linux 8 for x86_64 - Supplementary (RPMs)
存储库现在已启用。您可能希望尝试启用和禁用其他存储库以进行练习。
现在让我们尝试添加一个我们只知道其 URL 的存储库,例如 dnf config-manager
:
[root@rhel8 ~]# dnf config-manager --add-repo="http://mirror.uv.es/mirror/fedora-epel/8/Everything/x86_64/"
Updating Subscription Management repositories.
Adding repo from: http://mirror.uv.es/mirror/fedora-epel/8/Everything/x86_64/
[root@rhel8 ~]# dnf repolist
Updating Subscription Management repositories.
repo id repo name
mirror.uv.es_mirror_fedora-epel_8_Everything_x86_64_ created by dnf config-manager from http://mirror.uv.es/mirror/fedora-epel/8/Everything/x86_64/
rhel-8-for-x86_64-appstream-rpms Red Hat Enterprise Linux 8 for x86_64 - AppStream (RPMs)
rhel-8-for-x86_64-baseos-rpms Red Hat Enterprise Linux 8 for x86_64 - BaseOS (RPMs)
rhel-8-for-x86_64-supplementary-rpms Red Hat Enterprise Linux 8 for x86_64 - Supplementary (RPMs)
我们可以检查新创建的文件 – /etc/yum.repos.d/mirror.uv.es_mirror_fedora-epel_8_Everything_x86_64_.repo
:
[mirror.uv.es_mirror_fedora-epel_8_Everything_x86_64_]
name=created by dnf config-manager from http://mirror.uv.es/mirror/fedora-epel/8/Everything/x86_64/
baseurl=http://mirror.uv.es/mirror/fedora-epel/8/Everything/x86_64/
enabled=1
您可能已经意识到这个存储库中缺少一个选项,但是,让我们继续。我可以搜索 EPEL 中可用的软件包,例如 screen
:
[root@rhel8 ~]# dnf info screen
Updating Subscription Management repositories.
created by dnf config-manager from http://mirror.uv.es/mirror/fedor 18 MB/s | 8.9 MB 00:00
Last metadata expiration check: 0:00:02 ago on sáb 13 feb 2021 15:34:56 CET.
Available Packages
Name : screen
Version : 4.6.2
Release : 10.el8
Architecture : x86_64
Size : 582 k
Source : screen-4.6.2-10.el8.src.rpm
Repository : mirror.uv.es_mirror_fedora-epel_8_Everything_x86_64_
Summary : A screen manager that supports multiple logins on one terminal
URL : http://www.gnu.org/software/screen
License : GPLv3+
Description : The screen utility allows you to have multiple logins on just one
: terminal. Screen is useful for users who telnet into a machine or are
: connected via a dumb terminal, but want to use more than just one
: login.
:
: Install the screen package if you need a screen manager that can
: support multiple logins on one terminal.
找到了软件包,现在让我们尝试安装它:
[root@rhel8 ~]# dnf install screen
[omitted]
Install 1 Package
Total download size: 582 k
Installed size: 971 k
Is this ok [y/N]: y
Downloading Packages:
screen-4.6.2-10.el8.x86_64.rpm 2.8 MB/s | 582 kB 00:00
----------------------------------------------------------------------------------------------------
Total 2.8 MB/s | 582 kB 00:00
warning: /var/cache/dnf/mirror.uv.es_mirror_fedora-epel_8_Everything_x86_64_-ee39120d2e2a3152/packages/screen-4.6.2-10.el8.x86_64.rpm: Header V3 RSA/SHA256 Signature, key ID 2f86d6a1: NOKEY
Public key for screen-4.6.2-10.el8.x86_64.rpm is not installed
The downloaded packages were saved in cache until the next successful transaction.
You can remove cached packages by executing 'yum clean packages'.
Error: GPG check FAILED
正如我们所看到的,尝试从此源安装时出现了错误,因为它要求配置 gpgcheck
和 gpgkey
条目以确保具有适当的安全性(因为 gpg
确保交付的内容与创建的内容相同)。
我们可以从同一个镜像获取gpgkey
,URL 为mirror.uv.es/mirror/fedora-epel/RPM-GPG-KEY-EPEL-8
,并将其放在dnf
将搜索的位置/etc/pki/rpm-gpg/
:
[root@rhel8 ~]# curl -s http://mirror.uv.es/mirror/fedora-epel/RPM-GPG-KEY-EPEL-8 > /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-8
[root@rhel8 ~]# head –n 1 /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-8
-----BEGIN PGP PUBLIC KEY BLOCK-----
现在让我们修改文件/etc/yum.repos.d/mirror.uv.es_mirror_fedora-epel_8_Everything_x86_64_.repo
,使其如下所示:
[mirror.uv.es_mirror_fedora-epel_8_Everything_x86_64_]
name=created by dnf config-manager from http://mirror.uv.es/mirror/fedora-epel/8/Everything/x86_64/
baseurl=http://mirror.uv.es/mirror/fedora-epel/8/Everything/x86_64/
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-8
您可以看到我们在文件中添加了gpgcheck
和gpgkey
条目。让我们再次尝试安装screen
包:
[root@rhel8 ~]# dnf install screen
[omitted]
Install 1 Package
Total size: 582 k
Installed size: 971 k
Is this ok [y/N]: y
Downloading Packages:
[SKIPPED] screen-4.6.2-10.el8.x86_64.rpm: Already downloaded
warning: /var/cache/dnf/mirror.uv.es_mirror_fedora-epel_8_Everything_x86_64_-ee39120d2e2a3152/packages/screen-4.6.2-10.el8.x86_64.rpm: Header V3 RSA/SHA256 Signature, key ID 2f86d6a1: NOKEY
created by dnf config-manager from http://mirror.uv.es/mirror/fedor 1.6 MB/s | 1.6 kB 00:00
Importing GPG key 0x2F86D6A1:
Userid : "Fedora EPEL (8) <epel@fedoraproject.org>"
Fingerprint: 94E2 79EB 8D8F 25B2 1810 ADF1 21EA 45AB 2F86 D6A1
From : /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-8
Is this ok [y/N]: y
Key imported successfully
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
Preparing : 1/1
Running scriptlet: screen 4.6.2-10.el8.x86_64 1/1
Installing : screen-4.6.2-10.el8.x86_64 1/1
Running scriptlet: screen-4.6.2-10.el8.x86_64 1/1
Verifying : screen-4.6.2-10.el8.x86_64 1/1
Installed products updated.
Installed:
screen-4.6.2-10.el8.x86_64
Complete!
您会注意到有一步要求您确认gpg
密钥指纹是否正确:94E2 79EB 8D8F 25B2 1810 ADF1 21EA 45AB 2F86 D6A1
。为此,您可以转到 Fedora 安全页面进行检查,因为 Fedora 项目正在管理 EPEL。该页面的 URL 是getfedora.org/security/
:
图 7.12 – Fedora 安全页面的部分截图,带有 EPEL8 gpg 指纹
正如您所看到的,是正确的。我们刚刚验证了我们使用的签名与项目管理它的公告的指纹相同,现在从该仓库下载的所有包都将使用它进行验证,以避免包篡改(即在您收到包之前有人更改内容)。
让我们回顾一下我们使用的命令,dnf
提供了管理仓库的命令:
现在我们知道如何在 RHEL 中安全地管理仓库,让我们开始向系统添加更多的包,更新它们,并在需要时撤消安装。
使用 YUM/DNF 进行软件安装、更新和回滚
在前一节中,我们看到了如何安装一个包。在这个过程中,我们看到了一个确认请求,以确保我们确定要在系统中包含新软件。现在让我们使用dnf install
安装软件,但使用-y
选项来回答命令将发出的所有问题都是“是”:
[root@rhel8 ~]# dnf install zip –y
[omitted]
Installed:
unzip-6.0-43.el8.x86_64 zip-3.0-23.el8.x86_64
Complete!
正如您所看到的,zip
包已经安装,还有一个名为unzip
的依赖包,而不需要询问问题。我们还注意到dnf
找到了依赖包,解决了依赖关系,并安装了所有运行一个包所需的内容。这样,系统就保持在一个一致的状态,使其更加可靠和可预测。
我们可以使用dnf check-update
命令来查看哪些包准备更新:
[root@rhel8 ~]# dnf check-update
Updating Subscription Management repositories.
Last metadata expiration check: 0:20:00 ago on sáb 13 feb 2021 16:04:58 CET.
kernel.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.10.1.el8_3 rhel-8-for-x86_64-baseos-rpms
kernel-modules.x86_64 4.18.0-240.10.1.el8_3 rhel-8-for-x86_64-baseos-rpms
kernel-tools.x86_64 4.18.0-240.10.1.el8_3 rhel-8-for-x86_64-baseos-rpms
kernel-tools-libs.x86_64 4.18.0-240.10.1.el8_3 rhel-8-for-x86_64-baseos-rpms
python3-perf.x86_64 4.18.0-240.10.1.el8_3 rhel-8-for-x86_64-baseos-rpms
qemu-guest-agent.x86_64 15:4.2.0-34.module+el8.3.0+8829+e7a0a3ea.1 rhel-8-for-x86_64-appstream-rpms
selinux-policy.noarch 3.14.3-54.el8_3.2 rhel-8-for-x86_64-baseos-rpms
selinux-policy-targeted.noarch 3.14.3-54.el8_3.2 rhel-8-for-x86_64-baseos-rpms
sudo.x86_64 1.8.29-6.el8_3.1 rhel-8-for-x86_64-baseos-rpms
tzdata.noarch 2021a-1.el8 rhel-8-for-x86_64-baseos-rpms
更新包并应用修复和安全补丁的最简单方法是使用dnf update
:
[root@rhel8 ~]# dnf update tzdata –y
[omitted]
Upgraded:
tzdata-2021a-1.el8.noarch
Complete!
要更新所有内容,只需运行dnf update
而不指定包:
图 7.13 – RHEL 使用 dnf/yum 进行部分更新的截图
在系统中运行dnf update
的结果如下:
Upgraded:
kernel-tools-4.18.0-240.10.1.el8_3.x86_64
kernel-tools-libs-4.18.0-240.10.1.el8_3.x86_64
python3-perf-4.18.0-240.10.1.el8_3.x86_64
qemu-guest-agent 15:4.2.0-34.module+el8.3.0+8829+e7a0a3ea.1.x86_64
selinux-policy-3.14.3-54.el8_3.2.noarch
selinux-policy-targeted-3.14.3-54.el8_3.2.noarch
sudo-1.8.29-6.el8_3.1.x86_64
Installed:
kernel-4.18.0-240.10.1.el8_3.x86_64
kernel-core-4.18.0-240.10.1.el8_3.x86_64
kernel-modules-4.18.0-240.10.1.el8_3.x86_64
Complete!
这些是系统中升级的包的示例。您的系统,根据您上次升级的时间和新发布的包,可能会有不同的输出。
重要提示
kernel
是系统中最重要的部分。它使硬件访问和操作系统的所有基本功能都得以实现。这就是为什么,而不是升级它,会安装一个新版本。系统会保留前两个版本,以防系统无法启动,可以轻松选择其中一个来运行。
我们可以使用dnf search
命令搜索可用的包:
[root@rhel8 ~]# dnf search wget
Updating Subscription Management repositories.
Last metadata expiration check: 0:05:02 ago on sáb 13 feb 2021 16:34:00 CET.
=================== Name Exactly Matched: wget ===================
wget.x86_64 : A utility for retrieving files using the HTTP or FTP protocols
我们可以使用dnf info
来获取有关包的详细信息,无论是已安装还是未安装的:
[root@rhel8 ~]# dnf info wget
Updating Subscription Management repositories.
Last metadata expiration check: 0:06:45 ago on sáb 13 feb 2021 16:34:00 CET.
Available Packages
Name : wget
Version : 1.19.5
Release : 10.el8
Architecture : x86_64
Size : 734 k
Source : wget-1.19.5-10.el8.src.rpm
Repository : rhel-8-for-x86_64-appstream-rpms
Summary : A utility for retrieving files using the HTTP or FTP protocols
URL : http://www.gnu.org/software/wget/
License : GPLv3+
Description : GNU Wget is a file retrieval utility which can use either the HTTP or
: FTP protocols. Wget features include the ability to work in the
: background while you are logged out, recursive retrieval of
: directories, file name wildcard matching, remote file timestamp
: storage and comparison, use of Rest with FTP servers and Range with
: HTTP servers to retrieve files over slow or unstable connections,
: support for Proxy servers, and configurability.
我们还可以使用dnf remove
来删除已安装的包:
[root@rhel8 ~]# dnf remove screen –y
[omitted]
Removed: screen-4.6.2-10.el8.x86_64
Complete!
有时您想安装一些一起执行特定任务的包,这就是dnf grouplist
的作用:
[root@rhel8 ~]# dnf grouplist | grep Tools
Additional Virtualization Tools
RPM Development Tools
Security Tools
Development Tools
System Tools
Graphical Administration Tools
您可以不使用| grep Tools
来查看完整的列表。
让我们使用dnf groupinstall
来安装System Tools
组:
[root@rhel8 ~]# dnf groupinstall "System Tools"
Updating Subscription Management repositories.
Last metadata expiration check: 0:16:03 ago on sáb 13 feb 2021 16:34:00 CET.
Dependencies resolved.
上述命令的整个输出显示在以下截图中:
图 7.14 - RHEL 安装组 dnf/yum 的部分截图
一旦预安装完成,我们可以看到我们将安装 78 个软件包:
Install 78 Packages
Total download size: 44 M
Installed size: 141 M
Is this ok [y/N]:y
回复y
将执行安装(请注意,-y
选项在这里也有效,假设对所有问题都回答是)。
我们可以使用dnf history
来检查所有安装交易的历史记录:
图 7.15 - RHEL dnf/yum 历史记录的部分截图
从每个交易中获取特定信息很容易,只需指定交易编号为dnf history
:
[root@rhel8 ~]# dnf history info 12
Updating Subscription Management repositories.
Transaction ID : 12
Begin time : sáb 13 feb 2021 16:27:06 CET
Begin rpmdb : 393:cec089e1c176497af3eb97582311fcd7cb7adb02
End time : sáb 13 feb 2021 16:27:06 CET (0 seconds)
End rpmdb : 393:6cf80ca6746149100bb1a49d76ebbf7407804e56
User : root <root>
Return-Code : Success
Releasever : 8
Command Line : update tzdata
Comment :
Packages Altered:
Upgrade tzdata-2021a-1.el8.noarch @rhel-8-for-x86_64-baseos-rpms
Upgraded tzdata-2020d-1.el8.noarch @@System
更有趣的是,我们可以回滚到以dnf history rollback
标记的以前的某个点。为了加快速度,安装lsof
软件包,然后回滚到以前的编号:
[root@rhel8 ~]# dnf history rollback 15
[omitted]
Removed: lsof-4.93.2-1.el8.x86_64
Complete!
我们也可以使用yum history undo
来撤消单个交易。让我们看看这个交易:
[root@rhel8 ~]# dnf history undo 10 –y
[omitted]
Removed:
screen-4.6.2-10.el8.x86_64
Complete!
让我们回顾使用dnf
进行的最重要的交易:
在 RHEL 8 中有一个在以前版本中不可用的新功能,即dnf
,因此无需安装额外的软件:
[root@rhel8 repos]# dnf module list postgresql
Updating Subscription Management repositories.
Last metadata expiration check: 0:00:30 ago on dom 14 feb 2021 19:25:32 CET.
Red Hat Enterprise Linux 8 for x86_64 - AppStream (RPMs)
Name Stream Profiles Summary
postgresql 9.6 client, server [d] PostgreSQL server and client module
postgresql 10 [d] client, server [d] PostgreSQL server and client module
postgresql 12 client, server [d] PostgreSQL server and client module
Hint: [d]efault, [e]nabled, [x]disabled, [i]nstalled
提示
使用dnf module list
命令,不指定任何软件包,将显示完整的模块列表。试试看!
正如您所看到的,我们在 RHEL8 中有三个不同版本的 PostgreSQL 数据库可用,分别是 9.6、10 和 12。它们都没有启用,默认版本是 10。
使用dnf module
启用 PostgreSQL 的版本 12:
[root@rhel8 ~]# dnf module enable postgresql:12
[omitted]
Enabling module streams: postgresql 12
[omitted]
Is this ok [y/N]: y
Complete!
[root@rhel8 ~]# dnf module list postgresql
上述命令的输出可以在以下截图中看到:
图 7.16 - PostgreSQL 模块列表的截图
从现在开始,Yum 将在此系统中安装、更新和维护 PostgreSQL 的版本 12。让我们安装它:
[root@rhel8 ~]# dnf install postgresql -y
[omitted]
Installed:
libpq-12.5-1.el8_3.x86_64
postgresql-12.5-1.module+el8.3.0+9042+664538f4.x86_64
Complete!
在前面的例子中,安装了版本 12。
我们可以删除 PostgreSQL 软件包并重置模块状态以返回到初始状态:
[root@rhel8 ~]# dnf remove postgresql -y
[omitted]
Removing:
postgresql x86_64 12.5-1.module+el8.3.0+9042+664538f4 @rhel-8-for-x86_64-appstream-rpms 5.4 M
Removing unused dependencies:
libpq x86_64 12.5-1.el8_3 @rhel-8-for-x86_64-appstream-rpms 719 k
[omitted]
Complete!
[root@rhel8 ~]# dnf module reset postgresql
Updating Subscription Management repositories.
Last metadata expiration check: 1:23:08 ago on dom 14 feb 2021 19:25:32 CET.
Dependencies resolved.
=========================================================Package Architecture Version Repository Size
=========================================================Resetting modules:
postgresql
Transaction Summary
=========================================================Is this ok [y/N]: y
Complete!
[root@rhel8 ~]# dnf module list postgresql
Updating Subscription Management repositories.
Last metadata expiration check: 1:23:21 ago on dom 14 feb 2021 19:25:32 CET.
Red Hat Enterprise Linux 8 for x86_64 - AppStream (RPMs)
Name Stream Profiles Summary
postgresql 9.6 client, server [d] PostgreSQL server and client module
postgresql 10 [d] client, server [d] PostgreSQL server and client module
postgresql 12 client, server [d] PostgreSQL server and client module
Hint: [d]efault, [e]nabled, [x]disabled, [i]nstalled
让我们回顾一下本节中显示的模块化命令:
提示
要了解有关模块化的更多信息,请运行man dnf.modularity
查看系统的手册页。
现在我们已经学会了如何在 RHEL 中处理软件交易,让我们继续学习如何创建和处理本地存储库。
使用 createrepo 和 reposync 创建和同步存储库
通常我们会收到一个 RPM 文件并将其保存在我们可以在自己的机器上使用的存储库中(有时还会与具有 Web 服务器或 NFS 共享的其他机器共享)。当我们开始构建自己的 RPM 时,通常会分发它们,为了这样做,我们需要创建一个存储库。为此,我们可以使用createrepo工具。
首先让我们在/var/tmp
中为存储库创建一个文件夹:
[root@rhel8 ~]# cd /var/tmp/
[root@rhel8 tmp]# mkdir repos
[root@rhel8 tmp]# cd repos/
然后让我们为slack
创建一个文件夹,这是一个与您的团队进行通信的常用工具,并下载 RPM 软件包:
[root@rhel8 repos]# mkdir slack
[root@rhel8 repos]# cd slack/
[root@rhel8 repos]# curl -s -O https://downloads.slack-edge.com/linux_releases/slack-4.12.2-0.1.fc21.x86_64.rpm
[root@rhel8 slack]# ls -l
total 62652
-rw-r--r--. 1 root 64152596 feb 14 18:12 slack-4.12.2-0.1.fc21.x86_64.rpm
现在我们有一个带有 RPM 文件的存储库。我们可以有一个带有任意数量 RPM 的存储库,但我们将继续只使用这个单个软件包。
让我们安装createrepo
工具:
[root@rhel8 slack]# dnf install -y createrepo
[omitted]
Installed:
createrepo_c-0.15.11-2.el8.x86_64 createrepo_c-libs-0.15.11-2.el8.x86_64 drpm-0.4.1-3.el8.x86_64
Complete!
现在我们可以简单地运行它,在当前文件夹中使用以下命令创建一个存储库:
[root@rhel8 slack]# createrepo .
Directory walk started
Directory walk done - 1 packages
Temporary output repo path: ./.repodata/
Preparing sqlite DBs
Pool started (with 5 workers)
Pool finished
[root@rhel8 slack]# ls -l
total 62656
drwxr-xr-x. 2 root 4096 feb 14 18:19 repodata
-rw-r--r--. 1 root 64152596 feb 14 18:12 slack-4.12.2-0.1.fc21.x86_64.rpm
我们看到repodata
文件夹已经被创建。在其中,我们可以找到定义存储库内容的repomd.xml
文件,还有最近创建的索引文件:
[root@rhel8 slack]# ls repodata/
13b6b81deb95354164189de7fe5148b4dbdb247fb910973cc94c120d36c0fd27-filelists.xml.gz
18fb83942e8cb5633fd0653a4c8ac3db0f93ea73581f91d90be93256061043f0-other.sqlite.bz2
aa72116fa9b47caaee313ece2c16676dce26ffcc78c69dc74ebe4fc59aea2c78-filelists.sqlite.bz2
d5e2ff4b465544a423bfa28a4bc3d054f316302feab8604d64f73538809b1cf0-primary.xml.gz
e92cd0e07c758c1028054cfeb964c4e159004be61ae5217927c27d27ea2c7966-primary.sqlite.bz2
f68973de8a710a9a078faf49e90747baaf496c5a43865cd5dc5757512a0664a8-other.xml.gz
repomd.xml
现在我们可以将存储库添加到系统中。我们可以在没有gpg
签名的情况下进行,将gpgcheck
变量设置为0
,但为了更好的安全性,让我们使用gpg
签名。通过在slack
页面搜索,我们找到签名并将其下载到/etc/pki/rpm-gpg
目录:
[root@rhel8 slack]# curl https://slack.com/gpg/slack_pubkey_2019.gpg -o /etc/pki/rpm-gpg/RPM-GPG-KEY-SLACK
然后通过创建文件/etc/yum.repos.d/local-slack.repo
并添加以下内容将存储库添加到系统中:
[local-slack-repo]
name=Local Slack Repository
baseurl=file:///var/tmp/repos/slack
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-SLACK
现在我们可以尝试安装slack
。要完全运行,需要安装带有 GUI 的服务器软件包组,但是为了完成本练习,我们可以继续安装。我们可以通过运行dnf -y install slack
来实现这一点-请注意gpg
密钥如何自动导入并验证和安装软件包:
root@rhel8 slack]# dnf -y install slack
[omitted]
warning: /var/tmp/repos/slack/slack-4.12.2-0.1.fc21.x86_64.rpm: Header V4 RSA/SHA1 Signature, key ID 8e6c9578: NOKEY
Local Slack Repository 1.6 MB/s | 1.6 kB 00:00
Importing GPG key 0x8E6C9578:
Userid : "Slack Packages (Signing Key) <packages@slack-corp.com>"
Fingerprint: 93D5 D2A6 2895 1B43 83D8 A4CE F184 6207 8E6C 9578
From : /etc/pki/rpm-gpg/RPM-GPG-KEY-SLACK
Key imported successfully
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
[omitted]
slack-4.12.2-0.1.fc21.x86_64
Complete!
一旦出现 Slack 的新版本,我们可以将其下载到同一文件夹,并通过再次运行createrepo
来重新生成仓库索引。这样,所有使用该仓库的系统在运行yum update
时都会更新slack
。这是保持所有系统标准化和版本一致的好方法。有关管理 RPM 仓库的高级功能,请查看 Red Hat Satellite。
有时我们希望在我们的系统中有仓库的本地副本。为此,我们可以使用reposync工具。
首先,我们安装reposync
,它包含在yum-utils
软件包中:
[root@rhel8 ~]# dnf install yum-utils -y
[omitted]
Installed:
yum-utils-4.0.17-5.el8.noarch
Complete!
提示
如果尝试安装dnf-utils
软件包,将安装相同的软件包。
现在是时候禁用 Red Hat 提供的除rhel-8-for-x86_64-baseos-rpms
之外的所有仓库了,可以使用以下命令完成:
[root@rhel8 ~]# subscription-manager repos --disable="*" --enable="rhel-8-for-x86_64-baseos-rpms"
检查变化的时间到了:
[root@rhel8 ~]# dnf repolist
Updating Subscription Management repositories.
repo id repo name
local-slack-repo Local Slack Repository
mirror.uv.es_mirror_fedora-epel_8_Everything_x86_64_ created by dnf config-manager from http://mirror.uv.es/mirror/fedora-epel/8/Everything/x86_64/
rhel-8-for-x86_64-baseos-rpms Red Hat Enterprise Linux 8 for x86_64 - BaseOS (RPMs)
我们也可以禁用其他仓库,但这次我们将以不同的方式进行,将它们重命名为不以.repo
结尾的名称:
[root@rhel8 ~]# mv /etc/yum.repos.d/local-slack.repo /etc/yum.repos.d/local-slack.repo_disabled
[root@rhel8 ~]# mv /etc/yum.repos.d/mirror.uv.es_mirror_fedora-epel_8_Everything_x86_64_.repo /etc/yum.repos.d/mirror.uv.es_mirror_fedora-epel_8_Everything_x86_64_.repo_disabled
[root@rhel8 ~]# yum repolist
Updating Subscription Management repositories.
repo id repo name
rhel-8-for-x86_64-baseos-rpms Red Hat Enterprise Linux 8 for x86_64 - BaseOS (RPMs)
现在我们可以使用一些选项运行reposync
:
[root@rhel8 ~]# cd /var/tmp/repos
[root@rhel8 repos]# reposync --newest-only --download-metadata --destdir /var/tmp/repos
Updating Subscription Management repositories.
[omitted]
(1725/1726): selinux-policy-3.14.3-54.el8_3.2.noarch.rpm 2.3 MB/s | 622 kB 00:00
(1726/1726): selinux-policy-devel-3.14.3-54.el8_3.2.noarch.rpm 4.1 MB/s | 1.5 MB 00:00
[root@rhel8 repos]# ls
rhel-8-for-x86_64-baseos-rpms slack
[root@rhel8 repos]# ls rhel-8-for-x86_64-baseos-rpms/
Packages repodata
[root@rhel8 repos]# ls rhel-8-for-x86_64-baseos-rpms/repodata/
14d4e7f9bbf5901efa7c54db513a2ac68cb0b6650ae23a2e0bff15dc03565f25-other.sqlite.bz2
26727acbd819c59d4da7c8aeaddb027adbfb7ddb4861d31922465b4c0922f969-updateinfo.xml.gz
46f0b974d2456ad4f66dec3afff1490648f567ee9aa4fe695494ec2cfc9a88f6-primary.sqlite.bz2
580de0089dbaa82ca8963963da9cb74abf7a5c997842492210e2c10e1deac832-primary.xml.gz
5954c1ef-00bc-457b-9586-e51789358b97
a7504888345e2440fa62e21a85f690c64a5f5b9ffd84d8e525a077c955644abe-filelists.xml.gz
acad9f7dfbc7681c2532f2fd1ff56e0f4e58eb0e2be72cc1d4a4ec8613008699-comps.xml
d2e90d6a0f138e6d8ea190cf995902c821309a03606c7acc28857e186489974a-filelists.sqlite.bz2
e0a7c4b677c633b859dba5eac132de68e138223e4ad696c72a97c454f2fe70bd-other.xml.gz
repomd.xml
这将下载已启用通道的最新软件包。让我们来看看选项:
-
--newest-only
:Red Hat 仓库保留自首次发布以来的所有软件包版本。这将仅下载最新版本。 -
--download-metadata
:为了确保我们下载一个完全功能的仓库,并且不需要在其上运行createrepo
,我们可以使用这个选项,它将检索源仓库中的所有元数据。 -
--destdir /var/tmp/repos
:设置下载文件的目标目录。它还将为每个配置的仓库创建一个目录,因此指定的目录将是它们所有的父目录。
有了这个复制的仓库,我们还可以在隔离的环境中工作。准备测试环境可能非常方便。对于高级的仓库管理功能,请记得尝试 Red Hat Satellite。
在学习了仓库的基础知识以及如何使用它们来管理软件之后,让我们深入了解其背后的技术,即Red Hat 软件包管理器或RPM。
理解 RPM 内部
Linux 发行版往往有自己的软件包管理器,从 Debian 的.deb
到 Arch Linux 中的 Pacman 和其他更奇特的机制。软件包管理器的目的是保持系统上安装的软件,更新它,修补它,保持依赖关系,并维护系统上安装的内部数据库。RPM 被 Fedora、openSUSE、CentOS、Oracle Linux 和当然还有 RHEL 等发行版使用。
要处理 RPM 包,系统中有rpm
命令,但自从引入yum
/dnf
以来,它在系统管理中几乎不再使用,并且不包含在 RHCSA 中。
RPM 包含以下内容:
-
要安装在系统上的文件,以 CPIO 格式存储并压缩
-
有关每个文件的权限和分配的所有者和组的信息
-
每个软件包所需和提供的依赖关系,以及与其他软件包的冲突
-
在任何这些阶段应用的安装、卸载和升级脚本
-
确保软件包未被修改的签名
为了了解一些简单有用的命令,我们将展示一些。
检查软件包的命令包括以下内容:
-
rpm –qa
:列出系统中安装的所有软件包 -
rpm –qf <filename>
:显示安装了所述文件名的软件包 -
rpm –ql <packagefile>
:列出下载软件包中包含的文件(检查先前下载的软件包很有趣)
安装、升级和删除的命令包括以下内容:
-
rpm -i <packagefile>
:安装提供的软件包列表,不获取依赖项。 -
rpm -U <packagefile>
:使用下载的软件包升级一个软件包。检查依赖关系,但不管理它们。 -
rpm -e <packagename>
:删除指定的软件包,尽管它不会删除依赖项。
如果你想了解yum
/dnf
中的依赖管理系统是如何工作的,可以尝试使用rpm -i
安装软件包。
重要的是要知道,所有已安装软件包的数据库都位于/var/lib/rpm
中,并且可以使用rpmdb
命令进行管理。
在现代时代,不得不使用rpm
命令通常意味着有低级问题,所以最好在真实生活中使用之前先尝试在测试系统中进行测试。
通过这个,我们已经完成了 RHEL 系统中的软件管理。
总结
在本章中,我们已经了解了 RHEL 8 系统中软件管理的管理部分,从订阅到安装,再到模块化和其他杂项提示。
RHEL 中所有的系统修补、更新和管理都依赖于yum
/dnf
,简化了管理依赖关系、安装正确版本的软件以及在隔离环境中分发软件。这是系统管理员更常见的任务之一,应该完全理解。
对于红帽认证工程师级别,需要更深入地了解,包括创建 RPM 软件包,这对于在自己的环境中管理、维护和分发内部生产的软件非常有用,利用红帽提供的经验和工具。
现在我们的系统已经更新,让我们继续学习如何在即将到来的章节中远程管理它们。
第二部分:使用 SSH、SELinux、防火墙和系统权限进行安全管理
生产系统的安全是系统管理员的直接责任。为了处理这个问题,RHEL 包括了诸如 SELinux、集成防火墙和标准系统权限等功能。本节提供了 RHEL 安全机制的概述和理解,以便您可以执行日常维护任务。
本节包括以下章节:
-
第八章 远程管理系统
-
第九章 使用 firewalld 保护网络连接
-
第十章 用 SELinux 保护系统
-
第十一章 使用 OpenSCAP 进行系统安全配置文件
第八章:远程管理系统
在处理系统时,一旦安装了服务器,甚至在安装过程中,管理可以远程执行。一旦安装了一台机器,其生命周期中需要执行的任务与已经执行的任务并没有太大不同。
在本章中,我们将从连接的角度讨论如何连接到远程系统,传输文件,以及如何自动化连接,使其可以被脚本化,并在网络链接出现问题时使其具有弹性。可以在系统上执行的管理任务与我们在前几章中描述的相同,例如安装软件,配置额外的网络设置,甚至管理用户。
由于管理系统需要特权凭据,我们将重点关注可被认为是安全的可用工具,以执行此类连接,以及如何使用它们来封装其他流量。
我们将涵盖以下主题:
-
SSH 和 OpenSSH 概述和基本配置
-
使用 SSH 访问远程系统
-
使用 SSH 进行基于密钥的身份验证
-
使用 SCP/rsync 进行远程文件管理
-
高级远程管理 – SSH 隧道和 SSH 重定向
-
使用 tmux 进行远程终端管理
通过涵盖这些主题,我们将能够掌握远程系统访问,并将我们的管理技能提升到下一个水平。
让我们从下一节开始讨论 SSH 协议和 OpenSSH 客户端和服务器。
技术要求
您可以继续使用我们在本书开头创建的虚拟机,在第一章 安装 RHEL8中。所需的任何额外软件包将在文本中指示。本章所需的任何额外文件可以从github.com/PacktPublishing/Red-Hat-Enterprise-Linux-8-Administration
下载。
SSH 和 OpenSSH 概述和基本配置
SSH是Secure Shell Host的缩写。它开始取代传统的 telnet 使用,telnet 是一种远程登录协议,用于连接主机时不使用加密,因此用于登录的凭据以明文形式传输。这意味着在用户终端和远程服务器之间有系统的任何人都可以拦截用户名和密码,并使用该信息连接到远程系统。这类似于通过 HTTP 而不是 HTTPS 将凭据传输到 Web 服务器时发生的情况。
使用 SSH,即使在不受信任或不安全的网络上进行连接,也会在客户端和目标主机之间创建安全通道。在这里,创建的 SSH 通道是安全的,不会泄漏任何信息。
OpenSSH 提供了服务器和客户端(在Red Hat Enterprise Linux (RHEL)中的openssh-server
和openssh-clients
软件包),可用于连接到远程主机并允许远程主机连接。
提示
知道一切是不可能的,所以对于rpm –ql package
来说,如果您记不住要使用哪个文件,审查软件包提供的文件列表非常重要。
默认情况下,客户端和服务器都允许连接,但有许多可以调整的选项。
OpenSSH 服务器
OpenSSH 是基于 OpenBSD 成员创建的最后一个免费 SSH 版本的免费实现,并更新了所有相关的安全和功能。它已成为许多操作系统的标准,既作为服务器又作为客户端,以在它们之间建立安全连接。
OpenSSH 服务器的主要配置文件位于/etc/ssh/sshd_config
(您可以使用man sshd_config
获取有关不同选项的详细信息)。一些最常用的选项如下:
-
AcceptEnv
:定义客户端设置的哪些环境变量将在远程主机上使用(例如,区域设置,终端类型等)。 -
AllowGroups
:用户应该是其成员的一组组的列表,以便访问系统。 -
AllowTcpForwarding
:允许我们使用 SSH 连接转发端口(我们将在本章后面讨论这一点,在SSH 隧道和 SSH 重定向部分)。 -
DisableForwarding
:这优先于其他转发选项,使得更容易限制服务。 -
AuthenticationMethods
:定义可以使用的身份验证方法,例如禁用基于密码的访问。 -
Banner
:在允许身份验证之前发送给连接用户的文件。这默认为无横幅,这也可能会透露运行服务的人,这可能向可能的攻击者提供了太多数据。 -
Ciphers
:与服务器交互时要使用的有效密码列表。您可以使用+
或-
来启用或禁用它们。 -
ListenAddress
:sshd
守护程序应该监听传入连接的主机名或地址和端口。 -
PasswordAuthentication
:默认为是,可以禁用以阻止用户与系统进行交互连接,除非使用公钥/私钥对。 -
PermitEmptyPasswords
:允许没有密码的帐户访问系统(默认为否)。 -
PermitRootLogin
:定义根用户的登录方式,例如,避免根用户使用密码远程连接。 -
Port
:与ListenAddress
相关,这默认为22
。这是sshd
守护程序监听传入连接的端口号。 -
Subsystem
:配置外部子系统的命令。例如,它与sftp
一起用于文件传输。 -
X11Forwarding
:这定义了是否允许X11
转发,以便远程用户可以通过隧道连接在本地显示器上打开图形程序。
以下截图显示了我们在删除注释时系统安装的选项:
图 8.1 - 安装时在/etc/ssh/sshd_config 中定义的默认值
我们将在下一节检查配置的客户端部分。
OpenSSH 客户端
OpenSSH 的客户端部分通过/etc/ssh/ssh_config
文件和/etc/ssh/ssh_config.d/
文件夹中的文件进行系统范围的配置。它们还通过每个用户的~/.ssh/config
文件进行配置。
通常,系统范围的文件只包含一些注释,而不是实际设置,因此我们将专注于每个用户配置文件和命令行参数。
我们~/.ssh/config
文件中的一个示例条目可能如下:
Host jump
Hostname jump.example.com
User root
Compression yes
StrictHostKeyChecking no
GSSAPIAuthentication yes
GSSAPIDelegateCredentials yes
GSSAPIKeyExchange yes
ProxyCommand connect-proxy -H squid.example.com:3128 %h %p
ControlPath ~/.ssh/master-%r@%h:%p
ControlMaster auto
在前面的示例中,我们定义了一个名为jump
的条目(我们可以在ssh jump
中使用),它将root
用户名连接到jump.example.com
主机。
这是一个基本设置,但我们还定义了我们将使用ProxyCommand
中的辅助程序,该程序将利用端口3128
上的squid.example.com
代理服务器连接到%h
主机和%p
端口以到达我们的目标系统。此外,我们正在使用Compression
并使用ControlMaster
进行额外的GSSAPI
身份验证。
一个具有安全影响的特性是StrictHostKeyChecking
。当我们第一次连接到主机时,密钥在客户端和主机之间交换,并且服务器使用这些密钥来标识自己。如果它们被接受,它们将被存储在用户家目录下的.ssh/known_hosts
文件中。
如果远程主机密钥发生变化,ssh
客户端的终端将打印警告并拒绝连接,但当我们将StrictHostKeyChecking
设置为no
时,我们将接受服务器发送的任何密钥,这在我们使用频繁重新部署的测试系统时可能很有用(因此会生成新的主机密钥)。一般情况下不建议使用,因为它可以保护我们免受服务器被替换以及有人冒充我们要连接的服务器并记录用户名和密码以后访问我们系统的风险。
在接下来的部分,我们将学习如何使用ssh
访问远程系统。
使用 SSH 访问远程系统
正如我们在本章前面提到的,SSH 是用于连接远程系统的协议。一般来说,其最基本形式的语法就是在终端中执行ssh host
。
然后,ssh
客户端将使用当前登录用户的用户名默认地在目标主机上启动与ssh
服务器的连接,并尝试在默认的22/tcp
端口上到达远程服务器,这是 SSH 服务的默认端口。
在下面的截图中,我们可以看到离我们的localhost
系统最近的服务器,这意味着我们将连接到我们自己的服务器:
图 8.2 – 向本地主机发起 SSH 连接
在前面的截图中,我们可以看到与服务器的第一次交互打印了服务器的指纹以进行身份验证。这就是前一节讨论的内容;即StrictHostKeyChecking
。一旦接受,如果主机密钥发生变化,连接将被拒绝,直到我们手动删除旧密钥以确认我们知道服务器的变化。
让我们添加密钥并再试一次,如下面的截图所示:
图 8.3 – 向本地主机发起 SSH 连接被拒绝
在我们的第二次尝试中,连接失败了,但让我们来看一下输出;即Permission denied (publickey,gssapi-keyex,gssapi-with-mic)
。这是什么意思?如果我们注意到,password
没有列出,这意味着我们无法通过密码提示连接到这个主机(这是因为我们在/etc/ssh/sshd_config
文件中将PasswordAuthentication
设置为no
)。
在下面的截图中,我们可以看到一旦我们将PasswordAuthentication
设置为yes
,系统会要求输入密码,密码不会显示在屏幕上。一旦验证通过,我们就会得到一个 shell 提示,这样我们就可以开始输入命令了:
图 8.4 – SSH 连接已完成
一般来说,密码身份验证可能存在安全风险,因为键盘可能被拦截,有人可能在你身边偷看,可能会对帐户使用暴力攻击等等。因此,通常的做法是至少禁用root
用户的密码身份验证,这意味着试图登录系统的人应该知道一个用户的用户名和密码,然后使用系统工具成为root
。
让我们学习如何通过身份验证密钥登录禁用密码的远程系统。
使用 SSH 进行基于密钥的身份验证
SSH 连接的一个重要优势是可以给出要在远程主机上执行的命令,例如,获取可以用于监视的更新数据,而无需在主机上安装特定的代理。
在每次连接时提供登录详细信息并不是我们认为对用户体验有所改进的事情,但 SSH 也允许我们创建一个密钥对,用于对远程系统进行身份验证,因此不需要输入密码或凭据。
密钥包含两部分:一部分是公开的,必须在我们要连接的每个主机上进行配置,另一部分是私有的,必须得到保护,因为它将用于在我们尝试连接到远程主机时识别我们。
毋庸置疑,整个过程都是在 SSH 创建的加密连接上进行的。因此,使用 SSH 和压缩也将使我们的连接速度更快,而不是其他遗留方法,如未加密的 telnet。
首先,让我们为身份验证创建一个密钥对。
提示
建议每个用户至少拥有一个密钥对,以便每个用户在连接到服务器时都可以基于角色拥有密钥。即使密钥可以共享给角色中的用户,最好还是让每个用户拥有自己的密钥对,以便可以单独撤销密钥。例如,我们可以保留几个ssh
密钥对,用于不同的角色,如个人系统、生产系统、实验室系统等。必须指定用于连接的密钥对也是额外的安全措施:除非使用生产密钥对,否则我们无法连接到生产系统。
创建密钥对,我们可以使用ssh-keygen
工具,该工具有几个选项用于创建密钥,如下面的屏幕截图所示:
图 8.5 - ssh-keygen 选项
当没有提供参数时,默认情况下,它将为当前用户创建一个密钥,并要求为密钥设置密码。当我们使用默认值并不提供数值时,我们会得到类似于下面屏幕截图中所示的输出。
图 8.6 - ssh-keygen 执行在~/.ssh/{id_rsa,id_rsa.pub}下创建 RSA 密钥对
从这一点开始,该系统已为根用户创建了一个密钥对,并将其两部分存储在同一个文件夹中,默认情况下是.ssh
。公共部分包含.pub
后缀,而另一个包含私钥。
我们如何使用它们?如果我们在家目录的.ssh
文件夹中查看,可以看到几个文件:我们有一个authorized_keys
文件和一个known_hosts
文件,除了刚刚创建的密钥对。authorized_keys
文件将每行包含一个条目。这包含了可以用于此用户登录到此系统的公钥。
提示
可以与authorized_keys
一起使用的各种选项远不止添加常规密钥 - 您还可以定义要执行的命令、密钥的到期时间、可以用于连接的远程主机,以便只有这些主机才能成功使用该密钥,等等。再次强调,man sshd
是您的朋友,因此请查看其中的AUTHORIZED_KEYS FILE FORMAT
部分,以了解更复杂的设置。
为了简化在远程系统上设置密钥的过程,我们有ssh-copy-id
实用程序,它通过ssh
连接到远程主机。这将要求输入ssh
密码,并在我们的系统上安装可用的公钥。但是,这需要系统启用密码验证。
另一种方法是手动将我们的公钥附加到该文件(.ssh/authorized_keys
),如下面的屏幕截图所示:
图 8.7 - ssh-copy-id 失败和私钥手动授权
第一行尝试使用ssh-copy-id
,但由于我们启用了密码验证,它尝试复制我们的公钥并失败了。然后,我们使用>>
将公钥附加到authorized_keys
文件中。最后,我们演示了如何使用ssh
连接到localhost
并在不需要密码的情况下执行命令。
重要提示
.ssh
文件夹和authorized_keys
文件的权限不能太开放(例如,777)。如果是这样,ssh
守护程序将拒绝它们,因为有人可能已经添加了新的密钥,并试图在没有真正成为系统合法用户的情况下获得访问权限。
刚刚发生的事情打开了一个新的自动化世界。使用我们的系统和远程主机之间交换的密钥,我们现在可以远程连接到它们,以交互方式运行命令或对要在远程主机上执行的命令进行脚本化。我们可以在我们的终端中检查结果。让我们考虑这个简单的脚本,用于系统负载平均值检查,可以在github.com/PacktPublishing/Red-Hat-Enterprise-Linux-8-Administration/raw/main/chapter-08-remote-systems-administration/loadaverage-check.sh
找到:
#!/usr/bin/bash
for system in host1 host2 host3 host4;
do
echo "${system}: $(ssh ${system} cat /proc/loadavg)"
done
在这个例子中,我们正在运行一个循环来连接四个系统,然后输出该系统的名称和负载平均值,如下面的屏幕截图所示:
图 8.8-无密码登录到四个主机以检查其负载平均值
正如我们所看到的,我们迅速从四个主机上获取了信息。如果您想在您的环境中测试这一点,您可能想要实践一下我们在第六章中学到的关于在/etc/hosts
文件中创建条目的内容,该文件指向我们想要尝试的主机名的127.0.0.1
,以便连接到您自己的练习系统,正如我们在第六章中解释的那样,启用网络连接。
现在,想想我们远程管理系统的不同选项:
-
检查一系列主机的 IP。
-
安装更新或添加/删除一个软件包。
-
检查本地时间以防系统偏离。
-
在向系统添加新用户后重新启动一个服务。
还有更多选项,但这些是主要选项。
当然,还有更适合远程管理系统并确保错误被正确检测和处理的工具,比如使用 Ansible,但在这种情况下,对于简单的任务,我们可以继续进行。
以前,我们创建了一个密钥,并在要求输入密码时回复了<ENTER>
。如果我们输入了密码会怎样?我们将在下一节中讨论这个问题。
SSH 代理
如果我们决定创建一个带有密码保护的 SSH 密钥(明智的选择),我们将需要在每次使用密钥时输入密码,因此最终它可能与输入密码一样不安全,因为有人可能在我们的肩膀上观察。为了克服这一点,我们可以使用一个名为ssh-agent
的程序,它可以临时将密码保留在内存中。这很方便,可以减少在输入密钥时有人观察的机会。
当您使用图形桌面时,比如ssh-agent
。
当执行ssh-agent
时,它将输出一些变量,必须在我们的环境中设置这些变量,以便我们可以利用它,如下面的屏幕截图所示:
图 8.9-使用 ssh-agent 设置所需的变量
如前面的屏幕截图所示,在被执行之前,或者在我们执行代理时,这些变量是未定义的。但是,如果我们执行eval $(ssh-agent)
,我们将实现目标,即使这些变量被定义并准备好使用。
下一步是将密钥添加到代理。这可以通过ssh-add
命令来完成,该命令可以在不带参数的情况下使用,也可以通过指定要添加的密钥来使用。如果密钥需要密码,它将提示您输入密码。完成后,我们可能能够使用该密钥以缓存的密码登录到系统,直到我们退出执行代理的会话,从而将密码从内存中清除。
下面的屏幕截图显示了用于生成带密码的新密钥对的命令。在这里,我们可以看到唯一的区别是我们将其存储在名为withpass
的文件中,而不是我们在本章早些时候所做的:
图 8.10 - 使用密码创建额外的 ssh 密钥对
我们可以看到如何连接到我们的本地主机(我们已经为其添加了带密码的公共部分到我们的.ssh/authorized_keys
,同时删除了没有密码的部分),以及连接在下面的屏幕截图中的行为:
图 8.11 - 使用 ssh-agent 记住我们的密码
为了更清楚地说明这一点,让我们分析一下正在发生的事情:
-
首先,我们
ssh
到主机。由于我们使用的默认密钥已从authorized_keys
中删除,因此权限被拒绝。 -
我们再次
ssh
,但在定义身份文件(密钥对)以连接时,我们可以看到,我们被要求输入密钥的密码,而不是登录到系统。 -
然后,我们注销并关闭连接。
-
接下来,我们尝试添加密钥,但由于我们尚未为代理设置环境变量,因此出现错误。
-
按照我们介绍代理时的指示,我们在当前 shell 中执行加载代理环境变量的命令。
-
当我们尝试使用
ssh-add withpass
添加密钥时,代理会要求输入我们的密码。 -
当我们最终
ssh
到主机时,我们可以连接而无需密码,因为密钥已经在我们的密钥对的内存中。
在这里,我们已经实现了两件事:我们现在有了一个自动化/无人参与的连接系统的方法,并确保只有授权用户才能知道解锁它们的密码。
我们将在下一节学习如何进行远程文件管理!
SCP/rsync - 远程文件管理
与telnet
类似,许多设备和系统上已经用ssh
替换了它,使用不安全的文件传输解决方案正在减少。默认情况下是21
,但由于通信是明文的,因此很容易被拦截凭据。FTP 仍然被广泛使用,主要用于在只允许匿名访问并希望转移到更安全选项的服务器上提供文件。
SSH 通常启用两个接口来复制文件:scp
和sftp
。第一个用法类似于常规的cp
命令,但在这里,我们接受远程主机作为我们的目标或源,而sftp
使用了类似于与 FTP 服务器交互的传统ftp
命令的客户端方法。只需记住,在这两种情况下,连接都是加密的,并且在目标主机上通过22/tcp
端口进行。
我们将在下一节深入研究 SCP。
使用 OpenSSH 安全文件传输传输文件
scp
命令是openssh-clients
软件包的一部分,允许我们使用整个过程的ssh
层在系统之间复制文件。这使我们能够安全地传输文件内容,以及通过密钥对登录引入的所有自动化功能,到各种系统。
为了设置这个例子,我们将在我们的示例系统中创建一个新用户,该用户将用于使用本节描述的工具复制文件,如下面的屏幕截图所示:
图 8.12 - 准备我们的系统,添加额外用户以练习文件传输
您可以在github.com/PacktPublishing/Red-Hat-Enterprise-Linux-8-Administration/raw/main/chapter-08-remote-systems-administration/create-kys-user.sh
中找到前面的命令的脚本。
一旦用户已创建并且密钥已复制,我们就可以开始测试了!
在本章的前面,我们创建了一个名为withpass
的密钥,其公共对应物为withpass.pub
。为了将密钥提供给新创建的用户,我们可以通过以下命令将两个文件都复制到kys
用户:
scp withpass* kys@localhost:
让我们使用这个模板来分析命令的每个部分:
scp origin target
在我们的情况下,origin
用withpass.*
表示,这意味着它将选择以withpass
字符串开头的所有文件。
我们的target
值是一个远程主机。在这里,用户名是kys
,主机是localhost
,应该存储文件的文件夹是默认文件夹,通常是指定用户的主文件夹(在:
符号后的空路径的用户)。
在下面的截图中,我们可以看到命令的输出以及我们稍后可以通过远程执行进行的验证:
图 8.13 - 将 SCP 文件复制到远程路径并验证已复制的文件
在前面的截图中,您还可以检查由 root 用户拥有的文件是否已复制。复制的文件由kys
用户拥有,因此文件内容相同,但由于目标上的创建者是kys
用户,文件具有其所有权。
我们还可以通过首先指定远程文件然后将本地路径作为目标来进行更复杂的复制,以便将文件下载到我们的系统,或者甚至在远程位置之间复制文件(除非我们指定-3
选项,否则它们将直接从origin
到target
)。
提示
提醒时间!man scp
将向您显示scp
命令的所有可用选项,但由于它基于ssh
,我们使用ssh
的大多数选项也可用,以及我们在.ssh/config
文件中定义的主机定义。
我们将在下一节中探索sftp
客户端。
使用 sftp 传输文件
与scp
相比,可以像使用常规cp
命令一样编写脚本,sftp
具有用于浏览远程系统的交互式客户端。但是,当指定包含文件的路径时,它也可以自动检索文件。
要了解可用的不同命令,可以调用help
命令,它将列出可用的选项,如下面的截图所示:
图 8.14 - 可用的 sftp 交互模式命令
让我们通过以下截图来看一个例子:
图 8.15 - sftp 的两种操作模式 - 自动传输或交互传输
在这个例子中,我们创建了一个本地文件夹作为我们的工作文件夹,名为getfilesback
。首先,我们使用远程路径和我们识别的文件调用了sftp
。在这里,sftp
已自动传输了文件并停止执行。我们收到的文件现在属于我们的用户。
在第二个命令中,当我们使用用户和主机调用sftp
并进入交互模式时,我们可以执行多个命令,类似于在远程 shell 会话上可以执行的操作。最后,使用带有*
通配符字符的mget
命令,我们将文件传输到我们的本地系统。
在这两种情况下,文件都已从远程系统传输到我们的本地系统,因此我们的目标已经实现。但是,使用scp
需要知道要传输的文件的确切路径。另一方面,如果我们记不住,可能更方便使用sftp
交互式客户端内的ls
和cd
命令来浏览系统,直到找到要传输的文件。
现在,让我们学习如何使用rsync
快速传输文件和树。
使用 rsync 传输文件
虽然我们可以使用scp
的-r
选项来递归传输文件,但scp
只处理文件的完全复制,如果我们只是想在系统之间同步一些文件夹,这并不理想。
1996 年,rsync
推出,并且许多系统通过使用一个专用服务器来实现它,该服务器正在监听客户端连接。这是为了允许树与文件同步。这是通过复制文件之间的差异来完成的。在这里,比较了源和目标的部分,以查看是否应该复制差异。
通过ssh
,并且在客户端和服务器上都安装了rsync
软件包,我们可以利用ssh
创建的安全通道和rsync
提供的更快同步。
使用rsync
守护程序和使用ssh
的区别在于源或目标的语法,它要么使用rsync://
协议,要么在主机名后使用::
。在其他情况下,它将使用ssh
甚至本地文件系统。
下面的截图显示了我们通过rsync –help
命令提到的 URL 模式:
图 8.16 – rsync 命令的帮助输出
现在,让我们回顾一些我们可以与rsync
一起使用的有用选项:
-
-v
:在传输过程中提供更详细的输出。 -
-r
:递归进入目录。 -
-u
:更新 - 仅复制比目标文件更新的文件。 -
-a
:归档(包括多个选项,如–rlptgoD
)。 -
-X
:保留扩展属性。 -
-A
:保留 ACL。 -
-S
:稀疏 - 空值序列将转换为稀疏块。 -
--preallocate
:在传输文件之前声明所需的空间。 -
--delete-during
:在复制过程中删除目标上没有的文件。 -
--delete-before
:在复制之前删除目标上没有的文件。 -
--progress
:显示复制的进度信息(已复制的文件与总文件数)。
r``sync
算法将文件分成块,并为传输到源的每个块计算校验和。然后将它们与本地文件的校验和进行比较。我们只允许共享源和目标之间的差异。rsync
默认不检查修改文件日期和大小,因此,如果文件在没有留下任何更改的情况下发生了更改,除非对每个候选文件强制进行校验和检查,否则可能无法检测到更改。
让我们看一些基本的例子:
rsync –avr getfilesback/ newfolder/
将会复制本地getfilesback/
文件夹中的文件到newfolder/
,并显示进度更新,但只针对更新的文件,如下面的截图所示:
图 8.17 – 在相同的源/目标上使用的 rsync 操作,重复以说明传输优化
正如我们所看到的,第二个操作只发送了 85 字节并接收了 12 字节。这是因为在文件夹之间进行了一些校验和操作以验证,因为文件没有发生更改。如果我们使用rsync -avr --progress getfilesback/ root@localhost:newfolder/
的远程目标方法,也可以获得相同的输出,但在这种情况下,将使用ssh
传输。
让我们获取一些更大的示例文件,并通过在某个时间点检出 Git 存储库,传输文件,然后更新到最新版本来比较它们,以模拟对存储库的工作。然后,我们将再次进行同步。
首先,如果尚未安装,请安装git
并执行以下代码检出一个示例存储库:
dnf –y install git # install git in our system
git clone https://github.com/citellusorg/citellus.git # clone a repository over https
cd citellus # to enter into the repository folder
git reset HEAD~400 # to get back 400 commits in history
此时,我们有一个准备好进行传输的文件夹。完成后,我们将执行git pull
以与最新更改同步,并再次使用rsync
复制差异。稍后,我们将使用--delete
删除源上不再存在的任何文件。
让我们查看以下截图中显示的顺序:
图 8.18 - 使用 rsync 将 git 文件夹同步到新文件夹
在前面的截图中,注意命令的最后一行报告的加速情况。
现在,让我们执行git pull
以获取我们缺少的 400 个更改,并再次执行rsync
。我们将得到类似以下的输出:
图 8.19 - 再次使用 rsync 复制差异
在前面的截图中,注意最后一行报告的加速情况,以便与之前的进行比较。
通过这一系列截图,我们可以检查发送的总字节数的最后数字,以查看传输的改进,以及一些已接收的文件(因为我们添加了-v
修饰符以获取详细输出和--progress
)。
最大的优势在于在较慢的网络链接上执行复制,并且定期执行,例如,作为备份目的的远程复制。这是因为rsync
只会复制更改,更新源上已修改的更新文件,并允许我们在ssh
通道上使用压缩。例如,可以使用rsync
镜像www.kernel.org/
上的 Linux 内核。
在接下来的部分,我们将深入探讨 SSH 的一个非常有趣的功能,使得连接到没有直接访问权限的服务器变得容易。
高级远程管理 - SSH 隧道和 SSH 重定向
SSH 有两个非常强大的功能,即 SSH 隧道和 SSH 重定向。当建立 SSH 连接时,不仅可以用来向远程主机发送命令并让我们像在本地系统上一样工作,还可以创建相互连接我们系统的隧道。
让我们尝试想象一个在许多公司中很常见的场景,即使用 VPN 来访问内部网络和所有服务和服务器,但使用 SSH 而不是常规 VPN。
所以,让我们在这个想象的场景中加入一些背景。
我们可以使用一个接收外部流量的主机,将来自我们的互联网路由器的ssh
重定向到该系统中的ssh
服务。因此,简而言之,我们的路由器通过 TCP 在端口22
上接收连接,并将连接转发到我们的服务器。在本练习中,我们将为这个服务器命名为堡垒。
在这种情况下,我们的常识告诉我们,即使我们可以使用其他工具或甚至ssh
连接到其他系统,我们也可以通过 SSH 到达那个堡垒主机。
我们能直接连接到内部网络中的其他主机吗?答案是肯定的,因为默认情况下,SSH 允许我们使用 TCP 转发(sshd_config
设置AllowTcpForwarding
),这使我们作为远程登录用户能够创建端口重定向,甚至是用于我们的连接的SOCKS代理。
例如,我们可以使用那个堡垒主机创建一个隧道,通过Internet Message Access Protocol(IMAP)和Simple Mail Transfer Protocol(SMTP)协议到达我们的内部邮件服务器,只需执行以下代码:
ssh –L 10993:imap.example.com:993 –L 10025:smtp.example.com:25 user@bastionhost
这个命令将监听本地端口10993
和10025
。所有在那里执行的连接将被隧道传输,直到bastionhost
将它们连接到端口993
的imap.example.com
和端口25
的smtp.example.com
。这允许我们的本地系统使用这些自定义端口配置我们的电子邮件帐户,并使用localhost
作为服务器,仍然能够访问这些服务。
提示
1024
以下的端口被视为特权端口,通常只有 root 用户才能将服务绑定到这些端口。这就是为什么我们将它们用于我们的重定向端口10025
和10093
,这样普通用户就可以使用它们,而不需要 root 用户执行ssh
连接。当您尝试绑定到本地端口时,请注意ssh
消息,以防这些端口正在使用中,因为连接可能会失败。
此外,从目标服务器的角度来看,连接将看起来好像是从堡垒服务器发起的,因为它实际上是执行连接的服务器。
当打开端口列表开始增长时,最好回到本章开头所解释的内容:~/.ssh/config
文件可以保存主机定义,以及我们想要创建的重定向,就像这个例子中所示的那样。
Host bastion
ProxyCommand none
Compression yes
User myuser
HostName mybastion.example.com
Port 330
LocalForward 2224 mail.example.com:993
LocalForward 2025 smtp.example.com:25
LocalForward 2227 ldap.example.com:389
DynamicForward 9999
在这个例子中,当我们连接到我们的堡垒主机(通过ssh bastion
)时,我们会自动启用mybastion.example.com
的330
端口,并为我们的imap
,smtp
和ldap
服务器以及9999
端口的动态转发(SOCKS 代理)定义端口转发。如果我们有不同的身份(密钥对),我们还可以通过IdentityFile
配置指令为每个主机定义我们希望使用的身份,甚至可以使用通配符,如Host *.example.com
,自动将这些选项应用于以该域结尾且没有特定配置段的主机。
注意
有时,在使用ssh
,scp
或sftp
时,目标是要到达一个可以从堡垒主机访问的系统。这里不需要其他端口转发 - 只需要到达这些系统。在这种情况下,您可以使用方便的-J
命令行选项(相当于定义ProxyJump
指令)将该主机用作跳转主机,以便到达您想要到达的最终目标。例如,ssh -J bastion mywebsiteserver.example.com
将透明地连接到bastion
,然后从那里跳转到mywebsiteserver.example.com
。
在下一节中,我们将学习如何保护自己免受远程连接的网络问题,并充分利用我们的远程终端连接。
使用 tmux 的远程终端
tmux
是一个终端复用器,这意味着它允许我们在单个屏幕内打开和访问多个终端。一个很好的类比是图形桌面中的窗口管理器,它允许我们打开多个窗口,这样我们就可以在只使用一个监视器的情况下切换上下文。
tmux
还允许我们分离和重新连接会话,因此在连接中断的情况下,它是完美的工具。例如,想象一下在服务器上执行软件升级。如果由于某种原因连接中断,那么相当于突然停止了升级过程,无论它当时处于什么状态,都可能导致不良后果。但是,如果升级是在tmux
中启动的,命令将继续执行,一旦连接恢复,会话可以重新连接,并且输出将可供检查。
首先,让我们通过dnf -y install tmux
在我们的系统上安装它。这行将下载软件包并使tmux
命令可用。请记住,tmux
的目标不是在我们的系统上安装它(即使这很有用),而是让它在我们连接的服务器上可用,以便在发生断开连接时获得额外的保护层。因此,习惯于在我们连接的所有服务器上安装它是一个好习惯。
提示
在RHEL8
之前的版本中,用于创建虚拟多路复用终端的工具是screen
,它已被标记为不推荐使用,并且只能通过EPEL
存储库获得。如果您习惯于它的键绑定(CTRL-A + <key
>),那么在tmux
中大多数都是等效的(CTRL-B + <key>
)。
在下面的截图中,我们可以看到在命令行上执行tmux
后tmux
的默认配置是什么样子的:
图 8.20 – 执行后的 tmux 默认布局
如前面的截图所示,我们的终端的视图并没有改变太多,除了窗口下部的状态栏。这显示了有关主机的一些信息,例如其名称,时间,日期以及打开窗口的列表,其中0:bash
是活动窗口,如星号(*
)符号所示。
有很多组合可以使用tmux
,让我们熟悉一些最初的用例:
-
运行
tmux
以创建一个新会话。 -
运行
tmux at
以附加到先前的会话(例如,在重新连接到主机后)。 -
运行
tmux at –d
以附加到先前的会话并从中分离其他连接。
一旦我们进入tmux
,就有一整套命令可以使用,这些命令都是以CTRL+B
键为前缀的。让我们查看一些重要的命令(请记住在使用列表中的下一个项目之前必须先按下Ctrl + B):
-
?
:显示有关要使用的快捷键的内联帮助。 -
c
:创建一个新窗口。 -
n
/p
:转到下一个/上一个窗口。 -
d
:分离tmux
会话。 -
0-9
:转到按下数字编号的窗口。 -
,
:重命名窗口。 -
"
:水平分割窗格。 -
%
:垂直分割窗格。 -
space
:切换到下一个布局。 -
&
:关闭窗口。 -
Pg down
/pg up
:在窗口历史记录中向上或向下移动。 -
箭头键:选择按下的方向中的窗格。
让我们在下面的截图中看一个示例:
图 8.21 – tmux 中有四个窗格,在同一个窗口内运行不同的命令
正如我们所看到的,有几个命令同时运行 – top
,journalctl –f
,iostat –x
和ping
– 因此这是在执行操作时监视系统的好方法。
此外,tmux
的一个优点是可以进行脚本化,因此如果我们在管理系统时使用一个布局,我们可以复制该脚本,并在连接到它们时立即执行它,这样我们就可以享受相同的布局甚至正在执行的命令。
如果您想在您的系统上尝试,可以在github.com/PacktPublishing/Red-Hat-Enterprise-Linux-8-Administration/raw/main/chapter-08-remote-systems-administration/term.sh
找到带有额外注释和描述的以下代码:
#!/bin/bash
SESSION=$USER
tmux -2 new-session -d -s $SESSION # create new session
tmux select-window -t $SESSION:0 # select first window
tmux rename-window -t $SESSION "monitoring" #rename to monitoring
tmux split-window –h #split horizontally
tmux split-window –v #split vertically
tmux split-window –h # split again horizontally
tmux select-layout tiled #tile panes
tmux selectp –t1 # select pane 1
tmux send-keys "top" C-m #run top by sending the letters + RETURN
tmux selectp –t2 # select pane 2
tmux send-keys "journalctl -f" C-m # run journalctl
tmux selectp –t3 # select pane 3
tmux send-keys "iostat -x" C-m # run iostat
tmux selectp –t0 #select the pane without commands executed
一旦设置了带有tmux
的会话,我们可以通过执行tmux
附加到刚刚创建和配置的会话,这将显示类似于前面截图中显示的布局。
总结
在本章中,我们介绍了 SSH 以及如何使用它连接到远程系统,如何使用密钥进行身份验证,无论是否需要密码,以及如何利用它进行自动化,传输文件,甚至通过端口重定向使服务可访问或可达。通过tmux
,我们学会了如何使我们的管理会话在网络中断时保持存活,并且通过自动化布局一目了然地显示重要信息。
在下一章中,我们将深入探讨通过 firewalld 来保护我们的系统网络,以仅暴露所需的服务。
第九章:使用 firewalld 保护网络连接
一位在军事受限环境中工作的优秀导师和技术专家曾经告诉我:“唯一安全的系统是关闭的系统,断开任何网络连接,并埋在沙漠中。”当然,他是对的,但我们必须提供服务使系统有用。这意味着让它运行并连接到网络。
在安全中使用的一种技术是减少事件发生,例如避免意外暴露漏洞和启用未经授权的远程访问,这是减少攻击面和应用深度防御原则的步骤之一。在网络中这样做的第一步是使用firewall-cmd
和systemd
服务单元来过滤连接,以简化其管理。
在本章中,我们将涵盖以下主题,以便更好地了解如何管理 RHEL 中的默认防火墙:
-
介绍 RHEL 防火墙 - firewalld
-
在系统上启用 firewalld 并查看默认区域
-
审查 firewalld 下的不同配置项
-
启用和管理服务和端口
-
创建和使用 firewalld 的服务定义
-
使用 Web 界面配置 firewalld
介绍 RHEL 防火墙 - firewalld
RHEL 带有两种低级网络流量过滤机制:firewall-cmd
)。在本节中,我们将查看 RHEL 中的防火墙默认设置。
firewalld 默认安装在系统中,我们可以使用rpm
命令来检查,因此无需安装它:
[root@rhel8 ~]# rpm -qa | grep firewalld
firewalld-filesystem-0.8.2-2.el8.noarch
firewalld-0.8.2-2.el8.noarch
如果由于某种原因我们的安装不包括 firewalld,我们可以通过运行dnf install firewalld
来安装它。
firewalld 包括一个名为firewalld
的服务,默认情况下配置为在启动时运行。我们可以使用systemctl status firewalld
命令来检查这一点:
图 9.1 - "systemctl status firewalld"的输出
正如我们所看到的,firewalld
服务已启用并正在运行。这是 RHEL 系统的默认状态。
系统管理员配置 firewalld 的主要方式是使用firewall-cmd
命令。但是,您也可以执行以下操作:
-
在
/etc/firewalld/
中添加带有服务定义的新文件(如本章的创建和使用 firewalld 的服务定义部分所述) -
使用名为cockpit的 Web 界面配置防火墙(如本章的使用 Web 界面配置 firewalld部分所述)
-
在您的桌面环境中使用
firewall-config
图形界面
在本章中,我们将回顾主要机制和 Web 界面。
现在我们知道了 RHEL 主防火墙的默认设置,让我们学习如何启用它。
在系统上启用 firewalld 并查看默认区域
我们已经看到了systemctl
。让我们停止firewalld
服务:
[root@rhel8 ~]# systemctl stop firewalld
[root@rhel8 ~]# systemctl status firewalld
firewalld.service - firewalld - dynamic firewall daemon
Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled; vendor preset: enabled)
Active: inactive (dead) since Sun 2021-02-28 17:36:45 CET; 4s ago
Docs: man:firewalld(1)
Process: 860 ExecStart=/usr/sbin/firewalld --nofork --nopid $FIREWALLD_ARGS (code=exited, status=>
Main PID: 860 (code=exited, status=0/SUCCESS)
feb 28 17:36:19 rhel8.example.com systemd[1]: Starting firewalld - dynamic firewall daemon...
feb 28 17:36:20 rhel8.example.com systemd[1]: Started firewalld - dynamic firewall daemon.
feb 28 17:36:20 rhel8.example.com firewalld[860]: WARNING: AllowZoneDrifting is enabled. This is co>
feb 28 17:36:45 rhel8.example.com systemd[1]: Stopping firewalld - dynamic firewall daemon...
feb 28 17:36:45 rhel8.example.com systemd[1]: firewalld.service: Succeeded.
feb 28 17:36:45 rhel8.example.com systemd[1]: Stopped firewalld - dynamic firewall daemon.
在上一个输出中,如粗体所示,服务处于非活动状态。我们可以使用firewall-cmd --state
命令来检查这一点:
[root@rhel8 ~]# firewall-cmd --state
not running
目前,防火墙服务已停止,所有规则已被删除。然而,服务的配置并未更改,因此如果我们重新启动系统,firewalld 将会再次运行。
提示
我们可以通过运行nft list table filter
命令始终查看底层的netfilter
规则。您可能希望在停止服务之前和之后运行它以查看差异。
现在,让我们尝试重新启动服务:
[root@rhel8 ~]# systemctl start firewalld
[root@rhel8 ~]# systemctl status firewalld
firewalld.service - firewalld - dynamic firewall daemon
Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled; vendor preset: enabled)
Active: active (running) since Sun 2021-02-28 17:43:31 CET; 7s ago
Docs: man:firewalld(1)
Main PID: 1518 (firewalld)
Tasks: 2 (limit: 8177)
Memory: 23.3M
CGroup: /system.slice/firewalld.service
└─1518 /usr/libexec/platform-python -s /usr/sbin/firewalld --nofork –nopid
让我们检查 firewalld 是否正在运行:
[root@rhel8 ~]# firewall-cmd --state
running
要完全禁用服务,我们需要运行以下命令:
[root@rhel8 ~]# systemctl disable firewalld
Removed /etc/systemd/system/multi-user.target.wants/firewalld.service.
Removed /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service.
让我们看看服务已禁用但仍在运行:
[root@rhel8 ~]# systemctl status firewalld -n0
firewalld.service - firewalld - dynamic firewall daemon
Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; vendor preset: enabled)
Active: active (running) since Sun 2021-02-28 17:43:31 CET; 8min ago
Docs: man:firewalld(1)
Main PID: 1518 (firewalld)
Tasks: 2 (limit: 8177)
Memory: 24.1M
CGroup: /system.slice/firewalld.service
└─1518 /usr/libexec/platform-python -s /usr/sbin/firewalld --nofork –nopid
当您使用systemctl
管理服务时,您需要了解启用和禁用服务只影响启动顺序中的行为,而启动和停止只影响服务的当前状态。
提示
要在一条命令中禁用和停止,我们可以使用--now
选项;例如,systemctl disable firewalld --now
。此选项也可用于启用和启动;例如,systemctl enable firewalld --now
。
让我们重新启用服务,并确保它正在运行:
[root@rhel8 ~]# systemctl enable firewalld --now
Created symlink /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service → /usr/lib/systemd/system/firewalld.service.
Created symlink /etc/systemd/system/multi-user.target.wants/firewalld.service → /usr/lib/systemd/system/firewalld.service.
[root@rhel8 ~]# firewall-cmd --state
running
现在我们知道如何启动和停止,以及启用和禁用firewalld
服务,让我们通过审查默认配置来了解配置结构并学习如何与其交互。
审查 firewalld 下的不同配置项
firewalld 在其配置中管理三个概念:
-
区域:firewalld 区域是一组规则,可以一起激活并分配给网络接口。它包括不同的服务和规则,还包括改变网络流量过滤行为的设置。
-
服务:firewalld 服务是必须一起配置的端口或端口组,以便特定系统服务(因此得名)能够正常工作。
-
80
)和流量类型(即 TCP),可用于手动启用网络流量到自定义系统服务。
firewalld 管理两种类型的配置:
-
运行:当前应用于系统的规则。
-
永久:已保存的规则,将在服务启动时加载。
重要提示
运行与永久之间的概念是在运行系统中尝试网络过滤规则,一旦确保它们运行良好,就将它们保存为永久规则。记得检查你想要的规则是否已经正确保存在系统中。
现在,让我们检查一下我们的系统,看看有哪些可用的区域:
[root@rhel8 ~]# firewall-cmd --get-zones
block dmz drop external home internal nm-shared public trusted work
我们还可以检查默认应用的区域是哪个:
[root@rhel8 ~]# firewall-cmd --get-default-zone
public
让我们通过查看以下表格来回顾 firewalld 中可用的区域:
重要提示
您可以随时通过访问系统中可用的firewalld.zones
手册页面来获取有关这些区域以及更多信息。一个很好的练习是查看前面提到的手册页面。
上述服务将在下一节中进行更详细的审查。现在,让我们学习如何管理区域。
让我们将默认区域更改为home
:
[root@rhel8 ~]# firewall-cmd --set-default-zone=home
success
[root@rhel8 ~]# firewall-cmd --get-default-zone
home
我们可以将public
区域设为默认,并将home
区域分配给我们的本地网络:
[root@rhel8 ~]# firewall-cmd --set-default-zone=public
success
[root@rhel8 ~]# firewall-cmd --permanent --zone=internal \
--add-source=192.168.122.0/24
success
[root@rhel8 ~]# firewall-cmd --reload
success
[root@rhel8 ~]# firewall-cmd --get-active-zones
internal
sources: 192.168.122.0/24
public
interfaces: enp1s0
此配置允许我们仅将服务发布到本地网络,该网络被定义为192.168.122.0/24
,并分配给internal
区域。从现在开始,分配给internal
区域的任何服务或端口只有在从内部网络的 IP 地址访问时才能访问。我们避免允许其他网络访问这些服务。
此外,要使服务可以从任何其他网络访问,我们只需要将它们分配给public
区域。
让我们回顾一下常用的主要选项,以及可能有用的一些其他选项:
-
--get-zones
:列出系统中已配置的区域。 -
--get-default-zone
:显示默认配置的区域。 -
--set-default-zone=<zone>
:设置默认区域。这将应用于运行和永久配置。 -
--get-active-zones
:显示正在使用的区域以及它们适用于哪些网络/接口。 -
--zone=<zone>
:用于为另一个选项指定区域。 -
--permanent
:用于将更改应用于保存的配置。当使用此选项时,更改将不会应用于运行配置。 -
--reload
:加载保存的配置作为运行配置。 -
--add-source=<network>
:将源网络(CIDR 格式)添加到指定的区域。如果未指定区域,则使用默认区域。更改将应用于运行配置;使用--permanent
来保存它们。 -
--remove-source=<network>
:从指定的区域中删除源网络(CIDR 格式)。如果未指定区域,则使用默认区域。更改将应用于运行配置;使用--permanent
来保存它们。 -
--add-interface=<interface>
:将来自接口的流量路由到一个区域。如果没有指定,默认区域将被使用。 -
--change-interface=<interface>
:更改路由到接口的流量到一个区域。如果没有指定,将使用默认区域。
尽管这些选项列表可能非常有用,但完整的选项列表可在firewall-cmd
的手册页上找到。您应该经常使用它来重新配置防火墙选项。
提示
要查看firewall-cmd
的手册页,只需运行man firewall-cmd
。
既然我们知道了区域是什么以及它们是如何选择的,让我们学习如何管理服务和端口。
启用和管理服务和端口
正如我们在前一节中提到的,firewalld 服务是一种端口或一组端口,它们被一起配置为特定系统服务(因此得名)以使其正常工作。有一组服务在一个或多个可用的firewalld 区域中默认启用。让我们从回顾它们开始:
-
22
,是TCP
类型。 -
224.0.0.251
(IPv4)或ff02::fb
(IPv6),端口5353
,是UDP
类型。 -
631
,使用UDP
协议。 -
137
和138
,是UDP
类型。 -
fe80::/64
,端口546
,是UDP
类型。 -
9090
,它是TCP
类型。
如您所见,firewalld 服务可以指定多个端口、目标地址,甚至目标网络。
现在,让我们看看在我们的防火墙中配置的服务:
[root@rhel8 ~]# firewall-cmd --list-services
cockpit dhcpv6-client ssh
[root@rhel8 ~]# firewall-cmd --list-services --zone=internal
cockpit dhcpv6-client mdns samba-client ssh
请注意,当您没有建立一个区域时,显示的服务是与默认区域相关的服务 - 在这种情况下是public
。但是,请考虑我们配置了多个区域。
现在,让我们安装一个 Web 服务器 - 在这种情况下,是 Apache httpd
服务器:
[root@rhel8 ~]# dnf install httpd -y
Updating Subscription Management repositories.
Last metadata expiration check: 0:25:05 ago on lun 01 mar 2021 17:02:09 CET.
Dependencies resolved.
====================================================================================================
Package Arch Version Repository Size
====================================================================================================
Installing:
httpd x86_64 2.4.37-30.module+el8.3.0+7001+0766b9e7 rhel-8-for-x86_64-appstream-rpms 1.4 M
Installing dependencies:
apr x86_64 1.6.3-11.el8 rhel-8-for-x86_64-appstream-rpms 125 k
[omitted]
Installed:
apr-1.6.3-11.el8.x86_64
apr-util-1.6.1-6.el8.x86_64
apr-util-bdb-1.6.1-6.el8.x86_64
apr-util-openssl-1.6.1-6.el8.x86_64
httpd-2.4.37-30.module+el8.3.0+7001+0766b9e7.x86_64
httpd-filesystem-2.4.37-30.module+el8.3.0+7001+0766b9e7.noarch
httpd-tools-2.4.37-30.module+el8.3.0+7001+0766b9e7.x86_64
mailcap-2.1.48-3.el8.noarch
mod_http2-1.15.7-2.module+el8.3.0+7670+8bf57d29.x86_64
redhat-logos-httpd-81.1-1.el8.noarch
Complete!
让我们启用并启动httpd
服务:
[root@rhel8 ~]# systemctl enable httpd --now
Created symlink /etc/systemd/system/multi-user.target.wants/httpd.service → /usr/lib/systemd/system/httpd.service.
[root@rhel8 ~]# systemctl status httpd -n0
● httpd.service - The Apache HTTP Server
Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
Active: active (running) since Mon 2021-03-01 17:31:57 CET; 8s ago
Docs: man:httpd.service(8)
Main PID: 2413 (httpd)
Status: "Started, listening on: port 80"
Tasks: 213 (limit: 8177)
Memory: 25.0M
CGroup: /system.slice/httpd.service
├─2413 /usr/sbin/httpd -DFOREGROUND
├─2414 /usr/sbin/httpd -DFOREGROUND
├─2415 /usr/sbin/httpd -DFOREGROUND
├─2416 /usr/sbin/httpd -DFOREGROUND
└─2417 /usr/sbin/httpd -DFOREGROUND
现在,让我们检查服务是否在所有接口上监听:
[root@rhel8 ~]# ss -a -A "tcp" | grep http
LISTEN 0 128 *:http *:*
可选地,我们可以使用外部机器检查端口是否打开(如果有的话):
[root@external:~]# nmap 192.168.122.8
Starting Nmap 7.80 ( https://nmap.org ) at 2021-03-01 17:45 CET
Nmap scan report for rhel.redhat.lan (192.168.122.8)
Host is up (0.00032s latency).
Not shown: 998 filtered ports
PORT STATE SERVICE
22/tcp open ssh
9090/tcp closed zeus-admin
MAC Address: 52:54:00:E6:B4:A4 (QEMU virtual NIC)
Nmap done: 1 IP address (1 host up) scanned in 5.15 seconds
现在,我们可以在防火墙上启用http
服务:
[root@rhel8 ~]# firewall-cmd --add-service http \
--zone=public --permanent
success
[root@rhel8 ~]# firewall-cmd --add-service http \
--zone=internal --permanent
success
[root@rhel8 ~]# firewall-cmd --reload
success
[root@rhel8 ~]# firewall-cmd --list-services
cockpit dhcpv6-client http ssh
[root@rhel8 ~]# firewall-cmd --list-services --zone=internal
cockpit dhcpv6-client http mdns samba-client ssh
有了这个,服务已经启用,端口已经打开。我们可以从外部机器验证这一点(这是可选的):
[root@external:~]# nmap 192.168.122.8
Starting Nmap 7.80 ( https://nmap.org ) at 2021-03-01 17:50 CET
Nmap scan report for rhel.redhat.lan (192.168.122.8)
Host is up (0.00032s latency).
Not shown: 997 filtered ports
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
9090/tcp closed zeus-admin
MAC Address: 52:54:00:E6:B4:A4 (QEMU virtual NIC)
Nmap done: 1 IP address (1 host up) scanned in 5.18 seconds
我们现在可以看到端口80
已经打开。我们还可以从 Web 服务器检索主页并显示第一行:
[root@external:~]# curl -s http://192.168.122.8 | head -n 1
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
重要提示
firewalld 中的服务定义保存在/usr/lib/firewalld/services
目录中的独立文件中。如果您需要查看服务的详细信息,可以去那里检查文件和其定义。
现在,让我们尝试从公共网络中删除该服务,因为这将是一个内部服务:
[root@rhel8 ~]# firewall-cmd --list-services --zone=public
cockpit dhcpv6-client http ssh
[root@rhel8 ~]# firewall-cmd --remove-service http \
--zone=public --permanent
success
[root@rhel8 ~]# firewall-cmd --reload
success
[root@rhel8 ~]# firewall-cmd --list-services --zone=public
cockpit dhcpv6-client ssh
假设我们没有服务定义,但仍然想在public
接口上打开TCP
端口80
:
[root@rhel8 ~]# firewall-cmd --list-ports --zone=public
[root@rhel8 ~]# firewall-cmd --add-port 80/tcp --zone=public --permanent
success
[root@rhel8 ~]# firewall-cmd --reload
success
[root@rhel8 ~]# firewall-cmd --list-ports --zone=public
80/tcp
我们可以一次性查看端口和服务,如下所示:
[root@rhel8 ~]# firewall-cmd --list-all --zone=public
public (active)
target: default
icmp-block-inversion: no
interfaces: enp1s0
sources:
services: cockpit dhcpv6-client ssh
ports: 80/tcp
protocols:
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
现在,我们可以移除该端口:
[root@rhel8 ~]# firewall-cmd --list-ports --zone=public
80/tcp
[root@rhel8 ~]# firewall-cmd --remove-port 80/tcp --zone=public --permanent
success
[root@rhel8 ~]# firewall-cmd --reload
success
[root@rhel8 ~]# firewall-cmd --list-ports --zone=public
[root@rhel8 ~]#
有了这个,我们知道如何向防火墙添加和删除服务和端口,并检查它们的状态。让我们回顾一下我们可以用于firewall-cmd
的选项:
-
--zone=<zone>
:用于指定一个区域。当没有指定区域时,将使用默认区域。 -
--list-services
:显示指定区域的服务列表。 -
--add-service
:将服务添加到指定区域。 -
--remove-service
:从指定区域中删除一个服务。 -
--list-ports
:列出指定区域中打开的端口。 -
--add-port
:将端口添加到指定区域。 -
--remove-port
:从指定区域中删除一个端口。 -
--list-all
:列出与指定区域相关的端口、服务和所有配置项。 -
--permanent
:规则将应用于保存的配置,而不是运行的配置。 -
--reload
:从保存的配置重新加载规则。
现在我们知道如何在防火墙中为不同的区域分配服务和端口,让我们来看看它们是如何定义的。
创建和使用 firewalld 的服务定义
firewalld 的服务定义存储在/usr/lib/firewalld/services
目录中。让我们看一下一个简单的服务,比如存储在ssh.xml
文件中的ssh
服务,它具有以下内容:
<?xml version="1.0" encoding="utf-8"?>
<service>
<short>SSH</short>
<description>Secure Shell (SSH) is a protocol for logging into and executing commands on remote machines. It provides secure encrypted communications. If you plan on accessing your machine remotely via SSH over a firewalled interface, enable this option. You need the openssh-server package installed for this option to be useful.</description>
<port protocol="tcp" port="22"/>
</service>
在这里,我们可以看到我们只需要一个包含三个部分的 XML 文件来描述一个基本服务:
-
short
: 服务的简称 -
description
: 服务的详细描述 -
port
: 为此服务打开的端口
假设我们想在服务器上安装 Oracle 数据库。我们必须打开1521
端口,并且它必须是TCP
类型。让我们创建/etc/firewalld/services/oracledb.xml
文件,内容如下:
<?xml version="1.0" encoding="utf-8"?>
<service>
<short>OracleDB</short>
<description>Oracle Database firewalld service. It allows connections to the Oracle Database service. You will need to deploy Oracle Database in this machine and enable it for this option to be useful.</description>
<port protocol="tcp" port="1521"/>
</service>
我们可以使用以下代码来启用它:
[root@rhel8 ~]# firewall-cmd --reload
success
[root@rhel8 ~]# firewall-cmd --add-service oracledb
success
[root@rhel8 ~]# firewall-cmd --list-services
cockpit dhcpv6-client oracledb ssh
现在,它已经准备好在运行配置中使用。我们可以这样将其添加到永久配置中:
[root@rhel8 ~]# firewall-cmd --add-service oracledb --permanent
success
提示
很少需要打开更复杂的服务。无论如何,描述如何创建 firewalld 服务的手册页面是firewalld.service
,可以通过运行man firewalld.service
来打开。
有了这个,我们可以很容易地标准化要在我们系统的防火墙中打开的服务。我们可以将这些文件包含在我们的配置存储库中,以便与整个团队共享。
现在我们可以创建一个服务,让我们看一种更简单的方式来配置 RHEL 防火墙;也就是使用 Web 界面。
使用 Web 界面配置 firewalld
要使用 RHEL8 的 RHEL Web 管理界面,我们必须安装它。运行它的软件包和服务都称为cockpit
。我们可以通过运行以下代码来安装它:
[root@rhel8 ~]# dnf install cockpit -y
Updating Subscription Management repositories.
[omitted]
Installing:
cockpit x86_64 224.2-1.el8 rhel-8-for-x86_64-baseos-rpms 74 k
[omitted]
cockpit-224.2-1.el8.x86_64
cockpit-bridge-224.2-1.el8.x86_64
cockpit-packagekit-224.2-1.el8.noarch
cockpit-system-224.2-1.el8.noarch
cockpit-ws-224.2-1.el8.x86_64
Complete!
现在,让我们启用它:
[root@rhel8 ~]# systemctl enable --now cockpit.socket
Created symlink /etc/systemd/system/sockets.target.wants/cockpit.socket → /usr/lib/systemd/system/cockpit.socket.
提示
Cockpit 使用了一个巧妙的技巧来节省资源。界面被停止,但启用了一个套接字来监听端口9090
。当它接收到连接时,cockpit 就会启动。这样,它只会在使用时消耗您机器上的资源。
现在,让我们学习如何将DNS
服务添加到public
区域。
让我们通过将浏览器指向机器的 IP 和端口9090
来访问 cockpit – 在这种情况下,https://192.168.122.8:9090
。让我们使用在安装过程中提供的密码以root
身份登录:
图 9.2 – Cockpit 登录界面
现在,我们可以访问 cockpit 仪表板,其中包含有关系统的信息:
图 9.3 – Cockpit 初始界面和仪表板
现在,让我们转到网络,然后点击防火墙,如下面的截图所示:
图 9.4 – Cockpit 访问防火墙配置
在这一点上,我们可以点击添加服务在公共区域部分来修改它并添加一个服务:
图 9.5 – Cockpit 防火墙配置界面
将dns服务添加到防火墙的公共区域部分的步骤很简单:
-
点击服务。
-
通过输入
dns
来筛选服务。 -
选择dns服务,使用TCP:53和UDP:53。
-
点击添加服务:
图 9.6 – Cockpit 防火墙 – 将服务添加到公共区域
一旦你这样做了,该服务将被添加到运行和永久配置中。它将显示在 cockpit 的公共区域部分上:
图 9.7 – Cockpit 防火墙 – 将 DNS 服务添加到公共区域的结果
有了这个,我们知道如何使用 Web 界面对 RHEL8 中的防火墙进行修改。我们将把在本章开头使用命令行进行的配置删除并重新进行,但这次使用 Web 界面。
总结
安全性是系统管理的一个非常重要的部分。仅仅因为系统在隔离网络中就禁用安全措施是违背了深度防御原则的,因此这是极为不鼓励的。
在本章中,我们看到了在 RHEL8 中使用 firewalld 配置防火墙是多么简单和容易,从而为我们提供了另一个工具来管理、过滤和保护系统中的网络连接。我们还使用了 cockpit,这是一个使这项任务更加直观和易于执行的 Web 管理工具。
我们现在可以控制系统的网络连接,提供我们想要提供的服务,并为它们增加一层安全性。我们还知道如何管理区域以及如何根据系统的用例来使用它们。我们现在可以定义我们自己的自定义服务,以便我们始终可以为它们过滤网络连接。我们现在还可以通过使用 RHEL 中包含的防火墙来部署更安全的系统。
现在,我们准备在下一章中学习更多关于 RHEL 中的安全性。记住,安全是一个团队运动,系统管理员是关键。
第十章:使用 SELinux 保护系统
在本章中,我们将熟悉 SELinux。SELinux 已经存在一段时间了,但对其工作原理的不了解导致许多人建议禁用它。
这不是我们想要的,因为这就像告诉用户放弃密码因为难记一样。
我们将介绍 SELinux 的起源,以及默认模式和策略是什么。然后,我们将了解 SELinux 如何应用于我们的文件、文件夹和进程,以及如何将它们恢复到系统默认值。
此外,我们将探讨如何使用布尔值对策略进行微调,并通过以下部分的帮助解决常见问题:
-
强制和宽松模式下的 SELinux 使用
-
审查文件和进程的 SELinux 上下文
-
使用 semanage 调整策略
-
将更改的文件上下文恢复为默认策略
-
使用 SELinux 布尔设置启用服务
-
SELinux 故障排除和常见修复
最后,我们将更好地了解如何正确使用 SELinux 以及如何从它为我们的系统提供的额外保护中受益。
在本章中,将详细解释 SELinux 的工作原理,以帮助我们了解它的运作方式,即使在现实中使用它也要简单得多。我们还将使用这些示例来说明 SELinux 防止攻击或配置错误的情况。
让我们亲自动手使用 SELinux!
技术要求
可以继续使用本书开头创建的虚拟机第一章中的练习,安装 RHEL8。本章所需的任何额外软件包都将在文本旁边标明,并可从github.com/PacktPublishing/Red-Hat-Enterprise-Linux-8-Administration
下载。
强制和宽松模式下的 SELinux 使用
安全增强型 Linux(SELinux)于 2000 年 12 月通过 Linux-Kernel 邮件列表推出,是由国家安全局(NSA)启动的产品,旨在通过强制访问控制和基于角色的访问控制来提高操作系统的安全性,而不是系统中可用的传统自主访问控制。
在 Linux 内核引入 SELinux 之前,关于正确的实施方式进行了讨论,最终引入了一个名为Linux 安全模块(LSM)的内核框架,并使用它实施了 SELinux,以便其他方法也可以使用 LSM,而不仅仅是 SELinux。
SELinux 为 Linux 提供了安全改进,用户、进程甚至其他资源对文件的访问可以以非常精细的方式进行控制。
让我们举一个例子来更清楚地说明 SELinux 何时发挥作用:当 Web 服务器从用户中提供页面时,它会从用户的主目录中的public_html
或www
文件夹(最常见的文件夹)读取文件。能够从用户的主目录中读取文件可能会在 Web 服务器进程被攻击者劫持时泄露内容,而正是在这一刻,SELinux 发挥作用,因为它将自动阻止对 Web 服务器不应访问的文件的访问。
然后,SELinux 限制进程和服务只执行它们应该执行的操作,并且只使用经授权的资源。这是一个非常重要的功能,即使在可能导致访问意外文件或资源的软件错误的情况下也能保持控制。如果没有经活动策略授权,SELinux 将阻止它。
重要提示
如果用户由于不正确的文件权限而无法访问文件,那么 SELinux 权限总是在常规自主访问控制(DAC)之后出现。SELinux 在这里无能为力。
默认情况下,系统安装应该以“强制执行”模式部署,并使用“定向”策略。可以通过执行sestatus
来检查当前系统状态,如下面的屏幕截图所示:
图 10.1 – 我们系统的 sestatus 输出
正如我们所看到的,我们的系统已经启用了 SELinux,并使用了“定向”策略,目前处于“强制执行”状态。让我们了解一下这意味着什么。
SELinux 通过在系统中定义dnf list selinux-policy-*
来工作,“定向”和mls
是最常见的。
我们将专注于定向策略,但为了对mls
进行类比,su
或sudo
,它们仍然会附加原始标签,因此如果通过本地终端或远程连接进行根登录和sudo
执行,权限可能会降低。
列为“强制执行”的模式意味着当前正在执行策略,这与“宽松”相反。我们可以将其视为处于活动状态并提供保护,而“宽松”则意味着处于活动状态但只提供警告,不提供保护。
为什么我们有“宽松”而不是只禁用呢?这个问题有点棘手,所以让我们更详细地解释一下它的工作原理,以提供更好的答案。
SELinux 使用文件系统中的扩展属性来存储标签。每次创建文件时,都会根据策略分配一个标签,但只有在 SELinux 处于活动状态时才会发生这种情况,因此这使得 SELinux“禁用”与 SELinux“宽松”不同,因为前者不会为新创建的文件创建这些标签。
此外,SELinux 在“宽松”模式下允许我们查看如果程序没有得到良好的策略或文件没有适当的标签将会引发的错误。
从“强制执行”切换到“宽松”和反之都非常容易,始终通过setenforce
命令进行,而我们可以使用getenforce
来检索当前状态,如下面的屏幕截图所示:
图 10.2 – 改变 SELinux 强制执行状态
这可能看起来很基础,但实际上就是这么简单,只是运行一个命令而已。但是,如果状态被禁用,情况将完全不同。
SELinux 状态通过编辑/etc/selinux/config
文件进行配置,但更改只有在系统重新启动后才会生效;也就是说,我们可以实时从“强制执行”切换到“宽松”,或从“宽松”切换到“强制执行”,但当从“禁用”切换到“启用”,或反之,则需要重新启动系统。
一般建议是将 SELinux 保持在强制执行模式,但如果出于任何原因它被禁用,建议在从“禁用”切换时首先将 SELinux 切换到“宽松”。这将使我们能够检查系统是否实际上可以正常工作,而不会因为内核阻止对文件和资源的访问而被锁定在外面。
注意
在从“禁用”切换到“宽松”或“强制执行”后的重新启动过程中,系统将根据策略强制重新标记文件系统。这是通过在我们文件系统的根文件夹中创建一个名为/.autorelabel
的文件来实现的,这将触发该过程,并在之后再次重启。
但为什么选择禁用而不是“宽松”?例如,一些软件可能需要将其设置为禁用模式,即使以后可以重新启用以进行操作或出于其他原因,但请记住 SELinux 是一项保护系统的安全功能,应该保留。
请记住,SELinux 使用/var/log/audit/audit.log
文件以及系统日志,是一个缓存,因此规则不会被频繁检查,以加快操作速度。
让我们回到文件系统存储标签的概念,并跳转到下一节,看看它们与进程、文件以及 SELinux 提供的 RBAC 之间的关系。
审查文件和进程的 SELinux 上下文
SELinux 使用标签,也称为附加到每个文件的安全上下文,并定义了几个方面。让我们用ls –l
命令在我们的 home 文件夹中检查一个示例,但使用一个特殊的修饰符Z
,它也会显示 SELinux 属性,如下截图所示:
图 10.3 – 显示 SELinux 属性的文件列表
让我们专注于其中一个文件的输出:
-rw-r--r--. 1 root unconfined_u:object_r:admin_home_t:s0 540 Mar 6 19:33 term.sh
SELinux 属性是列为unconfined_u:object_r:admin_home_t:s0
的属性:
-
unconfined_u
-
object_r
-
admin_home_t
-
s0
在多级安全和多类别安全中
进程也会发生类似的情况,同样,我们可以在许多常见命令后添加Z
来获取上下文,例如,使用ps Z
,如下截图所示:
图 10.4 – 带有 SELinux 上下文的 ps 输出
再次,让我们检查其中一行:
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 2287661 pts/0 S+ 0:00 tmux
同样,我们可以看到相同的方法:用户、角色、类型和多级安全和多类别安全。
现在我们已经介绍了它的外观,让我们专注于它在有针对性的策略中的工作方式。
有针对性的策略允许所有东西都可以像系统中没有启用 SELinux 一样运行,除了它所针对的服务。这在安全性和可用性之间取得了很好的平衡。
在策略开发过程中,会添加新的服务,同时对其他服务进行改进,并且对许多最常见的服务编写了保护它们的策略。
SELinux 还具有名为转换的功能。转换允许由用户启动的一个进程,具有某个特定角色的二进制文件,通过执行转换为其他角色,后者用于定义其权限。
正如你所想象的那样,我们的用户也有一个 SELinux 上下文,同样,我们可以使用id -Z
命令来检查它:
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
因此,回到第一个例子,Apache Web 服务器由httpd
软件包提供,可以通过dnf –y install httpd
进行安装。安装后,让我们使用systemctl start httpd
启动它,并使用systemctl enable httpd
启用它,然后使用firewall-cmd --add-service=http
和firewall-cmd --add-service=https
打开防火墙,就像我们在前几章中对其他服务所做的那样。
先前的命令可以在以下脚本中找到:github.com/PacktPublishing/Red-Hat-Enterprise-Linux-8-Administration/raw/main/chapter-10-selinux/apache.sh
。
让我们看看以下截图中所有这些是如何发挥作用的:
图 10.5 – Web 服务器 SELinux 上下文
在这里,我们可以看到磁盘上的可执行文件具有上下文httpd_exec_t
,进程是httpd_t
,它提供的文件/文件夹是httpd_sys_content_t
,它可以工作!
现在让我们在我们的home
文件夹中创建一个index.htm
文件,并将其移动到Apache Web Root
文件夹中,如下所示:
# echo '<html><head><title>Our test</title></head><body>This is our test html</body></html>' > index.htm
# cp index.htm /var/www/html/index2.htm
# mv index.htm /var/www/html/index1.htm
让我们看看当我们尝试访问文件时会发生什么,如下截图所示:
图 10.6 – Apache 生成文件的行为
正如我们所看到的,每个文件都有一个 SELinux 上下文,但除此之外,Apache 拒绝访问我们移动的文件(index1.htm
),但显示我们复制的文件(index2.htm
)的内容。
这里发生了什么?我们复制了一个文件并移动了另一个文件,来自同一个源,但它们具有两个不同的 SELinux 上下文。
让我们扩展测试,如下截图所示:
图 10.7 – 在 SELinux 的宽容模式下重试
正如我们在前面的截图中所看到的,我们现在能够访问文件内容,所以你可以说:“SELinux 有什么问题,不允许我的网站工作?”,但正确的表达方式应该是:“看看 SELinux 如何保护我们不让个人文件在网站上泄露”。
如果不是直接将文件移动到 Apache 的/var/www/html
,而是攻击者试图访问我们的家庭文件夹文件,SELinux 将默认拒绝这些访问。httpd_t
进程无法访问admin_home_t
上下文。
当我们尝试让 Apache 或任何其他受目标策略约束的服务监听默认配置的端口之外的端口时,类似的事情会发生,了解我们可以或不可以做什么的最佳方法是学习semanage
实用程序。
使用semanage
,我们可以列出、编辑、添加或删除策略中的不同值,甚至导出和导入我们的自定义内容,所以让我们使用它来通过我们的httpd
示例学习更多关于它的知识。
让我们在下一节学习关于semanage
的知识。
使用 semanage 调整策略
正如我们之前介绍的,目标策略包含一些为其定义的服务强制执行的配置,允许保护这些服务,同时不干扰它不知道的服务。
有时候我们需要调整一些设置,比如允许http
或ssh
守护程序监听备用端口或访问其他文件类型,但又不失去 SELinux 提供的额外保护层。
首先,让我们确保在我们的系统中安装了policycoreutils
和policycoreutils-python-utils
,使用dnf –y install policycoreutils-python-utils policycoreutils
,因为它们提供了我们将在本章和下一节中使用的工具。
让我们通过一个例子来学习。让我们看看httpd_t
可以访问哪些端口,使用semanage port -l|grep http
命令:
http_cache_port_t tcp 8080, 8118, 8123, 10001-10010
http_cache_port_t udp 3130
http_port_t tcp 80, 81, 443, 488, 8008, 8009, 8443, 9000
正如我们所看到的,http_port_t
,由 Apache 守护程序使用,默认情况下允许使用tcp
的端口80
、81
、443
、488
、8008
、9009
、8443
和9000
。
这意味着如果我们想在这些端口中的任何一个上运行 Apache,不需要对策略进行任何更改。
如果我们重复这个命令,但是对于ssh
,我们只看到端口22
被打开(执行semanage port -l|grep ssh
):
ssh_port_t tcp 22
例如,我们可能想要添加另一个端口,比如2222
,到可能端口的列表中,以便隐藏标准端口被端口扫描器测试。我们可以通过semanage port -a -p tcp -t ssh_port_t 2222
来实现,然后使用先前的命令semanage port –l|grep ssh
进行验证,现在显示如下:
ssh_port_t tcp 2222, 22
正如我们所看到的,端口2222
已经添加到ssh_port_t
类型的可用端口列表中,这使得ssh
守护程序可以开始监听它(当然,这需要在我们获得可用服务之前对ssh
守护程序配置和防火墙进行额外的配置)。
同样地,例如,一些网络服务需要写入特定文件夹以存储配置,但默认情况下,/var/www/html
上的上下文是httpd_sys_content_t
,不允许写入磁盘。
我们可以通过semanage fcontext –l
检查可用的文件上下文,类似于我们对端口所做的方式,但是文件列表很长,因为 Web 服务器可能使用常见位置,如logs
和cgi-bin
,以及用于证书、配置和家目录的文件系统文件,以及 PHP 等扩展名。当您使用前面的命令检查上下文时,注意可用的不同类型以及一个列表的结构是什么,例如:
/var/www/html(/.*)?/wp-content(/.*)? all files system_u:object_r:httpd_sys_rw_content_t:s0
正如我们所看到的,有一个正则表达式匹配/var/www/html
路径内wp-content
文件夹中的文件,适用于所有文件,并设置了httpd_sys_rw_content_t
的 SELinux 上下文,这允许读写访问。这个文件夹被流行的博客软件WordPress使用,因此策略已经准备好覆盖一些最受欢迎的服务、文件夹和要求,而无需系统管理员自行编写。
在调用semanage
时,它将输出一些我们可以使用的子命令,例如以下内容:
-
import
:这允许导入本地修改。 -
export
:这允许导出本地更改。 -
login
:这允许管理登录和 SELinux 用户关联。 -
user
:这管理具有角色和级别的 SELinux 用户。 -
port
:这管理端口定义和类型。 -
ibpkey
:这管理 InfiniBand 定义。 -
ibendport
:这管理 InfiniBand 端口定义。 -
interface
:这定义了网络接口定义。 -
module
:这管理 SELinux 的策略模块。 -
node
:这管理网络节点的定义。 -
fcontext
:这管理文件上下文定义。 -
boolean
:这管理用于调整策略的布尔值。 -
permissive
:这管理强制模式。 -
dontaudit
:这管理策略中的dontaudit
规则。
对于上述每个命令,我们可以使用-h
参数来列出、帮助和了解可以用于每个命令的额外参数。
对于日常使用情况,大多数时候我们将使用port
和fcontext
,因为它们将涵盖扩展或调整 Red Hat Enterprise Linux 提供的可用服务,就像我们在ssh
监听额外端口的示例中展示的那样。
重要提示
传统上,semanage
,regexp
用于将要使用的路径。遵循这种方法时,如果文件系统重新标记或恢复上下文,应用程序将继续工作。
让我们看看如何手动设置文件的上下文以及如何在下一节中恢复默认值。
将更改的文件上下文恢复为默认策略
在前一节中,我们提到了semanage
如何使我们能够对策略进行更改,这是执行更改并将其持久化到未来文件和文件夹的推荐方式,但这并不是我们执行操作的唯一方式。
从命令行,我们可以使用chcon
实用程序来更改文件的上下文。这将允许我们为要更改的文件定义用户、角色和类型,并且与其他文件系统实用程序(如chmod
或chown
)类似,我们也可以递归地影响文件,因此很容易将整个文件夹层次结构设置为所需的上下文。
我一直觉得非常有趣的一个功能是能够通过--reference
标志复制文件的上下文,以便将引用文件的相同上下文应用于目标文件。
当我们在本章前面介绍httpd
的示例时,我们对index1.htm
和index2.htm
进行了测试,它们被移动并复制到/var/www/html
文件夹中。为了深入探讨这个例子,我们将额外复制index1.htm
,以便在下一张截图中演示chcon
的用法。请记住,直接在/var/www/html
文件夹中创建文件将设置文件具有适当的上下文,因此我们需要在/root
中创建它们,然后将它们移动到目标文件夹,正如我们在下一张截图中所看到的:
图 10.8 – 演示 chcon 用法
正如我们所看到的,index1.htm
和index3.htm
文件现在都具有适当的上下文,在第一种情况下,使用引用,在第二种情况下,定义要使用的类型。
当然,这不是唯一的方法。正如我们之前所指出的,为应用程序设置上下文的推荐方法是通过semanage
定义regexps
路径,这使我们能够使用restorecon
命令根据配置将正确的上下文应用于文件。让我们看看下面的截图中它是如何操作的:
图 10.9 – 使用 restorecon 恢复上下文
正如我们所见,我们使用了restorecon –vR /var/www/html/
,它自动将index3.htm
文件更改为httpd_sys_content_t
,这是我们在测试semanage
列出上下文时看到的该文件夹的定义。使用的参数v
和R
使实用程序报告更改(详细信息)并在提供的路径上递归工作。
假设我们通过在根文件系统上运行chcon
来搞乱了系统。修复的方法是什么?在这种情况下,正如我们之前提到的,我们应该执行以下操作:
-
将操作模式设置为
permissive
以通过setenforce 0
不阻止进一步访问。 -
放置标记以通过
touch /.autorelabel
重新标记文件系统。 -
修改
/etc/selinux/config
文件以将引导模式设置为permissive
。 -
重新启动系统以进行重新标记。
-
系统重新启动后,再次编辑
/etc/selinux/config
,将操作模式定义为enforcing
。
通过这种方式操作,而不仅仅是运行restorecon -R /
,我们确保系统是可操作的,并且在重新启动和对文件系统应用完整的重新标记后将继续运行,因此可以安全地重新启用enforcing
模式。
在下一节中,让我们看看如何在策略内部调整策略,使用布尔值来调整其工作方式。
使用 SELinux 布尔设置来启用服务
许多服务具有许多常见情况的广泛配置选项,但并非总是相同。例如,http
服务器不应访问用户文件,但与此同时,从每个用户的主目录中的www
或public_html
文件夹启用个人网站是一种常见的操作方式。
为了克服这种情况,并同时提供增强的安全性,SELinux 策略使用布尔值。
布尔值是管理员可以设置的可调整的条件,可以在策略代码中启用或禁用条件。例如,通过执行getsebol -a|grep ^http
(缩小列表)来查看httpd
可用的布尔值:
httpd_can_network_connect --> off
httpd_can_network_connect_db --> off
httpd_can_sendmail --> off
httpd_enable_homedirs --> off
httpd_use_nfs --> off
此列表是可用布尔值的缩小子集,但它确实给了我们一个它可以实现的想法;例如,默认情况下,http
不能使用网络连接到其他主机,或发送电子邮件(通常在 PHP 脚本中完成),甚至不能访问用户的主目录。
例如,如果我们想要在系统中启用用户从其主目录中的www
文件夹发布其个人网页,即/home/user/www/
,我们将不得不通过运行以下命令启用httpd_enable_homedirs
布尔值:
setsebool -P httpd_enable_homedirs=1
这将调整策略以使http
能够访问用户的主目录以在那里提供页面。如果服务器还存储在网络文件系统(NFS)或公共互联网文件系统(CIFS)挂载上,将需要额外的布尔值。我们仍然使用相同的有针对性的策略,但我们已经启用了内部条件,以允许访问不会被 SELinux 阻止。
重要提示
-P
参数对于setsebool
是必需的,以使更改永久。这意味着写入更改以使其持久化;如果没有它,一旦重新启动服务器,更改将丢失。
正如我们所见,getsebool
和setsebool
允许我们查询和设置调整策略的布尔值,而semanage boolean -l
也可以帮助我们,正如我们在下面的截图中所看到的:
图 10.10 - 使用 semanage 管理布尔值
在前面的截图中,我们不仅可以看到使用setsebool
编辑的布尔值,还可以看到预期行为的描述。
其中一个好处是,正如我们介绍的,semanage
允许我们导出和导入对策略的本地更改,因此可以将进行的任何自定义导出并导入到另一个系统,以便轻松设置类似的服务器配置文件。
策略中的所有可能的布尔值都可以使用semanage boolean –l
进行检查,类似于我们在http
示例中列出应用程序的绑定端口时所做的。
我们已经了解了使用布尔值来调整策略如何适应一些特定但相当常见的情况。接下来,我们将探索管理员可能最常用的部分,即故障排除,但重点是 SELinux。
SELinux 故障排除和常见修复
适应 SELinux 的主要问题之一是,许多不熟悉它的人会因为事情无法正常工作而责怪它;然而,这个论点已经有点过时了:SELinux 是在 2005 年推出的 Red Hat Enterprise Linux 4 中引入的。
大多数时候,与 SELinux 和我们的系统有关的问题都与更改文件上下文和更改服务端口有关,与策略本身有关的问题较少。
首先,有几个地方可以检查错误,但在我们的列表中,我们应该从审计日志或系统消息开始。例如,我们可以从我们在本章前面介绍的/var/log/audit/audit.log
文件开始。
还要记住,SELinux强制访问控制(MAC)只有在我们从常规自主访问控制(DAC)中获得了访问权限后才起作用,也就是说,如果我们没有权限检查文件(例如,模式 400 和我们的用户不是所有者),那么 SELinux 几乎不可能阻止访问。
大多数情况下,我们的系统将安装setroubleshoot-server
和setroubleshoot-plugins
软件包,提供多个工具,包括sealert
,用于查询接收到的 SELinux 消息,并且很多时候也会建议更改。
让我们来看看我们应该始终验证的一些基础知识:
-
审查所有其他控件(用户和组所有权和权限是否设置正确)。
-
不要禁用 SELinux。
如果程序无法正常工作,并且是随操作系统一起发布的,那可能是一个错误,应该通过支持案例或 Bugzilla 报告给bugzilla.redhat.com
。
只有当程序无法正常工作时,才可能使其运行不受限制,但通过定向策略保护所有其余系统服务。
- 如果这是一个现有程序,请考虑错误发生之前做了什么。
也许文件被移动而不是复制或创建,或者也许软件的端口或文件夹被更改了。
到达这一点后,我们应该检查audit.log
以获取相关消息。例如,关于我们提到的关于/var/www/html/
中文件错误上下文的示例,审计条目如下:
type=AVC msg=audit(1617210395.481:1603680): avc: denied { getattr } for pid=2826802 comm="httpd" path="/var/www/html/index3.htm" dev="dm-0" ino=101881472 scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:admin_home_t:s0 tclass=file permissive=0
看起来很奇怪,但如果我们检查参数,我们会看到受影响文件的路径、PID、源上下文(scontext
)和目标上下文(tcontext
),因此简而言之,我们可以看到httpd_t
尝试访问(获取属性)目标上下文admin_home_t
并且被拒绝的情况。
同时,如果我们正在使用setroubleshoot
,我们将在系统日志中收到这样的消息:
图 10.11 - 在系统日志中记录 setroubleshoot
正如我们在前面的截图中看到的,它已经确定其中一个插件建议对文件应用restorecon
命令,因为它与所在文件夹不匹配,并且甚至建议使用确切的命令来恢复标签。
另一个插件建议使用以下两个命令生成自定义策略:
# ausearch -c 'httpd' --raw | audit2allow -M my-httpd
# semodule -X 300 -i my-httpd.pp
然而,这种建议应该在了解正在进行的操作的情况下进行,这意味着前面的命令将修复httpd_t
以便访问home_admin_t
文件。我们可以通过仅运行第一个命令以及audit2allow
管道来了解会发生什么。
运行ausearch –c 'httpd' --raw | audit2allow –M my-httpd
在当前文件夹中创建了几个名为my-httpd
的文件,一个名为my-httpd.te
,另一个名为my-httpd.pp
。我们将不使用第二个命令来安装修改后的策略,请在了解发生了什么之前,永远不要这样做,因为我们将在接下来的行中看到。
现在对我们来说有趣的文件是my-httpd.te
(其中te表示类型强制):
module my-httpd 1.0;
require {
type httpd_t;
type admin_home_t;
class file getattr;
}
#============= httpd_t ==============
allow httpd_t admin_home_t:file getattr;
从那里,我们可以看到它使用了一个要求会话来处理涉及的类型,以及稍后的规则本身,这允许httpd_t
访问admin_home_t
文件以使用getattr
函数,没有其他东西,也没有更多东西。
正如之前所说,这将解决我们的问题吗?它将有效地允许httpd_t
访问index3.html
文件,因此将不再出现任何错误,但这将付出巨大的代价。从那时起,httpd_t
也可以读取主目录文件而不会有任何投诉。
重要提示
我不知道这个事实需要强调多少次,但在对系统采取行动之前三思。SELinux 是一种增加系统安全性的保护机制;不要禁用它,不要盲目接受audit2allow
创建的策略,而没有对问题进行初步调查和了解提出的解决方案可能是什么,因为这几乎等同于禁用 SELinux。
如果在这一点上,我们已经安装了该模块,我们可以使用semodule
来执行以下操作:
-
列出
semodule -l
。 -
安装
semodule -i $MODULE_NAME
。 -
删除
semodule –r $MODULE_NAME
。
通过前面的命令,我们可以检查或更改已加载策略模块的当前状态。
回顾系统日志后,我们可能会意识到某些事情实际上是在开始后的某个时候失败的,但不是从一开始就失败,因此使用ausearch
或将完整日志传递给audit2allow
可能没有帮助;但是,我们可以使用setroubleshootd
建议的命令来列出它们:
Mar 31 17:06:41 bender setroubleshoot[2924281]: SELinux is preventing /usr/sbin/httpd from getattr access on the file /var/www/html/index3.htm. For complete SELinux messages run: sealert -l 1b4d549b-f566-409f-90eb-7a825471aca8
如果我们执行sealert –l <ID>
,我们将收到不同插件提供的输出,以修复问题以及类似于图 10.11中显示的上下文信息。
在部署不支持 SELinux 的新软件的情况下,我们可以在测试系统中以相反的方式进行以下检查:
-
将 SELinux 设置为
permissive
模式。 -
部署软件。
-
分析收到的所有警报,看看是否有什么意外情况。
-
与软件供应商联系,并启动与 Red Hat 合作解决策略的支持案例。
如果我们因为 SELinux 正在执行并且我们已经严重搞乱了标签而被系统锁定,例如通过递归运行错误的chcon
命令来针对我们的根文件夹(例如,根据一个变量编写上下文更改的脚本,而该变量为空),我们仍然有以下方法来摆脱麻烦:
-
使用
setenforce 0
将 SELinux 置于permissive
模式。 -
运行
touch /.autorelabel
。 -
重新启动主机,以便在下次启动时,SELinux 恢复适当的标签
如果我们处于一个非常糟糕的情况,例如无法使用setenforce 0
或系统甚至无法正确引导或执行重标记,仍然有希望,但需要一些额外的步骤。
当系统重新启动时,我们可以在 grub 提示符下看到已安装内核的列表,并使用它来编辑内核引导参数。
使用selinux=0
参数,我们完全禁用了 SELinux,这是我们不想要的,但我们可以使用enforcing=0
来实现启用 SELinux,但处于permissive
模式。
一旦我们的系统启动进入permissive
模式,我们可以重复之前的过程,恢复到先前的行为,并继续在系统内部调试情况(检查系统日志等)。
总结
本章介绍了 SELinux 的工作原理,以及如何检查进程、文件和端口,以及如何通过添加新选项或使用布尔值来对它们进行微调。我们还介绍了一些初始的故障排除技能,我们应该进一步探索以增强我们的知识和经验。
正如我们所见,SELinux 是一个强大的工具,可以通过额外的层保护我们的系统,即使是来自软件本身缺陷的未知问题。
我们已经介绍了如何在文件和进程中找到 SELinux 上下文,以及这些上下文是如何通过策略应用的,以及如何调整它以使我们的系统受到保护,同时仍能提供预期的服务。
排除 SELinux 故障是一项技能,将帮助我们适应不带 Red Hat Enterprise Linux 的软件,以便仍能正常运行。
在下一章中,我们将学习使用 OpenSCAP 的安全配置文件,以继续保持我们的系统安全。
第十一章:使用 OpenSCAP 进行系统安全配置文件
SCAP代表安全内容自动化协议,这是一种标准化的检查、验证和报告漏洞评估和策略评估的方式。Red Hat Enterprise Linux (RHEL) 8 包括了工具OpenSCAP,以及用于审计和管理系统安全的配置文件。这有助于确保您正在管理的系统符合标准的安全策略,如支付卡行业数据安全标准(PCI DSS)或通用操作系统保护配置文件,或简称为OSPP,以及发现漏洞。
RHEL 8 包括了这个工具,用于审查安全配置文件以发现可能的攻击向量(配置错误或漏洞),并可以获得如何更好地加固系统的指导。我们将学习如何对系统进行扫描,并发现需要更改以准备系统完全符合监管要求的内容。我们还将学习如何使用这个工具来改进系统的安全性,以便通过审查和应用推荐的更改来提高系统的安全性。
为了了解如何使用 OpenSCAP,在本章中我们将讨论以下主题:
-
开始使用 OpenSCAP 并发现系统漏洞
-
使用 OpenSCAP 进行 OSPP 和 PCI DSS 的安全配置文件
开始使用 OpenSCAP 并发现系统漏洞
让我们从实际角度开始使用 OpenSCAP,首先审查安全工具
软件组,其中有一些值得了解的工具,然后继续运行一些扫描。
我们的初始步骤将是获取有关安全工具
的信息:
[root@rhel8 ~]# dnf group info "Security Tools"
Updating Subscription Management repositories.
Last metadata expiration check: 0:37:16 ago on dom 14 mar 2021 16:55:55 CET.
Group: Security Tools
Description: Security tools for integrity and trust verification.
Default Packages:
scap-security-guide
Optional Packages:
aide
hmaccalc
openscap
openscap-engine-sce
openscap-utils
scap-security-guide-doc
scap-workbench
tpm-quote-tools
tpm-tools
tpm2-tools
trousers
udica
这个组包括了几个安全工具,比如aide
,用于确保系统文件的完整性;tpm-tools
,用于管理openscap-utils
以审查系统中的安全策略。
我们可以通过使用dnf
来获取有关这些工具的更多信息。让我们来审查对本章更相关的一个工具,openscap-utils
:
[root@rhel8 ~]# dnf info openscap-utils
Updating Subscription Management repositories.
Last metadata expiration check: 0:03:24 ago on dom 14 mar 2021 17:38:49 CET.
Available Packages
Name : openscap-utils
Version : 1.3.3
Release : 6.el8_3
Architecture : x86_64
Size : 43 k
Source : openscap-1.3.3-6.el8_3.src.rpm
Repository : rhel-8-for-x86_64-appstream-rpms
Summary : OpenSCAP Utilities
URL : http://www.open-scap.org/
License : LGPLv2+
Description : The openscap-utils package contains command-line tools build on top
: of OpenSCAP library. Historically, openscap-utils included oscap
: tool which is now separated to openscap-scanner sub-package.
我们可以在上一个命令的输出中看到openscap-utils
软件包的相关信息,包括简要描述和主要网页的链接,其中包括更详细的信息。
提示
对于提到的每个工具运行dnf info
命令并访问它们的网页将会很有用。这样你就能更好地了解这些工具提供的功能,并能够使用它们。
现在让我们安装openscap-utils
:
[root@rhel8 ~]# dnf install openscap-utils -y
Updating Subscription Management repositories.
Last metadata expiration check: 0:04:25 ago on dom 14 mar 2021 17:38:49 CET.
Dependencies resolved.
====================================================================================================
Package Arch Version Repository Size
====================================================================================================
Installing:
openscap-utils x86_64 1.3.3-6.el8_3 rhel-8-for-x86_64-appstream-rpms 43 k
Installing dependencies:
GConf2 x86_64 3.2.6-22.el8 rhel-8-for-x86_64-appstream-rpms 1.0 M
[omitted]
rpmdevtools-8.10-8.el8.noarch
rust-srpm-macros-5-2.el8.noarch
zstd-1.4.4-1.el8.x86_64
Complete!
现在让我们安装scap-security-guide
,其中包括了 RHEL 特定的 SCAP 配置文件:
[root@rhel8 ~]# dnf install scap-security-guide -y
Updating Subscription Management repositories.
Last metadata expiration check: 15:06:55 ago on dom 14 mar 2021 17:38:49 CET.
Dependencies resolved.
====================================================================================================
Package Arch Version Repository Size
====================================================================================================
Installing:
scap-security-guide noarch 0.1.50-16.el8_3 rhel-8-for-x86_64-appstream-rpms 7.4 M
Installing dependencies:
xml-common noarch 0.6.3-50.el8 rhel-8-for-x86_64-baseos-rpms 39 k
[omitted]
Installed:
scap-security-guide-0.1.50-16.el8_3.noarch xml-common-0.6.3-50.el8.noarch
Complete!
这个软件包包括了 SCAP 安全指南,包括了与 RHEL 8 漏洞相关的指南,位于/usr/share/xml/scap/ssg/content/ssg-rhel8-oval.xml
。现在我们可以运行一个初始扫描,使用配置文件中包含的所有检查。请注意,这将包括 2323 个测试,并且这将作为一个学习可能漏洞和加固系统的练习。所以,让我们运行它:
[root@rhel8 ~]# oscap oval eval --report \
vulnerability.html \
/usr/share/xml/scap/ssg/content/ssg-rhel8-oval.xml
Definition oval:ssg-zipl_vsyscall_argument:def:1: false
Definition oval:ssg-zipl_slub_debug_argument:def:1: false
Definition oval:ssg-zipl_page_poison_argument:def:1: false
Definition oval:ssg-zipl_bootmap_is_up_to_date:def:1: false
[omitted]
Definition oval:ssg-accounts_logon_fail_delay:def:1: false
Definition oval:ssg-accounts_have_homedir_login_defs:def:1: true
Definition oval:ssg-account_unique_name:def:1: true
Definition oval:ssg-account_disable_post_pw_expiration:def:1: false
Evaluation done.
将生成一个名为vulnerability.html
的文件,其中包含扫描的输出。结果将如下所示:
图 11.1 – OpenSCAP 测试扫描的初始结果
让我们检查报告的一些细节。在左上角,我们将找到OVAL 结果生成器信息,其中包含运行的详细信息和结果摘要:
图 11.2 – OpenSCAP 测试扫描摘要
在右上角,我们可以看到OVAL 定义生成器信息,其中包含用于检查的定义摘要:
图 11.3 – OpenSCAP 测试扫描定义摘要
在这些信息标记下方,我们可以看到系统的基本摘要,如果我们有一个很长的扫描列表,并且想要将此扫描分配给适当的系统,这将非常有用:
图 11.4 - OpenSCAP 测试扫描系统摘要
在下面,我们有有关生成器的信息:
图 11.5 - OpenSCAP 测试扫描生成器信息
最后,检查结果如下:
图 11.6 - OpenSCAP 测试扫描结果
通过这次测试,我们对系统进行了漏洞扫描,得到了一组结果,根据系统的使用情况,这些结果将需要被处理。在许多情况下,收到的警告并不适用,因此我们需要仔细审查它们。这种练习在生产系统上必须小心进行,确保在应用更改之前有适当的备份和系统快照。建议在构建服务时在测试环境中运行加固,然后再将其移至生产环境。
重要提示
RHEL 8 红帽企业 Linux 系统设计指南是一个很好的文档,可以帮助我们开始系统安全工作。建议阅读该文档,以扩展本章中所学到的知识。可在access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/system_design_guide/index
找到。
让我们了解更多基础知识。对于这次扫描,我们使用了由系统软件包提供的 Red Hat 安全公告开放式漏洞评估语言(OVAL)订阅。为了检查,我们运行了 OpenSCAP 工具来审查不同的安全公告和漏洞,这些漏洞是按照 OVAL 编写的。
OVAL 要求分析的资源处于特定状态才能被认为是正确的。它以声明方式进行,这意味着描述和审查的是最终状态,而不是如何达到这个状态。
红帽安全团队生成红帽安全公告,以解决系统可能存在的不同漏洞,并为每一个漏洞发布一个 OVAL 定义。这些是公开发布的,并可在www.redhat.com/security/data/oval/v2/
上找到。
现在让我们看一下在我们的报告中找到的一个例子:
-
oval:ssg-accounts_logon_fail_delay:def:1
-
false
-
合规性
-
[accounts_logon_fail_delay]
-
确保在/etc/login.defs 中配置了 FAIL_DELAY
我们可以通过运行man login.defs
来查看其手册页面。在其中,我们会找到以下内容:
FAIL_DELAY (number)
Delay in seconds before being allowed another attempt after a
login failure.
这是一个用来确定用户在失败的登录尝试后需要等待多长时间的值。它旨在避免对系统中的帐户进行暴力攻击。我们可以采取两种方法来解决这个问题:
-
将
FAIL_DELAY
变量和值添加到login.defs
中。 -
只允许使用 SSH 密钥而不是密码来登录系统。
或者更好的是,两者都做(深度安全)。我们可以继续审查列表中的每一项,并了解每一项,以完成系统的加固,尽量避免暴露。这通常需要与安全团队协调,并且需要持续审查。
现在我们已经运行了第一次漏洞扫描,让我们看看如何在下一节中进行合规性扫描。
使用 OpenSCAP 进行 OSPP 和 PCI DSS 的安全配置文件
在行业中有几种用于合规性的安全配置文件。其中两种最常见的,我们将在这里进行审查,分别是操作系统保护配置文件(OSPP)和 PCI DSS。
OSPP 标准在公共部门中被广泛使用,为通用系统提供服务,并且也作为其他更严格环境(即,国防认证系统)的基线。
PCI DSS 是金融领域中最广泛使用的标准之一,也适用于其他希望使用信用卡进行在线支付的部门。
RHEL 8 提供了使用 OpenSCAP 工具验证这些配置文件的参考。让我们转到/usr/share/xml/scap/ssg/content/
目录,查看它们所在的位置:
[root@rhel8 ~]# cd /usr/share/xml/scap/ssg/content/
[root@rhel8 content]# ls *rhel8*
ssg-rhel8-cpe-dictionary.xml
ssg-rhel8-ds-1.2.xml
ssg-rhel8-ocil.xml
ssg-rhel8-xccdf.xml
ssg-rhel8-cpe-oval.xml
ssg-rhel8-ds.xml
ssg-rhel8-oval.xml
正如您所看到的,我们有不同类型的描述可以与 OpenSCAP 一起使用。我们已经了解了 OVAL。让我们检查最重要的几个:
-
可扩展配置清单描述格式(XCCDF):XCCDF 用于构建安全检查表。它非常常用于合规性测试和评分。
-
通用平台枚举(CPE):CPE 通过分配唯一的标识符名称来帮助识别系统。这样,它可以关联测试和名称。
-
开放清单交互语言(OCIL):OCIL 是 SCAP 标准的一部分。它是一种聚合来自不同数据存储的其他检查的方法。
-
数据流(DS):DS 是一种格式,它将几个组件组合成一个单个文件。它用于轻松分发配置文件。
提示
有关不同安全描述和组件的更多信息可以在 OpenSCAP 网页上找到,通过检查组件 URL:www.open-scap.org/features/scap-components/
。
在这种情况下,我们将使用ssg-rhel8-ds.xml
文件。让我们检查与之相关的信息:
[root@rhel8 content]# oscap info ssg-rhel8-ds.xml
Document type: Source Data Stream
[omitted]
Profiles:
Title: CIS Red Hat Enterprise Linux 8 Benchmark
Id: xccdf_org.ssgproject.content_profile_cis
Title: Unclassified Information in Non-federal Information Systems and Organizations (NIST 800-171)
Id: xccdf_org.ssgproject.content_profile_cui
Title: Australian Cyber Security Centre (ACSC) Essential Eight
Id: xccdf_org.ssgproject.content_profile_e8
Title: Health Insurance Portability and Accountability Act (HIPAA)
Id: xccdf_org.ssgproject.content_profile_hipaa
Title: Protection Profile for General Purpose Operating Systems
Id: xccdf_org.ssgproject.content_profile_ospp
Title: PCI-DSS v3.2.1 Control Baseline Red Hat Enterprise Linux 8
Id: xccdf_org.ssgproject.content_profile_pci-dss
Title: [DRAFT] DISA STIG for Red Hat Enterprise Linux 8
Id: xccdf_org.ssgproject.content_profile_stig
Referenced check files: ssg-rhel8-oval.xml
system: http://oval.mitre.org/XMLSchema/oval-definitions-5
ssg-rhel8-ocil.xml
system: http://scap.nist.gov/schema/ocil/2
security-data-oval-com.redhat.rhsa-RHEL8.xml
system: http://oval.mitre.org/XMLSchema/oval-definitions-5
Checks:
Ref-Id: scap_org.open-scap_cref_ssg-rhel8-oval.xml
Ref-Id: scap_org.open-scap_cref_ssg-rhel8-ocil.xml
Ref-Id: scap_org.open-scap_cref_ssg-rhel8-cpe-oval.xml
Ref-Id: scap_org.open-scap_cref_security-data-oval-com.redhat.rhsa-RHEL8.xml
Dictionaries:
Ref-Id: scap_org.open-scap_cref_ssg-rhel8-cpe-dictionary.xml
如您所见,它包括 RHEL 8 的 OSPP 和 PCI DSS 配置文件。让我们试试看。
扫描 OSPP 合规性
我们可以使用oscap
的--profile
选项来获取特定于OSPP配置文件的信息:
[root@rhel8 content]# oscap info --profile \
ospp ssg-rhel8-ds.xml
Document type: Source Data Stream
Imported: 2020-10-12T09:41:22
Stream: scap_org.open-scap_datastream_from_xccdf_ssg-rhel8-xccdf-1.2.xml
Generated: (null)
Version: 1.3
WARNING: Datastream component 'scap_org.open-scap_cref_security-data-oval-com.redhat.rhsa-RHEL8.xml' points out to the remote 'https://www.redhat.com/security/data/oval/com.redhat.rhsa-RHEL8.xml'. Use '--fetch-remote-resources' option to download it.
WARNING: Skipping 'https://www.redhat.com/security/data/oval/com.redhat.rhsa-RHEL8.xml' file which is referenced from datastream
Profile
Title: Protection Profile for General Purpose Operating Systems
Id: xccdf_org.ssgproject.content_profile_ospp
Description: This profile reflects mandatory configuration controls identified in the NIAP Configuration Annex to the Protection Profile for General Purpose Operating Systems (Protection Profile Version 4.2.1). This configuration profile is consistent with CNSSI-1253, which requires U.S. National Security Systems to adhere to certain configuration parameters. Accordingly, this configuration profile is suitable for use in U.S. National Security Systems.
在信息中,我们可以看到 OSPP 配置文件被描述为xccdf
。我们现在可以运行oscap
,指定我们要使用xcddf
选项的格式,并且我们要执行的操作是使用eval
评估系统。命令如下:
[root@rhel8 content]# oscap xccdf eval \
--report ospp-report.html --profile ospp ssg-rhel8-ds.xml
[omitted]
Title Set Password Maximum Consecutive Repeating Characters
Rule xccdf_org.ssgproject.content_rule_accounts_password_pam_maxrepeat
Ident CCE-82066-2
Result fail
Title Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating Characters from Same Character Class
Rule xccdf_org.ssgproject.content_rule_accounts_password_pam_maxclassrepeat
Ident CCE-81034-1
Result fail
[omitted]
Title Disable Kerberos by removing host keytab
Rule xccdf_org.ssgproject.content_rule_kerberos_disable_no_keytab
Ident CCE-82175-1
Result pass
我们将获得ospp-report.html
文件,其中包含有关 OSPP 规则结果的完整报告:
图 11.7 – OpenSCAP OSPP 扫描结果
它将显示需要修改以符合配置文件的要点:
图 11.8 – OpenSCAP OSPP 扫描结果,需要采取行动的详细规则
现在我们可以一步一步地遵循建议并修复它们,以便完全符合 OSPP。此外,我们可以使用此扫描来加固系统,即使它们不需要符合 OSPP,也将处于暴露的网络中,例如 DMZ,并且我们希望对它们进行加固。
重要提示
Red Hat 提供了一种自动应用所有这些更改的方法。它基于自动化工具/usr/share/scap-security-guide/ansible/rhel8-playbook-ospp.yml
。
现在我们已经审查了 OSPP 合规性的系统,让我们转向下一个目标,即 PCI DSS 合规性。
扫描 PCI DSS 合规性
我们可以按照之前的步骤进行,同样使用oscap
的--profile
选项来获取特定于 PCI DSS 配置文件的信息:
[root@rhel8 content]# oscap info --profile pci-dss \
ssg-rhel8-ds.xml
Document type: Source Data Stream
Imported: 2020-10-12T09:41:22
Stream: scap_org.open-scap_datastream_from_xccdf_ssg-rhel8-xccdf-1.2.xml
Generated: (null)
Version: 1.3
WARNING: Datastream component 'scap_org.open-scap_cref_security-data-oval-com.redhat.rhsa-RHEL8.xml' points out to the remote 'https://www.redhat.com/security/data/oval/com.redhat.rhsa-RHEL8.xml'. Use '--fetch-remote-resources' option to download it.
WARNING: Skipping 'https://www.redhat.com/security/data/oval/com.redhat.rhsa-RHEL8.xml' file which is referenced from datastream
Profile
Title: PCI-DSS v3.2.1 Control Baseline for Red Hat Enterprise Linux 8
Id: xccdf_org.ssgproject.content_profile_pci-dss
Description: Ensures PCI-DSS v3.2.1 security configuration settings are applied.
我们可以使用与上一节相同的选项运行oscap
,但指定pci-dss
作为配置文件。它将生成适当的报告:
[root@rhel8 content]# oscap xccdf eval –report \
pci-dss-report.html --profile pci-dss ssg-rhel8-ds.xml
WARNING: Datastream component 'scap_org.open-scap_cref_security-data-oval-com.redhat.rhsa-RHEL8.xml' points out to the remote 'https://www.redhat.com/security/data/oval/com.redhat.rhsa-RHEL8.xml'. Use '--fetch-remote-resources' option to download it.
WARNING: Skipping 'https://www.redhat.com/security/data/oval/com.redhat.rhsa-RHEL8.xml' file which is referenced from datastream
WARNING: Skipping ./security-data-oval-com.redhat.rhsa-RHEL8.xml file which is referenced from XCCDF content
Title Ensure PAM Displays Last Logon/Access Notification
Rule xccdf_org.ssgproject.content_rule_display_login_attempts
Ident CCE-80788-3
Result pass
[omitted]
Title Specify Additional Remote NTP Servers
Rule xccdf_org.ssgproject.content_rule_chronyd_or_ntpd_specify_multiple_servers
Ident CCE-80764-4
Result fail
[root@rhel8 content]# ls -l pci-dss-report.html
-rw-r--r--. 1 root root 3313684 mar 21 20:16 pci-dss-report.html
我们可以开始审查报告中的项目并开始修复它们。
重要提示
与上一节一样,Red Hat 还提供了一种使用 Ansible 自动应用所有这些更改的方法。PCI DSS 的 playbook 位于/usr/share/scap-security-guide/ansible/rhel8-playbook-pci-dss.yml
。
我们已经看到,使用 OpenSCAP 从一个配置文件切换到另一个配置文件非常容易,我们可以扫描尽可能多的配置文件。
总结
通过学习OpenSCAP的基础知识,我们已经准备好审查和加固系统,使其符合我们需要其运行的法规要求。
现在,如果您被要求遵守任何监管要求,您可以找到适合它的 SCAP 配置文件(如果不存在,可以构建它),并确保您的系统完全符合要求。
此外,即使没有监管要求,使用 OpenSCAP 也可以帮助您发现系统中的漏洞,或者应用更安全(和限制性)的配置以减少风险。
通过学习 Ansible 并能够自动应用系统变更的方式,我们可以扩展我们的知识和技能,这种方式易于扩展,以及 Red Hat Satellite,它可以帮助我们对我们管理的整个 IT 基础进行 SCAP 扫描,即使我们可能谈论的是成千上万的系统。
现在我们的安全技能正在提高并得到巩固,让我们深入探讨更多关于本地存储和文件系统的低级主题,如下一章所述。
第三部分:资源管理 - 存储、引导过程、调优和容器
管理运行 RHEL 的机器的资源对于构建高性能、高效的 IT 环境至关重要。了解存储、调优性能(包括在引导过程中使其永久生效所需的配置),然后使用容器来隔离进程并更有效地分配资源,这些都是系统管理员在日常工作中必然会涉及的领域。
本节包括以下章节:
-
第十二章, 管理本地存储和文件系统
-
第十三章, 使用 LVM 进行灵活的存储管理
-
第十四章, 使用 Stratis 和 VDO 进行高级存储管理
-
第十五章, 了解引导过程
-
, 使用 tuned 进行内核调优和管理性能配置文件
-
第十七章, 使用 Podman、Buildah 和 Skopeo 管理容器
第十二章:管理本地存储和文件系统
在之前的章节中,我们已经学习了安全和系统管理。在本章中,我们将专注于资源管理,特别是存储管理。
存储管理是保持系统运行的重要部分:系统日志可能会占用可用空间,新应用程序可能需要为它们设置额外的存储空间(甚至在单独的磁盘上以提高性能),这些问题可能需要我们采取行动来解决。
在本章中,我们将学习以下主题:
-
分区磁盘(主引导记录(MBR)和全局唯一标识符(GUID)分区表(GPT)磁盘)
-
格式化和挂载文件系统
-
在
fstab
中设置默认挂载和选项 -
使用网络文件系统(NFS)的网络文件系统
这将为我们提供基本知识,以便在存储管理技能上建立,以保持系统运行。
让我们动手操作!
技术要求
您可以继续使用本书开头创建的虚拟机(VM)进行练习第一章,安装 RHEL8。本章所需的任何其他软件包将在文本旁边指示。您还需要分区磁盘(MBR 和 GPT 磁盘)。
让我们从一个定义开始
分区是存储设备的逻辑分割,用于将可用存储逻辑地分成较小的部分。
现在,让我们继续学习一些关于存储起源的知识,以更好地理解它。
一点历史
存储也与系统使用它的能力有关,因此让我们简要解释一下个人计算机(PC)的历史,允许它们引导的软件(基本输入/输出系统(BIOS)),以及这如何影响存储管理。
这可能听起来有点奇怪,但最初的存储需求只是一小部分千字节(KB),对于 PC 中的第一块硬盘,存储只是几兆字节(MB)。
PC 还具有一个特点和限制:PC 是兼容的,这意味着后续型号与最初的国际商业机器(IBM)PC 设计兼容。
传统的磁盘分区在 MBR 之后使用了一些空间,允许四个分区寄存器(起始、结束、大小、分区类型、活动标志),称为主分区。
当 PC 启动时,BIOS 将通过在 MBR 中运行一个小程序来检查磁盘的分区表,然后加载活动分区的引导区域并执行它,以启动操作系统。
包含磁盘操作系统(DOS)和兼容(MS-DOS、DR-DOS、FreeDOS 等)的 IBM PC 还使用了一个名为文件分配表(FAT)的文件系统。 FAT 包含了几个基于其演变的结构,指示为簇寻址大小(以及其他一些特性)。
由于簇的数量有限,更大的磁盘意味着更大的块,因此,如果一个文件只使用了有限的空间,剩下的空间就不能被其他文件使用。因此,将更大的硬盘分成较小的逻辑分区变得更加正常,这样小文件就不会因为限制而占用可用空间。
把这看作是一个议程,最多有一定数量的条目,类似于手机上的快速拨号:如果你只有九个快速拨号的位置,一个短号码,比如打语音信箱,仍然会占用一个位置,就像存储一个大的国际号码一样。
其中一些限制在 FAT 大小的后续版本中得到了减少,与此同时增加了最大支持的磁盘大小。
当然,其他操作系统也引入了自己的文件系统,但使用相同的分区模式。
后来,创建了一种新的分区类型:扩展分区,它使用了四个可用的主分区插槽之一,并允许在其中定义额外的分区,从而使我们能够创建逻辑磁盘以根据需要分配。
此外,拥有多个主分区还允许在同一台计算机上安装不同操作系统,并且这些操作系统具有完全独立的专用空间。
所以...分区允许计算机拥有不同的操作系统,更好地利用可用的存储空间,甚至通过在不同的区域保留数据来逻辑地对数据进行排序,例如将操作系统空间与用户数据分开,以便用户填满可用空间不会影响计算机的运行。
正如我们所说,许多这些设计都带有原始 IBM PC 的兼容性限制,因此当新的使用可扩展固件接口(EFI)的计算机出现以克服传统 BIOS 的限制时,就出现了一种新的分区表格式称为GPT。
使用 GPT 的系统使用 32 位和 64 位支持,而 BIOS 使用 16 位支持(从 IBM PC 兼容性继承),因此可以为磁盘使用更大的寻址,以及额外的功能,如扩展控制器加载。
现在,让我们在下一节学习关于磁盘分区。
分区磁盘(MBR 和 GPT 磁盘)
正如前面提到的,使用磁盘分区允许我们更有效地利用计算机和服务器中可用的空间。
让我们首先通过识别要操作的磁盘来深入了解磁盘分区。
重要提示
一旦我们了解了导致磁盘被分区以及其限制的原因,我们应该根据我们的系统规格遵循一个模式或另一个模式,但要记住 EFI 需要 GPT,BIOS 需要 MBR,因此支持 UEFI 的系统,但磁盘分区为 MBR,将会将系统引导到兼容 BIOS 的模式。
Linux 根据连接到系统的方式使用不同的符号表示磁盘,因此,例如,您可以看到磁盘为hda
或sda
或mmbclk0
,具体取决于所使用的连接。传统上,使用hda
,hdb
等连接的磁盘,而使用sda
,sdb
等连接的磁盘。
我们可以使用fdisk –l
或lsblk –fp
列出可用设备,如下面的屏幕截图所示:
图 12.1 – lsblk-fp 和 fdisk –l 输出
正如我们所看到的,我们的名为/dev/sda
的磁盘有三个分区:sda1
,sda2
和sda3
,其中sda3
是一个LVM
卷组,其卷名为/dev/mapper/rhel-root
。
为了以安全的方式演示磁盘分区,并使读者在使用虚拟机进行测试时更容易,我们将创建一个虚拟的truncate
实用程序,该实用程序随coreutil
软件包一起提供,以及一个随util-linux
软件包一起提供的losetup
实用程序。
为了创建一个 VHD,我们将按照图 12.2中显示的命令序列执行以下命令:
truncate –s 20G myharddrive.hdd
注意
此命令创建一个大小为 20GB的文件,但这将是一个空文件,这意味着该文件实际上并未在我们的磁盘上使用 20 GB 的空间,只是显示了那个大小。除非我们使用它,它将不会占用更多的磁盘空间(这称为稀疏文件)。
-
losetup –f
,将找到下一个可用设备 -
losetup /dev/loop0 myharddrive.hdd
,将loop0
与创建的文件关联 -
lsblk –fp
,验证新循环磁盘 -
fdisk –l /dev/loop0
,列出新磁盘中的可用空间
以下屏幕截图显示了前面顺序命令的输出:
图 12.2 – 执行指定命令以创建一个虚拟硬盘
losetup -f
命令找到下一个可用的回环设备,这是用于将访问回环到支持文件的设备。例如,这经常用于本地挂载 ISO 文件。
使用第三个命令,我们使用先前可用的回环设备来设置设备loop0
和我们用第一个命令创建的文件之间的回环连接。
正如我们所看到的,在剩下的命令中,当运行相同的命令时,设备现在会出现,我们在图 12.1中执行,显示我们有一个可用的 20 GB 磁盘。
重要提示
在磁盘上进行分区操作可能是危险的,并且可能使系统无法使用,需要恢复或重新安装。为了减少这种可能性,本章中的示例将使用/dev/loop0
虚拟创建的磁盘,并且只与此交互。在对真实卷、磁盘等执行此操作时要注意。
让我们通过在我们新创建的设备上执行fdisk /dev/loop0
来开始创建分区,如下一张截图所示:
图 12.3 - fdisk 在/dev/loop0 上执行
正如我们在图 12.3中所看到的,磁盘不包含已识别的分区表,因此创建了一个新的 DOS 分区磁盘标签,但更改只保留在内存中,直到写回磁盘。
在fdisk
命令中,我们可以使用多个选项来创建分区。我们应该注意的第一个选项是m
,如图 12.3中所示,它显示了帮助功能和可用命令。
首先要考虑的是我们之前关于 UEFI、BIOS 等的解释。默认情况下,fdisk
正在创建一个 DOS 分区,但正如我们在手册(m
)中所看到的,我们可以通过在fdisk
中运行g
命令来创建一个 GPT 分区。
要记住的一个重要命令是p
,它打印当前磁盘布局和分区,如下一张截图中所定义的:
图 12.4 - fdisk 创建新的分区表
正如我们所看到的,初始的disklabel
类型是dos
,现在是gpt
,与 EFI/UEFI 兼容。
让我们回顾一些我们可以使用的基本命令,如下所示:
-
n
:创建一个新分区 -
d
:删除一个分区 -
m
:显示手册页(帮助) -
p
:打印当前布局 -
x
:进入高级模式(专为专家设计的额外功能) -
q
:退出而不保存 -
w
:将更改写入磁盘并退出 -
g
:创建新的 GPT 磁盘标签 -
o
:创建 DOS 磁盘标签 -
a
:在 DOS 模式下,将可引导标志设置为其中一个主分区
创建具有用于操作系统的可引导分区和用于用户数据的另一个分区的新传统磁盘分区布局的顺序是什么?
这将是命令的顺序(这些命令也显示在图 12.5中):
-
o
并按Enter创建新的 DOS 磁盘标签 -
n
并按Enter创建一个新分区 -
按Enter接受主分区类型
-
按Enter确认使用第一个分区(
1
) -
按Enter接受初始扇区
-
+10G
并按Enter指示从第一个扇区开始的大小为 10 GB -
n
并按Enter创建第二个新分区 -
按Enter接受它作为主分区类型
-
按Enter接受分区号(
2
) -
按Enter接受 fdisk 提出的默认第一个扇区
-
按Enter接受 fdisk 提出的默认结束扇区
-
a
并按Enter将分区标记为可引导 -
1
并按Enter标记第一个分区
正如您所看到的,大多数选项接受默认值;唯一的更改是指定分区大小为+10G
,表示应为 10 GB(磁盘为 20 GB),然后使用新的n
命令开始第二个分区,现在不指定大小,因为我们要使用所有剩余的分区。最后一步是将第一个分区标记为可引导的。
当然,记住我们之前说过的:除非执行w
命令,否则更改不会写入磁盘,我们可以使用p
来查看它们,如下面的屏幕截图所示:
图 12.5 – 在将其写回磁盘之前创建和验证磁盘分区布局
为了结束本节,让我们使用w
命令将更改写入磁盘,并继续讨论下一节中的文件系统。然而,在此之前,让我们执行partprobe /dev/loop0
,以使内核更新其对磁盘的内部视图,并找到两个新分区。如果不这样做,/dev/loop0p1
和/dev/loop0p2
特殊文件可能不会被创建,也无法使用。
请注意,一些分区修改即使在执行partprobe
后也不会更新,并可能需要系统重新启动。例如,在使用分区的磁盘上,例如我们计算机中保存根文件系统的磁盘上,就会发生这种情况。
格式化和挂载文件系统
在上一节中,我们学习了如何在逻辑上划分我们的磁盘,但该磁盘仍然无法用于存储数据。为了使其可用于存储数据,我们需要在其上定义一个文件系统,这是使其对我们的系统可用的第一步。
文件系统是一个逻辑结构,定义了文件、文件夹等的存储方式,并根据每种类型提供了不同的功能集。
支持的文件系统数量和类型取决于操作系统版本,因为在其演变过程中,可能会添加、删除新的文件系统等。
提示
请记住,Red Hat Enterprise Linux (RHEL) 专注于稳定性,因此严格控制了哪些功能被添加或在新版本中被淘汰,但不包括当前版本内。您可以在access.redhat.com/articles/rhel8-abi-compatibility
了解更多信息。
在 RHEL 8 中,默认文件系统是eXtended File System (XFS),但您可以在 RHEL 文档中找到可用文件系统的列表,网址为access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/system_design_guide/overview-of-available-file-systems_system-design-guide
,当然,也可以使用Fourth Extended Filesystem (EXT4)等其他文件系统。
文件系统的选择取决于诸多因素,如使用意图、将要使用的文件类型等,不同的文件系统可能会对性能产生影响。
例如,EXT4 和 XFS 都是日志文件系统,可以提供更多的保护,防止断电故障,但在其他方面,如文件系统的最大值等方面有所不同。
在选择文件系统之前,了解部署的文件类型和它们的使用模式是一个很好的做法,因为选择错误的文件系统可能会影响系统性能。
正如我们在上一节中定义的,在我们的 VHD 上创建了两个分区,我们可以尝试创建 XFS 和 EXT4 文件系统。然而,在执行操作时要非常小心,因为文件系统的创建是一种破坏性操作,会将新的结构写回磁盘,当以系统的 root 用户操作时,选择错误的文件系统可能会在几秒钟内摧毁我们系统上的可用数据。
重要提示
请记住查看正在使用的命令的 man 页面,以熟悉每个命令的不同建议和可用选项。
然后,让我们使用我们创建的两个分区来测试两种文件系统,XFS 和 EXT4,分别使用mkfs.xfs
和mkfs.ext4
命令对每个设备进行操作,如下所示:
图 12.6—在创建的 VHD 上创建文件系统
请注意,我们已经指定了不同的循环设备分区,并且还为每个命令指定了一个-L
参数。稍后我们将再次查看这个。
现在文件系统已经创建,我们可以运行lsblk -fp
来验证这一点,我们可以看到两个设备,现在指示文件系统正在使用以及LABEL
和UUID
值(我们使用mkfs
创建文件系统时显示的值),如下面的屏幕截图所示:
图 12.7—创建文件系统后 lsblk –fp 的输出
从前面的输出中,重要的是要注意UUID
和LABEL
的值(如果您记得,列出的值是我们在mkfs
命令中使用-L
选项指定的值),因为我们将在本章后面使用它们。
现在文件系统已经创建,为了使用它们,我们需要挂载它们,这意味着使文件系统在我们的系统中的某个路径上可用,这样每次我们存储在该路径中,我们将使用该设备。
挂载文件系统可以通过多种方式完成,但最简单的方法是使用自动检测,只需指定要挂载的设备和要挂载的本地路径,但在检查man mount
帮助页面时,还可以找到更复杂的方法,允许定义多个选项。
为了挂载我们创建的两个文件系统,我们将创建两个文件夹,然后执行以下命令挂载每个设备:
-
cd
-
mkdir first second
-
mount /dev/loop0p1 first/
-
mount /dev/loop0p2 second/
此时,两个文件系统将在我们的主文件夹(根用户)中的名为first
和second
的子文件夹中可用。
内核已自动找到每个设备正在使用的文件系统,并通过适当的控制器加载它,这很有效,但有时我们可能想要定义特定的选项——例如,强制文件系统类型,在过去使用ext2
和ext3
作为常见文件系统时启用或禁用日志记录,或者例如,禁用更新文件或目录访问时间的内置功能,以减少磁盘 I/O 并提高性能。
在命令行上指定的所有选项,或者挂载的文件系统,在系统重新启动后将不可用,因为这些只是运行时更改。让我们继续下一节,学习如何在系统启动时定义默认选项和文件系统挂载。
在 fstab 中设置默认挂载和选项
在前一节中,我们介绍了如何挂载磁盘和分区,以便我们的服务和用户可以使用它们。在本节中,我们将学习如何以持久的方式使这些文件系统可用。
/etc/fstab
文件包含系统的文件系统定义,并且当然有一个专门的手册页面,可以使用man fstab
来查看,其中包含有关格式、字段、排序等必须考虑的有用信息,因为这个文件对系统的平稳运行至关重要。
文件格式由用制表符或空格分隔的几个字段定义,以#
开头的行被视为注释。
例如,我们将使用这行来查看每个字段的描述:
LABEL=/ / xfs defaults 0 0
第一个字段是设备定义,可以是特殊的块设备、远程文件系统,或者—正如我们所看到的—由LABEL
、UUID
或PARTUUID
或PARTLABEL
制作的选择器。mount
、blkid
和lsblk
的man
页面提供了有关设备标识符的更多信息。
第二个字段是文件系统的挂载点,这是根据我们的系统目录层次结构使该文件系统的内容可用的位置。一些特殊的设备/分区,如交换区,将其定义为none
,因为实际上内容不会通过文件系统可用。
第三个字段是由mount
命令或swap
支持的文件系统类型,用于交换分区。
第四个字段是由mount
或swapon
命令支持的挂载选项(查看它们的man
页面以获取更多详细信息),在其默认设置下,它是大多数常见选项的别名(读/写,允许设备,允许执行,自动挂载启动,异步访问等)。其他常见选项可能是noauto
,它定义了文件系统但不会在启动时挂载(通常与可移动设备一起使用),user
,它允许用户挂载和卸载它,以及_netdev
,它定义了需要在尝试挂载之前网络处于连接状态的远程路径。
第五个字段由dump
用于确定应使用哪些文件系统 - 其值默认为0
。
第六个字段由fsck
用于确定在启动时要检查的文件系统的顺序。根文件系统的值应为 1,其他文件系统的值应为 2(默认值为 0,而不是fsck
)。检查是并行执行的,以加快启动过程。请注意,具有日志的文件系统本身可以执行快速验证而不是完整验证。
在下面的屏幕截图中,让我们看看我们系统中cat /etc/fstab
的输出是什么:
图 12.8 - 我们系统的 fstab 示例
为什么我们应该使用UUID
或LABEL
而不是/dev/sda1
等设备?
当系统启动时,磁盘排序可能会发生变化,因为一些内核可能会引入设备访问方式的差异等,导致设备的枚举发生变化;这不仅发生在可移动设备(如通用串行总线(USB)设备),还发生在网络接口或硬盘等内部设备上。
当我们使用UUID
或LABEL
而不是指定设备时,即使在设备重新排序的情况下,系统仍将能够找到正确的设备并从中引导。这在系统以前使用IDE和串行高级技术附件(SATA)驱动器和SCSI驱动器时尤为重要,甚至在今天,Internet SCSI(iSCSI)设备可能以与预期不同的顺序连接,导致设备名称更改和在到达时失败。
请记住使用blkid
或lsblk -fp
命令来检查文件系统的标签和通用唯一标识符(UUID),这些标识符在引用它们时可能会用到。
重要提示
在编辑/etc/fstab
文件时,务必小心:更改系统使用的挂载点可能会导致系统无法使用。如果有疑问,请仔细检查任何更改,并确保熟悉系统恢复方法,并在需要时准备好救援介质。
让我们在下一节学习如何挂载远程 NFS
使用 NFS 进行网络文件系统
挂载远程 NFS 与挂载本地设备并没有太大区别,但是与在上一节中使用/dev/loop0p1
文件指定本地设备不同,我们提供server:export
作为设备。
我们可以通过检查手册页面man mount
来找到一系列可用选项,这将向我们显示几个选项以及设备的外观。
当要使用 NFS 挂载时,管理员需要使用主机和导出名称来挂载该设备,例如,基于以下关于 NFS 导出的数据:
-
server.example.com
-
/isos
-
/mnt/nfs
有了上述数据,很容易构建mount
命令,它将如下所示:
mount –t nfs sever.example.com:/isos /mnt/nfs
如果我们分析上述命令,它将定义要挂载的文件系统类型为nfs
,由server.example.com
主机名提供,并使用/isos
NFS 导出,并将在本地的/mnt/nfs
文件夹下可用。
如果我们想要在启动时定义此文件系统为可用,我们应该在/etc/fstab
中添加一个条目,但是...我们应该如何指示这一点呢?
根据本章节中解释的设置,构建的条目将看起来像这样:
server.example.com:/isos /mnt/nfs nfs defaults,_netdev 0 0
上一行代码包含了我们在命令行上指定的参数,但它还添加了在尝试挂载之前需要网络访问的资源,因为网络访问是必需的,以便能够访问 NFS 服务器,类似于其他基于网络的存储,如 Samba 挂载、iSCSI 等,都需要的情况。
重要提示
重申保持系统可引导的想法,一旦我们对/etc/fstab
配置文件进行修改,建议执行mount -a
,以便在运行系统时执行验证。如果执行后新的文件系统可用,并且在执行例如df
时显示,并且没有出现错误,那么应该是安全的。
总结
在本章中,我们学习了如何对磁盘进行逻辑划分,以便最佳利用存储空间,并且如何稍后在该磁盘划分上创建文件系统,以便实际存储数据。
一旦实际文件系统被创建,我们学会了如何在系统中使其可访问,以及如何通过修改/etc/fstab
配置文件来确保在下次系统重启后它仍然可用。
最后,我们还学习了如何使用提供给我们的数据来使用 NFS 远程文件系统,并将其添加到我们的fstab
文件中以使其持久化。
在下一章中,我们将学习如何通过逻辑卷管理(LVM)使存储更加有用,它赋予了定义不同逻辑单元的能力,可以调整大小,组合以提供数据冗余等。
第十三章:使用 LVM 进行灵活的存储管理
通过使用逻辑卷管理器(LVM),可以以比第十二章中更灵活的方式来管理本地存储和文件系统。LVM 允许您将多个磁盘分配给同一个逻辑卷(在 LVM 中相当于分区),在不同磁盘之间复制数据,并对卷进行快照。
在本章中,我们将回顾 LVM 的基本用法和用于管理存储的主要对象。我们将学习如何准备磁盘以便与 LVM 一起使用,然后将它们聚合到一个池中,从而不仅增加了可用空间,还使您能够一致地使用它。我们还将学习如何将聚合的磁盘空间分配到类似分区的块中,如果需要的话可以很容易地扩展。为此,我们将学习以下主题:
-
理解 LVM
-
创建、移动和删除物理卷
-
将物理卷合并到卷组中
-
创建和扩展逻辑卷
-
向卷组添加新磁盘并扩展逻辑卷
-
删除逻辑卷、卷组和物理卷
-
审查 LVM 命令
技术要求
在这一章中,我们将向我们正在使用的机器添加两个磁盘,以便能够按照本章中提到的示例进行操作。以下是您的选择:
-
如果您正在使用物理机,您可以添加一对 USB 驱动器。
-
如果您正在使用本地虚拟机,您需要添加两个新的虚拟驱动器。
-
如果您正在使用云实例,可以向其添加两个新的块设备。
例如,让我们看看如何在 Linux 中将这些磁盘添加到我们的虚拟机中。首先,我们关闭了在第一章中安装的虚拟机,安装 RHEL8,名为rhel8
。然后我们打开虚拟机的特性页面。在那里我们找到了添加硬件按钮:
图 13.1-编辑虚拟机属性
提示
根据您使用的虚拟化平台,到达虚拟机特性的路径可能不同。但是,很常见的是从虚拟机菜单直接访问选项。
单击添加硬件将打开以下截图中的对话框。在其中,我们将选择存储选项,并指定要创建并附加到虚拟机的虚拟磁盘的大小,本例中为 1 GiB,然后单击完成:
图 13.2-向虚拟机添加磁盘
我们将重复此过程两次以添加两个磁盘。最终结果将如下所示:
图 13.3-向虚拟机添加两个新磁盘,总共三个
现在我们将打开虚拟机并登录以检查新设备的可用性:
[root@rhel8 ~]# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
vda 252:0 0 10G 0 disk
├─vda1 252:1 0 1G 0 part /boot
└─vda2 252:2 0 9G 0 part
├─rhel-root 253:0 0 8G 0 lvm /
└─rhel-swap 253:1 0 1G 0 lvm [SWAP]
vdb 252:16 0 1G 0 disk
vdc 252:32 0 1G 0 disk
我们可以看到新的 1 GiB 磁盘vdb
和vdc
是可用的。现在我们有一个系统磁盘,我们在其中安装了 RHEL 8 操作系统,还有两个可以使用的磁盘,我们准备继续进行本章的操作。
提示
在 Linux 中,磁盘设备的命名取决于它们使用的驱动程序。连接为 SATA 或 SCSI 的设备显示为sd
和一个字母,例如sda
或sdb
。连接为 IDE 总线的设备使用hd
和一个字母,例如hda
或hdb
。例如使用 VirtIO 虚拟化驱动程序的设备使用vd
和一个字母,例如vda
或vdb
。
理解 LVM
LVM 使用三层来管理系统中的存储设备。这些层如下:
-
物理卷(PV):LVM 的第一层。直接分配给块设备。物理卷可以是磁盘上的分区,也可以是完整的原始磁盘本身。
-
卷组(VG):LVM 的第二层。它将物理卷组合起来以聚合空间。这是一个中间层,不太显眼,但它的作用非常重要。
-
逻辑卷(LV):LVM 的第三层。它分配了卷组聚合的空间。
让我们看看我们想要使用这两个新添加的磁盘来实现的示例:
图 13.4 – 使用两个磁盘的 LVM 示例
让我们解释这个例子图表,以理解所有的层:
-
我们有两个磁盘,在图中分别是Disk1和Disk2。
-
Disk1被分成了两个分区,Part1和Part2。
-
Disk2没有分区。
-
有三个物理卷。它们的任务是准备磁盘空间以供 LVM 使用。物理卷如下:
-
PV1,创建在Disk1的Part1分区上
-
PV2,创建在Disk1的Part2分区上
-
PV3,直接创建在Disk2上
-
一个卷组VG1,聚合了所有三个物理卷PV1、PV2和PV3。现在,所有的磁盘空间都被整合起来,可以很容易地重新分配。
-
为了分配空间,有四个逻辑卷 – LV1、LV2、LV3和LV4。请注意,逻辑卷并不使用整个磁盘。这样,如果我们需要扩展一个卷或创建一个快照,都是可能的。
这是对层是如何分布的基本描述,而不涉及复杂的情况,比如镜像、薄置备或快照。
作为一个经验法则,我们需要理解 PVs 的设计是为了准备设备供 LVM 使用,VGs 用于聚合 PVs,LVs 用于分配聚合空间。
有趣的是,如果我们创建了一个 VG,我们可以向其添加额外的磁盘,从而增加其大小,而无需停止或重新启动机器。同样,我们可以将添加的空间分配给需要它的 LV,而无需停止或重新启动机器。这是 LVM 如此强大并且被推荐用于每台服务器的主要原因之一,几乎没有例外。
现在我们知道 LVM 被分成了几层,让我们开始使用它们来开始理解它们是如何工作的。
创建、移动和删除物理卷
根据技术要求部分的说明,我们的机器已准备好了两个新磁盘vdb
和vdc
,我们可以开始在我们的机器上实现示例图表,就像图 13.4中所示的那样。
第一步与 LVM 没有直接关联,但继续示例仍然很重要。这一步涉及对vdb
磁盘进行分区。让我们用分区管理工具parted
来看一下:
[root@rhel8 ~]# parted /dev/vdb print
Error: /dev/vdb: unrecognised disk label
Model: Virtio Block Device (virtblk)
Disk /dev/vdb: 1074MB
Sector size (logical/physical): 512B/512B
Partition Table: unknown
Disk Flags:
重要提示
您的磁盘设备,如果您使用的是物理机器或不同的磁盘驱动程序,可能会有所不同。例如,如果我们使用 SATA 磁盘,它将是/dev/sdb
而不是/dev/vdb
。
磁盘完全未分区,正如我们在unrecognised disk label
消息中所看到的。正如在第十二章中所解释的,管理本地存储和文件系统,我们可以使用两种类型的磁盘标签;msdos
(也称为gpt
,这是一种新类型,适用于带有gpt
的机器,就像我们在这个例子中所做的那样。用于使用parted
创建新标签的选项是mklabel
:
[root@rhel8 ~]# parted /dev/vdb mklabel gpt
Information: You may need to update /etc/fstab.
[root@rhel8 ~]# parted /dev/vdb print
Model: Virtio Block Device (virtblk)
Disk /dev/vdb: 1074MB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags:
Number Start End Size File system Name Flags
提示
要创建一个msdos
标签,命令将是parted /dev/vdb mklabel msdos
。
现在我们有一个带有gpt
标签的磁盘,但没有分区。让我们使用交互模式中的mkpart
选项来创建一个分区:
[root@rhel8 ~]# parted /dev/vdb mkpart
现在我们可以输入分区名称mypart0
:
Partition name? []? mypart0
对于下一步,指定文件系统,我们将使用ext2
:
File system type? [ext2]? ext2
现在是设置起始点的时候了。我们将使用第一个可用的扇区,即2048s
:
Start? 2048s
提示
现代磁盘中的第一个扇区,根据定义是2048s
。这不是由工具提供的。当有疑问时,我们可以通过运行parted /dev/vda unit s print
来查看其他现有磁盘。
然后我们来到最后一步,设置终点,也就是我们想要创建的分区的大小:
End? 200MB
该命令附带以下警告:
Information: You may need to update /etc/fstab.
为了确保分区表在系统中得到刷新,并且允许设备在/dev
下生成,我们可以运行以下命令:
[root@rhel8 ~]# udevadm settle
提示
在非交互模式下运行的完整命令是parted /dev/vdb mkpart mypart0 xfs 2048s 200MB
。
我们可以看到新的分区可用:
[root@rhel8 ~]# parted /dev/vdb print
Model: Virtio Block Device (virtblk)
Disk /dev/vdb: 1074MB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags:
Number Start End Size File system Name Flags
1 1049kB 200MB 199MB mypart0
我们需要更改分区以能够托管LVM
物理卷。parted
命令使用set
选项来更改分区类型。我们需要指定分区的编号,即1
,然后输入lvm
和on
来激活:
root@rhel8 ~]# parted /dev/vdb set 1 lvm on
Information: You may need to update /etc/fstab.
[root@rhel8 ~]# udevadm settle
[root@rhel8 ~]# parted /dev/vdb print
Model: Virtio Block Device (virtblk)
Disk /dev/vdb: 1074MB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags:
Number Start End Size File system Name Flags
1 1049kB 200MB 199MB mypart0 lvm
我们看到分区的标志现在设置为lvm
。
让我们添加第二个分区,mypart1
:
[root@rhel8 ~]# parted /dev/vdb mkpart mypart1 xfs \
200MB 100%
Information: You may need to update /etc/fstab.
[root@rhel8 ~]# parted /dev/vdb set 2 lvm on
Information: You may need to update /etc/fstab.
[root@rhel8 ~]# parted /dev/vdb print
Model: Virtio Block Device (virtblk)
Disk /dev/vdb: 1074MB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags:
Number Start End Size File system Name Flags
1 1049kB 200MB 199MB mypart0 lvm
2 200MB 1073MB 872MB mypart1 lvm
现在我们已经创建了两个分区,/dev/vdb1
(名称为mypart0
)和/dev/vdb2
(名称为mypart1
),这就是我们的存储的样子:
图 13.5 - 在我们的两个新磁盘上创建的分区
提示
RHEL8 中默认提供了另一个用于管理分区的工具,即fdisk
。您可能想尝试一下,看看是否更容易使用。
现在是创建持久卷的时候了。我们只会在新创建的分区上执行。首先,我们使用pvs
命令检查可用的持久卷:
[root@rhel8 ~]# pvs
PV VG Fmt Attr PSize PFree
/dev/vda2 rhel lvm2 a-- <9,00g 0
现在,我们继续使用pvcreate
创建持久卷:
[root@rhel8 ~]# pvcreate /dev/vdb1
Physical volume "/dev/vdb1" successfully created.
[root@rhel8 ~]# pvcreate /dev/vdb2
Physical volume "/dev/vdb2" successfully created.
然后我们再次使用pvs
检查它们是否已正确创建:
[root@rhel8 ~]# pvs
PV VG Fmt Attr PSize PFree
/dev/vda2 rhel lvm2 a-- <9,00g 0
/dev/vdb1 lvm2 --- 190,00m 190,00m
/dev/vdb2 lvm2 --- 832,00m 832,00m
请注意,持久卷没有自己的名称,而是使用它们所创建的分区(或设备)的名称。我们可以将它们称为PV1
和PV2
来绘制图表。
现在的状态是:
图 13.6 - 在两个新分区中创建的持久卷
我们也可以直接在磁盘设备vdc
上创建一个持久卷。让我们来做一下:
[root@rhel8 ~]# pvcreate /dev/vdc
Physical volume "/dev/vdc" successfully created.
[root@rhel8 ~]# pvs
PV VG Fmt Attr PSize PFree
/dev/vda2 rhel lvm2 a-- <9,00g 0
/dev/vdb1 lvm2 --- 190,00m 190,00m
/dev/vdb2 lvm2 --- 832,00m 832,00m
/dev/vdc lvm2 --- 1,00g 1,00g
与之前的示例一样,物理卷没有名称,我们将其称为PV3
。结果如下:
图 13.7 - 在两个新分区和新磁盘设备中创建的持久卷
现在我们有了持久卷,让我们在下一节中使用虚拟卷组对它们进行分组。
将物理卷合并为卷组
现在是创建一个新的卷组,使用之前添加的物理卷。在这之前,我们可以使用vgs
命令检查可用的卷组:
[root@rhel8 ~]# vgs
VG #PV #LV #SN Attr VSize VFree
rhel 1 2 0 wz--n- <9,00g 0
我们可以看到只有在安装过程中为操作系统创建的卷组可用。让我们使用vgcreate
命令创建我们的storage
卷组,使用/dev/vdb1
和/dev/vdb2
分区:
[root@rhel8 ~]# vgcreate storage /dev/vdb1 /dev/vdb2
Volume group "storage" successfully created
[root@rhel8 ~]# vgs
VG #PV #LV #SN Attr VSize VFree
rhel 1 2 0 wz--n- <9,00g 0
storage 2 0 0 wz--n- 1016,00m 1016,00m
如您所见,新的storage
卷组已经创建。当前状态的图表现在看起来是这样的:
图 13.8 - 使用两个物理卷创建的第一个卷组
重要提示
卷组是 LVM 中的一个非常薄的层,其唯一目标是将磁盘或分区聚合成一个存储池。对该存储的高级管理,例如在两个不同的磁盘上镜像数据,是通过逻辑卷完成的。
我们已经准备好了将分区和磁盘作为物理卷,并将它们聚合到卷组中,因此我们有了一个磁盘空间池。让我们继续学习如何使用逻辑卷来分配该磁盘空间的分布。
创建和扩展逻辑卷
我们目前已经创建了几个物理卷,并且其中两个被分组到一个卷组中。让我们移动到下一层,并使用lvs
命令检查逻辑卷:
[root@rhel8 ~]# lvs
LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert
root rhel -wi-ao---- <8,00g
swap rhel -wi-ao---- 1,00g
我们在rhel
卷组上看到了root
和swap
卷,它们承载着操作系统。
现在,我们可以在storage
卷组上创建一个名为data
的简单逻辑卷,大小为 200 MB:
[root@rhel8 ~]# lvcreate --name data --size 200MB storage
Logical volume "data" created.
[root@rhel8 ~]# lvs
LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert
root rhel -wi-ao---- <8,00g
swap rhel -wi-ao---- 1,00g
data storage -wi-a----- 200,00m
我们的配置现在如下:
图 13.9 - 使用卷组空间创建的第一个逻辑卷
创建的逻辑卷是一个块设备,并且类似于磁盘分区。因此,为了使用它,我们需要用文件系统格式化它。让我们通过使用xfs
格式对其进行格式化:
[root@rhel8 ~]# mkfs.xfs /dev/storage/data
meta-data=/dev/storage/data isize=512 agcount=4, agsize=12800 blks
= sectsz=512 attr=2, projid32bit=1
= crc=1 finobt=1, sparse=1, rmapbt=0
= reflink=1
data = bsize=4096 blocks=51200,imaxpct=25
= sunit=0 swidth=0 blks
naming =version 2 bsize=4096 ascii-ci=0, ftype=1
log =internal log bsize=4096 blocks=1368, version=2
= sectsz=512 sunit=0 blks, lazy-count=1
realtime =none extsz=4096 blocks=0, rtextents=0
Discarding blocks...Done.
现在可以挂载了。我们可以创建/srv/data
目录并在那里挂载它:
[root@rhel8 ~]# mkdir /srv/data
[root@rhel8 ~]# mount -t xfs /dev/storage/data /srv/data
[root@rhel8 ~]# df -h /srv/data/
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/storage-data 195M 12M 184M 6% /srv/data
我们已经设置了 LVM 启用的可用空间。手动挂载文件系统,就像前面的例子一样,在系统关闭或重新启动时有效。为了使其持久化,我们需要将以下行添加到/etc/fstab
中:
/dev/storage/data /srv/data xfs defaults 0 0
为了测试该行是否正确编写,我们可以运行以下命令。首先,卸载文件系统:
[root@rhel8 ~]# umount /srv/data
检查挂载点中的可用空间:
[root@rhel8 ~]# df -h /srv/data/
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/rhel-root 8,0G 2,8G 5,3G 35% /
df
(磁盘空闲)命令的输出显示/srv/data/
目录中的空间与root
分区相关联,这意味着该文件夹没有任何关联的文件系统。现在让我们在系统启动时运行mount
命令:
[root@rhel8 ~]# mount –a
/etc/fstab
中的所有未挂载的文件系统将被挂载,如果存在任何问题(例如/etc/fstab
中的拼写错误),则会显示错误。让我们检查它是否已挂载:
[root@rhel8 ~]# df -h /srv/data/
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/storage-data 195M 12M 184M 6% /srv/data
重要提示
/dev/storage/data
和/dev/mapper/storage-data
设备是由一个名为设备映射器的组件生成的同一设备的别名(或者更准确地说是符号链接)。它们是完全可互换的。
正如我们所看到的,文件系统已正确挂载。现在我们知道如何创建逻辑卷并为其分配文件系统和挂载点,我们可以继续进行更高级的任务,例如在我们的 LVM 层和更高级别中扩展磁盘空间。
添加新磁盘到卷组并扩展逻辑卷
LVM 的一个很棒的功能,更具体地说是卷组,是我们可以向其中添加新的磁盘并开始使用新扩展的空间。让我们尝试通过将/dev/vdc
中的物理卷添加到storage
卷组来实现:
[root@rhel8 ~]# vgs
VG #PV #LV #SN Attr VSize VFree
rhel 1 2 0 wz--n- <9,00g 0
storage 2 1 0 wz--n- 1016,00m 816,00m
[root@rhel8 ~]# vgextend storage /dev/vdc
Volume group "storage" successfully extended
[root@rhel8 ~]# vgs
VG #PV #LV #SN Attr VSize VFree
rhel 1 2 0 wz--n- <9,00g 0
storage 3 1 0 wz--n- <1,99g 1,79g
现在,我们的磁盘分布如下:
图 13.10 - 扩展的卷组,包含三个物理卷
现在让我们通过向data
逻辑卷添加 200 MB 来扩展它:
[root@rhel8 ~]# lvs
LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert
root rhel -wi-ao---- <8,00g
swap rhel -wi-ao---- 1,00g
data storage -wi-ao---- 200,00m
[root@rhel8 ~]# lvextend --size +200MB /dev/storage/data
Size of logical volume storage/data changed from 200,00 MiB (50 extents) to 400,00 MiB (100 extents).
Logical volume storage/data successfully resized.
[root@rhel8 ~]# lvs
LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert
root rhel -wi-ao---- <8,00g
swap rhel -wi-ao---- 1,00g
data storage -wi-ao---- 400,00m
逻辑卷已经扩展。但是上面的文件系统还没有:
[root@rhel8 ~]# df -h /srv/data/
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/storage-data 195M 12M 184M 6% /srv/data
我们需要扩展文件系统。要执行此操作的工具取决于文件系统的类型。在我们的情况下,由于它是xfs
,扩展它的工具是xfs_growfs
。让我们来做:
[root@rhel8 ~]# xfs_growfs /dev/storage/data
meta-data=/dev/mapper/storage-data isize=512 agcount=4, agsize=12800 blks
= sectsz=512 attr=2, projid32bit=1
= crc=1 finobt=1, sparse=1, rmapbt=0
= reflink=1
data = bsize=4096 blocks=51200 imaxpct=25
= sunit=0 swidth=0 blks
naming =version 2 bsize=4096 ascii-ci=0, ftype=1
log =internal log bsize=4096 blocks=1368 version=2
= sectsz=512 sunit=0 blks, lazy-count=1
realtime =none extsz=4096 blocks=0, rtextents=0
data blocks changed from 51200 to 102400
[root@rhel8 ~]# df -h /srv/data/
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/storage-data 395M 14M 382M 4% /srv/data
现在,文件系统已经添加了一些额外的空间并可用。
重要提示
在执行此任务时,逻辑卷可以被挂载并被系统使用。LVM 已准备好在运行时对生产系统进行卷扩展。
重新分配空间并添加另一个逻辑卷非常容易:
[root@rhel8 ~]# lvcreate --size 100MB --name img storage
Logical volume "img" created.
[root@rhel8 ~]# lvs
LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert
root rhel -wi-ao---- <8,00g
swap rhel -wi-ao---- 1,00g
data storage -wi-ao---- 400,00m
img storage -wi-a----- 100,00m
[root@rhel8 ~]# mkfs.xfs /dev/storage/img
meta-data=/dev/storage/img isize=512 agcount=4, agsize=6400 blks
= sectsz=512 attr=2, projid32bit=1
= crc=1 finobt=1, sparse=1, rmapbt=0
= reflink=1
data = bsize=4096 blocks=25600 imaxpct=25
= sunit=0 swidth=0 blks
naming =version 2 bsize=4096 ascii-ci=0, ftype=1
log =internal log bsize=4096 blocks=1368, version=2
= sectsz=512 sunit=0 blks, lazy-count=1
realtime =none extsz=4096 blocks=0, rtextents=0
Discarding blocks...Done.
[root@rhel8 ~]# mkdir /srv/img
[root@rhel8 ~]# mount -t xfs /dev/storage/img /srv/img
[root@rhel8 ~]# df /srv/img/
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/mapper/storage-img 96928 6068 90860 7% /srv/img
[root@rhel8 ~]# df -h /srv/img/
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/storage-img 95M 6,0M 89M 7% /srv/img
lvcreate
命令的--size
和--extents
选项有几个选项可用于定义要使用的空间:
-
GB
,或者兆字节,使用MB
(换句话说,--size 3GB
)。 -
--extents
,该命令将使用其内部度量单位extents
,它类似于磁盘分区的块大小(即--extents 125
)。
--size
和--extents
选项也适用于lvextend
命令。在这种情况下,我们可以使用先前显示的选项来定义逻辑卷的新大小。我们还有其他选项来定义分配给它们的空间的增量:
-
在
lvextend
命令的数字之前加上+
符号,这将以提供的度量单位增加大小(即--size +1GB
会向当前逻辑卷添加 1GB 的额外空间)。 -
--extents
,以及要使用的剩余空间的百分比,后面跟着%FREE
(即--extents 10%FREE
)。
提示
正如我们之前在其他工具中看到的那样,我们可以使用手册页来了解可用的选项。请运行man lvcreate
和man lvextend
来熟悉这些工具的手册页。
我们将创建一个逻辑卷用作交换空间,这是系统用作内存停车位的磁盘的一部分。系统将消耗内存但不活动的进程放在那里,以便释放物理内存(比磁盘快得多)。当系统中没有更多的空闲物理内存时,也会使用它。
让我们在 LVM 上创建一个交换设备:
[root@rhel8 ~]# lvcreate --size 100MB --name swap storage
Logical volume "swap" created.
[root@rhel8 ~]# mkswap /dev/storage/swap
Setting up swapspace version 1, size = 100 MiB (104853504 bytes)
no label, UUID=70d07e58-7e8d-4802-8d20-38d774ae6c22
我们可以使用free
命令检查内存和交换状态:
[root@rhel8 ~]# free
total used free shared buff/cache available
Mem: 1346424 218816 811372 9140 316236 974844
Swap: 1048572 0 1048572
[root@rhel8 ~]# swapon /dev/storage/swap
[root@rhel8 ~]# free
total used free shared buff/cache available
Mem: 1346424 219056 811040 9140 316328 974572
Swap: 1150968 0 1150968
重要提示
这两个新的更改需要为每个添加一行到/etc/fstab
,以便在重新启动时持久地使用它们。
我们的磁盘空间分布现在看起来是这样的:
图 13.11 - 扩展的卷组,有三个物理卷
这个分布看起来很像我们用来描述 LVM 层的初始示例。我们现在已经练习了所有层,创建了每一层所需的部分。我们知道如何创建,现在是时候学习如何在下一节中删除它们了。
删除逻辑卷、卷组和物理卷
首先,让我们从用于移除的命令开始,先做一个简单的步骤,移除img
逻辑卷。首先,我们需要检查它是否已挂载:
[root@rhel8 ~]# mount | grep img
/dev/mapper/storage-img on /srv/img type xfs (rw,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota)
因为它已经挂载,我们需要卸载它:
[root@rhel8 ~]# umount /srv/img
[root@rhel8 ~]# mount | grep img
最后一个命令显示了空输出,这意味着它没有被挂载。让我们继续移除它:
[root@rhel8 ~]# lvremove /dev/storage/img
Do you really want to remove active logical volume storage/img? [y/n]: y
Logical volume "img" successfully removed
现在,我们也可以移除挂载点:
[root@rhel8 ~]# rmdir /srv/img
逻辑卷的移除也完成了。这个过程是不可逆的,所以要小心运行。我们的磁盘分布现在看起来是这样的:
图 13.12 - 移除逻辑卷的卷组
现在是时候进行一个更复杂的任务了,从虚拟组中移除物理卷。这样做的原因是有时您想要将存储在物理磁盘上的数据转移到另一个磁盘,然后将其分离并从系统中移除。这是可以做到的,但首先让我们向data
逻辑卷添加一些文件:
[root@rhel8 ~]# cp -ar /usr/share/scap-security-guide \
/srv/data/
[root@rhel8 ~]# ls /srv/data/
scap-security-guide
[root@rhel8 ~]# du -sh /srv/data/
30M /srv/data/
现在让我们使用pvmove
命令从/dev/vdb1
中疏散数据:
[root@rhel8 ~]# pvmove /dev/vdb1
/dev/vdb1: Moved: 7,75%
/dev/vdb1: Moved: 77,52%
/dev/vdb1: Moved: 100,00%
重要提示
根据分配的 extent,您可能会收到一条消息,指出“没有要移动的数据”。这意味着保存的数据已经分配给了其他磁盘。您可以使用pvmove
与其他设备来尝试。
现在/dev/vdb1
中没有存储数据,可以从卷组中移除。我们可以使用vgreduce
命令来做到这一点:
[root@rhel8 ~]# vgreduce storage /dev/vdb1
Removed "/dev/vdb1" from volume group "storage"
我们可以看到存储卷组中现在有更少的空间:
[root@rhel8 ~]# vgs
VG #PV #LV #SN Attr VSize VFree
rhel 1 2 0 wz--n- <9,00g 0
storage 2 2 0 wz--n- 1,80g 1,30g
[root@rhel8 ~]# vgdisplay storage
--- Volume group ---
VG Name storage
System ID
Format lvm2
Metadata Areas 2
Metadata Sequence No 20
VG Access read/write
VG Status resizable
MAX LV 0
Cur LV 2
Open LV 2
Max PV 0
Cur PV 2
Act PV 2
VG Size 1,80 GiB
PE Size 4,00 MiB
Total PE 462
Alloc PE / Size 129 / 516,00 MiB
Free PE / Size 333 / 1,30 GiB
VG UUID 1B6Nil-rvcM-emsU-mBLu-wdjL-mDlw-66dCQU
我们还可以看到物理卷/dev/vdb1
没有连接到任何卷组:
[root@rhel8 ~]# pvs
PV VG Fmt Attr PSize PFree
/dev/vda2 rhel lvm2 a-- <9,00g 0
/dev/vdb1 lvm2 --- 190,00m 190,00m
/dev/vdb2 storage lvm2 a-- 828,00m 312,00m
/dev/vdc storage lvm2 a-- 1020,00m 1020,00m
[root@rhel8 ~]# pvdisplay /dev/vdb1
"/dev/vdb1" is a new physical volume of "190,00 MiB"
--- NEW Physical volume ---
PV Name /dev/vdb1
VG Name
PV Size 190,00 MiB
Allocatable NO
PE Size 0
Total PE 0
Free PE 0
Allocated PE 0
PV UUID veOsec-WV0n-JP9D-WMz8-UYeZ-Zjs6-sJSJst
提示
vgdisplay
、pvdisplay
和lvdisplay
命令显示了 LVM 的任何部分的详细信息。
最重要的部分是,我们可以在系统运行生产工作负载的同时执行这些操作。我们的磁盘分布现在看起来是这样的:
图 13.13 - 带有移除物理卷的卷组
现在是时候移除卷组了,但我们需要先移除逻辑卷,就像之前做的一样(随时运行lvs
和vgs
来检查进度):
[root@rhel8 ~]# swapoff /dev/storage/swap
[root@rhel8 ~]# lvremove /dev/storage/swap
Do you really want to remove active logical volume storage/swap? [y/n]: y
Logical volume "swap" successfully removed
现在,我们已经移除了/dev/storage/swap
。现在让我们使用--yes
选项移除/dev/storage/data
,这样我们就不会被要求确认(在脚本中使用此命令时很重要):
[root@rhel8 ~]# umount /dev/storage/data
[root@rhel8 ~]# lvremove --yes /dev/storage/data
Logical volume "data" successfully removed
现在是时候移除storage
卷组了:
[root@rhel8 ~]# vgremove storage
storage
卷组已成功移除。
最后,清理物理卷:
[root@rhel8 ~]# pvremove /dev/vdb1 /dev/vdb2
Labels on physical volume "/dev/vdb1" successfully wiped.
Labels on physical volume "/dev/vdb2" successfully wiped.
通过这样,我们知道如何在我们的 RHEL8 系统中处理 LVM 的每个部分。让我们回顾下一节中使用的命令。
回顾 LVM 命令
作为管理物理卷使用的命令的总结,让我们看一下下表:
现在,让我们回顾一下用于管理卷组的命令:
最后,让我们回顾一下用于管理逻辑卷的命令:
请记住,您可以随时使用每个命令的手册页面获取有关要使用的选项的更多信息,并通过运行man <command>
来学习新的选项。
重要提示
Web 管理界面 Cockpit 具有用于管理存储组件的扩展。可以使用以下命令以root
(或使用sudo
)安装它:dnf install cockpit-storaged
。您可以尝试在 Cockpit 的存储界面中重复本章中所做的过程,这对您来说是一个很好的练习。
总结
LVM 是 Red Hat Enterprise Linux 中非常有用的一部分,它提供了管理、重新分配、分发和分配磁盘空间的能力,而无需停止系统中的任何内容。经过多年的考验,它是系统管理员的关键组件,同时也有助于在我们的系统中引入其他扩展功能(一种通过 iSCSI 共享存储的灵活方式)。
在测试机上练习 LVM 非常重要,这样我们就可以确保在生产系统上运行的命令不会导致服务停止或数据丢失。
在本章中,我们已经看到了可以使用 LVM 完成的最基本但也最重要的任务。我们已经了解了 LVM 的不同层如何工作:物理卷、卷组和逻辑卷。此外,我们还看到了它们如何相互作用以及如何进行管理。我们已经练习了创建、扩展和删除逻辑卷、卷组和物理卷。重要的是要练习它们以巩固所学知识,并能够在生产系统中使用它们。然而,现在已经奠定了这样做的基础。
现在,让我们继续下一章,发现 RHEL8 中的一个新功能,通过添加去重功能来进一步改进存储层 - 虚拟数据优化器(VDO)。
第十四章:使用 Stratis 和 VDO 进行高级存储管理
在本章中,我们将学习Stratis和虚拟数据优化器(VDO)。
Stratis 是一个存储管理工具,用于简化运行最典型的日常任务。它使用前几章中解释的基础技术,如 LVM、分区模式和文件系统。
VDO 是一个存储层,包括一个驱动程序,位于我们的应用程序和存储设备之间,提供数据的去重和压缩,以及管理此功能的工具。这将使我们能够最大化系统容纳虚拟机(VM)实例的能力,这些实例将仅基于使它们独特的内容占用磁盘空间,但只存储它们共同的数据一次。
我们还可以使用 VDO 来存储我们备份的不同副本,知道磁盘使用仍将被优化。
在本章结束时,我们将了解 VDO 的工作原理以及为系统设置它所需的内容。
我们将在以下部分中探讨如何准备、配置和使用我们的系统:
-
理解 Stratis
-
安装和启用 Stratis
-
使用 Stratis 管理存储池和文件系统
-
准备系统以使用 VDO
-
创建 VDO 卷
-
将 VDO 卷分配给 LVM
-
测试 VDO 卷并查看统计信息
让我们开始准备我们的系统以使用 VDO。
技术要求
可以继续使用本书开头创建的 VM 的做法第一章,安装 RHEL8。本章所需的任何其他软件包将被指示,并可以从github.com/PacktPublishing/Red-Hat-Enterprise-Linux-8-Administration
下载。
在理解 Stratis部分,我们将需要与第十三章中添加的相同两个磁盘,使用 LVM 进行灵活的存储管理,在所有 LVM 组件都已从中清理出来后。
理解 Stratis
作为一项新功能,为了管理存储,Stratis作为技术预览包含在 RHEL 8 中(截至 RHEL 8.3 版本)。Stratis 是为了通过将系统服务stratisd与 LVM 中的知名工具(在第十三章中解释,使用 LVM 进行灵活的存储管理)和 XFS 文件系统(在第十二章中解释,管理本地存储和文件系统)相结合来管理本地存储,这使其非常稳固和可靠。
重要提示
使用 Stratis 创建的文件系统/池应始终使用它来管理,而不是使用 LVM/XFS 工具。同样,已创建的 LVM 卷不应使用 Stratis 来管理。
Stratis 将本地磁盘组合成池,然后将存储分配到文件系统中,如下图所示:
图 14.1 - Stratis 简化架构图
可以看到,与 LVM 相比,Stratis 提供了一个更简单和易于理解的存储管理界面。在接下来的部分中,我们将安装和启用 Stratis,然后使用在第十三章中创建的相同磁盘,使用 LVM 进行灵活的存储管理,来创建一个池和一对文件系统。
安装和启用 Stratis
要能够使用 Stratis,我们将从安装它开始。与之一起使用的两个软件包是这些:
-
stratis-cli
:执行存储管理任务的命令行工具 -
stratisd
:一个系统服务(也称为守护程序),接收命令并执行低级任务
要安装它们,我们将使用dnf
命令:
[root@rhel8 ~]# dnf install stratis-cli stratisd
Updating Subscription Management repositories.
Red Hat Enterprise Linux 8 for x86_64 - BaseOS (RPMs) 17 MB/s | 32 MB 00:01
Red Hat Enterprise Linux 8 for x86_64 - AppStream (RPMs) 12 MB/s | 30 MB 00:02
Dependencies resolved.
====================================================================================================
Package Arch Version Repository Size
====================================================================================================
Installing:
stratis-cli noarch 2.3.0-3.el8 rhel-8-for-x86_64-appstream-rpms 79 k
stratisd x86_64 2.3.0-2.el8 rhel-8-for-x86_64-appstream-rpms 2.1 M
[omitted]
Complete!
现在我们可以使用systemctl
启动stratisd
服务:
[root@rhel8 ~]# systemctl start stratisd
[root@rhel8 ~]# systemctl status stratisd
● stratisd.service - Stratis daemon
Loaded: loaded (/usr/lib/systemd/system/stratisd.service; enabled; vendor preset: enabled)
Active: active (running) since Sat 2021-05-22 17:31:35 CEST; 53s ago
Docs: man:stratisd(8)
Main PID: 17797 (stratisd)
Tasks: 1 (limit: 8177)
Memory: 1.2M
CGroup: /system.slice/stratisd.service
└─17797 /usr/libexec/stratisd --log-level debug
[omitted]
现在我们将启用它以在启动时启动:
[root@rhel8 ~]# systemctl enable stratisd
[root@rhel8 ~]# systemctl status stratisd
● stratisd.service - Stratis daemon
Loaded: loaded (/usr/lib/systemd/system/stratisd.service; enabled; vendor preset: enabled)
[omitted]
提示
我们可以用一个命令完成这两个任务,即systemctl enable --now stratisd
。
让我们用stratis-cli
检查守护进程(也称为系统服务)是否正在运行:
[root@rhel8 ~]# stratis daemon version
2.3.0
我们已经准备就绪,现在是时候开始处理磁盘了。让我们继续下一个子部分。
使用 Stratis 管理存储池和文件系统
为了为 Stratis 提供一些存储空间,我们将使用/dev/vdb
和/dev/vdc
磁盘。我们需要确保它们上面没有任何逻辑卷或分区。让我们检查一下它们:
[root@rhel8 ~]# lvs
LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert
root rhel -wi-ao---- <8,00g
swap rhel -wi-ao---- 1,00g
[root@rhel8 ~]# vgs
VG #PV #LV #SN Attr VSize VFree
rhel 1 2 0 wz--n- <9,00g 0
[root@rhel8 ~]# pvs
PV VG Fmt Attr PSize PFree
/dev/vda2 rhel lvm2 a-- <9,00g 0
我们很好:所有由 LVM 创建的对象都在磁盘/dev/vda
上。让我们检查另外两个磁盘,/dev/vdb
和/dev/vdc
:
[root@rhel8 ~]# parted /dev/vdb print
Model: Virtio Block Device (virtblk)
Disk /dev/vdb: 1074MB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags:
Number Start End Size File system Name Flags
[root@rhel8 ~]# parted /dev/vdc print
Error: /dev/vdc: unrecognised disk label
Model: Virtio Block Device (virtblk)
Disk /dev/vdc: 1074MB
Sector size (logical/physical): 512B/512B
Partition Table: unknown
Disk Flags:
磁盘/dev/vdc
没有分区表标签。这个没问题。然而,磁盘/dev/vdb
有一个分区表。让我们移除它:
[root@rhel8 ~]# dd if=/dev/zero of=/dev/vdb count=2048 bs=1024
2048+0 records in
2048+0 records out
2097152 bytes (2,1 MB, 2,0 MiB) copied, 0,0853277 s, 24,6 MB/s
提示
dd
命令,代表磁盘转储,用于从设备转储数据和到设备。特殊设备/dev/zero
只是生成零,我们用它来覆盖磁盘的初始扇区,标签所在的位置。请谨慎使用dd
;它可能在没有警告的情况下覆盖任何内容。
现在我们准备使用stratis
命令创建第一个池:
[root@rhel8 ~]# stratis pool create mypool /dev/vdb
[root@rhel8 ~]# stratis pool list
Name Total Physical Properties
mypool 1 GiB / 37.63 MiB / 986.37 MiB ~Ca,~Cr
我们目前已经创建了池,如下图所示:
图 14.2 – 创建的 Stratis 池
我们已经创建了池;现在可以在其上创建文件系统:
[root@rhel8 ~]# stratis filesystem create mypool data
[root@rhel8 ~]# stratis filesystem list
Pool Name Name Used Created Device UUID
mypool data 546 MiB May 23 2021 19:16 /dev/stratis/mypool/data b073b6f1d56843b888cb83f6a7d80a43
存储的状态如下:
图 14.3 – 创建的 Stratis 文件系统
让我们准备挂载文件系统。我们需要在/etc/fstab
中添加以下行:
/dev/stratis/mypool/data /srv/stratis-data xfs defaults,x-systemd.requires=stratisd.service 0 0
重要提示
为了在启动过程中正确挂载 Stratis 文件系统,我们应该添加x-systemd.requires=stratisd.service
选项,以便在stratisd
服务启动后挂载它。
现在我们可以挂载它:
[root@rhel8 ~]# mkdir /srv/stratis-data
[root@rhel8 ~]# mount /srv/stratis-data/
现在让我们扩展池:
[root@rhel8 ~]# stratis blockdev list mypool
Pool Name Device Node Physical Size Tier
mypool /dev/vdb 1 GiB Data
[root@rhel8 ~]# stratis pool add-data mypool /dev/vdc
[root@rhel8 ~]# stratis blockdev list mypool
Pool Name Device Node Physical Size Tier
mypool /dev/vdb 1 GiB Data
mypool /dev/vdc 1 GiB Data
由于底层层使用了薄池,我们不需要扩展文件系统。存储如下:
图 14.4 – Stratis 池扩展
使用stratis snapshot
命令创建快照的时间。让我们创建一些数据,然后对其进行快照:
[root@rhel8 ~]# stratis filesystem
Pool Name Name Used Created Device UUID
mypool data 546 MiB May 23 2021 19:54 /dev/stratis/mypool/data 08af5d5782c54087a1fd4e9531ce4943
[root@rhel8 ~]# dd if=/dev/urandom of=/srv/stratis-data/file bs=1M count=512
512+0 records in
512+0 records out
536870912 bytes (537 MB, 512 MiB) copied, 2,33188 s, 230 MB/s
[root@rhel8 ~]# stratis filesystem
Pool Name Name Used Created Device UUID
mypool data 966 MiB May 23 2021 19:54 /dev/stratis/mypool/data 08af5d5782c54087a1fd4e9531ce4943
[root@rhel8 ~]# stratis filesystem snapshot mypool data data-snapshot1
[root@rhel8 ~]# stratis filesystem
Pool Name Name Used Created Device UUID
mypool data 1.03 GiB May 23 2021 19:54 /dev/stratis/mypool/data 08af5d5782c54087a1fd4e9531ce4943
mypool data-snapshot1 1.03 GiB May 23 2021 19:56 /dev/stratis/mypool/data-snapshot1 a2ae4aab56c64f728b59d710b82fb682
提示
要查看 Stratis 的内部组件,可以运行lsblk
命令。通过它,您将看到 Stratis 在树中使用的组件:物理设备、元数据和数据的分配、池和文件系统。所有这些都被 Stratis 抽象化了。
通过这些,我们已经了解了 Stratis 的概述,以便覆盖其管理的基础知识。请记住,Stratis 目前处于预览阶段,因此不应在生产系统中使用。
现在让我们继续研究存储管理中的其他高级主题,通过回顾使用 VDO 进行数据去重。
准备系统使用 VDO
如前所述,VDO 是一个驱动程序,具体来说是一个 Linux 设备映射器驱动程序,它使用两个内核模块:
-
kvdo
:这做数据压缩。 -
uds
:这负责去重。
常规存储设备,如本地磁盘、廉价磁盘冗余阵列(RAID)等,是数据存储的最终后端;顶部的 VDO 层通过以下方式减少磁盘使用:
-
去除零块,只在元数据中存储它们。
-
去重:重复的数据块在元数据中被引用,但只存储一次。
-
使用 4KB 数据块和无损压缩算法(LZ4:
lz4.github.io/lz4/
)进行压缩。
这些技术过去在其他解决方案中被使用过,比如只保留虚拟机之间的差异的薄配置VMs,但 VDO 使这一切变得透明。
与薄配置类似,VDO 可以意味着更快的数据吞吐量,因为数据可以被系统控制器和多个服务或甚至虚拟机缓存,而无需额外的磁盘读取来访问它。
让我们安装所需的软件包,以便通过安装vdo
和kmod-kvdo
软件包来创建 VDO 卷:
dnf install vdo kmod-kvdo
现在,安装了软件包,我们准备在下一节创建我们的第一个卷。
创建 VDO 卷
为了创建 VDO 设备,我们将利用我们在第十二章中创建的回环设备,管理本地存储和文件系统,所以我们首先检查它是否已挂载,执行以下命令:
mount|grep loop
如果没有输出显示,我们可以准备在其上创建我们的vdo
卷,使用以下命令:
vdo create -n myvdo --device /dev/loop0 –force
输出显示在以下截图中:
图 14.5 - vdo 卷创建
卷创建后,我们可以执行vdo status
来获取有关创建的卷的详细信息,如下截图所示:
图 14.6 - vdo 状态输出
](https://gitee.com/OpenDocCN/freelearn-linux-zh/raw/master/docs/rhel8-adm/img/B16799_14_006.jpg)
图 14.6 - vdo 状态输出
正如我们所看到的,这里有关于kvdo
版本、正在使用的配置文件以及我们的卷(大小、压缩状态等)的信息。
新卷现在可以通过/dev/mapper/myvdo
看到(我们使用–n
分配的名称),并且可以使用了。
我们可以执行vdo status|egrep -i "compression|dedupli"
并获得以下输出:
图 14.7 - 检查 VDO 压缩和重复数据删除的状态
](https://gitee.com/OpenDocCN/freelearn-linux-zh/raw/master/docs/rhel8-adm/img/B16799_14_007.jpg)
图 14.7 - 检查 VDO 压缩和重复数据删除的状态
这意味着我们的卷上同时启用了压缩和重复数据删除,所以我们准备在下一节将其添加到 LVM 卷中进行功能测试。
将 VDO 卷分配给 LVM 卷
在上一节中,我们创建了一个 VDO 卷,现在将成为我们创建 LVM 卷组和一些逻辑卷的物理卷(PV)。
让我们通过以下命令序列创建 PV:
-
pvcreate /dev/mapper/myvdo
-
vgcreate myvdo /dev/mapper/myvdo
-
lvcreate -L 15G –n myvol myvdo
此时,我们的/dev/myvdo/myvol
已准备好格式化。让我们使用 XFS 文件系统:
mkfs.xfs /dev/myvdo/myvol
文件系统创建后,让我们通过挂载放一些数据:
mount /dev/myvdo/myvol /mnt
现在让我们在下一节测试 VDO 卷。
测试 VDO 卷并查看统计信息
为了测试重复数据删除和压缩,我们将使用一个大文件进行测试,比如在access.redhat.com/downloads/content/479/ver=/rhel---8/8.3/x86_64/product-software
上可用的 RHEL 8 KVM 客户机镜像。
下载后,将其保存为rhel-8.3-x86_64-kvm.qcow2
并将其复制四次到我们的 VDO 卷:
cp rhel-8.3-x86_64-kvm.qcow2 /mnt/vm1.qcow2
cp rhel-8.3-x86_64-kvm.qcow2 /mnt/vm2.qcow2
cp rhel-8.3-x86_64-kvm.qcow2 /mnt/vm3.qcow2
cp rhel-8.3-x86_64-kvm.qcow2 /mnt/vm4.qcow2
这将是一个典型情况,对于一个持有以相同基础磁盘镜像启动的 VM 的服务器,但我们是否看到了任何改进?
让我们执行vdostats --human-readable
来验证数据。请注意,从ls –si
报告的图像下载大小为 1.4 GB。从vdostats --human-readable
获得的输出如下:
Device Size Used Available Use% Space saving%
/dev/mapper/myvdo 20.0G 5.2G 14.8G 25% 75%
原始卷(回环文件)为 20 GB,所以我们可以看到这个大小,但是从输出来看,我们创建的 LVM 卷为 15 GB,而且我们看到只消耗了大约 1.2 GB,即使我们有四个大小为 1.4 GB 的文件。
百分比也非常清楚。我们节省了 75%的空间(四个文件中有三个是完全相同的)。如果我们再复制一份,我们会看到百分比变为 80%(5 份复制中有 1 份)。
让我们看看另一种方法,通过创建一个空文件(填充为零):
[root@bender mnt]# dd if=/dev/zero of=emptyfile bs=16777216 count=1024
dd: error writing 'emptyfile': No space left on device
559+0 records in
558+0 records out
9361883136 bytes (9.4 GB, 8.7 GiB) copied, 97.0276 s, 96.5 MB/s
正如我们所看到的,磁盘完全填满之前,我们能够写入 9.4 GB,但让我们再次使用vdostats --human-readable
检查vdo
统计信息,如下截图所示:
图 14.8 - 检查 vdostats 输出
正如我们所看到的,我们仍然有 14.8GB 可用,并且我们已经将磁盘空间从 80%增加到 92%,因为这个大文件是空的。
等等 - 如果我们使用去重和压缩,为什么我们填满了 92%的卷呢?
由于我们没有指定 VDO 卷的逻辑大小,默认情况下它与底层设备的比例为 1:1。这是最安全的方法,但我们没有真正利用压缩和去重的性能。
为了充分利用优化,我们可以在现有卷的基础上创建一个更大的逻辑驱动器。例如,如果经过长时间后我们相当确定磁盘优化可能是相似的,我们可以使用以下命令扩展逻辑大小:
vdo growLogical --name=myvdo --vdoLogicalSize=30G
当然,这不会增加可用的大小,因为我们定义了一个 PV 与卷组和顶部的逻辑卷。因此,我们还需要通过执行以下命令来扩展它:
-
pvresize /dev/mapper/myvdo
-
lvresize –L +14G /dev/myvdo/myvol
-
xfs_growfs /mnt
通过这样做,我们扩展了物理卷,增加了逻辑卷的大小,并扩展了文件系统,因此现在可以使用这些空间。
如果现在执行df|grep vdo
,我们会看到类似这样的内容:
图 14.9 - 调整卷大小后的磁盘空间可用性
从这一点开始,我们必须非常小心,因为我们对磁盘空间的实际使用可能不像以前那样在可能的压缩方面进行了优化,导致写入失败。因此,需要监视可用的磁盘空间以及 VDO 状态,以确保我们没有尝试使用比可用空间更多的空间,例如,如果存储的文件无法以相同的比例进行压缩或去重。
重要提示
诱人的是,我们可以从真实的物理磁盘空间中设置一个非常大的逻辑卷,但我们应该提前计划并考虑避免未来可能出现的问题,比如压缩比可能不像我们的乐观主义那样高的可能性。充分地对存储的实际数据和其典型的压缩比进行分析可以让我们更好地了解在继续积极监视逻辑卷和物理卷的磁盘使用情况演变时使用的安全方法。
很久以前,当磁盘空间非常昂贵(硬盘总共只有 80MB)时,使用工具来通过透明的压缩层增加磁盘空间变得非常流行,这些工具可以通过一些估算和报告更大的空间来实现增加磁盘空间;但实际上,我们知道像图片和电影这样的内容并不像文本文件这样的其他文档格式那样容易压缩。一些文档格式,比如 LibreOffice 使用的格式,已经是压缩文件,因此不会获得额外的压缩好处。
但是,当我们谈论虚拟机时,情况就不同了,每个虚拟机的基础更多或更少是相等的(基于公司政策和标准),并且是通过克隆磁盘映像部署的,然后进行一些小的定制,但本质上,大部分磁盘内容是共享的。
提示
总的来说,要记住优化实际上只是一种权衡。在调整配置文件的情况下,您是在调整吞吐量以换取延迟,而在我们的情况下,您是在交换 CPU 和内存资源以换取磁盘可用性。判断某种东西是否值得权衡的唯一方法是实施它并查看其性能,看看获得了什么好处,然后继续随着时间的推移监视性能。
总结
在本章中,我们学习了 VDO 和 Stratis。我们看了一些简单的管理存储的方法,如如何透明地节省磁盘空间以及如何在过程中获得一些吞吐量。
使用 Stratis,我们创建了一个具有两个磁盘的池,并将其分配给一个挂载点。这比使用 LVM 要简单一些,但另一方面,我们对我们所做的事情的控制更少。无论如何,我们学会了如何在 RHEL 8 中使用这个预览技术。
使用 VDO,我们使用创建的卷来定义一个 LVM PV,并在其上创建了一个卷组和一个逻辑卷,我们使用在之前章节中获得的知识来格式化它,以存储多个 VM 磁盘映像,模拟从同一基础启动多个 VM 的场景。
我们还学会了如何检查 VDO 的优化和节省的磁盘空间量。
现在,我们准备使用 Stratis 而不是 LVM 来组合和分配存储(尽管不用于生产)。我们还可以为我们的服务器实施 VDO 来开始优化磁盘使用。
在下一章中,我们将学习关于引导过程。
第十五章:理解引导过程
引导过程是指从您打开机器(物理或虚拟)的那一刻到操作系统完全加载的过程。
就像许多好的视频游戏一样,它有三个阶段:硬件执行的初始启动(再次是物理或虚拟),操作系统初始阶段的加载,然后是帮助在系统中运行所需服务的机制。 我们将在本章中审查这三个阶段,并且还将添加提示和技巧,以干预系统并执行救援操作。
本章中我们将涵盖的部分如下:
-
理解引导过程 - BIOS 和 UEFI 引导
-
使用 GRUB,引导加载程序和 initrd 系统映像
-
使用 systemd 管理引导顺序
-
干预引导过程以获取对系统的访问权限
在引导过程的前两个阶段,您很可能不需要进行太多更改,但在紧急情况,取证或重大故障的情况下,这些点可能极其有帮助。 这就是为什么仔细阅读它们很重要。
第三阶段,由 systemd 管理,将执行更多操作和更改,以管理系统中默认运行的服务。 我们已经在之前的章节中看到了大部分要执行的任务的示例; 但是,在这一章中,我们将提供全面的审查。
让我们开始第一阶段。
理解引导过程 - BIOS 和 UEFI 引导
计算机具有硬件嵌入式软件控制器,也称为 固件,可让您管理硬件的最底层。 这个固件是对系统中可用的硬件进行第一次识别以及启用的硬件功能(如 预引导网络执行,称为 PXE)。
在被称为 PC(个人计算机)的架构中,也称为 x86,由英特尔和 IBM 推广,嵌入式固件称为 BIOS,代表 基本输入输出系统。
BIOS 引导过程,使用 Linux,采取以下步骤:
-
计算机开机并加载 BIOS 固件。
-
固件初始化设备,如键盘,鼠标,存储和其他外围设备。
-
固件读取配置,包括引导顺序,指定哪个存储设备是继续引导过程的设备。
-
一旦选择了存储设备,BIOS 将加载其中的 主引导记录 (MBR),这将启用 操作系统加载程序。 在 RHEL 中,操作系统加载程序称为 Grand Unified Bootloader (GRUB)。
-
GRUB 加载配置和
vmlinuz
,以及名为initrd
的初始引导映像文件。 所有 GRUB 配置vmlinuz
和initrd
文件都存储在/boot
分区中。 -
初始引导映像使得加载系统的第一个进程成为可能,也称为
init
,在 RHEL8 中是 systemd。 -
systemd 加载操作系统的其余部分。
为了使这个过程发生,磁盘必须有一个 MBR 分区表,并且分配给 /boot
的分区必须标记为可引导。
提示
MBR 分区表格式非常有限,只允许四个主分区,并使用扩展分区等扩展来克服这一限制。 不建议使用这种类型的分区,除非完全需要。
UEFI 引导过程与 BIOS 引导过程非常相似。 UEFI 代表 统一可扩展固件接口。 引导顺序的主要区别在于 UEFI 可以直接访问和读取磁盘分区。 其流程如下:
-
计算机开机并加载 UEFI 固件。
-
固件初始化设备,如键盘,鼠标,存储和其他外围设备。
-
固件读取配置,其中指定了继续引导过程所需的存储设备和可引导分区(UEFI 不需要 MBR 引导)。
-
选择存储设备后,从
/boot/efi
分区读取其中的分区,并继续加载 GRUB。 -
然后,GRUB 加载
vmlinuz
和initrd
。GRUB 配置vmlinuz
和initrd
文件存储在/boot
分区中。 -
初始引导映像使系统的第一个进程加载,也称为
init
,在 RHEL8 中是systemd。 -
systemd加载操作系统的其余部分。
UEFI 相对于 BIOS 具有几个优点,可以启用更完整的预引导环境和其他功能,例如安全引导和对 GPT 分区的支持,可以超出 MBR 分区的 2TB 限制。
安装程序将负责创建引导以及如果需要的 UEFI 分区和二进制文件。
需要了解的预引导部分是如何从中加载操作系统加载程序,这是红帽认证系统管理员认证考试的一部分。通过 BIOS 或 UEFI,我们可以选择从哪个存储设备加载操作系统,并转移到下一个阶段。让我们在下一节中进入下一个阶段。
使用 GRUB、引导加载程序和 initrd 系统映像进行工作。
预引导执行完成后,系统将运行 GRUB 引导加载程序。
GRUB 的任务是加载操作系统的主文件kernel,向其传递参数和选项,并加载初始 RAM 磁盘,也称为initrd。
可以使用grub2-install
命令安装 GRUB。我们需要知道将用于引导的磁盘设备,例如/dev/vda
:
[root@rhel8 ~]# grub2-install /dev/vda
Installing for i386-pc platform.
Installation finished. No error reported.
重要提示
您应该将grub-install
指向您将用于引导系统的磁盘,与您在 BIOS/UEFI 中配置的相同磁盘。
这是用于手动重建系统或修复损坏引导的。
GRUB 文件存储在/boot/grub2
中。主配置文件是/boot/grub2/grub.cfg
;但是,如果您仔细查看此文件,您将看到以下标题:
[root@rhel8 ~]# head -n 6 /boot/grub2/grub.cfg
#
# DO NOT EDIT THIS FILE
#
# It is automatically generated by grub2-mkconfig using templates
# from /etc/grub.d and settings from /etc/default/grub
#
如您所见,此文件是自动生成的,因此不打算手动编辑。那么我们如何进行更改呢?有两种方法可以这样做:
-
第一种方法是按照
grub.cfg
文件中提到的说明进行操作。这意味着编辑/etc/default/grub
文件和/或/etc/grub.d/
目录中的内容,然后通过运行grub2-mkconfig
重新生成 GRUB 配置。 -
第二种方法是使用
grubby
命令行工具。
重要提示
在 RHEL 中,当有新版本的内核时,不会更新现有内核,而是在先前的内核旁边安装新的内核,并在 GRUB 中添加新的条目。这样,如果需要,可以轻松回滚到以前的工作内核。在安装过程中,为新内核创建了新的更新的initrd
。
让我们使用grubby
查看当前的内核配置。--default-kernel
选项将显示默认加载的内核文件:
[root@rhel8 ~]# grubby --default-kernel
/boot/vmlinuz-4.18.0-240.15.1.el8_3.x86_64
--default-title
选项将显示引导时使用的名称:
[root@rhel8 ~]# grubby --default-title
Red Hat Enterprise Linux (4.18.0-240.15.1.el8_3.x86_64) 8.3 (Ootpa)
通过使用--info
选项,我们可以查看默认内核的更多信息:
[root@rhel8 ~]# grubby --info=/boot/vmlinuz-4.18.0-240.15.1.el8_3.x86_64
index=0
kernel="/boot/vmlinuz-4.18.0-240.15.1.el8_3.x86_64"
args="ro crashkernel=auto resume=/dev/mapper/rhel-swap rd.lvm.lv=rhel/root rd.lvm.lv=rhel/swap rhgb quiet $tuned_params"
root="/dev/mapper/rhel-root"
initrd="/boot/initramfs-4.18.0-240.15.1.el8_3.x86_64.img $tuned_initrd"
title="Red Hat Enterprise Linux (4.18.0-240.15.1.el8_3.x86_64) 8.3 (Ootpa)"
id="21e418ac989a4b0c8afb156418393409-4.18.0-240.15.1.el8_3.x86_64"
我们可以看到传递给 GRUB 的选项:
-
index
:显示条目的索引号 -
kernel
:包含将加载以运行操作系统核心的内核的文件 -
root
:将分配给根/
目录并挂载的分区或逻辑卷 -
initrd
:包含 RAM 磁盘的文件,用于执行引导过程的初始部分 -
title
:在引导过程中向用户显示的描述性标题 -
id
:引导项的标识符
提示
您可能希望运行grubby
命令以获取默认配置的内核信息。为此,可以通过运行以下命令来执行:grubby --info=$(grubby --default-kernel)
。
通过删除传递给内核的quiet
和rhbg
参数,让引导过程更加详细:
[root@rhel8 ~]# grubby --remove-args="rhgb quiet" \
--update-kernel=/boot/vmlinuz-4.18.0-240.15.1.el8_3.x86_64
[root@rhel8 ~]# grubby \
--info=/boot/vmlinuz-4.18.0-240.15.1.el8_3.x86_64
index=0
kernel="/boot/vmlinuz-4.18.0-240.15.1.el8_3.x86_64"
args="ro crashkernel=auto resume=/dev/mapper/rhel-swap rd.lvm.lv=rhel/root rd.lvm.lv=rhel/swap $tuned_params"
root="/dev/mapper/rhel-root"
initrd="/boot/initramfs-4.18.0-240.15.1.el8_3.x86_64.img $tuned_initrd"
title="Red Hat Enterprise Linux (4.18.0-240.15.1.el8_3.x86_64) 8.3 (Ootpa)"
id="21e418ac989a4b0c8afb156418393409-4.18.0-240.15.1.el8_3.x86_64"
让我们使用systemctl reboot
命令重新启动机器进行测试。这是一个示例输出:
图 15.1 - 详细引导
在正常引导中,这可能并不是非常有用,因为它进行得太快了。然而,如果有问题,它可以帮助从控制台调试情况。要在引导后查看这些消息,可以使用dmesg
命令:
图 15.2 - dmesg 命令的输出
我们可以使用--args
选项向内核添加参数。让我们再次添加quiet
选项:
[root@rhel8 ~]# grubby --args="quiet" \
--update-kernel=/boot/vmlinuz-4.18.0-240.15.1.el8_3.x86_64
[root@rhel8 ~]# grubby \
--info=/boot/vmlinuz-4.18.0-240.15.1.el8_3.x86_64
index=0
kernel="/boot/vmlinuz-4.18.0-240.15.1.el8_3.x86_64"
args="ro crashkernel=auto resume=/dev/mapper/rhel-swap rd.lvm.lv=rhel/root rd.lvm.lv=rhel/swap $tuned_params quiet"
root="/dev/mapper/rhel-root"
initrd="/boot/initramfs-4.18.0-240.15.1.el8_3.x86_64.img $tuned_initrd"
title="Red Hat Enterprise Linux (4.18.0-240.15.1.el8_3.x86_64) 8.3 (Ootpa)"
id="21e418ac989a4b0c8afb156418393409-4.18.0-240.15.1.el8_3.x86_64"
重要提示
--info
和--update-kernel
选项接受ALL
选项来查看或执行所有配置的内核的操作。
如果任何管理任务需要我们更改内核参数,现在我们知道如何做了。让我们转到引导过程的下一部分,initrd
。
/boot/initramfs-4.18.0-240.15.1.el8_3.x86_64.img
。可以使用dracut
命令重新生成。让我们看一个重新构建当前initrd
文件的例子:
[root@rhel8 ~]# dracut --force --verbose
dracut: Executing: /usr/bin/dracut --force --verbose
dracut: dracut module 'busybox' will not be installed, because command 'busybox' could not be found!
[omitted]
dracut: *** Including module: shutdown ***
dracut: *** Including modules done ***
dracut: *** Installing kernel module dependencies ***
dracut: *** Installing kernel module dependencies done ***
dracut: *** Resolving executable dependencies ***
dracut: *** Resolving executable dependencies done***
dracut: *** Hardlinking files ***
dracut: *** Hardlinking files done ***
dracut: *** Generating early-microcode cpio image ***
dracut: *** Constructing GenuineIntel.bin ****
dracut: *** Constructing GenuineIntel.bin ****
dracut: *** Store current command line parameters ***
dracut: *** Stripping files ***
dracut: *** Stripping files done ***
dracut: *** Creating image file '/boot/initramfs-4.18.0-240.15.1.el8_3.x86_64.img' ***
dracut: *** Creating initramfs image file '/boot/initramfs-4.18.0-240.15.1.el8_3.x86_64.img' done ***
我们可以在先前的输出中看到,initrd
文件中包括的用于早期访问的内核模块和文件。当我们的initrd
文件损坏时,这一步是有用的,也是在从备份中恢复系统时,如果在不同的硬件上进行,需要包括适当的存储驱动程序。
提示
查看dracut
的手册页面,了解创建initrd
文件的选项。有一篇红帽知识库文章可以解压initrd
,这是一个学习更多知识的有趣练习:[access.redhat.com/solutions/24029.
](https://access.redhat.com/solutions/24029
)
我们已经学习了引导过程的早期阶段的基础知识,以便能够开始排除引导问题,这是成为 RHCSA 所需的。这个高级主题可以在一本完整的书中进行详细介绍,但在作为系统管理员的日常任务中几乎不会用到。这就是为什么我们只包括了其中必要的方面。我们将在本章的最后一节中包括一个特定的用例,名为干预引导过程以访问系统,并修复磁盘问题。让我们继续下一个关于如何使用systemd管理 RHEL 中服务的主题。
使用 systemd 管理引导顺序
我们已经学习了系统固件将如何指向一个磁盘来运行操作系统加载程序,在 RHEL 中就是 GRUB。
GRUB 将加载内核和 initrd 以准备系统启动。然后是启动系统的第一个进程,也称为进程 1 或 PID 1(PID代表进程标识符)。这个进程必须有效地负责加载系统中所有所需的服务。在 RHEL8 中,PID 1 由systemd运行。
在第四章,常规操作工具中,我们描述了使用 systemd 管理服务和目标。让我们在本章中回顾它与引导顺序的交互。
与systemctl
工具相关的引导顺序的前两件事:
[root@rhel8 ~]# systemctl reboot
我们将看到系统将重新启动。我们可以使用uptime
命令检查系统运行了多长时间:
[root@rhel8 ~]# uptime
11:11:39 up 0 min, 1 user, load average: 0,62, 0,13, 0,04
现在是时候检查poweroff
了。在这样做之前,请记住运行此命令后,您将需要一种方法再次打开机器。一旦我们了解了要遵循的流程,让我们运行它:
[root@rhel8 ~]# systemctl poweroff
现在我将再次打开我的机器。
有一个命令可以停止系统,但不发送关闭机器的信号,那就是systemctl halt
。可以使用这个命令的情况很少;然而,知道它的存在和作用是很好的。
重要提示
先前显示的命令可以缩写为reboot
和poweroff
。如果您检查/usr/sbin/poweroff
中的文件,您会发现它是一个指向systemctl
的符号链接。
在第四章中,常规操作工具,我们还回顾了如何设置默认的systemctl
。然而,我们可以通过传递systemd.unit
参数给内核来在启动时覆盖默认配置。我们可以使用grubby
来做到这一点:
[root@rhel8 ~]# systemctl get-default
multi-user.target
[root@rhel8 ~]# grubby --args="systemd.unit=emergency.target" --update-kernel=/boot/vmlinuz-4.18.0-240.15.1.el8_3.x86_64
[root@rhel8 ~]# systemctl reboot
现在系统正在重新启动。systemd.unit=emergency.target
参数已经被GRUB传递给内核,然后从内核传递给systemd,systemd将忽略默认配置并加载紧急目标所需的服务。
现在系统以紧急模式启动,并等待根密码以让您控制:
图 15.3 - RHEL 系统以紧急模式启动
在紧急模式下,没有配置网络,也没有其他进程在运行。您可以对系统进行更改,而无需担心其他用户正在访问。此外,只有/
文件系统以只读模式挂载。
如果系统中的文件系统损坏,这将是一个检查它的好方法,而没有任何服务访问它。让我们尝试使用检查文件系统的命令fsck
:
[root@rhel8 ~]# fsck /boot
fsck from util-linux 2.32.1
If you wish to check the consistency of an XFS filesystem or
repair a damaged filesystem, see xfs_repair(8).
文件系统正常。如果有问题需要修复(fsck
检测到使用的文件系统),我们可以在其上运行xfs_repair
,因为它是一个xfs
文件系统。
此时我们可能会想,如果根文件系统已经以只读方式挂载在/
上,我们如何对其进行更改?这个过程从将/
文件系统重新挂载为读写开始:
[root@rhel8 ~]# mount -o remount -o rw /
记住,您可以通过运行man mount
来访问命令的手册页面。现在我们的根文件系统以读写方式挂载在/
上。我们还需要挂载/boot
,所以让我们这样做:
[root@rhel8 ~]# mount /boot
有了/boot
挂载,让我们做一些管理员任务,比如删除我们在 GRUB 中使用的参数:
[root@rhel8 ~]# grubby --remove-args="systemd.unit=emergency.target" --update-kernel=/boot/vmlinuz-4.18.0-240.15.1.el8_3.x86_64
[root@rhel8 ~]# reboot
然后我们回到了系统中的常规启动。这可能不是在 Linux 中进入紧急模式的实际方法,但它展示了如何在启动时传递参数给 systemd。
提示
有rescue.target
加载更多服务并使过程变得更加容易。它通过等待sysinit.target
完成来实现,而紧急目标不会这样做。一个很好的练习是使用rescue.target
重复之前的序列。
在接下来的部分中,我们将看到如何对一次性启动进行此更改,以及在 GRUB 启动序列期间更轻松地进行类似的更改,而且无需密码。
干预引导过程以访问系统
有时您需要干预一个交接的系统,而您没有root
用户的密码。尽管这听起来像是一个紧急情况,但实际上比您想象的更频繁。
重要提示
引导顺序必须没有任何加密的磁盘才能正常工作,否则您将需要加密卷的密码。
执行此过程的方法是在 GRUB 菜单中停止引导过程。这意味着我们需要重新启动系统。一旦 BIOS/UEFI 检查完成,系统将加载 GRUB。在那里,我们可以通过按下向上或向下箭头键来停止计数,就像以下截图中所示:
图 15.4 - GRUB 菜单选择内核
我们回到第一个条目。然后我们阅读屏幕底部,那里有编辑引导行的说明:
图 15.5 - GRUB 菜单选择内核
如果我们按下E键,我们将能够编辑菜单中选择的引导行。我们将看到以下五行:
图 15.6 - GRUB 菜单以选择内核
](https://gitee.com/OpenDocCN/freelearn-linux-zh/raw/master/docs/rhel8-adm/img/B16799_15_006.jpg)
图 15.6 - GRUB 菜单以选择内核
前三行load_video
,set
gfx_payload=keep
和insmod gzio
设置了 GRUB 的选项。接下来的两个选项是重要的。让我们来回顾一下它们:
-
linux
:定义要加载的内核并向其传递参数 -
initrd
:定义了从哪里加载 initrd 以及是否有任何选项
提示
请注意,linux
行非常长,已经换行,我们可以看到\
符号,这意味着该行在下面继续。
现在我们应该转到linux
行的末尾,并添加rd.break
选项,如下面的屏幕截图所示:
图 15.7 - 使用 rd.break 选项编辑的 linux 内核行
要引导编辑后的行,我们只需要按下Ctrl + X。rd.break
选项在加载 initrd 之前停止引导过程。现在的情况如下:
-
加载了单个 shell。
-
当前根文件系统挂载在
/
上,是一个带有基本管理命令的最小文件系统。 -
目标根文件系统以只读方式挂载在
/sysroot
上(而不是在/
上)。 -
没有其他文件系统被挂载。
-
SELinux 未加载。
现在我们可以使用chroot
切换到真正的磁盘根文件系统:
switch_root:/# chroot /sysroot
sh-4.4#
现在我们的根文件系统已经正确挂载,但是只读。让我们以与上一节相同的方式进行更改:
sh-4.4# mount –o remount –o rw /
现在我们需要使用passwd
命令更改 root 用户密码:
sh-4.4# passwd
Changing password for user root
New password:
Retype new password:
passwd: all authentication tokens updated successfully
root 用户的密码现在已更改,并且/etc/shadow
文件已更新。但是,它是在未启用 SELinux 的情况下修改的,因此可能会在下一次引导时引发问题。为了避免这种情况,有一种机制可以在下一次引导时修复 SELinux 标签。该机制包括创建/.autorelabel
隐藏的空文件,然后重新启动系统:
sh-4.4# touch /.autorelabel
创建文件后,现在是时候重新启动以应用 SELinux 更改。在此状态下,可能需要强制关闭电源,然后重新上电。在下一次引导时,我们将看到 SELinux 自动标记的发生:
图 15.8 - 引导期间的 SELinux 自动标记
现在我们可以使用 root 用户及其新密码登录。
总结
我们在本章中已经审查了引导顺序。正如您所见,它并不长,但它很复杂,而且也非常重要,因为如果系统无法引导,它就无法运行。我们已经了解了 BIOS 启用系统和 UEFI 系统之间的主要区别,后者可以实现一些功能,但也有自己的要求。我们还了解了 GRUB 及其在引导顺序中的重要作用,以及如何使用grubby
永久修改条目以及如何进行一次性修改。我们现在知道了引导的主要文件,如内核vmlinuz
和初始 RAM 磁盘initrd
。
本章还向我们展示了如何在紧急和救援模式下启动,以及如何干预系统以重置 root 密码。
通过这些工具和程序,我们现在更有准备处理系统中的任何困难情况。现在是时候深入了解内核调优和性能配置文件了。
第十六章:内核调优和使用tuned
管理性能配置文件
如前几章中偶尔描述的,每个系统性能配置文件必须适应我们系统的预期用途。
内核调优在这种优化中起着关键作用,我们将在本章的以下部分进一步探讨这一点:
-
识别进程,检查内存使用情况和终止进程
-
调整内核调度参数以更好地管理进程
-
安装
tuned
和管理调优配置文件 -
创建自定义的
tuned
配置文件
在本章结束时,您将了解如何应用内核调优,如何通过tuned
使用快速配置文件以适应不同系统角色的一般用例,以及如何进一步扩展这些自定义配置以适用于您的服务器。
此外,识别已成为资源消耗者的进程以及如何终止它们或对它们进行优先处理将是在最需要时更充分利用我们的硬件的有用方法。
让我们动手学习这些主题!
技术要求
您可以继续使用本书开头创建的虚拟机(VM)第一章中的,安装 RHEL8。本章所需的任何其他软件包都将在文本旁边指示。
识别进程,检查内存使用情况和终止进程
进程是在我们系统上运行的程序 - 它可能是通过安全外壳(SSH)登录的用户,具有运行的 bash 终端进程,甚至是 SSH 守护程序的部分,用于监听和回复远程连接,或者可能是诸如邮件客户端、文件管理器等正在执行的程序。
当然,进程占用了我们系统的资源:内存、中央处理单元(CPU)、磁盘等。对于系统管理员来说,识别或定位可能行为不端的进程是一项关键任务。
一些基础知识已经在第四章中涵盖了,常规操作工具,但在继续之前,最好先复习一下;然而,在这里,我们将展示并使用一些这些工具,例如 - 例如top
命令,它允许我们查看进程并根据 CPU 使用情况、内存使用情况等对列表进行排序。(查看man top
的输出,了解如何更改排序标准。)
在检查系统性能时要注意的一个参数是负载平均值,它是由准备运行或等待1
、5
和15
分钟的进程组成的移动平均值 - 并且可以让我们了解负载是增加还是减少的想法。一个经验法则是,如果负载平均值低于 1,那么没有资源饱和。
负载平均值可以通过许多其他工具显示,例如前面提到的top
,或者使用uptime
或w
等。
如果系统负载平均值正在增长,CPU 或内存使用率正在上升,并且如果列出了一些进程,那么定位将更容易。如果负载平均值也很高且正在增加,可能是 I/O 操作在增加。可以安装iotop
软件包,它提供iotop
命令来监视磁盘活动。执行时,它将显示系统中的进程和磁盘活动:读取、写入和交换,这可能会给我们一些更多关于查找位置的提示。
一旦确定了占用太多资源的进程,我们就可以发送一个信号来控制它。
可以使用kill -l
命令获取信号列表,如下截图所示:
图 16.1 - 发送给进程的可用信号
请注意,每个信号都包含一个数字和一个名称 - 都可以用于通过其进程标识符(PID)向进程发送信号。
让我们来回顾一下最常见的信号,如下所示:
从图 16.1中显示的列表中,重要的是要知道每个信号都有一个man 7 信号
,如下面的截图所示:
图 16.2 - 信号列表,数字等效物,处置(操作)和行为(man 7 信号)
到达这一点时最典型的用法之一是终止行为不端的进程,因此定位进程、获取 PID 并向其发送信号是一项非常常见的任务...甚至是如此常见,以至于甚至有工具可以让您将这些阶段组合成一个命令。
例如,我们可以将ps aux|grep -i chrome|grep –v grep|awk '{print $2}'|xargs kill –9
与pkill –9 –f chrome
进行比较:两者都会执行相同的操作,搜索名为chrome
的进程,并向它们发送信号9
(杀死)。
当然,即使用户登录也是系统中的一个进程(运行 SSH 或 shell 等);我们可以通过类似的构造(使用ps
、grep
和其他工具)或使用pgrep
选项(如pgrep -l -u user
)找到我们目标用户启动的进程。
请注意,正如信号所指示的那样,最好发送一个TERM
信号,以便让进程在退出之前运行其内部清理步骤,直接杀死它们可能会在我们的系统中留下残留物。
在终端复用器(如tmux
或screen
)变得普遍之前,一个广泛使用的有趣命令是nohup
,它被添加到持续时间较长的命令之前,例如下载大文件。这个命令捕获了终端挂起信号,允许执行的进程继续执行,并将输出存储在nohup.out
文件中,以便以后检查。
例如,要从客户门户下载最新的Red Hat Enterprise Linux(RHEL)Image Standard Optical(ISO)文件,选择一个版本,例如 8.4,然后在access.redhat.com/downloads/content/479/ver=/rhel---8/8.4/x86_64/product-software
登录后,我们将选择二进制 ISO 并右键单击复制下载的统一资源定位符(URL)。
提示
从客户门户复制时获得的 URL 是有时间限制的,这意味着它们只在短时间内有效,之后,下载链接将不再有效,应在刷新 URL 后获取新的链接。
然后,在终端中,我们将执行以下带有复制的 URL 的命令:
nohup wget URL_OBTAINED_FROM_CUSTOMER_PORTAL &
使用前面的命令,nohup
将不会在终端挂断(断开连接)时关闭进程,因此wget
将继续下载 URL,并且结束的&
符号将执行从活动终端分离,将其作为后台作业,我们可以使用jobs
命令检查直到它完成。
如果我们忘记添加&
,程序将阻塞我们的输入,但我们可以在键盘上按下Ctrl + Z,进程将被停止。然而,由于我们真的希望它继续在后台执行,我们将执行bg
,这将继续执行它。
如果我们想要将程序带回以接收我们的输入并与其交互,我们可以使用fg
命令将其移到前台。
如果我们按下Ctrl + C,而程序有我们的输入,它将收到中断和停止执行的请求。
您可以在以下截图中看到工作流程:
图 16.3 - 挂起进程,恢复到后台,带到前台,中止
在这种情况下,我们正在下载 Fedora 34 安装 ISO(8 nohup
和wget
;因为我们忘记添加&,我们执行了Ctrl + Z(显示为^Z
)。
作业被报告为作业[1]
,状态为Stopped
(在执行jobs
时也会报告)。
然后,我们使用bg
将作业切换到后台执行,现在,jobs
将其报告为Running
。
之后,我们使用fg
将作业切换回前台,并执行Ctrl + C,在屏幕上表示为^C
,以结束它。
这个功能使我们能够运行多个后台命令 - 例如,我们可以并行复制文件到多台主机,如下面的截图所示:
图 16.4 - 使用 nohup 复制文件到多台服务器的示例 for 循环
在这个例子中,通过scp
执行的复制操作将会并行进行,而且,如果从我们的终端断开连接,作业将继续执行,并且输出将存储在我们执行它的文件夹中的nohup.out
文件中。
重要提示
使用nohup
启动的进程将不会获得任何额外的输入,因此如果程序要求输入,它将停止执行。如果程序要求输入,建议使用tmux
,因为它仍然可以防止终端断开连接,但也允许与启动的程序进行交互。
我们并不总是愿意杀死进程或停止或恢复它们;我们可能只想降低或提高它们的优先级 - 例如,对于可能不是关键的长时间运行的任务。
让我们在下一节中了解这个功能。
调整内核调度参数以更好地管理进程
Linux 内核是一款高度可配置的软件,因此有一整个世界的可调参数可用于调整其行为:用于进程、网络卡、磁盘、内存等等。
最常见的可调参数是nice
进程值和 I/O 优先级,分别调节 CPU 和 I/O 时间相对于其他进程的优先级。
对于即将启动的进程进行交互,我们可以使用nice
或ionice
命令,在要执行的命令前面加上一些参数(记得检查每个命令的man
内容以获取完整的可用选项范围)。只需记住,对于nice
,进程的优先级可以从-20 到+19,0 是标准值,-20 是最高优先级,19 是最低优先级(值越高,进程越好)。
每个进程都有一个获得内核关注的可能性;通过在执行之前通过nice
或在运行时通过renice
改变优先级,我们可以稍微改变它。
让我们考虑一个长时间运行的进程,比如执行备份 - 我们希望任务成功,所以我们不会停止或杀死进程,但与此同时,我们也不希望它改变我们服务器的生产或服务水平。如果我们将进程定义为 19 的nice
值,这意味着系统中的任何进程都会获得更高的优先级 - 也就是说,我们的进程将继续运行,但不会使我们的系统更忙碌。
这让我们进入了一个有趣的话题 - 许多新来到 Linux 世界的用户,或者其他平台的管理员,当他们看到系统使用了大量内存(随机存取内存,或 RAM),却使用了交换空间,或者系统负载很高时,会感到震惊。很明显,轻微使用交换空间并且有大量空闲 RAM 只意味着内核通过将未使用的内存交换到磁盘上进行了优化。只要系统不感到迟缓,高负载只意味着系统有一个长队列的进程等待执行,但是 - 例如 - 如果进程被niced到 19,它们在队列中,但是如前所述,任何其他进程都会超过它。
当我们使用top
或ps
检查系统状态时,我们也可以检查进程运行的时间,这也是由内核计算的。一个新创建的进程开始占用 CPU 和 RAM,被内核杀死的可能性更高,以确保系统的可操作性(还记得第四章中提到的内存不足(OOM)杀手,常规操作工具吗?)。
例如,让我们使用以下代码将运行备份的进程(包含进程名称中的备份模式)的优先级降低到最低:
pgrep –f backup | xargs renice –n 19
143405 (process ID) old priority 0, new priority 19
144389 (process ID) old priority 0, new priority 19
2924457 (process ID) old priority 0, new priority 19
3228039 (process ID) old priority 0, new priority 19
正如我们所看到的,pgrep
已经收集了一系列 PID,并且该列表已被作为renice
的参数进行了管道传输,优先级调整为 19,使实际在系统中运行的进程更加友好。
让我们在系统中通过使用bc
运行π(π)计算来重复前面的例子,就像bc
的 man 页面中所示。首先,我们将计算系统所需的时间,然后通过renice
执行它。所以,让我们动手操作—首先,让我们计时,如下所示:
time echo "scale=10000; 4*a(1)" | bc –l
在我的系统中,这是结果:
real 3m8,336s
user 3m6,875s
sys 0m0,032s
现在,让我们使用renice
运行它,如下所示:
time echo "scale=10000; 4*a(1)" | bc -l &
pgrep –f bc |xargs renice –n 19 ; fg
在我的系统中,这是结果:
real 3m9,013s
user 3m7,273s
sys 0m0,043s
有 1 秒的轻微差异,但您可以尝试在您的环境中运行更多进程以生成系统活动,使其更加明显,并在规模上增加更多的零以增加执行时间。同样,ionice
可以调整进程引起的 I/O 操作(读取、写入)的优先级—例如,对于我们的备份进程重复操作,我们可以运行以下命令:
pgrep –f backup|xargs ionice –c 3 –p
默认情况下,它不会输出信息,但我们可以通过执行以下命令来检查值:
pgrep -f backup|xargs ionice -p
idle
idle
idle
idle
在这种情况下,我们已将备份进程移动,以便在系统空闲时处理 I/O 请求。
我们使用-c
参数指定的类可以是以下之一:
-
0
:无 -
1
:实时 -
2
:尽力而为 -
3
:空闲
使用-p
,我们指定要操作的进程。
我们可以应用到系统的大多数设置都来自特定的设置,通过/proc/
虚拟文件系统应用到每个 PID,例如—例如—调整oom_adj
文件以减少oom_score
文件上显示的值,最终确定进程是否应在 OOM 需要杀死一些进程以尝试拯救系统免受灾难时更高。
当然,还有一些系统级设置,例如/proc/sys/vm/panic_on_oom
,可以调整系统如何在 OOM 必须被调用时做出反应(是否恐慌)。
磁盘还有一个设置,用于定义正在使用的调度程序—例如,对于名为sda
的磁盘,可以通过cat /sys/block/sda/queue/scheduler
进行检查。
磁盘使用的调度程序有不同的方法,取决于内核版本—例如,在 RHEL 7 中,它曾经是noop
、deadline
或cfq
,但在 RHEL 8 中,这些已被移除,我们有md-deadline
、bfq
、kyber
和none
。
这是一个如此庞大而复杂的主题,甚至有一个专门的手册,网址为access.redhat.com/documentation/en-us/red_hat_enterprise_linux_for_real_time/8/html-single/tuning_guide/index
,所以如果您有兴趣深入了解,请查看它。
我希望在这里实现两件事,如下所示:
-
明确指出系统有很多调整选项,并且有自己的文档,甚至有一个 Red Hat 认证架构师考试,网址为
www.redhat.com/en/services/training/rh442-red-hat-enterprise-performance-tuning
。 -
这并不是一项容易的任务—在本书中多次强调了一个观点:使用您系统的工作负载测试一切,因为结果可能因系统而异。
幸运的是,不需要对系统调优感到害怕——我们可以通过经验在各个层面(知识、硬件、工作负载等)变得更加熟练,但另一方面,系统也包括一些更简单的方法来进行快速调整,适用于许多场景,我们将在下一节中看到。
安装 tuned 和管理调优配置文件
希望在前面的部分中发生了一些危言耸听之后,您已经准备好迎接更简单的路径了。
以防万一,请确保已安装了tuned
软件包,或者使用dnf –y install tuned
进行安装。该软件包提供了一个必须启用并启动的tuned服务;作为复习,我们通过运行以下命令来实现这一点:
systemctl enable tuned
systemctl start tuned
现在我们已经准备好与该服务进行交互并获取更多信息,该服务在dnf info tuned
中宣布自己是一个根据某些观察动态调整系统的守护进程,目前正在以太网网络和硬盘上运行。
通过tuned-adm
命令与守护进程进行交互。为了说明,我们在下图中展示了可用的命令行选项和配置文件列表:
图 16.5 - tuned-adm 命令行选项和配置文件
正如我们所看到的,有一些选项可以列出、禁用和获取有关配置文件的信息,获取有关要使用哪个配置文件的建议,验证设置是否已被更改,自动选择配置文件等。
要记住的一件事是,较新版本的tuned
软件包可能会带来额外的配置文件或配置(存储在/usr/lib/tuned/
文件夹层次结构中),因此您的系统可能会有所不同。
让我们在下表中回顾一些最常见的选项:
正如前面提到的,每个配置都是一种权衡:提高性能需要更多的功耗,或者提高吞吐量可能会增加延迟。
让我们为我们的系统启用latency-performance
配置文件。为此,我们将执行以下命令:
tuned-adm profile latency-performance
我们可以通过tuned-adm active
来验证它是否已激活,可以看到它显示了latency-performance
,如下图所示:
图 16.6 - tuned-adm 配置文件激活和验证
我们还通过sysctl -w vm.swappiness=69
(故意)修改了系统,以演示tuned-adm verify
操作,因为它报告说一些设置已经从配置文件中定义的设置发生了变化。
重要提示
截至目前,默认情况下动态调整是禁用的——要启用或检查当前状态,请检查/etc/tuned/tuned-main.conf
文件中是否出现了dynamic_tuning=1
。在性能配置文件中它是被禁用的,因为默认情况下它试图在功耗和系统性能之间取得平衡,这与性能配置文件的目标相反。
另外,请记住,本书介绍的Cockpit界面还提供了一种更改性能配置文件的方法——如下截图所示——一旦您在主 Cockpit 页面上点击了Performance profile链接,就会打开此对话框:
图 16.7 - 在 Cockpit Web 界面中更改 tuned 配置文件
在下一节中,我们将探讨调优配置文件在幕后是如何工作的,以及如何创建自定义配置文件。
创建一个自定义的调优配置文件
一旦我们评论了不同的 tuned 配置文件... 它们是如何工作的?如何创建一个?
例如,让我们通过检查/usr/lib/tuned/latency-performance/tuned.conf
文件来检查latency-performance
。
一般来说,文件的语法在man tuned.conf
页面中有描述,但是文件,正如您将能够检查的那样,是一个初始化(ini)文件——也就是说,它是一个在括号之间表达的类别文件,并且由等号(=
)分配的键和值对。
主要部分定义了配置文件的摘要,如果它通过include
从另一个配置文件继承,并且其他部分取决于安装的插件。
要了解可用的插件,man 页面中包含的文档指示我们执行rpm -ql tuned | grep 'plugins/plugin_.*.py$'
,这将提供类似于以下的输出:
图 16.8 - 系统中可用的 tuned 插件
重要提示
如果两个或更多的插件尝试对相同的设备进行操作,replace=1
设置将标记运行它们所有还是只运行最新的一个。
回到latency-performance
配置文件,它有三个部分:main
、cpu
和sysctl
。
对于 CPU,它设置了性能调度器,我们可以通过cat /sys/devices/system/cpu/*/cpufreq/scaling_governor
检查每个系统中可用的 CPU 是否支持。请记住,在某些系统中,路径可能不同,甚至可能不存在,我们可以通过执行cpupower frequency-info –governors
来检查可用的路径,powersave
和performance
是最常见的。
对于每个插件的部分名称可能是任意的,如果我们指定type
关键字来指示要使用哪个插件,并且我们可以使用devices
关键字来对一些设备进行操作,例如,根据正在配置的磁盘的不同设置,允许定义几个磁盘部分。例如,我们可能希望为系统磁盘(比如sda
)和用于数据备份的磁盘(比如sdb
)定义一些设置,如下所示:
[main_disk]
type=disk
devices=sda
readahead=>4096
[data_disk]
type=disk
devices=!sda
spindown=1
在前面的例子中,名为sda
的磁盘使用readahead
进行配置(它在当前利用之前读取扇区,以便在实际请求访问数据之前将数据缓存),我们告诉系统spindown
数据磁盘,这些磁盘可能仅在备份时使用,因此在不使用时减少噪音和功耗。
另一个有趣的插件是sysctl
,被几个配置文件使用,它以与sysctl
命令相同的方式定义设置,因此可能性是巨大的:定义用于调整网络、虚拟内存管理、透明大页等的传输控制协议(TCP)窗口大小。
提示
从头开始进行任何性能调整都很困难,而且由于tuned
允许我们从父级继承设置,因此找到可用配置文件中最接近我们想要实现的目标的配置文件,检查其中的配置,当然,与其他配置文件进行比较是有意义的(正如我们所看到的,其他插件也有示例),并将其应用到我们的自定义配置文件中。
为了了解定义的系统配置文件如何影响系统,我的 RHEL 8 系统对cat /usr/lib/tuned/*/tuned.conf|grep -v ^#|grep '^\'|sort –u
命令显示以下输出:
![图 16.9 - 系统提供的配置文件中的部分
图 16.9 - 系统提供的配置文件中的部分
因此,正如我们所看到的,它们涉及到很多领域,我想强调script
部分,它定义了一个用于powersave
配置文件执行的 shell 脚本,以及variables
部分,它用于throughput-performance
配置文件,用于定义后续匹配和基于 CPU 应用设置的正则表达式。
一旦我们准备好,我们将在/etc/tuned/newprofile
下创建一个新的文件夹。必须创建一个tuned.conf
文件,其中包含摘要的主要部分和我们想要使用的插件的其他部分。
创建新配置文件时,如果我们将感兴趣的配置文件从/usr/lib/tuned/$profilename/
复制到我们的/etc/tuned/newprofile/
文件夹中,并从那里开始定制,可能会更容易。
一旦准备就绪,我们可以使用tuned-adm profile newprofile
启用配置文件,就像我们在本章中介绍的那样。
您可以在官方文档中找到有关可用配置文件的更多信息access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html-single/monitoring_and_managing_system_status_and_performance/index
。
有了这个,我们为调整性能设置设置了自定义配置文件。
摘要
在本章中,我们学习了如何识别进程,检查它们的资源消耗,以及如何向它们发送信号。
关于信号,我们了解到其中一些具有一些额外的行为,比如优雅或突然终止进程,或者只是发送通知,一些程序将其理解为重新加载配置而不重新启动等等。
此外,关于进程,我们学习了如何调整它们相对于 CPU 和 I/O 的优先级,以便我们可以调整长时间运行的进程或磁盘密集型进程,以免影响其他正在运行的服务。
最后,我们介绍了tuned
守护程序,其中包括几个通用的使用案例配置文件,我们可以直接在我们的系统中使用,允许tuned
应用一些动态调整,或者我们可以通过创建自己的配置文件来微调配置文件,以提高系统性能或优化功耗。
在下一章中,我们将学习如何使用容器、注册表和其他组件,以便应用程序可以在供应商提供的情况下运行,同时与运行它们的服务器隔离。
第十七章:使用 Podman、Buildah 和 Skopeo 管理容器
在本章中,我们将学习如何使用 Podman 和 Red Hat Universal Base Image(UBI)。Podman 和 UBI 共同为用户提供了在Red Hat Enterprise Linux(RHEL)上运行、构建和共享企业级容器所需的软件。
近年来,理解和使用容器已成为 Red Hat 系统管理员的关键要求。在本章中,我们将回顾容器的基础知识,容器的工作原理以及管理容器的标准任务。
您将学习如何使用简单命令运行容器,构建企业级容器镜像,并在生产系统上部署它们。您还将学习何时使用更高级的工具,如 Buildah 和 Skopeo。
本章将涵盖以下主题:
-
容器简介
-
使用 Podman 和 UBI 在本地 RHEL 8 系统上运行容器
-
何时使用 Buildah 和 Skopeo
技术要求
在本章中,我们将回顾 Podman、Buildah 和 Skopeo 的基本用法,以及如何使用 Red Hat UBI 构建和运行容器。
我们将在本地 RHEL 8 系统上创建和运行容器,就像我们在第一章中部署的那样,安装 RHEL8。您需要安装container-tools:rhel8
应用流。
容器简介
容器为用户提供了在 Linux 系统上运行软件的新方式。容器以一种一致的可再分发方式提供了与给定软件相关的所有依赖关系。虽然最初是由 Docker、Google、Red Hat 等推广的,但许多其他公司加入 Docker 创建了一组名为Open Container Initiative(OCI)的开放标准。OCI 标准的流行促进了一个大型的工具生态系统,用户不必担心流行的容器镜像、注册表和工具之间的兼容性。近年来,容器已经标准化,大多数主要工具遵循 OCI 规范,如下所述:
-
镜像规范:规定了容器镜像在磁盘上的保存方式
-
运行时规范:指定了如何通过与操作系统(特别是 Linux 内核)通信来启动容器
-
分发规范:规定了如何从注册表服务器推送和拉取镜像
您可以在 https://opencontainers.org/了解更多信息。
所有容器工具(Docker、Podman、Kubernetes 等)都需要一个操作系统来运行容器,每个操作系统可以选择不同的技术集来保护容器,只要它们符合 OCI 标准。RHEL 使用以下操作系统功能来安全存储和运行容器:
-
命名空间:这是 Linux 内核中的一种技术,有助于将进程相互隔离。命名空间防止容器化进程看到主机操作系统上的其他进程(包括其他容器)。命名空间是使容器感觉像虚拟机(VM)的技术。
-
控制组(Cgroups):这些限制了给定进程/容器可用的中央处理单元(CPU)、内存、磁盘输入/输出(I/O)和/或网络 I/O 的数量。这可以防止“吵闹的邻居”问题。
-
安全增强型 Linux(SELinux):如第十章中所述,使用 SELinux 可以提供额外的操作系统安全层,可以限制安全漏洞造成的损害。当与容器一起使用时,SELinux 几乎是透明的,并且可以在工具(如 Podman、Docker 或 Runc)存在漏洞时提供安全突破的缓解。
许多系统管理员使用虚拟机来隔离应用程序及其依赖项(库等)。容器提供了相同级别的隔离,但减少了虚拟化的开销。由于容器是简单的进程,它们不需要具有所有翻译开销的虚拟 CPU(vCPU)。容器也比虚拟机小,这简化了管理和自动化。这对于持续集成/持续交付(CI/CD)特别有用。
RHEL 为用户提供了与所有 OCI 标准兼容的容器工具和镜像。这意味着它们的工作方式对于使用过 Docker 的人来说非常熟悉。对于不熟悉这些工具和镜像的人,以下概念很重要:
-
层:容器镜像是作为一组层构建的。通过添加新层(甚至删除内容)来创建新容器,这些新层重用现有的较低层。使用现有的预打包容器的能力对于只想对其应用程序进行更改并以可重现的方式进行测试的开发人员非常方便。
-
分发和部署:由于容器提供了与应用程序耦合的所有依赖项,因此它们易于部署和重新分发。将它们与容器注册表结合使用,可以轻松共享容器镜像,并且协作、部署和回滚都更快更容易。
RHEL 提供的容器工具使得在小规模上部署容器变得容易,即使是用于生产工作负载。但是,要以可靠的方式大规模管理容器,容器编排(如 Kubernetes)是更好的选择。红帽公司根据构建 Linux 发行版的经验,创建了一个名为OpenShift的 Kubernetes 发行版。如果您需要大规模部署容器,我们建议您看看这个平台。RHEL 提供的容器工具和镜像,以及本章介绍的内容,将为以后准备好部署到 Kubernetes/OpenShift 提供坚实的基础。本章介绍的工具将为您的应用程序在准备好时部署到 Kubernetes 做好准备。
安装容器工具
RHEL 8 提供了两个容器工具的应用流。第一个是每 12 周更新一次的快速移动流。第二个是每年发布一次并支持 24 个月的稳定流。
在安装容器工具之前,让我们看一下有哪些可用的,如下所示:
[root@rhel8 ~]# yum module list | grep container-tools
container-tools rhel8 [d][e] common [d] Most recent (rolling) versions of podman, buildah, skopeo, runc, conmon, runc, conmon, CRIU, Udica, etc as well as dependencies such as container-selinux built and tested together, and updated as frequently as every 12 weeks.
container-tools 1.0 common [d] Stable versions of podman 1.0, buildah 1.5, skopeo 0.1, runc, conmon, CRIU, Udica, etc as well as dependencies such as container-selinux built and tested together, and supported for 24 months.
container-tools 2.0 common [d] Stable versions of podman 1.6, buildah 1.11, skopeo 0.1, runc, conmon, etc as well as dependencies such as container-selinux built and tested together, and supported as documented on the Application Stream lifecycle page.
container-tools 3.0 common [d] Stable versions of podman 3.0, buildah 1.19, skopeo 1.2, runc, conmon, etc as well as dependencies such as container-selinux built and tested
together, and supported as documented on the Application Stream lifecycle page.
让我们来看一下我们列出的主要工具,如下所示:
-
podman
:这是运行容器的命令。您可以在任何情况下使用它,就像您在互联网上发现的示例中使用docker
命令一样。这是我们在本章中用来运行我们自己的容器的命令。 -
buildah
:这是一个用于创建容器镜像的特定工具。它使用与 Docker 相同的 Dockerfile 定义,但不需要守护进程。 -
skopeo
:这是一个用于审查容器并检查不同层的工具,以便我们可以查看它们是否包含任何不符合规范的问题。
我们将安装快速移动流,以便访问 Podman、Skopeo 和 Buildah 的最新版本,如下所示:
[root@rhel8 ~]# yum module install container-tools:rhel8
... [output omitted] ...
现在您已经安装了所有在 RHEL 8 系统上构建、运行和管理容器所需的工具。
使用 Podman 和 UBI 运行容器
现在您已经安装了容器工具的应用流,让我们运行一个基于红帽 UBI 的简单容器,这是一组基于 RHEL 的官方容器镜像和额外软件。要运行 UBI 镜像,只需要一个命令,如下面的代码片段所示:
[root@rhel8 ~]# podman run –it registry.access.redhat.com/ubi8/ubi bash
[root@407ca121cbbb /]#
提示
这些教程以 root 身份运行命令,但 Podman 的一个好处是它可以以普通用户身份运行容器,无需特殊权限或在系统中运行守护程序。
现在您有一个完全隔离的环境,可以在其中执行任何您想要的操作。您可以在此容器中运行任何命令。它与主机和可能正在运行的其他容器隔离,并且甚至可以在其中安装软件。
注意
Red Hat UBI 基于 RHEL 的软件和软件包。这是用于 RHEL 的官方镜像,并为您的容器提供了一个坚实、企业级的基础。UBI 在本章中被广泛使用。
运行这样的一次性容器对于测试新的配置更改和新的软件部件而不干扰主机上的软件非常有用。
让我们来看看容器中正在运行的进程,如下所示:
[root@ef3e08e4eac2 /]# ps -efa
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 13:50 pts/0 00:00:00 bash
root 12 1 0 13:52 pts/0 00:00:00 ps -efa
正如您所看到的,唯一正在运行的进程是我们正在使用的 shell 和我们刚刚运行的命令。这是一个完全隔离的环境。
现在,通过运行以下命令退出容器:
[root@407ca121cbbb /]# exit
[root@rhel8 ~]#
现在我们已经在本地缓存了一组可工作的容器工具和 UBI 容器镜像,我们将继续进行一些更基本的命令。
基本容器管理-拉取、运行、停止和移除
在本节中,我们将运行一些基本命令,以熟悉使用容器。首先,让我们拉取一些更多的镜像,如下所示:
[root@rhel8 ~]# podman pull registry.access.redhat.com/ubi8/ubi-minimal
...
[root@rhel8 ~]# podman pull registry.access.redhat.com/ubi8/ubi-micro
...
[root@rhel8 ~]# podman pull registry.access.redhat.com/ubi8/ubi-init
...
我们现在本地缓存了几个不同的镜像。让我们在这里看看它们:
[root@rhel8 ~]# podman images
REPOSITORY TAG IMAGE ID CREATED SIZE
registry.access.redhat.com/ubi8/ubi latest 613e5da7a934 2 weeks ago 213 MB
registry.access.redhat.com/ubi8/ubi-minimal latest 332744c1854d 2 weeks ago 105 MB
registry.access.redhat.com/ubi8/ubi-micro latest 75d0ed7e8b6b 5 weeks ago 38.9 MB
registry.access.redhat.com/ubi8/ubi-init latest e13482c4e694 2 weeks ago 233 MB
请注意,我们本地缓存了四个镜像。Red Hat UBI 实际上有多种不同的版本,如下所述:
-
ubi8/ubi
): 这是一个基于 RHEL 的容器基础镜像,镜像中包含了YellowDog Updater Modified (YUM)/Dandified YUM (DNF)。它可以像任何其他 Linux 基础镜像一样使用。这个镜像针对 80%的用户使用情况,并且可以轻松地在 Dockerfile 或 Containerfile 中使用。这个镜像的折衷之处在于它比其他一些镜像更大。 -
ubi8/ubi-minimal
): 这个基础镜像通过使用一个名为microdnf
的小型包管理器来最小化尺寸,该包管理器是用 C 编写的,而不是像标准的 YUM/DNF 那样使用 Python。这个 C 实现使它更小,并且在容器镜像中拉取更少的依赖项。这个基础镜像可以在任何 Dockerfile 或 Containerfile 中使用,只需使用microdnf
命令而不是yum
。这个镜像在内存中节省了大约 80 兆字节(MB)。 -
ubi8/ubi-micro
): 这个基础镜像没有包管理器。它不能与标准的 Dockerfile 或 Containerfile 一起使用。用户可以使用容器主机上的 Buildah 工具向这个镜像添加软件。这个镜像是 RHEL 提供的最小的基础镜像。 -
ubi8/ubi-init
): 基于 RHEL 标准镜像,这个镜像也支持在容器中使用systemd
。这使得安装一些软件、使用systemd
启动它们并将容器视为 VM 变得很容易。这个镜像最适合那些不介意略大一些镜像,只想要使用方便的用户。
现在您已经了解了四种基础镜像的基础知识,让我们在后台启动一个容器,以便在其运行时进行检查。使用以下命令在后台启动它:
[root@rhel8 ~]# podman run -itd --name background ubi8 bash
262fa3beb8348333d77381095983233bf11b6584ec1f 22090604083c0d94bc50
请注意,当我们启动容器时,shell 返回正常状态,我们无法在容器中输入命令。我们的终端不会进入容器中的 shell。-d
选项指定容器应在后台运行。这就是大多数基于服务器的软件(如 Web 服务器)在 Linux 系统上运行的方式。
如果需要,我们仍然可以将我们的 shell 连接到后台运行的容器,但是我们必须确定要连接到哪个容器。为此,请使用以下命令列出所有正在运行的容器:
[root@rhel8 ~]# podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
262fa3beb834 registry.access.redhat.com/ubi8:latest bash About a minute ago Up About a minute ago background
我们可以使用容器 ID 值引用容器,但我们已经使用名称 background 启动了容器,以便更容易引用。我们可以使用 exec 子命令进入容器并查看其中发生的情况,如下所示:
[root@rhel8 ~]# podman exec –it background bash
[root@262fa3beb834 /]#
在输入一些命令后,通过运行以下命令退出容器:
[root@262fa3beb834 /]# exit
现在,让我们通过运行以下命令停止容器化进程:
[root@262fa3beb834 /]# podman stop background 262fa3beb8348333d77381095983233bf11b6584ec1f 22090604083c0d94bc50
通过运行以下命令确保它确实已停止:
[root@rhel8 ~]# podman ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
262fa3beb834 registry.access.redhat.com/ubi8:latest bash 7 minutes ago Exited (0) About a minute ago background
注意状态是Exited
。这意味着进程已停止并且不再在内存中,但存储仍然可用在磁盘上。容器可以重新启动,或者我们可以使用以下命令永久删除它:
[root@rhel8 ~]# podman rm background
262fa3beb8348333d77381095983233bf11b6584ec1f 22090604083c0d94bc50
这将删除存储,容器现在已经永远消失。通过运行以下命令来验证:
[root@rhel8 ~]# podman ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
本节向您介绍了一些基本命令,但现在让我们转向附加存储。
将持久存储附加到容器
请记住,容器中的存储是临时的。一旦执行了podman rm
命令,存储就会被删除。如果您有需要在容器被删除后保存的数据,您需要使用卷。要使用卷运行容器,请执行以下命令:
[root@rhel8 ~]# podman run –it --rm -v /mnt:/mnt:Z --name data ubi8 bash
[root@12ad2c1fcdc2 /]#
前面的命令已将/mnt
挂载到容器中,并且Z
选项已告诉它适当地更改 SELinux 标签,以便可以向其写入数据。--rm
选项确保一旦退出 shell,容器就会被删除。您现在可以在此卷上保存数据,并且在退出容器时不会被删除。通过运行以下命令添加一些数据:
[root@12ad2c1fcdc2 /]# touch /mnt/test.txt
[root@12ad2c1fcdc2 /]# exit
exit
[root@rhel8 ~]#
现在,通过运行以下命令检查您创建的测试文件:
[root@rhel8 ~]# ls /mnt/data
test.txt
请注意,尽管容器已被删除并且其内部存储已被删除,但文件仍然存在于系统上。
在生产系统上使用systemd
部署容器
由于 Podman 不是守护程序,它依赖于systemd
在系统启动时启动容器。Podman 通过创建一个systemd
来轻松启动一个systemd
容器,systemd
看起来像这样:
-
使用 Podman 以与生产环境完全相同的方式运行容器。
-
导出一个
systemd
单元文件。 -
配置
systemd
以使用此单元文件。
首先,让我们运行一个示例容器,如下所示:
[root@rhel8 ~]# podman run -itd --name systemd-test ubi8 bash
D8a96d6a51a143853aa17b7dd4a827efa2755820c9967bee52 fccfeab2148e98
现在,让我们导出我们将用于启动此容器的systemd
单元文件,如下所示:
[root@rhel8 ~]# podman generate systemd --name --new systemd-test > /usr/lib/systemd/system/podman-test.service
通过运行以下命令启用并启动服务:
systemctl enable --now podman-test
Created symlink /etc/systemd/system/multi-user.target.wants/podman-test.service → /usr/lib/systemd/system/podman-test.service.
Created symlink /etc/systemd/system/default.target.wants/podman-test.service → /usr/lib/systemd/system/podman-test.service
通过执行以下命令测试容器是否正在运行:
[root@rhel8 ~]# systemctl status podman-test
● podman-test.service - Podman container-systemd-test.service
Loaded: loaded (/usr/lib/systemd/system/podman-test.service; enabled; vendor preset: disabled)
Active: active (running) since Thu 2021-04-29 20:29:30 EDT; 13min ago
[output omitted]
...
现在,使用podman
命令检查容器是否正在运行,如下所示:
[root@rhel8 ~]# podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7cb55cc98e81 registry.access.redhat.com/ubi8:latest bash About a minute ago Up About a minute ago systemd-test
这个容器现在将在系统启动时启动;即使您使用 Podman 杀死容器,systemd
也会始终确保此容器正在运行。Podman 和systemd
使得在生产环境中运行容器变得容易。现在,让我们使用systemctl
停止容器并禁用它,如下所示:
systemctl stop podman-test
systemctl disable podman-test
使用 Dockerfile 或 Containerfile 构建容器镜像
现在我们知道如何运行容器,让我们学习如何构建自己的容器镜像。容器镜像通常是使用作为每次构建它的蓝图的文件构建的。具有以下内容的Containerfile
:
FROM registry.access.redhat.com/ubi8/ubi
RUN yum update -y
这个简单的Containerfile
拉取了 UBI 标准基础镜像,并对其应用了所有最新的更新。现在,通过运行以下命令构建一个容器镜像:
[root@rhel8 ~]# podman build –t test-build ./Containerfile
STEP 1: FROM registry.access.redhat.com/ubi8/ubi
STEP 2: RUN yum update –y
... [output omitted] ...
现在您有一个名为test-build
的新镜像,其中包含来自 Red Hat UBI 存储库的所有更新包的新层,如下面的代码片段所示:
[root@rhel8 ~]# podman images
REPOSITORY TAG IMAGE ID CREATED SIZE
localhost/test-build latest 6550a939d3ef 9 minutes ago 335 MB
... [output omitted] ...
从 Dockerfile 或 Containerfile 构建图像的工作流程几乎与 RHEL 7 中的 Docker 或任何其他操作系统中的工作流程相同。这使得系统管理员和开发人员可以轻松地转移到 Podman。
配置 Podman 以搜索注册表服务器
容器注册表就像容器镜像的文件服务器。它们允许用户构建和共享容器镜像,从而实现更好的协作。通常,从位于互联网上的公共注册表服务器中拉取容器镜像是很有用的,但在许多情况下,公司有私有注册表,这些注册表不是公开的。Podman 可以轻松地搜索多个注册表,包括公司网络上的私有注册表。
Podman 带有一个配置文件,允许用户和管理员选择默认搜索哪些注册表。这使得用户可以轻松找到管理员希望他们找到的容器镜像。
一组默认的注册表搜索在/etc/containers/registries.conf
中定义。让我们通过过滤其中的所有注释来快速查看这个文件,如下所示:
[root@rhel8 ~]# cat /etc/containers/registries.conf | grep -v ^#
[registries.search]
registries = ['registry.access.redhat.com', 'registry.redhat.io', 'docker.io']
[registries.insecure]
registries = []
[registries.block]
registries = []
unqualified-search-registries = ["registry.fedoraproject.org", "registry.access.redhat.com", "registry.centos.org", "docker.io"]
如您所见,我们在registries.search
部分中为安全注册表定义了两个主要的 Red Hat 注册表,registry.access.redhat.com
和registry.redhat.io
,以及docker.io
Docker 注册表。所有这些注册表都在registries.insecure
部分中进行了安全配置。
除了 TLS 之外,Red Hat 提供的所有镜像都经过签名,并提供一个签名存储库,可用于验证它们。这不是默认配置,并且超出了本章的范围。
要验证 Podman 是否正在使用和搜索正确的注册表,请运行以下命令:
[root@rhel8 ~]# podman info | grep registries -A 4
registries:
search:
- registry.access.redhat.com
- registry.redhat.io
- docker.io
提示
如果您想发布自己的镜像,可以在 Red Hat 提供的服务中这样做:quay.io
。您还可以配置registries.conf
来搜索您在那里存储的镜像的quay.io
。
Podman 选项摘要
让我们来回顾一下本章中与 Podman 一起使用的选项,如下所示:
通过查看表格,您可以看到 Podman 包括管理完整容器生命周期的选项。大多数 Podman 命令与docker
兼容。Podman 甚至提供了一个包(podman-docker
),它提供了从podman
到docker
的别名,以便用户可以继续输入他们熟悉的命令。虽然 Podman 和 Docker 在使用上感觉相似,但 Podman 可以作为普通用户运行,不需要持续运行的守护进程。让我们继续下一节,探索一些高级用例。
何时使用 Buildah 和 Skopeo
Podman 是一个通用的容器工具,应该能够解决用户 95%的需求。Podman 利用 Buildah 和 Skopeo 作为库,并将这些工具集成到一个界面下。也就是说,有一些边缘情况,用户可能希望单独利用 Buildah 或 Skopeo。我们将探讨两种这样的用例。
使用 Buildah 构建容器镜像
从 Dockerfile 或 Containerfile 构建非常容易,但也伴随着一些权衡。例如,Buildah 在以下情况下很好用:
-
当您需要对提交的镜像层进行细粒度控制时。当您希望运行两到三个命令,然后提交一个单独的层时,这可能是必要的。
-
当您有难以安装的软件时——例如,一些第三方软件带有标准化的安装程序,这些安装程序不知道它们正在 Dockerfile 中运行。许多这些
install.sh
安装程序假定它们可以访问整个文件系统。 -
当一个容器镜像没有提供包管理器时。UBI Micro 构建非常小的镜像,因为它没有安装 Linux 包管理器,也没有任何包管理器的依赖项。
对于这个例子,让我们在 UBI Micro 的基础上构建,以演示为什么 Buildah 是一个如此好用的工具。首先,创建一个新的容器来使用,如下所示:
[root@rhel8 ~]# buildah from registry.access.redhat.com/ubi8/ubi-micro
ubi-micro-working-container
上面的命令创建了一个对名为ubi-micro-working-container
的新容器的引用。一旦 Buildah 创建了这个引用,您就可以在其基础上构建。为了更方便,让我们重新开始并将引用保存在一个 shell 变量中,如下所示:
microcontainer=$(buildah from registry.access.redhat.com/ubi8/ubi-micro)
然后,您可以将新容器挂载为一个卷。这样可以通过更改目录中的文件来修改容器镜像。运行以下命令来执行此操作:
micromount=$(buildah mount $microcontainer)
一旦容器存储被挂载,您可以以任何您想要的方式修改它。这些更改最终将被保存为容器镜像中的一个新层。这就是您可以运行一个安装程序(install.sh
)的地方,但在下面的示例中,我们将使用主机上的软件包管理器在 UBI Micro 中安装软件包:
yum install \
--installroot $micromount \ --releasever 8 \ --setopt install_weak_deps=false \ --nodocs -y \ httpd
... [output omitted] ...
[root@rhel8 ~]# yum clean all \
--installroot $micromount
... [output omitted] ...
当软件包安装完成后,我们将卸载存储并将新的镜像层提交为一个名为ubi-micro-httpd
的新容器镜像,如下面的代码片段所示:
[root@rhel8 ~]# buildah umount $microcontainer
467403b1633fbcb42535e818929fd49a5e381b86733c99d 65cd8b141e9d64fff
[root@rhel8 ~]# buildah commit $microcontainer ubi-micro-httpd
Getting image source signatures
Copying blob 5f70bf18a086 skipped: already exists
Copying blob 8e7500796dee skipped: already exists
Copying blob 881a7504d0b5 skipped: already exists
Copying blob 771043083e15 done
Copying config 9579d04234 done
Writing manifest to image destination
Storing signatures
9579d0423482e766d72e3909f34e8c10d4258128d5cae394 c1f0816ac637eda0
您现在有一个安装了httpd
的新容器镜像,构建在 UBI Micro 上。只引入了一组最小的依赖关系。看看这个镜像有多小:
[root@rhel8 ~]# podman images
localhost/ubi-micro-httpd latest 9579d0423482 About a minute ago 152 MB
Buildah 是一个很棒的工具,可以让您对构建方式有很多控制。现在,我们将转向 Skopeo。
使用 Skopeo 检查远程容器
Skopeo 专门设计和构建用于远程容器存储库。使用以下命令,您可以轻松地远程检查图像的可用标签:
[root@rhel8 ~]# skopeo inspect docker://registry.access.redhat.com/ubi8/ubi
{
"Name": "registry.access.redhat.com/ubi8/ubi",
"Digest": "sha256:37e09c34bcf8dd28d2eb7ace19d3cf634f8a073058ed63ec6e 199e3e2ad33c33",
"RepoTags": [
"8.2-343-source",
"8.1-328",
"8.2-265-source",
... [output omitted] ...
远程检查对于确定是否要拉取图像以及使用哪个标签非常有用。Skopeo 还可以用于在两个远程注册服务器之间进行复制,而不在本地存储中缓存副本。有关更多信息,请参阅skopeo
手册页。
总结
在本章中,我们已经回顾了在 RHEL 8 上运行、构建和共享容器的基础知识。您已经准备好创建自己的容器,运行它们,管理它们,甚至使用systemd
来确保它们在生产环境中始终运行。
您现在已经准备好利用容器提供的功能和部署便利性。虽然深入研究将软件迁移到容器中的所有复杂性超出了本书的范围,但容器简化了应用程序的打包和交付,使其准备好以其所有依赖项一起执行。
容器现在是信息技术(IT)行业的一个重点关注领域。容器本身简化了应用程序的打包和交付,但基于 Kubernetes 的 OpenShift 等编排平台使得在规模上部署、升级和管理容器化应用程序变得更加容易。
恭喜您——您已经完成了本章的学习!现在是时候转到下一章,进行自我评估,确保您已经掌握了材料并练习了您的技能。还有两章要学习。
第四部分:实际练习
本节包括实际练习,以复习前几节所学内容。它包括中级练习和更高级的练习,让您评估自己的进步。
本节包括以下章节:
-
第十八章,练习题-1
-
第十九章,练习题-2
第十八章:练习 1
在这个练习中,我们将运行一系列步骤,检查您在整本书中所学到的知识。与之前的章节不同,不会指示所有步骤,因此您可以自行决定执行所需的步骤以完成您的目标。建议避免参考以前的章节进行指导。相反,尝试使用您的记忆或系统中可用的工具。如果正确执行此练习,将有效地为官方考试进行培训。
强烈建议在进行此练习时使用时钟来跟踪时间。
技术要求
本章中的所有练习都需要使用虚拟机(VM),运行安装了基本安装的 Red Hat Enterprise Linux 8。此外,存储操作将需要新的虚拟驱动器。
对于练习,假设您拥有以下内容:
-
安装了基本操作系统最小安装软件选择的 Red Hat Enterprise Linux 8。
-
访问 Red Hat 客户门户,具有有效的订阅。
-
虚拟机必须是可扩展的。这是因为在练习期间对其执行的操作可能使其无法使用,并需要重新安装。
练习提示
这是任何测试的一般建议清单,大多数属于常识范畴,但在进行任何测试之前将它们牢记在心是非常重要的:
-
在开始官方考试或任何测试之前,请先阅读所有问题。
-
特定的词语具有特定的含义,可以提示关于要求或完成目标的方法。这就是为什么先阅读所有内容可能会给您多个完成测试的途径。
-
让自己感到舒适。安装您喜欢的编辑器,并运行
updatedb
以获得一个新的软件包和已安装文件的数据库,以备使用。定义您的键盘布局。安装tmux
并学习如何使用它,这样您就可以打开新标签并命名它们,而无需额外的窗口。 -
查找请求之间的依赖关系,因为有些目标取决于其他目标的完成。找到这些依赖关系,看看如何在不必后来回来重新做一些步骤的情况下找到解决方案。
-
使用计时器。这对于了解哪些练习将花费更多时间来完成是很重要的,以便看到您需要改进的领域。
-
不要记住具体的命令行。学习如何使用系统中的文档,通过
man
、/usr/share/docs
或像--help
这样的参数来获取所需命令的帮助。 -
确保更改持久并在重新启动后仍然有效。有些更改可能在运行时是有效的,但必须持久。例如防火墙规则、启动时要启动的服务等。
-
记住使用
dnf whatprovides /COMMAND"
来查找提供您可能缺少的文件的软件包。 -
检查以下链接:
www.redhat.com/en/services/training/ex200-red-hat-certified-system-administrator-rhcsa-exam?=Objectives
。这将为您提供官方 EX200 考试目标。
练习 1
重要提示
以下练习是有意设计的,因此不会突出显示命令、软件包等。记住迄今为止学到的知识,以便检测关键字,看看需要做什么。
不要过早地进行实际操作。试着记住已经涵盖的内容。
练习
-
将时区配置为 GMT。
-
允许 root 用户使用 SSH 进行无密码登录。
-
创建一个可以无密码连接到机器的用户(名为user)。
-
用户
user
应该每周更改密码,提前 2 天警告,过期后使用 1 天。 -
root 用户必须能够以user的身份通过 SSH 进行连接,而无需密码,以便没有人可以使用密码远程连接为 root。
-
用户user应能够在无需密码的情况下成为 root 用户,并且还能够在无需密码的情况下执行命令。
-
当用户尝试通过 SSH 登录时,显示有关不允许未经授权访问该系统的法律消息。
-
SSH 必须在端口22222上监听,而不是默认的端口(22)。
-
创建一个名为
devel
的组。 -
将
user
添加为devel
的成员。 -
将用户成员身份存储在名为
userids
的文件中,位于user的主文件夹中。 -
用户user和root用户应能够通过 SSH 连接到本地主机,而无需指定端口,并默认使用压缩进行连接。
-
查找系统中所有的 man 页名称,并将名称放入名为manpages.txt的文件中。
-
打印未允许登录到系统的用户的用户名。对于每个用户名,打印该用户的用户 ID 和组。
-
每 5 分钟监视可用系统资源。不使用 cron。存储为/root/resources.log。
-
添加一个每分钟的作业,报告可用磁盘空间的百分比,并将其存储在/root/freespace.log中,以便显示文件系统和可用空间。
-
配置系统仅保留 3 天的日志。
-
配置/root/freespace.log和/root/resources.log的日志轮换。
-
使用快速同步配置时间同步针对pool.ntp.org。
-
为子网172.22.0.1/24提供 NTP 服务器服务。
-
配置系统统计信息,每分钟收集一次。
-
将系统中用户的密码长度配置为 12 个字符。
-
创建一个名为privacy的机器人用户,其文件默认情况下只对自己可见。
-
创建一个在shared中可以被所有用户访问的文件夹,并将新文件和目录默认为仍然可以被devel组的用户访问。
-
配置一个名为mynic的具有 IPv4 和 IPv6 地址的网络连接,使用以下数据:
Ip6: 2001:db8:0:1::c000:207/64 g
gateway 2001:db8:0:1::1
Ipv4 192.0.1.3/24
gateway 192.0.1.1
-
允许主机使用google主机名访问www.google.com,并使用redhat主机名访问www.redhat.com。
-
报告从供应商分发的文件中修改的文件,并将它们存储在/root/altered.txt中。
-
使我们的系统安装媒体包通过 HTTP 在/mirror路径下可供其他系统用作镜像,配置我们系统中的存储库。从该镜像中删除内核包,以便其他系统(甚至我们自己的系统)无法找到新的内核。防止从该存储库安装 glibc 包而不将其删除。
-
在user身份下,将/root文件夹复制到/home/user/root/文件夹,并使其每天保持同步,同步添加和删除。
-
检查我们的系统是否符合 PCI-DSS 标准。
-
向系统添加第二个 30GB 的硬盘。但是,只使用 15GB 将镜像移动到其中,并使用压缩和去重功能使其在启动时可用。将其放置在/mirror/mirror下。
-
由于我们计划基于相同数据镜像自定义软件包集,因此配置文件系统报告至少可供我们的镜像使用的 1,500GB。
-
在/mirror/mytailormirror下创建镜像的第二个副本,删除所有以字母k开头的包。
-
在添加的硬盘剩余空间(15GB)中创建一个新卷,并将其用于扩展根文件系统。
-
创建一个启动项,允许您进入紧急模式,以更改根密码。
-
创建一个自定义调整配置文件,定义第一个驱动器的预读为4096,第二个驱动器的预读为1024。此配置文件还应在发生 OOM 事件时使系统崩溃。
-
禁用并删除已安装的 HTTP 包。然后,使用registry.redhat.io/rhel8/httpd-24镜像设置 HTTP 服务器。
对于这一部分,我们将复制目标列表中的每个项目,然后在其下方提供解释,使用适当的语法突出显示和解释。
练习 1 解决方案
1. 将时区配置为 GMT
我们可以通过执行date
命令来检查当前系统日期。在随后打印的行的最后部分,将显示时区。为了配置它,我们可以使用timedatectl
命令,或者修改/etc/localtime
符号链接。
因此,为了实现这个目标,我们可以使用以下之一:
-
timedatectl set-timezone GMT
-
rm –fv /etc/localtime; ln –s /usr/share/zoneinfo/GMT /etc/localtime
现在date
应该报告正确的时区。
2. 允许无密码登录到 root 用户使用 SSH
这将需要以下操作:
-
SSH 必须已安装并可用(这意味着已安装并已启动)。
-
root 用户应该生成一个 SSH 密钥并将其添加到授权密钥列表中。
首先,让我们通过 SSH 来解决这个问题,如下所示:
dnf –y install openssh-server; systemctl enable sshd; systemctl start sshd
现在,让我们通过按Enter来生成一个 SSH 密钥以接受所有默认值:
ssh-keygen
现在,让我们将生成的密钥(/root/.ssh/id_rsa
)添加到授权密钥中:
cd; cd .ssh; cat id_rsa.pub >> authorized_keys; chmod 600 authorized_keys
为了验证这一点,我们可以执行ssh localhost date
,之后我们将能够在不提供密码的情况下获取当前系统的日期和时间。
3. 创建一个名为'user'的用户,可以在没有密码的情况下连接到该机器
这需要创建一个用户和一个类似于 root 用户的 SSH 密钥。接下来的选项也将与用户相关,但为了演示目的,我们将它们作为单独的任务来解决:
useradd user
su – user
现在,让我们通过按Enter来生成一个 SSH 密钥以接受所有默认值:
ssh-keygen
现在,让我们将生成的密钥(/root/.ssh/id_rsa
)添加到授权密钥中:
cd; cd .ssh; cat id_rsa.pub >> authorized_keys; chmod 600 authorized_keys
为了验证这一点,我们可以执行ssh localhost date
,我们将能够在不提供密码的情况下获取当前系统日期和时间。
然后,使用logout
返回到我们的root
用户。
4. 用户'user'应该每周更改密码,提前 2 天警告,过期后使用 1 天
这要求我们调整用户限制,如下所示:
chage –W 2 user
chage –I 1 user
chage -M 7 user
5. root 用户必须能够以'user'的身份通过 SSH 登录,而无需密码,以便没有人可以使用密码远程连接为 root 用户
这需要两个步骤。第一步是使用 root 的授权密钥启用'user',然后调整sshd
守护程序,如下所示:
cat /root/id_rsa.pub >> ~user/.ssh/authorized_keys
编辑/etc/sshd/sshd_config
文件,并添加或替换PermitRootLogin
行,使其看起来像下面这样:
PermitRootLogin prohibit-password
保存,然后重新启动sshd
守护程序:
systemctl restart sshd
6. 用户'user'应能够成为 root 并执行命令而无需密码
这意味着通过添加以下行来配置/etc/sudoers
文件:
user ALL=(ALL) NOPASSWD:ALL
7. 当用户尝试通过 SSH 登录时,显示有关不允许未经授权访问此系统的法律消息
创建一个文件,例如/etc/ssh/banner
,其中包含要显示的消息。例如,"Get out of here"
。
修改/etc/ssh/sshd_config
并将banner
行设置为/etc/ssh/banner
,然后使用systemctl restart sshd
重新启动sshd
守护程序。
8. SSH 必须在端口 22222 上监听,而不是默认端口
这是一个棘手的问题。第一步是修改/etc/ssh/sshd_config
并定义端口22222
。完成后,使用以下命令重新启动sshd
:
systemctl restart sshd
这当然会失败...为什么?
必须配置防火墙:
firewall-cmd –-add-port=22222/tcp --permanent
firewall-cmd –-add-port=22222/tcp
然后必须配置 SELinux:
semanage port -a -t ssh_port_t -p tcp 22222
现在,sshd
守护程序可以重新启动:
systemctl restart sshd
9. 创建名为'devel'的组
使用以下命令:
groupadd devel
10. 使'user'成为'devel'的成员
使用以下命令:
usermod –G devel user
11. 将用户成员身份存储在名为'userids'的文件中,在'用户'的主文件夹中
使用以下命令:
id user > ~user/userids
12. 用户'user'和 root 用户应能够通过 SSH 连接到本地主机,而无需指定端口,并默认为连接进行压缩
我们修改了默认的 SSH 端口为22222
。
为'user'和 root 创建一个名为.ssh/config
的文件,内容如下:
Host localhost
Port 22222
Compression yes
13. 查找系统中所有 man 页面名称,并将名称放入名为'manpages.txt'的文件中
手册页存储在 /usr/share/man
。因此,使用以下命令:
find /usr/share/man/ -type f > manpages.txt
14. 打印没有登录的用户的用户名,以便他们可以被允许访问系统,并打印每个用户的用户 ID 和组
以下命令首先构建了一个使用 nologin
shell 的系统用户列表:
for user in $(cat /etc/passwd| grep nologin|cut -d ":" -f 1)
do
echo "$user -- $(grep $user /etc/group|cut -d ":" -f 1|xargs)"
done
从列表中检查 /etc/group
文件中的成员资格,仅保留组名,并使用 xargs
将它们连接成一个要打印的字符串。
上面的示例使用了 for
循环和命令的内联执行,通过 $()
。
15. 每 5 分钟监视可用的系统资源,而不使用 cron,并将它们存储为 /root/resources.log
监视某些东西的理想方式是使用 cron,但由于我们被告知不要使用它,这只留下了我们使用 systemd 定时器。 (您可以通过以下链接检查经过测试的文件:[github.com/PacktPublishing/Red-Hat-Enterprise-Linux-8-Administration/tree/main/chapter-18-exercise1.
](https://github.com/PacktPublishing/Red-Hat-Enterprise-Linux-8-Administration/tree/main/chapter-18-exercise1
)
创建 /etc/systemd/system/monitorresources.service
,内容如下:
[Unit]
Description=Monitor system resources
[Service]
Type=oneshot
ExecStart=/root/myresources.sh
创建 /etc/systemd/system/monitorresources.timer
,内容如下:
[Unit]
Description=Monitor system resources
[Timer]
OnCalendar=*-*-* *:0,5,10,15,20,25,30,35,40,45,50,55:00
Persistent=true
[Install]
WantedBy=timers.target
创建 /root/myresources.sh
,内容如下:
#!/bin/bash
df > /root/resources.log
启用新的定时器,如下所示:
systemctl daemon-reload
systemctl enable monitorresources.timer
它有效吗?如果不行,journalctl –f
将提供一些细节。SELinux 阻止我们执行 root 文件,所以让我们将其转换为二进制类型并标记为可执行,如下所示:
chcon –t bin_t /root/myresources.sh
chmod +x /root/myresources.sh
16. 添加每分钟的作业,报告可用的空闲磁盘空间百分比,并将其存储在 /root/freespace.log 中,以显示文件系统和可用空间
df
报告已使用的磁盘空间和可用空间,所以我们需要进行一些数学运算。
这将报告挂载位置、大小、已用空间和可用空间,使用 ;
作为分隔符。参考以下内容:
df|awk '{print $6";"$2";"$3";"$4}'
Bash 允许我们进行一些数学运算,但这些运算缺少小数部分。幸运的是,我们可以做一个小技巧:我们将循环执行它,如下所示:
for each in $(df|awk '{print $6";"$2";"$3";"$4}'|grep -v "Mounted")
do
FREE=$(echo $each|cut -d ";" -f 4)
TOTAL=$(echo $each|cut -d ";" -f 2)
echo "$each has $((FREE*100/TOTAL)) free"
done
for
循环将检查所有可用的数据,抓取一些特定字段,用 ;
分隔它们,然后对每一行在 $each
变量中运行循环。
我们截取输出,然后获取第四个字段。这是可用空间。
我们截取输出,然后获取第二个字段。这是总块数。
由于 bash
可以进行整数除法,我们可以乘以 100,然后除以获取百分比,并将一个字符串添加到输出中。
或者(但不够说明性),我们可以通过 df
已经给出的使用百分比减去 100,并节省一些计算步骤。
我们还需要将输出存储在一个文件中。为此,我们可以将整个循环包装在重定向中,或者将其添加到 echo
行中,以便将其附加到一个文件中。
我们还需要通过 cron 来完成,因此完整的解决方案如下:
创建一个 /root/myfreespace.sh
脚本,内容如下:
for each in $(df|awk '{print $6";"$2";"$3";"$4}'|grep -v "Mounted")
do
FREE=$(echo $each|cut -d ";" -f 4)
TOTAL=$(echo $each|cut -d ";" -f 2)
echo "$each has $((FREE*100/TOTAL)) free"
done
然后,使用 chmod 755 /root/myfreespace.sh
使其可执行。
运行 crontab -e
来编辑 root 的 crontab,并添加以下行:
*/1 * * * * /root/myfreespace.sh >> /root/freespace.log
17. 配置系统只保留 3 天的日志
这可以通过编辑 /etc/logrorate.conf
来完成,设置如下:
daily
rotate 3
删除其他的每周、每月等出现,只留下我们想要的一个。
18. 为 /root/freespace.log 和 /root/resources.log 配置日志轮转
创建一个 /etc/logrotate.d/rotateroot
文件,内容如下:
/root/freespace.log {
missingok
notifempty
sharedscripts
copytruncate
}
/root/resources.log {
missingok
notifempty
sharedscripts
copytruncate
}
19. 针对 pool.ntp.org 进行快速同步的时间同步配置
编辑 /etc/chrony.conf
,添加以下行:
pool pool.ntp.org iburst
然后运行以下命令:
systemctl restart chronyd
20. 为子网 172.22.0.1/24 提供 NTP 服务器服务
编辑 /etc/chrony.conf
,添加以下行:
Allow 172.22.0.1/24
然后运行以下命令:
systemctl restart chronyd
21. 每分钟配置系统统计收集
运行以下命令:
dnf –y install sysstat
现在我们需要修改/usr/lib/systemd/system/sysstat-collect.timer
。让我们通过创建一个覆盖来做到这一点,如下所示:
cp /usr/lib/systemd/system/sysstat-collect.timer /etc/systemd/system/
编辑/etc/systemd/system/sysstat-collect.timer
,将OnCalendar
值替换为以下内容:
OnCalendar=*:00/1
然后,使用以下命令重新加载单元:
systemctl daemon-reload
22. 配置系统中用户密码长度为 12 个字符
使用以下行编辑/etc/login.defs
:
PASS_MIN_LEN 12
23. 创建一个名为'privacy'的机器人用户,它默认情况下只能自己看到它的文件
要做到这一点,请运行以下命令:
adduser privacy
su – privacy
echo "umask 0077" >> .bashrc
此解决方案使用umask
从所有新创建的文件中删除其他人的权限。
24. 创建一个名为/shared 的文件夹,所有用户都可以访问,并将新文件和目录默认设置为仍然可以被‘devel’组的用户访问
要做到这一点,请运行以下命令:
mkdir /shared
chown root:devel /shared
chmod 777 /shared
chmod +s /shared
25. 使用提供的数据 Ip6,配置一个名为'mynic'的具有 IPv4 和 IPv6 地址的网络连接,如下所示:2001:db8:0:1::c000:207/64 g gateway 2001:db8:0:1::1 IPv4 192.0.1.3/24 gateway 192.0.1.1
查看以下内容以了解如何完成此操作:
nmcli con add con-name mynic type ethernet ifname eth0 ipv6.address 2001:db8:0:1::c000:207/64 ipv6.gateway 2001:db8:0:1::1 ipv4.address 192.0.1.3/24 ipv4.gateway 192.0.1.1
26. 允许主机使用 google 主机名访问 www.google.com,使用 redhat 主机名访问 www.redhat.com
运行并记录获取的 IP,如下所示:
ping www.google.com
ping www.redhat.com
记下上面获取的 IP。
通过添加以下内容编辑/etc/hosts
:
IPFORGOOGLE google
IPFORREDHAT redhat
然后,保存并退出。
27. 报告从供应商分发的文件中修改的文件,并将它们存储在/root/altered.txt
中
查看以下内容以了解如何完成此操作:
rpm -Va > /root/altered.txt
28. 通过 HTTP 在路径/mirror
下使我们的系统安装媒体包对其他系统可用,并在我们的系统中配置存储库。从该镜像中删除内核软件包,以便其他系统(甚至我们自己)无法找到新的内核。忽略此存储库中的 glibc 软件包,以便安装而不删除它们
这是一个复杂的问题,所以让我们一步一步地来看看。
安装http
并使用以下命令启用它:
dnf –y install httpd
firewall-cmd --add-service=http --permanent
firewall-cmd --add-service=http
systemctl start httpd
systemctl enable httpd
在/mirror
下创建一个文件夹,然后复制源媒体包并通过http
使其可用:
mkdir /mirror /var/www/html/mirror
mount /dev/cdrom /mnt
rsync –avr –progress /mnt/ /mirror/
mount –o bind /mirror /var/www/html/mirror
chcon -R -t httpd_sys_content_t /var/www/html/mirror/
删除内核软件包:
find /mirror -name kernel* -exec rm '{}' \;
使用以下命令创建存储库文件元数据:
dnf –y install createrepo
cd /mirror
createrepo .
使用我们创建的存储库文件,并在系统上设置它,忽略其中的glibc*
软件包。
通过添加以下内容编辑/etc/yum.repos.d/mymirror.repo
:
[mymirror]
name=My RHEL8 Mirror
baseurl=http://localhost/mirror/
enabled=1
gpgcheck=0
exclude=glibc*
29. 作为‘user’,将/root 文件夹复制到/home/user/root/文件夹中,并每天保持同步,同步添加和删除
查看以下内容以了解如何完成此操作:
su – user
crontab –e
编辑 crontab 并添加以下行:
@daily rsync -avr –-progress –-delete root@localhost:/root/ /home/user/root/
30. 检查我们的系统是否符合 PCI-DSS 标准
dnf –y install openscap scap-security-guide openscap-utils
oscap xccdf eval --report pci-dss-report.html --profile pci-dss /usr/share/xml/scap/ssg/content/ssg-rhel8-ds.xml
31. 向系统添加一个 30GB 的第二硬盘,但只使用 15GB 将镜像移动到其中,并使用压缩和去重功能在启动时使其可用,并在/mirror/mirror
下可用
这句话中的压缩和去重意味着 VDO。我们需要将当前的镜像移动到 VDO,并使我们以前的镜像移到那里。
如果我们有安装媒体,我们可以选择复制它并重复内核删除或转移。为此,首先让我们在新的硬盘(sdb
)的分区中创建 VDO 卷:
fdisk /dev/sdb
n <enter>
p <enter>
1 <enter>
<enter>
+15G <enter>
w <enter>
q <enter>
这将从开始创建一个 15GB 的分区。让我们使用以下命令在其上创建一个 VDO 卷:
dnf –y install vdo kmod-kvdo
vdo create –n myvdo –device /dev/sdb --force
pvcreate /dev/mapper/myvdo
vgcreate myvdo /dev/mapper/myvdo
lvcreate –L 15G –n myvol myvdo
mkfs.xfs /dev/myvdo/myvol
# Let's umount cdrom if it was still mounted
umount /mnt
# Mount vdo under /mnt and copy files over
mount /dev/myvdo/myvol /mnt
rsync –avr –progress /mirror/ /mnt/mirror/
# Delete the original mirror once copy has finished
rm –Rfv /mirror
umount /mnt
mount /dev/myvdo/myvol /mirror
此时,旧的镜像已复制到 VDO 卷上的mirror
文件夹中。这在/mirror
下挂载,因此它在/mirror/mirror
下有原始镜像,如要求的。我们可能需要执行以下操作:
-
将
/mirror
绑定到/var/www/html/mirror/
以使文件可用。 -
恢复 SELinux 上下文以允许
httpd
守护程序访问/var/www/html/mirror/
中的文件。
调整我们创建的 repofile 以指向新路径。
32. 配置文件系统报告至少 1,500GB 的大小,供我们的镜像使用
查看以下命令:
vdo growLogical --name=myvdo --vdoLogicalSize=1500G
33. 在/mirror/mytailormirror 下创建镜像的第二个副本,并删除所有以 k*开头的软件包
请参考以下内容如何完成此操作:
rsync –avr –progress /mirror/mirror/ /mirror/mytailormirror/
find /mirror/mytailormirror/ -name "k*" -type f –exec rm '{}' \;
cd /mirror/mytailormirror/
createrepo .
34. 在硬盘的剩余空间(15 GB)中创建一个新的卷,并用它来扩展根文件系统
请参考以下内容如何完成此操作:
fdisk /dev/sdb
n <enter>
p <enter>
<enter>
<enter>
w <enter>
q <enter>
pvcreate /dev/sdb2
# run vgscan to find out the volume name to use (avoid myvdo as is the VDO from above)
vgextend $MYROOTVG /dev/sdb2
# run lvscan to find out the LV storing the root filesystem and pvscan to find the maximum available space
lvresize –L +15G /dev/rhel/root
35. 创建一个引导项,允许我们进入紧急模式以更改根密码
请参考以下内容如何完成此操作:
grubby --args="systemd.unit=emergency.target" --update-kernel=/boot/vmlinuz-$(uname –r)
36. 创建一个自定义调整配置文件,定义第一个驱动器的预读取为 4096,第二个驱动器的预读取为 1024 - 此配置文件还应在发生 OOM 事件时使系统崩溃
参考以下命令:
dnf –y install tuned
mkdir –p /etc/tuned/myprofile
编辑/etc/tuned/myprofile/tuned.conf
文件,添加以下内容:
[main]
summary=My custom tuned profile
[sysctl]
vm.panic_on_oom=1
[main_disk]
type=disk
devices=sda
readahead=>4096
[data_disk]
type=disk
devices=!sda
readahead=>1024
37. 禁用并删除已安装的 httpd 软件包,并使用 registry.redhat.io/rhel8/httpd-24 镜像设置 httpd 服务器
请参考以下内容如何完成此操作:
rpm –e httpd
dnf –y install podman
podman login registry.redhat.io # provide RHN credentials
podman pull registry.redhat.io/rhel8/httpd-24
podman run -d --name httpd –p 80:8080 -v /var/www:/var/www:Z registry.redhat.io/rhel8/httpd-24
第十九章:练习 2
在本章的第二个练习中,我们将运行一系列练习,以检查您在本书中所学知识。与本书的其他章节不同,不是所有步骤都会被指定;您可以自行决定执行必要的步骤以完成必要的目标。建议您避免查阅章节以获取指导,而是尝试使用您的记忆或系统中可用的工具。当您参加官方考试时,这种经验将是一个关键因素。
强烈建议您在开始练习时使用时钟,以便知道您完成所需时间。
技术要求
本章中的所有实际练习都需要安装运行 Red Hat Enterprise Linux 8 的虚拟机(VM)以及基本安装。此外,还需要新的虚拟驱动器来进行存储操作。
练习假设您具有以下内容:
-
安装了基本操作系统最小安装软件选择的 Red Hat Enterprise Linux 8。
-
访问具有有效订阅的 Red Hat 客户门户网站。
-
VM 必须是可扩展的;也就是说,您对其执行的操作可能会使其无法使用,因此必须重新安装。
练习的提示
这是任何测试的一般建议清单,其中大部分都是常识,但始终记住它们是很有趣的:
-
在开始考试之前,先阅读问题的全部内容。
-
特定的词语具有特定的含义,可以提供关于要求或完成练习的方法的提示。因此,再次阅读所有内容可能会增加或减少可能性。
-
使自己感到舒适:安装您喜欢的编辑器,运行
updatedb
以便您有一个新的软件包和文件数据库准备好,并定义您的键盘布局。安装并学习如何使用tmux
的基础知识,以便您可以打开新标签并命名它们,而无需额外的窗口。 -
查找请求之间的依赖关系。一些目标依赖于其他目标的完成,因此找到这些依赖关系,以查看如何构建解决方案,而无需返回并重做一些步骤。
-
使用计时器。重要的是要了解哪些练习花费了更多的时间,以便您可以找到需要改进的地方。
-
不要记住具体的命令。相反,学习如何使用系统中可用的文档,例如使用
man
,/usr/share/docs
参数,如--help
命令等。 -
确保更改在重新启动后仍然有效。有些更改可能在运行时是有效的,但必须持久:防火墙规则,要在启动时启动的服务等。
-
记住,您可以使用
dnf whatprovides "*/COMMAND"
来查找与您可能缺少的文件相关的软件包。 -
查看
www.redhat.com/en/services/training/ex200-red-hat-certified-system-administrator-rhcsa-exam?=Objectives
以获取官方 EX200 考试目标。
练习 2
重要提示
根据设计,在以下练习中,命令、软件包等将不会被突出显示。记住到目前为止学到的知识,以便检测关键字,看看需要做什么。
不要过早地跳入解决方案;尝试思考和记住所涵盖的内容。
练习
-
从本书的 GitHub 存储库中下载所需的文件
raw.githubusercontent.com/PacktPublishing/Red-Hat-Enterprise-Linux-8-Administration/main/chapter-19-exercise2/users.txt
。 -
使用
users.txt
文件以自动化的方式使用提供的值在系统中生成用户,顺序如下:用户名
,占位符
,uid
,gid
,名称
,主目录
,shell
。 -
创建名为 users 的组,并将该组添加为所有用户的主要组,将它们自己的组(以每个用户的名称命名)作为辅助组。
-
更改用户的主目录,使其由组拥有。
-
设置一个 HTTP 服务器,并为每个用户启用一个网页,为每个用户提供一个不同的小介绍。
-
允许
users
组中的所有用户在无需密码的情况下成为 root。 -
为每个用户创建 SSH 密钥,并将每个密钥添加到 root 和其他用户,以便每个用户都可以像其他用户一样进行 SSH 连接,即无需密码。
-
禁用通过 SSH 访问系统的密码。
-
使用
/dev/random
为每个用户设置不同的密码,并将密码存储在users.txt
文件的第二个字段中。 -
如果用户名中的字母数是 2 的倍数,则将该事实添加到每个用户描述网页中。
-
创建一个容器,以
yq
python 包作为入口点运行。 -
为非 2 的倍数的用户配置密码到期。
-
使用日期命名的文件配置一个每日压缩的日志轮换,为一个月的日志。
-
保存当天生成的所有日志在
/root/errors.log
中。 -
安装系统库的所有可用更新。
-
使用先前在
/root
文件夹中可用的已下载软件包修复损坏的 rpm 二进制文件。 -
使用户执行的所有进程都以低优先级运行,而来自 john 的进程则以更高优先级运行(+/- 5)。
-
使系统以最高的吞吐量和性能运行。
-
更改系统网络接口,使其使用比原来更高的 IP 地址。为同一接口添加另一个 IPv6 地址。
-
为所有用户将
/opt/mysystem/bin/
创建并添加到系统 PATH 中。 -
创建一个防火墙区域,将其分配给一个接口,并将其设置为默认区域。
-
添加一个托管在
https://myserver.com/repo/
上的存储库,使用https://myserver.com/mygpg.key
上的 GPG 密钥添加到系统中,因为我们的服务器可能会宕机。配置它以便在不可用时可以跳过它。
练习 2 的答案
在本节中,我们将复制目标列表中的每一项,并在使用适当的语法高亮时加以解释。
1. 从本书的 GitHub 存储库 https://raw.githubusercontent.com/PacktPublishing/Red-Hat-Enterprise-Linux-8-Administration/main/chapter-19-exercise2/users.txt 下载必要的文件
wget https://raw.githubusercontent.com/PacktPublishing/Red-Hat-Enterprise-Linux-8-Administration/main/chapter-19-exercise2/users.txt
2. 使用users.txt
文件以自动化方式在系统中生成用户,顺序如下:用户名、占位符、uid、gid、名称、主目录、shell
首先,让我们使用以下代码检查users.txt
文件:
cat users.txt
user;x;1000;1000;myuser1;/home/user1; /bin/false
john ;x ;1001 ;1001; John; /home/john ;/bin/false
doe ;x ;1001 ;1001; Doe; /home/doe ; /bin/csh
athena ;x ;1011 ;1011; Athena Jones; /home/ajones ; /bin/rsh
pilgrim ;x ;2011 ;2011; Scott Pilgrim; /home/spilgrim ; /bin/rsh
laverne; x ; 2020;2020; LaVerne;/home/LaVerne;/bin/bash
如请求中所述,该文件中的字段为username
、placeholder
、uid
、gid
、name
、home
、shell
。通常不要求创建用户的占位符是密码,因此我们可以在忽略该字段的同时使用其他数据。
正如我们也可以看到的那样,每个字段至少由一个;
符号分隔,但有些在其前后有额外的空格。由于我们还有姓氏,我们不能只是删除所有空格;我们需要在实际文本之前和之后执行此操作。
我们需要使用带有;
字段分隔符的 cut 命令,但首先,我们需要逐行读取文件。
我们可以使用 Bash 的内置read
函数来实现这一点:
cat users.txt|while read -r line; do echo ${line};done
基于此,我们可以开始构建我们将需要创建用户的所有内容。让我们首先着手处理各个步骤,然后构建完整的命令行。
我们有很多行,因此对于每一行,我们需要定义字段并删除末尾/开头的空格:
NEWUSERNAME=$(echo ${line}|cut -d ";" -f 1)
NEWUID=$(echo ${line}|cut -d ";" -f 3)
NEWGID=$(echo ${line}|cut -d ";" -f 4)
NEWNAME=$(echo ${line}|cut -d ";" -f 5)
NEWSHELL=$(echo ${line}|cut -d ";" -f 6)
在前面的示例中,我们正在回显每一行,并使用-f
指定的字段和;
字段分隔符进行切割。这使我们能够精确选择包含我们要查找的数据的字段。为了使这更容易,我们可以将每个存储在一个变量中,以便我们可以重用该代码片段,并且仍然清楚地了解每个脚本将要执行的操作。
前面的代码将起作用,但它将在空格处失败,因此我们需要将它们扩展到只捕获实际文本而不包括空格。让我们使用 xargs 来实现这一点:
NEWUSERNAME=$(echo ${line}|cut -d ";" -f 1|xargs)
NEWUID=$(echo ${line}|cut -d ";" -f 3|xargs)
NEWGID=$(echo ${line}|cut -d ";" -f 4|xargs)
NEWNAME=$(echo ${line}|cut -d ";" -f 5|xargs)
NEWHOME=$(echo ${line}|cut -d ";" -f 6|xargs)
NEWSHELL=$(echo ${line}|cut -d ";" -f 7|xargs)
下一步是构建添加用户的命令行:
useradd --d "${NEWHOME}" --m --s "${NEWSHELL}" --u "${NEWUID}" --g "${NEWGID}" --c "${NEWNAME}" "${NEWUSERNAME}"
现在一切准备就绪,让我们构建解决方案:
cat users.txt| while read -r line ; do
NEWUSERNAME=$(echo ${line}|cut -d ";" -f 1|xargs)
NEWUID=$(echo ${line}|cut -d ";" -f 3|xargs)
NEWGID=$(echo ${line}|cut -d ";" -f 4|xargs)
NEWNAME=$(echo ${line}|cut -d ";" -f 5|xargs)
NEWHOME=$(echo ${line}|cut -d ";" -f 6|xargs)
NEWSHELL=$(echo ${line}|cut -d ";" -f 7|xargs)
useradd -d "${NEWHOME}" -m -s "${NEWSHELL}" -u "${NEWUID}" -g "${NEWGID}" -c "${NEWNAME}" "${NEWUSERNAME}"
done
3. 创建名为 users 的组,并将该组添加为所有用户的主要组,将它们自己的组,以每个用户命名,作为辅助组
在这种情况下,我们需要创建我们在上一步中没有创建的组。因此,一旦新组已创建,我们将循环遍历用户,为每个用户创建新组,然后修改用户以获得 users 组并将其自己添加为辅助组:
groupadd users
cat users.txt| while read -r line ; do
NEWUSERNAME=$(echo ${line}|cut -d ";" -f 1|xargs)
groupadd -g ${NEWGID} ${NEWUSERNAME}
usermod -g users -G ${NEWUSERNAME} ${NEWUSERNAME}
done
4. 更改用户的主文件夹,使其成为组所有
cat users.txt| while read -r line ; do
NEWUSERNAME=$(echo ${line}|cut -d ";" -f 1|xargs)
NEWHOME=$(echo ${line}|cut -d ";" -f 6|xargs)
chown -R ${NEWUSERNAME}:users ${NEWHOME}/
done
5. 设置 HTTP 服务器并为每个用户启用一个网页,每个网页都有一个不同的小介绍
dnf -y install httpd
firewall-cmd --add-service=http --permanent f
firewall-cmd --reload
-
cat users.txt| while read -r line ; do
NEWUSERNAME=$(echo ${line}|cut -d ";" -f 1|xargs)
NEWUID=$(echo ${line}|cut -d ";" -f 3|xargs)
NEWGID=$(echo ${line}|cut -d ";" -f 4|xargs)
NEWNAME=$(echo ${line}|cut -d ";" -f 5|xargs)
NEWHOME=$(echo ${line}|cut -d ";" -f 6|xargs)
NEWSHELL=$(echo ${line}|cut -d ";" -f 7|xargs)
mkdir -p ${NEWHOME}/public_html/
echo "Hello, my name is ${NEWNAME} and I'm a user of this system" > ${NEWHOME}/public_html/index.htm
Done
最后,我们需要通过编辑/etc/httpd/conf.d/userdir.conf 并禁用 UserDir 来启用 homedirs,以便它变为 Userdir public_html:
service httpd start
6. 允许 users 组中的所有用户成为 root 而无需密码
这可以通过多种方式实现,但由于所有用户都在 users 组中,我们可以添加该组:
echo "%users ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
7. 为每个用户创建 SSH 密钥,并将每个密钥添加到 root 和其他用户,以便每个用户都可以像其他用户一样进行 SSH,即无需密码
首先,让我们为每个用户创建密钥并将密钥添加到 root:
cat users.txt| while read -r line ; do
NEWHOME=$(echo ${line}|cut -d ";" -f 6|xargs)
mkdir -p ${NEWHOME}/.ssh/
ssh-keygen -N '' -f ${NEWHOME}/.ssh/id_dsa
cat ${NEWHOME}/.ssh/id_dsa.pub >> /root/.ssh/authorized_keys
done
现在,让我们为每个用户复制授权密钥:
cat users.txt| while read -r line ; do
NEWUSERNAME=$(echo ${line}|cut -d ";" -f 1|xargs)
NEWHOME=$(echo ${line}|cut -d ";" -f 6|xargs)
cp /root/.ssh/authorized_keys ${NEWHOME}/.ssh/ >>
chown -R ${NEWUSERNAME}:users ${NEWHOME}/.ssh/
Done
验证用户是否可以像其他用户一样进行 ssh:
USERS=$(cat users.txt|cut -d ";" -f1|xargs)
for user in ${USERS};
do
for userloop in ${USERS};
do
su -c "ssh ${user}@localhost" ${userloop}
done
done
前面的命令应该适用于所有用户,因为我们复制了 authorized_keys,对吗?这并不是这种情况,因为一些用户已经禁用了他们的 shell。
8. 禁用通过 SSH 访问系统的密码
编辑/etc/ssh/sshd_config 并将 PasswordAuthentication 的任何值替换为 no。
然后,重新启动 sshd:
systemctl restart sshd
9. 使用/dev/random 为每个用户设置不同的密码,并将密码存储在 users.txt 文件的文件的第二个字段中
从/dev/random,我们可以获取随机数据,但它是二进制的,所以如果我们想以后用它进行登录,它可能无效。我们可以对接收到的数据使用哈希函数,并将其用作密码:
MYPASS=$(dd if=/dev/urandom count=1024 2>&1|md5sum|awk '{print $1}')
这将是密码,无需加密。
使用 usermod,我们可以根据其加密种子定义密码,因此我们将两者结合起来。
此外,我们被告知将生成的密码存储在 users.text 中,因此我们需要编辑该文件。
但是有一个问题:编辑.txt 文件中的特定字段可能不容易,但我们可以完全重写它:
cat users.txt| while read -r line ; do
MYPASS=$(dd if=/dev/random count=12>&1|md5sum|awk '{print $1}')
NEWUSERNAME=$(echo ${line}|cut -d ";" -f 1|xargs)
NEWUID=$(echo ${line}|cut -d ";" -f 3|xargs)
NEWGID=$(echo ${line}|cut -d ";" -f 4|xargs)
NEWNAME=$(echo ${line}|cut -d ";" -f 5|xargs)
NEWHOME=$(echo ${line}|cut -d ";" -f 6|xargs)
NEWSHELL=$(echo ${line}|cut -d ";" -f 7|xargs)
echo "${NEWUSERNAME};${MYPASS};${NEWUID};${NEWGID};${NEWNAME};${NEWHOME};${NEWSHELL}" >> newusers.txt
echo ${MYPASS} | passwd ${NEWUSERNAME} --stdin
done
cp newusers.txt users.txt
通过这种方式,我们已经将 users.txt 文件重写为一个新文件,通过添加我们拥有的所有字段,并用我们的新副本覆盖了 users.txt。
循环中的最后一个命令从变量中读取密码,并将其提供给 passwd 文件,该文件将对其进行加密和存储,同时从 stdin 中读取它。
10. 如果用户名中的字母数是 2 的倍数,则将该事实添加到每个用户的描述网页中
cat users.txt| while read -r line ; do
NEWUSERNAME=$(echo ${line}|cut -d ";" -f 1|xargs)
NEWHOME=$(echo ${line}|cut -d ";" -f 6|xargs)
LETTERSINNAME=$(( $(echo ${NEWUSERNAME}|wc -m) - 1 ))
if [ "$((${LETTERSINNAME} % 2 ))" == "0" ]; then
echo "My name is multiple of 2" >> ${NEWHOME}/public_html/index.htm
done
done
在这个例子中,我们重复相同的字段计算,但是我们添加了 wc 命令来获取字符数,并删除一个来调整到字母数。
在比较中,我们评估除以 2 时的余数,这样当没有余数时,这意味着我们的字母数是 2 的倍数。
11. 创建一个运行 yq Python 包的容器
当我们读到"Python package"时,我们应该考虑 PIP。不建议直接在系统上使用 PIP,因为它可能会改变系统提供的 Python 库,最好使用虚拟环境。或者,您可以使用一个容器来保持它的隔离。
如第十七章中所述,使用 Podman、Buildah 和 Skopeo 管理容器,最简单的方法是创建一个定义容器创建步骤的文件。
对于容器,如果您的系统中没有安装podman
包和container-tools
模块,还需要安装它们。
由于这个文件是一个 Python 包,我们需要一个已经包含 Python 的容器;例如,catalog.redhat.com/software/containers/rhel8/python-38/5dde9cb15a13461646f7e6a2
。
因此,让我们创建一个包含以下内容的Containerfile
(可在github.com/PacktPublishing/Red-Hat-Enterprise-Linux-8-Administration/raw/main/chapter-19-exercise2/ContainerFile
中找到):
FROM registry.access.redhat.com/ubi8/python-38
MAINTAINER RHEL8 Student <student@redhat.com>
LABEL name="yq image" \
maintainer="student _AT_ redhat.com" \
vendor="Risu" \
version="1.0.0" \
release="1" \
summary="yq execution container" \
description="Runs yq"
ENV USER_NAME=risu \
USER_UID=10001 \
LC_ALL=en_US.utf8
RUN pip3 install --upgrade pip --no-cache-dir && \
pip3 install --upgrade yq --no-cache-dir
USER 10001
VOLUME /data
ENTRYPOINT ["/opt/app-root/bin/yq"]
CMD ["-h"]
与podman build -t yq -f ContainerFile
结合使用时,它将拉取带有 Python 的ubi8
镜像,以便我们只需运行pip3 install
命令来安装yq
,然后将其分配为我们的entrypoint
。
例如,如果我们定义了一个无效的entrypoint
(因为我们可能不知道程序安装在哪里),我们可以使用podman run -it --entrypoint /bin/bash <podmanid>
。我们可以通过运行podman images
并检查系统中可用的每个 pod 的生成日期来获取 podman ID。
可以使用podman run –it <podmanid>
来测试创建的容器,它将输出关于yq
命令的信息。
请注意,yq
,如其在github.com/kislyuk/yq
的存储库中所述,需要我们安装jq
命令,但我们故意将其排除在外,以演示如何创建容器。
12. 为非 2 的倍数的用户配置密码过期,以便它们过期
cat users.txt| while read -r line ; do
NEWUSERNAME=$(echo ${line}|cut -d ";" -f 1|xargs)
NEWHOME=$(echo ${line}|cut -d ";" -f 6|xargs)
LETTERSINNAME=$(( $(echo ${NEWUSERNAME}|wc -m) - 1 ))
if [ "$((${LETTERSINNAME} % 2 ))" != "0" ]; then
chage -M 30 ${NEWUSERNAME}
done
done
在这里,我们重用了问题 10 中的循环,但是反转了条件。由于对密码过期的使用没有要求,我们只需要将需要密码更改的最大天数定义为“30 天”。
13. 使用日期命名的文件配置每月日志的每日压缩日志轮换
首先,我们需要确保logrotate
已安装:
dnf -y install logrotate
安装后,编辑/etc/logrotate.conf
文件,使其包含以下内容:
rotate 30
daily
compress
dateext
我们需要确保没有定义其他周期(每月、每周等)。
14. 将当天生成的所有日志保存在/root/errors.log 中
这有一个技巧:有些程序将日志记录到日志中,而有些程序将日志记录到*.log
文件中。
今天的日期可以用+%Y-%m-%d
获得。这种使用年-月-日格式的格式通常用于程序日志:
grep "$(date '+%Y-%m-%d')" -Ri /var/log/*.log|grep -i error > /root/errors.log
journalctl --since "$(date '+%Y-%m-%d')" >> /root/errors.log
通过这样做,我们结合了两个输出。当然,我们可以尝试按日期对条目进行排序,以便它们相关联,但请记住,第一个grep
执行递归搜索,因此文件名被前置,这使得排序更加困难。
15. 为系统库安装所有可用的更新
通常,系统库中包含lib
子字符串,因此更新应该只是运行以下命令的问题:
dnf upgrade *lib*
因为它会要求确认,所以请查看列出的软件包,确保没有发生错误。
16. 使用先前在/root 文件夹中可用的下载包修复损坏的 rpm 二进制文件
这是一个棘手但有用的知识检查。
首先,让我们确保rpm
包可用:
yumdownloader rpm
使用以下命令验证文件是否存在:
ls –l rpm*.rpm
检查文件,确保我们有办法回退,以防我们破坏它无法修复:
rpm -qip rpm*.rpm
现在,让我们看一下有助于验证我们解决问题的破坏性操作:
rm -fv /usr/bin/rpm
从这里开始,就像看吧,不用手...没有 RPM 可用来安装rpm*.rpm
包,但我们仍然需要安装它来解决问题。
rpm
包是压缩的cpio
存档,所以我们可以使用以下命令:
rpm2cpio rpm*.rpm |cpio –idv
这将提取压缩的rpm
内容(无需运行脚本)。
将未压缩的rpm
文件移回/usr/bin
:
mv usr/bin/rpm /usr/bin/rpm
验证rpm
的安装和操作:
rpm –V rpm
它会抱怨,说至少日期已经改变。然而,如果下载的文件更新了大小和 md5sum,它也可能已经更新了。
通过重新安装rpm
软件包将系统移动到一个合理的状态:
rpm -i rpm*.rpm
这将使系统抱怨,因为软件包已经安装(它将说明它将覆盖rpm
、rpm2archive
、rpm2cpio
、rpmdb
、rpmkeys
等)。
如果rpm
版本不同,我们可以使用以下命令升级它:
rpm -Uvh rpm*.rpm
然后,我们可以使用以下命令验证这一点:
rpm –V rpm
关于数据库包含的内容,不应该报告任何更改。如果我们无法升级,我们可以使用--force
参数运行安装,告诉rpm
可以继续并覆盖文件。
或者,一旦rpm
二进制文件已经被cpio
恢复,我们可以使用以下命令:
dnf –y reinstall rpm
另一种方法是从类似系统scp
rpm
二进制文件,或者使用救援介质。
17. 使用户 doe 执行的所有进程以低优先级运行,而由 john 运行的进程以更高优先级运行(+/- 5)
我们无法将其设置为默认值,但我们可以结合一个 cron 作业来实现。
以 root 身份执行crontab -e
来编辑 root 的 crontab 并设置一个每分钟运行的作业:
*/1 * * * * pgrep -u doe |xargs renice +5
*/1 * * * * pgrep -u john|xargs renice -5
这将使用pgrep
来获取 john 和 doe 的所有 PID,并通过xargs
将它们传递给renice
进程。
或者,我们可以使用以下内容:
renice +5 $(pgrep -u doe)
这可以作为xargs
命令的替代方法。
18. 使系统以最高吞吐量和性能运行
tuned
是一个系统守护程序,我们可以安装它来自动应用一些众所周知的参数到我们的系统,这将成为我们特定优化的基础:
dnf -y install tuned
systemctl enable tuned
systemctl start tuned
tuned-adm profile throughput-performance
19. 更改系统网络接口,使其使用比原来更高的 IP 地址。在同一个接口上添加另一个 IPv6 地址
使用nmcli
,检查当前系统 IP 地址:
nmcli con show
输出应该如下:
图 19.1 - nmcli con show 的输出
有了这个,我们可以找到正在使用和连接的系统接口。假设它是ens3
,它连接在名为Wired Connection
的连接上。
让我们使用nmcli con show "Wired Connection"|grep address
来查找当前的地址。
如果我们的地址是,例如,10.0.0.6
,我们可以使用以下代码:
nmcli con mod "Wired Connection" ipv4.addresses 10.0.0.7
nmcli con mod "Wired Connection" ipv6.addresses 2001:db8:0:1::c000:207
使用以下命令验证这一点:
nmcli con show "Wired Connection"|grep address
20. 为所有用户创建并添加/opt/mysystem/bin/
到系统路径
编辑/etc/profile.d/mysystempath.sh
文件,并放入以下内容:
export PATH=${PATH}:/opt/mysystem/bin
要验证这一点,将+x
属性添加到文件中,并使用以下命令创建文件夹:
chmod +x /etc/profile.d/mysystempath.sh
mkdir -p /opt/mysystem/bin
重新登录用户时,执行以下命令应该显示新的路径:
echo ${PATH}
21. 创建一个防火墙区域,将其分配给一个接口,并将其设置为默认区域
这是一个棘手的问题。在这本书中,我们已经解释了如何查询区域以及如何更改默认区域,甚至展示了用于管理防火墙的cockpit
的屏幕截图,所以现在作为一个有经验的用户,这应该不难。
当你不知道如何做某事时,第一件事就是查看手册页:
man firewall-cmd
这并不显示很多有趣的信息。然而,在 man 页面的末尾,有一个名为firewalld.zones(5)
的部分。这意味着我们可以查看手册的第五部分firewalld.zones
。
我们通常不指定部分,因为可能没有很多重复,所以我们可以运行以下命令:
man firewalld.zones
这指示我们在/usr/lib/firewalld/zones
和/etc/firewalld/zones
中检查默认值,所以让我们这样做:
cp /usr/lib/firewalld/zones/public.xml /etc/firewalld/zones/dazone.xml
现在,让我们编辑新复制的文件,名为/etc/firewalld/zones/dazone.xml
,并将其名称从Public
更改为dazone
。然后,我们需要重新加载防火墙:
firewall-cmd -reload
让我们使用以下命令验证新的区域是否存在:
firewall-cmd --get-zones
让我们把它设置为默认区域:
firewall-cmd --set-default-zone=dazone
现在,添加默认接口(ens3
):
firewall-cmd --add-interface=ens3 --zone=dazone
它会失败。这是预期的,因为ens3
已经被分配给一个区域(public
)。所以,让我们使用以下命令:
firewall-cmd -remove-interface=ens3 --zone=public
firewall-cmd -add-interface=ens3 --zone=dazone
正如你所看到的,即使没有关于创建新区域的先前知识,我们也能够利用我们关于查找信息的系统知识来实现这个目标。
22. 添加一个托管在 https://myserver.com/repo/上的存储库,使用来自 https://myserver.com/mygpg.key 的 GPG 密钥添加到系统中,因为我们的服务器可能会宕机。配置它以便在不可用时可以跳过它
如果我们不记得存储库的语法,我们可以使用系统上可用的示例之一。要做到这一点,转到/etc/yum.repos.d/
,列出可用的文件,并选择一个来创建一个名为myserver.repo
的文件,其中包含以下内容:
[myserver]
name=My server repository
baseurl=https://myserver.com/repo/
enabled=1
gpgcheck=1
gpgkey=https://myserver.com/mygpg.key
如果不可用,我们如何跳过它?让我们查看yum
的手册页。同样,在man dnf.conf
中有指定。这列出了一个可能帮助我们的布尔值,所以让我们将其添加到我们的repofile
中:
skip_if_unavailable=1
有了这个,我们已经完成了我们的目标。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 什么是nginx的强缓存和协商缓存
· 一文读懂知识蒸馏
· Manus爆火,是硬核还是营销?