RHEL-服务器秘籍-全-

RHEL 服务器秘籍(全)

原文:annas-archive.org/md5/1e1510ec60598edc256dc3445fdaac01

译者:飞龙

协议:CC BY-NC-SA 4.0

前言

Gnu/Linux 是数据中心中最重要的操作系统,但你如何利用它?你如何维护和管理它?许多 Gnu/Linux 发行版尝试回答这些问题,但并非所有都成功。红帽企业 Linux 就是一个能够成功回答这些问题的系统。

下一个问题是,作为系统管理员,你如何管理一个 RHEL 基础设施?你如何部署不止一个系统,而是多个系统?你如何确保它们安全并且保持更新?你如何监控系统组件?

这或许对你来说有些奇怪,但作为一名红帽认证工程师,我更倾向于采用“懒惰”方法——不是那种“我不想做”的懒,而是“我喜欢一次做对,第一次就做到位,剩下的时间用来做有趣的事情”。

本书旨在向你展示如何设置和配置系统,主要通过提供有用的信息来实现自动化设置、配置和管理。这也解释了本书中不使用图形用户界面的原因。坦白说,我的笔记本电脑或桌面电脑上离不开图形界面,但我认为服务器不应该使用图形界面。基于图形界面的应用程序通常没有命令行版本,我坚信,如果你不能通过脚本安装、配置、管理和维护一款软件,那么它就不适合用于服务器。

本书并不自称是所有问题的最终答案(那个答案是 42),但我希望你能学到一些新东西,并且将这些知识好好利用。记住,能力越大,责任越大!

本书内容概述

第一章,使用 KVM 客户机,并不会从安装一个基本的 RHEL 系统开始,而是首先介绍 KVM(如果你还不熟悉的话)。你将学会如何安装和配置 KVM 主机,以及如何管理你的 KVM 客户机(虚拟机)。本章将讨论如何动态添加资源、移动磁盘,甚至将整个客户机迁移到另一个 KVM 主机。

第二章,部署 RHEL "En Masse",将探讨安装 RHEL 系统的方法,介绍你使用 Kickstart 部署,这种方法可以简化自动化系统安装。如果你想管理你的环境,本章将为你奠定构建基础。

第三章,配置你的网络,将探索如何使用 NetworkManager 工具来管理网络配置,包括 VLAN、链路聚合和桥接等高级话题。它将展示如何利用其命令行工具,在系统部署期间或安装完成后,自动化系统的网络配置。

第四章, 配置你的新系统,将解释如何配置基本设置,例如日志保留、时间和启动环境。它还将介绍新的 systemd,它是 SysVinit 的替代品,以及如何监控和管理你的服务。

第五章, 使用 SELinux,将为你提供一个概述,虽然简短,但足以让你了解如何在系统中管理和故障排除 SELinux。由于其安全性实现,SELinux 在当今世界变得越来越重要,了解它总比因为无法处理它而选择关闭它要好。

第六章, 使用 Ansible 进行编排,将为你介绍 Ansible,它最近被 Red Hat 收购。它将展示如何创建简单的 playbook,轻松部署新系统,以及如何管理系统配置。

第七章, Puppet 配置管理,将教你如何设置和配置 Puppet。它还将向你展示 Puppet 在配置管理方面的能力。

第八章, Yum 与软件源,将探讨 yum 软件源,如何创建自己现有(Red Hat)软件源的镜像,以及如何利用它保持 RHEL 环境的最新状态,轻松应对更新。

第九章, 加固 RHEL 7,将把安全配置和审计问题进一步探讨。我们将探索如何配置集中式安全认证和权限提升。它将展示如何操作一个看似“卡住”的系统,并追踪事件的根本原因。

第十章, 监控与性能调优,将展示基本的性能调优方法,以及如何监控系统资源。

本书所需的工具

本书中的所有食谱所需的唯一工具是 Red Hat Enterprise Linux 7 安装 DVD,你可以从access.redhat.com/downloads下载试用许可证。本书中使用的所有软件都可以通过 RHEL 介质或在食谱中指定的 yum 软件源获得。

本书适合的人群

本书面向那些希望了解新版本 RHEL 及其管理或认证功能的系统管理员。虽然本书提供了大量信息,帮助你获得 Red Hat Certified System Administrator(RHCSA)和/或 Red Hat Certified Engineer(RHCE)认证,但它并不是一个完整的指南,无法让你轻松获得认证!

为了充分利用本书,你应该具备一定的基本(RHEL)系统管理和管理工具的知识。

章节

本书中,你会发现一些经常出现的章节标题(准备工作、如何操作、工作原理、更多内容、以及另见)。

为了给出清晰的完成食谱的步骤,我们使用以下这些章节:

准备工作

本节告诉你在食谱中可以期待什么,并描述如何设置任何软件或完成食谱所需的任何前期设置。

如何操作…

本节包含执行此食谱所需的步骤。

工作原理…

本节通常包含对上一节内容的详细解释。

还有更多…

本节包含关于该食谱的额外信息,旨在让读者对该食谱有更深入的了解。

另见

本节提供了指向其他有用信息的链接,供完成食谱时参考。

规范

在本书中,你会发现许多文本样式,用来区分不同类型的信息。以下是这些样式的一些示例以及它们的含义说明。

文本中的代码字、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟网址、用户输入以及 Twitter 账号名称都以以下方式显示:“我们可以通过使用include指令包含其他内容。”

代码块的设置如下所示:

node /^www[0-9]+\.critter\.be$/ {
}
node /^repo[0-9]+\.critter\.be$/ {
}

任何命令行输入或输出都如下所示:

~]# yum install -y /tmp/puppetlabs-release-el-7.noarch.rpm

新术语重要单词以粗体显示。你在屏幕上看到的单词,例如,在菜单或对话框中,都会像这样出现在文本中:“点击下一步按钮会将你带到下一个屏幕。”

注意

警告或重要的提示会以这种方式出现在框中。

提示

提示和技巧以这种方式出现。

读者反馈

我们始终欢迎读者的反馈。让我们知道你对本书的看法——你喜欢或不喜欢的部分。读者反馈对我们非常重要,它帮助我们开发出你真正能从中受益的书籍。

若要向我们提供一般反馈,只需发送电子邮件至<feedback@packtpub.com>,并在邮件主题中提及书名。

如果你在某个领域有专长,并且有兴趣编写或为书籍贡献内容,请查看我们的作者指南:www.packtpub.com/authors

客户支持

现在你已经是一本 Packt 图书的骄傲拥有者,我们提供了一些资源,帮助你最大限度地从购买中获益。

下载本书的彩色图片

我们还为你提供了一份包含本书中使用的截图/图表的彩色图片的 PDF 文件。这些彩色图片将帮助你更好地理解输出中的变化。你可以从 www.packtpub.com/sites/default/files/downloads/RedHatEnterpriseLinuxServerCookbook_ColorImages.pdf 下载此文件。

勘误

虽然我们已尽力确保内容的准确性,但错误还是难免发生。如果你在我们的书籍中发现错误——可能是文本或代码的错误——我们将非常感激你能向我们报告。通过这样做,你可以帮助其他读者避免困扰,并帮助我们改进后续版本的内容。如果你发现任何勘误,请通过访问 www.packtpub.com/submit-errata 来报告,选择你的书籍,点击勘误提交表格链接,并输入勘误的详细信息。一旦勘误被验证,你的提交将被接受,并且勘误将被上传到我们的网站或添加到该书籍的勘误列表中。

要查看之前提交的勘误,请访问 www.packtpub.com/books/content/support,并在搜索框中输入书名。所需的信息将出现在勘误部分。

盗版

互联网盗版问题是所有媒体面临的持续问题。在 Packt,我们非常重视保护我们的版权和许可证。如果你在互联网上发现任何形式的非法复制我们的作品的内容,请立即提供该地址或网站名称,以便我们采取相应的措施。

如有任何盗版材料的相关信息,请通过<copyright@packtpub.com>联系我们,附上涉嫌盗版的材料链接。

我们感谢你帮助保护我们的作者及我们为你提供有价值内容的能力。

问题

如果你对本书的任何部分有疑问,可以通过<questions@packtpub.com>与我们联系,我们将尽力解决问题。

第一章:与 KVM 客户机的工作

本章将涵盖以下内容:

  • 安装和配置 KVM

  • 配置资源

  • 构建虚拟机

  • 动态添加 CPU

  • 动态添加内存

  • 动态添加磁盘

  • 将磁盘移动到另一个存储

  • 移动虚拟机

  • 备份虚拟机元数据

简介

本书将尝试向你展示如何不费太多力气地部署 RHEL 7 系统。由于本书是以自动化为目标编写的,因此我将强调命令行工具,而不是详细讨论其图形界面版本,因为图形界面对于自动化没有什么帮助。

本章解释了如何使用 libvirt 接口和围绕它构建的各种工具来构建和管理 KVM 客户机。它将简要概述如何在 RHEL 上设置 KVM 并管理其资源。此概述中的设置远非企业级准备,因为它不提供通常在企业中所需的冗余。然而,提供的食谱对于企业设置仍然具有参考意义,因为界面保持不变。大多数情况下,你可能会使用一个管理层(如 RHEV 或 oVirt),这将使你在管理冗余时更加轻松。

注意

Libvirt 是用户与各种虚拟化和容器层之间的 API,例如 KVM、VMware、Hyper-V 和 Linux 容器。查看 libvirt.org/drivers.html 了解完整的支持的虚拟化程序和容器解决方案列表。

由于大多数任务最终需要自动化,我倾向于不使用任何图形界面,因为这些界面无法轻松转换为脚本。因此,本章不会涉及任何图形界面的操作。这些内容将主要聚焦于 virsh,即 libvirt 管理用户界面,用于管理你的 KVM 主机及其虚拟机的各个方面。虽然很多人依赖 virsh 的编辑选项,但它不允许你实时编辑虚拟机的配置。通过这种方式编辑虚拟机的 XML 配置,需要你关机并重启虚拟机,才能使更改生效。重启虚拟机并不奏效,因为虚拟机实例需要完全重新读取 XML 配置文件才能应用更改。只有重新启动虚拟机才能做到这一点。

virsh 接口也是一个 shell,因此通过启动 virsh 而不带任何命令,你将进入 libvirt 管理 shell。一个非常有趣的命令是 help。此命令将按关键字输出所有可用的命令。每个命令都可以接受 --help 参数,显示可能的参数及其说明,供你使用。

安装和配置 KVM

本章介绍如何在 RHEL 7 上安装虚拟化工具和软件包。

默认情况下,RHEL 7 系统并未预安装 KVM 或 libvirt。可以通过以下三种方式安装:

  • 通过系统设置过程中的图形化设置

  • 通过 kickstart 安装

  • 通过命令行进行手动安装

对于本教程,您应该知道如何使用 yum 安装软件包,并且您的系统应该配置为可以访问默认的 RHEL 7 仓库(有关更多信息,请参见 第八章,Yum 和仓库),这是我们将要使用的软件包所必需的。

或者,您可以使用 rpm 从安装介质中安装软件包,但您需要自己解决依赖问题。

使用以下命令检查 rpm 的依赖项:

~]# rpm -qpR <rpm file>

这将输出安装此软件包之前需要安装的二进制文件、库和文件的列表。

通过以下命令检查哪个软件包包含这些文件:

~]# rpm -qlp <rpm package>

如您所想,这是一项繁琐的工作,可能需要相当长的时间,因为您需要为每个要以这种方式安装的软件包找出每个依赖项。

准备工作

安装 KVM 时,您至少需要 6 GB 的空闲磁盘空间、2 GB 的 RAM,并且每个虚拟机需要额外的一个核心或线程。

检查您的 CPU 是否支持虚拟化标志(如 SVM 或 VMX)。某些硬件厂商在 BIOS 中禁用了该功能,因此您可能还需要检查您的 BIOS。请运行以下命令:

~]# grep -E 'svm|vmx' /proc/cpuinfo
flags    : ... vmx ...

或者,您可以运行以下命令:

~]# grep -E 'svm|vmx' /proc/cpuinfo
flags    : ... svm ...

使用以下命令检查硬件虚拟化模块(如 kvm_intelkvm)是否已加载到内核中:

~]# lsmod | grep kvm
kvm_intel             155648  0
kvm                   495616  1 kvm_intel

如何操作……

我们将介绍将 KVM 安装到系统上的三种方式。

手动安装

这种安装 KVM 的方式通常是在使用其他方式安装基本系统后进行的。您需要执行以下步骤:

  1. 使用以下命令安装提供虚拟化客机环境所需的软件:

    ~]# yum -y install qemu-kvm qemu-img libvirt
    
    

    这些软件包的安装将包含相当多的依赖项。

  2. 运行此命令安装配置 libvirt 和安装虚拟机所需的附加实用工具:

    ~]# yum -y install virt-install libvirt-python python-virthost libvirt-client
    
    
  3. 默认情况下,libvirt 守护进程会在每次启动时自动启动。通过执行以下命令检查它是否已启用:

    ~]# systemctl status libvirtd
    libvirtd.service - Virtualization daemon
     Loaded: loaded (/usr/lib/systemd/system/libvirtd.service; enabled)
     Active: inactive
     Docs: man:libvirtd(8)
     http://libvirt.org
    
    
  4. 如果由于某些原因情况并非如此,请通过执行以下命令将其标记为自动启动:

    ~]# systemctl enable libvirtd
    
    
  5. 要手动停止/启动/重启 libvirt 守护进程,您需要执行以下命令:

    ~]# systemctl stop libvirtd
    ~]# systemctl start libvirtd
    ~]# systemctl restart libvirtd
    
    

Kickstart 安装

在 kickstart 过程中安装 KVM 提供了一种简单的方式来自动化 KVM 实例的安装。请按照以下步骤操作:

  1. 在您的 kickstart 文件的 %packages 部分添加以下软件包组:

    @virtualization-hypervisor
    @virtualization-client
    @virtualization-platform
    @virtualization-tools
    
  2. 使用此 kickstart 文件开始安装您的主机。

在系统设置过程中进行图形化设置

这可能是安装 KVM 最不常见的方式。我唯一使用这种方式的时间是在编写本教程时。以下是如何操作:

  1. 从 RHEL 7 安装介质启动。

  2. 完成除软件选择步骤之外的所有步骤。系统设置中的图形界面设置

  3. 前往软件选择完成 KVM 软件选择。

  4. 基础环境中选择虚拟化主机单选按钮,在为选定环境添加附加组件中勾选虚拟化平台复选框:系统设置中的图形界面设置

  5. 完成安装。

  6. 安装总结屏幕上,完成其他步骤并点击开始安装

另请参见

要设置您的软件仓库,请查看第八章,Yum 和仓库

要使用 kickstart 部署系统,请参考第二章,大规模部署 RHEL

有关如何使用 libvirt 的更深入信息,请访问www.libvirt.org/

RHEL 7 有某些支持限制,列在以下位置:

access.redhat.com/articles/rhel-kvm-limits

access.redhat.com/articles/rhel-limits

配置资源

虚拟机需要 CPU、内存、存储和网络访问,类似于物理机器。此食谱将向您展示如何通过 libvirt 设置基本的 KVM 环境,以便轻松管理资源。

存储池是一个虚拟容器,受到两个因素的限制:

  • qemu-kvm允许的最大大小

  • 物理机器上磁盘的大小

存储池的大小不得超过主机磁盘的大小。最大值如下:

  • virtio-blk = 2⁶³ 字节或 8 艾字节(原始文件或磁盘)

  • EXT4 = ~16 TB(使用 4KB 块大小)

  • XFS = ~8 艾字节

准备工作

对于此食谱,您需要至少 2GB 的卷挂载在/vm,并且可以访问 NFS 服务器及其导出目录。

我们将使用NetworkManager创建一个桥接,因此请确保不要禁用NetworkManager,并且已安装bridge-utils

如何操作…

让我们看看如何管理存储池和网络。

创建存储池

为了创建存储池,我们需要向 KVM 提供必要的详细信息,以便它能够创建存储池。您可以按以下方式进行操作:

  1. 使用virsh/vm上创建一个localfs存储池,如下所示:

    ~]# virsh pool-define-as --name localfs-vm --type 
    dir --target /vm
    
    
  2. 通过以下命令创建存储池的目标:

    ~# mkdir -p /nfs/vm
    
    
  3. 使用virsh在 NFS 服务器上创建一个 NFS 存储池:/export/vm,如下所示:

    ~]# virsh pool-define-as --name nfs-vm --type network --source-host nfsserver --source-path /export/vm –target /nfs/vm
    
    
  4. 通过以下命令使存储池在重启后保持持久:

    ~]# virsh pool-autostart localfs-vm
    ~]# virsh pool-autostart nfs-vm
    
    
  5. 启动存储池,如下所示:

    ~]# virsh pool-start localfs-vm
    ~]# virsh pool-start nfs-vm
    
    
  6. 验证存储池是否已创建、启动并在重启后保持持久。为此,运行以下命令:

    ~]# virsh pool-list
     Name                 State      Autostart
    -------------------------------------------
     localfs-vm           active     yes
     nfs-vm               active     yes
    
    

查询存储池

在某些时刻,您需要知道存储池中剩余的空间。

执行以下命令获取存储池的信息:

~]# virsh pool-info --pool <pool name>
Name:           nfs-vm
UUID:           some UUID
State:          running
Persistent:     yes
Autostart:      yes
Capacity:       499.99 GiB
Allocation:     307.33 GiB
Available:      192.66 GiB

如您所见,该命令可以轻松地显示磁盘空间的分配和可用性。

提示

但请小心,如果使用支持稀疏文件的文件系统,这些数字很可能是错误的。您需要手动计算文件的大小!

要检测文件是否是稀疏文件,请运行ls -lhs命令查看文件。-s命令会显示一个额外的列(第一个),显示文件占用的确切空间,如下所示:

~]# ls -lhs myfile
121M -rw-------. 1 root root  30G Jun 10 10:27 myfile

删除存储池

有时,存储会被淘汰,因此需要从主机中移除。

在继续之前,您必须确保没有虚拟机正在使用存储池中的卷,并且需要移除存储池中所有剩余的卷。操作方法如下:

  1. 按照以下方式删除存储卷:

    ~]# virsh vol-delete --pool <pool name> --vol <volume name>
    
    
  2. 通过以下命令停止存储池:

    ~]# virsh pool-destroy --pool <pool name>
    
    
  3. 使用以下命令删除存储池:

    ~]# virsh pool-delete --pool <pool name>
    
    

创建虚拟网络

在创建虚拟网络之前,我们需要在现有的网络接口上构建一个桥接。为了方便起见,这个 NIC 将被称为eth0。确保记录下您当前的网络配置,因为我们将销毁它并在桥接上重新创建它。

与存储池不同,我们需要创建 XML 配置文件来定义网络。没有类似于pool-create-as的命令用于网络。执行以下步骤:

  1. 按照以下方式在您的网络接口上创建桥接接口:

    ~]# nmcli connection add type bridge autoconnect yes con-name bridge-eth0 ifname bridge-eth0
    
    
  2. 使用以下命令移除您的 NIC 配置:

    ~]# nmcli connection delete eth0
    
    
  3. 按照以下方式配置您的桥接:

    ~]# nmcli connection modify bridge-eth0 ipv4.addresses <ip address/cidr> ipv4.method manual
    ~# nmcli connection modify bridge-eth0 ipv4.gateway <gateway ip address>
    ~]# nmcli connection modify bridge-eth0 ipv4.dns <dns servers>
    
    
  4. 最后,通过执行以下命令将您的网络接口卡(NIC)添加到桥接中:

    ~]# nmcli connection add type bridge-slave autoconnect yes con-name slave-eth0 ifname eth0 master bridge-eth0
    
    

首先,我们来看一下如何创建一个类似于默认配置并称为默认的 NAT 网络:

  1. 创建网络 XML 配置文件/tmp/net-nat.xml,方法如下:

    <network>
      <name>NATted</name>
      <forward mode='nat'>
        <nat>
          <port start='1024' end='65535'/>
        </nat>
      </forward>
      <bridge name='virbr0' stp='on' delay='0'/>
      <ip address='192.168.0.1' netmask='255.255.255.0'>
        <dhcp>
          <range start='192.168.0.2' end='192.168.0.254'/>
        </dhcp>
      </ip>
    </network>
    
  2. 使用前述 XML 配置文件在 KVM 中定义网络。执行以下命令:

    ~]# virsh net-define /tmp/net-nat.xml
    
    

现在,让我们通过以下步骤创建一个桥接网络,该网络可以通过该桥接使用绑定的网络:

  1. 通过运行以下命令创建网络 XML 配置文件/tmp/net-bridge-eth0.xml

    <network>
        <name>bridge-eth0</name>
        <forward mode="bridge" />
        <bridge name="bridge-eth0" />
    </network>
    
  2. 使用前述文件在 KVM 中创建网络,方法如下:

    ~]# virsh net-define /tmp/net-bridge-eth0.xml
    
    

还有一种值得提及的网络类型:隔离网络。该网络只能供定义在该网络中的虚拟机访问,因为它与“真实”世界没有连接。

  1. 使用以下代码创建网络 XML 配置文件/tmp/net-local.xml

    <network>
      <name>isolated</name>
      <bridge name='virbr1' stp='on' delay='0'/>
      <domain name='isolated'/>
    </network>
    
  2. 使用上述文件在 KVM 中创建网络:

    ~]# virsh net-define /tmp/net-local.xml
    
    

通过这种方式创建网络将使它们在 KVM 中注册,但不会激活它们或使其在重启后保持持久性。因此,这是您需要为每个网络执行的额外步骤。现在,执行以下步骤:

  1. 使用以下命令使网络在重启后保持持久性:

    ~]# virsh net-autostart <network name>
    
    
  2. 按照以下方式激活网络:

    ~]# virsh net-start <network name>
    
    
  3. 通过执行以下命令来验证 KVM 网络是否存在:

    ~]# virsh net-list --all
     Name                 State      Autostart     Persistent
    ----------------------------------------------------------
     bridge-eth0          active     yes           yes
     default              inactive   no            yes
     isolated             active     yes           yes
     NATted               active     yes           yes
    
    

删除网络

在某些情况下,网络会被淘汰;在这种情况下,我们需要从设置中删除该网络。

在执行此操作之前,你需要确保没有虚拟机使用你想要删除的网络。请执行以下步骤删除网络:

  1. 使用以下命令停止网络:

    ~# virsh net-destroy --network <network name>
    
    
  2. 然后,使用以下命令删除网络:

    ~]# virsh net-undefine --network <network name>
    
    

它是如何工作的…

使用 define-pool-as 命令创建多个存储池非常简单,如你所见。每种类型的存储池需要的参数多或少。以 NFS 存储池为例,我们需要指定 NFS 服务器和导出路径。这通过分别指定 --source-host--source-path 来完成。

创建网络稍微复杂一些,因为它需要你创建一个 XML 配置文件。当你想要一个网络透明地连接到你的物理网络时,你只能使用桥接网络,因为不可能将网络直接绑定到网络接口。

还有更多…

本食谱中创建的存储后端并不是限制。Libvirt 还支持以下后端池:

本地存储池

本地存储池直接连接到物理机器。它们包括本地目录、磁盘、分区和 LVM 卷组。由于本地存储池不支持实时迁移,因此不适合企业使用。

网络或共享存储池

网络存储池包括通过标准协议在网络上共享的存储。这在我们在物理主机之间迁移虚拟机时是必需的。支持的网络存储协议包括基于 Fibre Channel 的 LUN、iSCSI、NFS、GFS2 和 SCSI RDMA。

通过在 libvirt 中定义存储池和网络,你确保了虚拟机资源的可用性。如果由于某些原因资源不可用,KVM 将不会尝试启动使用这些资源的虚拟机。

当查看 virsh (1) 的手册页时,你会发现一个类似于 net-definepool-define 的命令:net-createpool-create(以及 pool-create-as)。net-create 命令类似于 pool-createpool-create-as,它创建临时资源,这些资源在 libvirt 重启后将消失。另一方面,net-definepool-define(以及 pool-define-as)创建持久性资源,这些资源在你重启 libvirt 后仍然存在。

另见

你可以在 libvirt.org/storage.html 上了解更多关于 libvirt 存储后端池的信息

更多关于 libvirt 网络的信息可以在 wiki.libvirt.org/page/Networking 上找到

创建客户端

在宿主系统上安装并配置 KVM 后,你可以创建来宾操作系统。每个来宾由一组以 XML 格式存储的资源和参数定义。当你想要创建一个新来宾时,创建这样的 XML 文件是相当繁琐的。创建来宾有两种方法:

  • 使用 virt-manager

  • 使用 virt-install

本教程将采用后者,因为它非常适合脚本编写,而 virt-manager 是一个 GUI,不太适合自动化操作。

准备工作

在本教程中,我们将介绍如何使用 bridge-eth0 网络桥接来创建一个新的虚拟机,并在 localfs-vm 存储池上创建一个虚拟磁盘,格式为 QCOW2。QCOW2 格式是流行的虚拟磁盘格式,因为它允许薄配给和快照。我们将从位于 localfs-iso 存储池中的 RHEL 7 安装媒体(rhel7-install.iso)启动,开始安装一个新的 RHEL 7 系统。

如何操作…

让我们创建一些来宾并删除它们。

创建来宾

让我们先为来宾创建一个磁盘,然后在此磁盘上创建来宾,步骤如下:

  1. localfs-vm 存储池中创建一个 10 GB 的 QCOW2 格式磁盘,步骤如下:

    ~]# virsh vol-create-as --pool localfs-vm --name rhel7_guest-vda.qcows2 --format qcows2 –capacity 10G
    
    
  2. 通过以下命令创建虚拟机并启动它:

    ~]# virt-install \
    --hvm \
    --name rhel7_guest \
    –-memory=2048,maxmemory=4096 \
    --vcpus=2,maxvcpus=4 \
    --os-type linux \
    --os-variant rhel7 \
    --boot hd,cdrom,network,menu=on \
    --controller type=scsi,model=virtio-scsi \
    --disk device=cdrom,vol=localfs-iso/rhel7-install.iso,readonly=on,bus=scsi \
    --disk device=disk,vol=localfs-vm/rhel7_guest-vda.qcow2,cache=none,bus=scsi \
    --network network=bridge-eth0,model=virtio \
    --graphics vnc \
    --graphics spice \
    --noautoconsole \
    --memballoon virtio
    
    

删除来宾

在某些情况下,你需要移除来宾。你可以按以下步骤进行:

  1. 首先,确保通过运行以下命令让来宾关闭:

    ~]# virsh list –all
     Id    Name                           State
    ----------------------------------------------------
    -     rhel7_guest                     shut off
    
    

    如果状态不是 shut off,你可以强制关闭它:

    ~]# virsh destroy --domain <guest name>
    
    
  2. 列出当前来宾正在使用的存储卷,并将其复制到某个地方:

    ~]# virsh domblklist <guest name>
    Type       Device     Target     Source
    ------------------------------------------------
    file       disk       vda        /vm/rhel7_guest-vda.qcow2
    file       cdrom      hda        /iso/rhel7-install.iso
    
    
  3. 通过以下命令删除来宾:

    ~]# virsh undefine --domain <guest name> --storage vda
    
    

    在命令中添加 --remove-all-storage 将在删除存储池中的卷之前清除该来宾专用存储卷上的数据。

它是如何工作的…

virt-install 命令支持通过指定池、大小和格式来创建存储卷(磁盘)。但是,如果该存储卷已存在,应用程序将失败。根据 KVM 宿主机磁盘(本地或网络)的速度以及来宾磁盘的大小,创建新磁盘的过程可能需要一些时间才能完成。通过使用 virt-install 指定现有磁盘,如果需要重新安装来宾,你可以重用该磁盘。可以在第一次创建时只创建磁盘,并在此后相应地更改命令行。然而,事实是,使用 virsh vol-create-as 能让你对所做的操作有更精细的控制。

我们使用 QCOW2 格式来存储来宾的磁盘,因为它是存储 KVM 来宾磁盘时流行的格式。这是因为它支持薄配给和快照。

在创建虚拟机时,我们指定了maxmemory选项来配置内存,以及maxvcpus选项来配置虚拟 CPU。这将允许我们在虚拟机运行时增加 CPU 和内存。如果我们没有指定这些选项,我们将不得不先关闭系统,然后才能使用以下命令更改 XML 配置:

~# virsh edit <hostname>

如你所见,我们使用virtio驱动程序来支持任何硬件(网络、磁盘或气球设备),因为它是 KVM 的本地驱动,并且包含在 RHEL 7 内核中。

注意

如果由于某些原因,虚拟机操作系统不支持virtio驱动程序,你应该删除命令行中的--controller选项以及--disk选项中的总线规范。

有关virtio支持的更多信息,请访问 wiki.libvirt.org/page/Virtio

--memballoon选项将确保我们在内存过度分配时不会遇到问题。当特定虚拟机需要更多内存时,气球驱动程序将确保“空闲”虚拟机的内存可以均匀地重新分配。

graphics选项将允许你通过宿主机连接到虚拟机,可以使用 VNC(这是一种常用的远程计算机控制客户端)或 spice(这是virt-manager的默认客户端)。不过,VNC 和 spice 的配置都是不安全的。你可以通过指定密码进行设置——在每个 graphics 配置块中添加password=<password>,或者通过编辑 KVM 宿主机上的/etc/libvirt/qemu.conf文件来进行设置,这样的设置将适用于所有虚拟机。

还有更多…

在本教程中,我们使用了“本地”安装介质,以 ISO 镜像的形式来安装系统。然而,也可以在没有 CD、DVD 或 ISO 镜像的情况下安装虚拟机。--location安装方法选项允许你指定一个 URI,URI 中包含启动安装所需的内核/initrd 文件对。

--location--extra-args结合使用将允许你指定内核命令行参数传递给安装程序。例如,可以用来传递 Anaconda kickstart 文件的位置,进行自动化安装和/或在安装过程中指定 IP 配置。

另见

查看virt-install (1)的手册页,了解更多如何充分利用它的信息。

动态添加 CPU

想象一下,一个企业必须从一开始就正确地为所有系统进行扩展。在我的经验中,这非常困难。你可能会低估需求,客户在某个时刻会抱怨性能,或者你会过度配置,导致机器空闲,这也不是最优的。这就是硬件供应商提出hot-add资源的原因。这样,系统可以在不需要停机的情况下升级或增加 CPU、内存和/或磁盘。KVM 为其客户机实现了类似的功能,允许你动态增加 CPU、内存和磁盘。

实际的操作非常简单,但需要满足一些前提条件。

准备工作

为了能够动态为客户机添加 CPU,客户机的配置必须支持该功能。

有两种方法可以实现这一点:

  • 必须在创建时指定max选项,如下所示:

    --vcpus 2,maxvcpus=4
    
  • 你可以通过以下命令使用virsh设置最大值(将在下次启动时应用):

    ~]# virsh setvcpus --domain <guestname> --count <max cpu count> --config --maximum
    
    
  • 你可以编辑客户机的 XML 文件,如下所示:

    ~]# virsh edit <guestname>
    
    

最后两种选项要求你关闭并启动(而不是重启)客户机,因为这些命令无法更改“实时”配置。

客户机的 XML 文件必须包含以下元素及其随后的属性:

<domain type='kvm'>
...
<vcpu current='2'>4</vcpu>
...
</domain>

这里,current表示正在使用的 CPU 数量,而节点内的数字表示可以分配的 vCPU 的最大数量。这个数字可以增加,但永远不能超过主机的核心数或线程数。

如何操作…

让我们给客户机增加一些 CPU。

在 KVM 主机上,执行以下步骤:

  1. 获取可以分配的最大 vCPU 数量,如下所示:

    ~]# virsh dumpxml <guestname> |grep vcpu
    <vcpu placement='static' current='4'>8</vcpu>
    
    
  2. 现在,通过以下命令设置新的 vCPU 数量:

    ~]# virsh setvcpus --domai
    n <guestname> --count <# of CPUs> --live
    
    

在 KVM 客户机上,执行以下操作:

  1. 通过执行以下命令告诉客户机操作系统有更多的 CPU 可用:

    ~]# for i in $(grep -H 0 /sys/devices/system/cpu/cpu*/online | awk -F: '{print $1}'); do echo 1 > $i; done
    
    

动态添加 RAM

与 CPU 一样,动态添加内存在任务关键型环境中是一个附加价值,其中停机时间可能会给公司带来数百万欧元的损失。

这里介绍的操作非常简单,类似于 CPU 的操作。在这里,客户机也需要为使用此功能做好准备。

准备工作

如果你想能够动态为客户机添加内存,必须配置以支持此功能。与 CPU 一样,这必须被激活。实现这一点有三种方法:

  • 客户机必须在创建时指定maxmem选项,如下所示:

    --memory 2G,maxmemory=4G
    
  • 你可以使用virsh命令设置最大内存,如下所示:

    ~]# virsh setmaxmem --domain <guestname> --size <max mem> --live
    
    
  • 你可以编辑客户机的 XML 文件:

    ~]# virsh edit <guestname>
    
    

当然,后两种选项要求你关闭客户机,这在生产环境中并不总是可能的。

确保客户机的 XML 配置文件包含以下元素及其随后的属性:

<domain type='kvm'>
...
    <memory unit='KiB'>4194304</memory>
    <currentMemory unit='KiB'>2097152</currentMemory>
...
</domain>

如何操作…

让我们增加客户机的内存。

在 KVM 主机上,执行以下步骤:

  1. 获取来宾当前和最大内存分配,操作如下:

    ~]# virsh dumpxml srv00002 |grep -i memory
     <memory unit='KiB'>4194304</memory>
     <currentMemory unit='KiB'>4194304</currentMemory>
    
    
  2. 通过执行以下命令来设置来宾的新内存量:

    ~]# virsh setmem --domain <guestname> --size <memory> --live
    
    

在 KVM 来宾上,执行以下操作:

  1. 通过以下命令通知来宾操作系统内存增加:

    ~]# for i in $(grep -H offline /sys/devices/system/memory/memory*/state | awk -F: '{print $1}'); do echo online > $i; done
    
    

动态添加磁盘

本教程包括了如何创建不同类型的存储卷的说明。存储卷是为来宾专门划分的存储空间。

准备工作

向来宾添加磁盘所需的准备工作不多,这与添加 CPU 和内存的过程不同。

你只需要确保存储池有足够的空闲磁盘空间来容纳新磁盘。

如何操作……

类似于创建来宾的过程,你首先需要创建一个磁盘。可以按以下方式操作:

  1. 通过以下命令,在localfs-vm存储池中创建一个30GB 的原始磁盘:

    ~]# virsh vol-create-as --pool localfs-vm --name rhel7_guest-vdb.raw --format raw --capacity 30G
    
    
  2. 查找新创建卷的路径,操作如下:

    ~]# virsh vol-list --pool localfs-vm |awk '$1 ~ /^rhel7_guest-vdb.raw$/ {print $2}'
    
    

    这将显示你卷的路径;以下是一个示例:

    /vm/rhel7_guest-vdb.raw
    
    
  3. 按以下方式将磁盘附加到来宾:

    ~]# virsh attach-disk --domain <guestname> --source <the above path> --target vdb --cache none --persistent –live
    
    

工作原理……

使用vol-create-as创建磁盘可能需要一些时间,这取决于主机磁盘的速度和来宾磁盘的大小。

我们将查找新创建卷的路径,因为这是将磁盘附加到来宾时所需的参数。在大多数情况下,你不需要这样做,因为你会知道主机的配置,但是当你编写脚本来实现此功能时,就需要这一步骤。

以这种方式添加磁盘将使用virtio驱动程序附加磁盘,正如前面所述,virtio驱动程序经过优化,适用于 KVM。

还有更多内容……

如果由于某种原因,原始来宾不支持virtio驱动程序,或者你没有virtio控制器,你可以自行创建此控制器。将 XML 配置文件保存为/tmp/controller.xml,并包含以下内容:

<controller type='scsi' model='virtio' />

你可以通过检查主机的 XML 文件中的前述语句来了解这一点。

然后,导入 XML 配置文件,操作如下:

~]# virsh attach-device –domain <guestname> /tmp/controller.xml

这将允许你使用virtio创建磁盘。

将磁盘移动到另一个存储位置

移动磁盘是来宾生命周期的一部分。存储池中的磁盘(无论是本地的还是网络上的)可能会因容量管理不当而发生故障或填满。另一个原因可能是涉及的磁盘的成本或速度。迟早这些事情会发生,届时你就需要将存储迁移到别的地方。

通常情况下,必须关闭来宾,复制存储卷文件到其他地方(如果它是一个文件),等待,更新机器的 XML 配置,并重新启动来宾。然而,在今天的关键任务企业中,这种操作可能并不总是可行。

准备工作

为了执行此复制,你需要磁盘的源路径和目标路径。你可以通过检查 XML 配置文件来获取源路径,或者更好的是,通过查询存储卷本身来获取。这确实要求你知道磁盘所在的存储池。

执行以下命令:

~]# virsh vol-list --pool <storage pool> |awk '$1 ~ /^<volume name>$/ {print $2}'

确保目标是现有的存储池;如果没有,请创建一个。

查看本章中的配置资源教程,以创建存储池。

如果你记不住池的路径位置,可以执行以下命令:

~]# virsh pool-dumpxml <poolname> |awk '/<path>.*<\/path>/ {print $1}'

如何操作…

移动磁盘可能需要一些时间,因此确保你有足够的时间。执行以下步骤:

  1. 转储来宾的非活动 XML 配置文件,如下所示:

    ~]# virsh dumpxml --inactive <guestname> > /tmp/<guestname>.xml
    
    

    –-inactive文件将确保不会复制任何与来宾无关的临时信息。

  2. 通过以下命令取消定义来宾:

    ~]# virsh undefine <guestname>
    
    
  3. 执行以下命令将虚拟磁盘复制到另一个位置:

    ~]# virsh blockcopy --domain <guestname> --path <original path> --dest <destination path> --wait --verbose –-pivot
    
    
  4. 现在,编辑来宾的 XML 配置文件,并将磁盘路径更改为新位置。

  5. 重新定义来宾,如下所示:

    ~]# virsh define /tmp/<guestname>.xml
    
    
  6. 在对结果满意后,移除源磁盘。执行以下命令:

    ~]# virsh vol-delete --pool <poolname> --vol <volname>
    
    

它的工作原理是…

磁盘移动只能在瞬态域中执行,这也是我们执行virsh undefine命令的原因。为了在迁移后能再次使其持久化,我们还需要转储 XML 配置文件并修改存储卷路径。

移动磁盘时会做两件事,分别是:

  • 首先,它将源数据全部复制到目标位置

  • 其次,当复制完成时,源和目标将保持镜像状态,直到通过执行blockjob --pivot命令切换到新目标,或者通过blockjob --abort取消任务。

上述blockcopy命令同时完成所有任务。--wait命令在命令失败或成功之前不会将控制权返回给用户。它本质上与以下命令相同:

~]# virsh blockcopy --domain <guestname> --path <source path> --dest <destination path>

通过执行以下命令监控复制进度:

~]# watch -n10 "virsh blockjob –domain <guestname> --path <source path> --info"

完成后,执行以下命令:

~]# virsh blockjob –domain <guestname> --path <source path> --pivot

还有更多…

还可以在迁移过程中改变磁盘格式,通过指定--format参数和目标格式。如果你想将其复制到块设备,可以指定--blockdev

移动虚拟机

移动磁盘将减少磁盘故障的风险。当你的 CPU、内存和其他非磁盘相关组件开始出现故障时,你别无选择,只能将来宾迁移到其他主机。

本任务的过程相对简单,但正是前提条件决定了任务是否能够成功,或者彻底失败。

准备就绪

本教程的前提条件相当复杂。

对于主机,以下是要求:

  • 你需要有访问共享数据的权限。源主机和目标主机上的 KVM 机器都需要能够访问相同的存储——例如 iSCSI、NFS 等。

  • 两台主机需要使用相同类型的 CPU——即 Intel 或 AMD(不能将来宾从 Intel CPU 的主机迁移到 AMD CPU 的主机)。

  • 两台主机需要安装相同版本和更新的 libvirt。

  • 两台主机需要开放相同的网络端口。

  • 两台主机必须具有相同的 KVM 网络配置,或者至少在来宾使用的接口上有相同的网络配置。

  • 两台主机必须通过网络互通。

  • 最好设置并连接一个管理网络,连接到两台主机,供数据传输使用。这会减少你“生产”网络上的流量,并提高整体速度。

  • No execution 位必须在两台主机上保持一致。

来宾的要求是:

  • 所有以写模式打开的块设备必须指定 cache=none

如何操作……

有多种方式迁移主机,但我们只会突出介绍两种最常见的方式。

默认网络上的实时本地迁移

迁移主机的过程幸运的是非常简单,可以通过一条命令来概括。

在源主机上执行以下操作:

~]# virsh migrate --domain <guestname> --live –-persistent --undefinesource --verbose --desturl qemu+ssh://<host 2>/system

专用网络上的实时本地迁移

可以通过专用网络进行迁移。默认情况下,它会使用找到的第一个适合的网络。你需要指定监听地址(在主机上)和协议。这个过程与之前的命令相同,只不过我们需要指定本地监听 IP 地址和协议,例如 TCP。

在源主机上执行以下操作:

~]# virsh migrate --domain <guestname> --live –-persistent --undefinesource --verbose --desturl qemu+ssh://<host 2>/system tcp://<local ip address on dedicated network>/

它是如何工作的……

这种类型的迁移被称为“虚拟化管理程序本地”传输。该类型迁移的最大优点是通过最小化涉及的数据复制次数,从而带来了最低的计算成本。

当我们迁移主机时,它会将来宾的内存复制到新主机。当复制成功时,它会在源主机上终止来宾并在新主机上启动它。由于内存是逐步复制的,所以中断时间非常短。

还有更多……

两台主机之间的通信通过 SSH,这已经相当安全。然而,通过指定 --tunnelled 选项,也可以通过一个更加加密的通道隧道化数据。这会在你的网络上增加更多流量,因为两台主机之间会有额外的数据通信。

如果你希望减少网络上的流量,--compress 选项可以帮助你,但这会增加主机的负载,因为它们需要进行数据的压缩/解压缩,这反过来可能会影响来宾的性能。如果时间不是关键,但流量需要减少,这是一个不错的解决方案。

参见:

关于这个过程有非常详细的文档可以参考:libvirt.org/migration.html

备份你的虚拟机元数据

虽然 KVM 会将部分资源的配置以可读格式存储在磁盘上,但查询 libvirt 以获取资源的配置是一个不错的选择。

如何操作……

在这个步骤中,我们将通过以下步骤备份所有相关的 KVM 元数据:

这是网络配置:

~]# for i in $(virsh net-list --all | sed -e '1,2d' |awk '{print $1}'); do \
 virsh net-dumpxml --network $i --inactive > /tmp/net-$i.xml; \
done

这是存储配置:

~]# for i in $(virsh pool-list --all | sed -e '1,2d' |awk '{print $1}'); do \
 for j in $(virsh vol-list --pool $i |sed -e '1,2d') | awk '{print $1}'; do \
 virsh vol-dumpxml --pool $i --vol $j > /tmp/vol-$j.xml; \
 done \
 virsh pool-dumpxml --pool $i --inactive > /tmp/pool-$i.xml; \
done

这是来宾配置:

~]# for i in $(virsh list --all | sed -e '1,2d' |awk '{print $1}'); do \
 virsh dumpxml --domain $i --inactive > /tmp/domain-$i.xml; \
done

它是如何工作的……

virsh net-dumpxml命令允许你转储指定网络的精确配置。结合virsh net-list,你可以创建一个循环,列举所有网络并将其转储到文件中。通过指定--all,你将导出所有网络,包括那些不活跃的网络。如果你不希望备份非活动网络的配置,可以将virsh net-list --all替换为virsh net-list

存储池可以像网络一样使用virsh net-list进行列举。不过,除了单个存储池配置外,我们还对单个存储卷的配置感兴趣。幸运的是,二者都实现了listdumpxml命令!如果你不关心非活动存储池,可以在virsh pool-list中省略--all选项。

客户机也可以类似地进行列举,并使用dumpxml转储其 XML 配置。同样,如果你不关心非活动客户机,可以在virsh list中省略--all选项。

另请参阅

virsh (1)的手册页列出了前面章节中使用的所有命令选项。

第二章:部署 RHEL "大规模"

在本章中,提供了以下教程:

  • 创建一个 kickstart 文件

  • 使用 httpd 发布你的 kickstart 文件

  • 使用 pxe 部署系统

  • 使用自定义引导 ISO 文件部署系统

简介

本章将解答如何部署多个系统,且它们具有相同的基本配置。我们将首先创建一个应答文件,即驱动无人值守安装的 kickstart 文件。然后,我们将探讨一种可能的方式,通过 Apache Web 服务器使这个 kickstart 文件可访问。最后,我们将讨论安装物理和虚拟机器的两种常见方法。

本章假设你已经具备系统网络配置组件的基本知识,例如 DNS、DNS 搜索、IP 地址等,以及 yum 仓库。

创建一个 kickstart 文件

kickstart 文件本质上是一个包含所有安装过程中会被询问的必要问题答案的文件。它是 Red Hat 针对自动化安装需求而创建的。通过使用 kickstart,管理员可以创建一个包含所有指令的文件或模板。

创建 kickstart 文件有三种方式:

  • 手动方式

  • 使用 GUI 的 system-config-kickstart 工具

  • 使用标准的 Red Hat 安装程序 Anaconda

在这个教程中,我将介绍前两者的结合方式。

准备工作

在我们深入生成基础 kickstart 文件或模板的细节之前,需要安装 system-config-kickstart。运行以下命令:

~# yum install -y system-config-kickstart

如何操作…

首先,让我们通过以下步骤为我们的 kickstart 文件创建一个基础模板:

  1. 首先,从菜单中启动 Kickstart 配置器

  2. Kickstart 配置器 GUI 中选择系统的基本配置。

    以下截图显示了你可以在 基本配置 视图中设置的选项:

    如何操作…

  3. 现在,从 Kickstart 配置器 GUI 中选择安装方法。

    以下截图显示了你可以在 安装方法 视图中设置的选项:

    如何操作…

  4. 接下来,将 HTTP 服务器HTTP 目录 的值替换为你自己的仓库。

  5. 确保为 引导加载程序 应用正确的设置。

    以下截图显示了你可以在 引导加载程序选项 视图中设置的选项:

    如何操作…

  6. 配置你的磁盘和分区信息。只需创建一个 /boot 分区,搞定!我们将手动编辑文件以实现更好的定制。

    以下截图显示了在 分区信息 视图中可以设置的选项:

    如何操作…

  7. 配置你的网络。如果你想正确配置网络,你需要知道设备的名称。

    以下截图显示了你可以在 网络配置 视图中编辑的 网络设备 信息:

    如何操作…

  8. 现在,禁用 安装图形环境

    我们希望安装尽可能少的软件包。以下截图展示了你可以在 显示配置 视图中设置的选项:

    如何操作...

  9. 接下来,执行你认为必要的任何预安装和/或后安装任务。我通常会通过 SSH 和密钥使 root 账户可访问。

    以下截图展示了你可以在 后安装脚本 视图中设置的选项:

    如何操作...

  10. 保存 kickstart 文件。

  11. 使用你喜欢的编辑器打开文件,并将以下内容添加到分区部分:

    part pv.01 --size=1 --ondisk=sda --grow
    volgroup vg1 pv.01
    logvol / --vgname=vg1 --size=2048 --name=root
    logvol /usr --vgname=vg1 --size=2048 --name=usr
    logvol /var --vgname=vg1 --size=2048 --name=var
    logvol /var/log --vgname=vg1 --size=1024 --name=var
    logvol /home --vgname=vg1 --size=512 --name=home
    logvol swap --vgname=vg1 --recommended --name=swap –fstype=swap
    
  12. 现在,将以下脚本添加到你的网络行中:

    --hostname=rhel7
    
  13. %post 前添加以下脚本:

    %packages –nobase
    @core --nodefaults
    %end
    
  14. 创建一个密码哈希,用于下一步,如下所示:

    ~]# openssl passwd -1 "MySuperSecretRootPassword"
    $1$mecIlXKN$6VRdaRkevjw9nngcMtRlO.
    
    
  15. 保存生成的文件。你应该得到类似这样的内容:

    #platform=x86, AMD64, or Intel EM64T
    #version=DEVEL
    # Install OS instead of upgrade
    install
    # Keyboard layouts
    keyboard 'be-latin1'
    # Halt after installation
    halt
    # Root password
    rootpw --iscrypted $1$mecIlXKN$6VRdaRkevjw9nngcMtRlO.
    # System timezone
    timezone Europe/Brussels
    # Use network installation
    url –url="http://repo.example.com/rhel/7/os/x86_64/"
    # System language
    lang en_US
    # Firewall configuration
    firewall --disabled
    # Network information
    network  --bootproto=static --device=eno1 --gateway=192.168.0.254 --ip=192.168.0.1 --nameserver=192.168.0.253 --netmask=255.255.255.0 --hostname=rhel7# System authorization information
    auth  --useshadow  --passalgo=sha512
    # Use text mode install
    text
    # SELinux configuration
    selinux --enforcing
    # Do not configure the X Window System
    skipx
    # System bootloader configuration
    bootloader --location=none
    # Clear the Master Boot Record
    zerombr
    # Partition clearing information
    clearpart --all --initlabel
    # Disk partitioning information
    part /boot --fstype="xfs" --ondisk=sda --size=512
    part pv.01 --size=1 --ondisk=sda --grow
    volgroup vg1 pv.01
    logvol / --vgname=vg1 --size=2048 --name=root --fstype=xfs
    logvol /usr --vgname=vg1 --size=2048 --name=usr --fstype=xfs
    logvol /var --vgname=vg1 --size=2048 --name=var --fstype=xfs
    logvol /var/log --vgname=vg1 --size=1024 --name=var --fstype=xfs
    logvol /home --vgname=vg1 --size=512 --name=home --fstype=xfs
    logvol swap --vgname=vg1 --recommended --name=swap --fstype=swap
    
    %packages --nobase
    @core --nodefaults
    %end
    
    %post
    mkdir -p ~/.ssh
    chmod 700 ~/.ssh
    # Let's download my authorized keyfile from my key server...
    curl -O ~/.ssh/authrorized_keys https://keys.example.com/authorized_keys
    chmod 600 ~/.ssh/authrorized_keys
    %end
    

它是如何工作的……

system-config-kickstart 用于生成最小安装,因为任何添加都会比工具能处理的更复杂,我们需要能够在之后手动/动态地添加它们。软件包数量越少越好,因为每个安装的软件包都需要应用 bug 修复和安全更新。

虽然图形界面让我们可以配置大部分需要的选项,但我更喜欢手动调整其中一些部分,因为通过图形界面处理起来并不那么直观。

第 9 步添加必要的信息,将剩余磁盘用作 LVM 物理卷,并对其进行分区,以便 大型 文件系统在必要时可以轻松扩展。

SWAP 分区的 --recommended 参数根据 Red Hat 设置的交换大小建议创建一个交换分区。

第 10 步为你的主机添加一个主机名。如果你没有指定,系统会尝试解析 IP 地址并使用该主机名。如果无法确定主机名,它会将 localhost.localdomain 用作 fqdn

第 11 步确保只安装核心系统,其他内容不安装,这样你可以从此基础上构建。

如果你想准确了解核心组中安装了哪些软件包,可以在 RHEL 7 系统上运行以下命令:

~# yum groupinfo core

还有更多……

我没有覆盖在 准备工作 部分中提到的一个选项,因为它会在你手动安装系统时自动生成。安装完成后,文件可以在 /root/anaconda-ks.cfg 找到。你可以使用此文件开始,而不是使用 system-config-kickstart 工具生成 kickstart 文件。

从 RHEL 7 开始,kickstart 部署支持附加组件。这些附加组件可以通过多种方式扩展标准的 kickstart 安装。要使用 kickstart 附加组件,只需像 %pre%post 部分一样,添加 %addon addon_name 选项,后跟 %end。Anaconda 自带 kdump 附加组件,你可以在安装过程中通过在 kickstart 文件中提供以下部分来安装和配置 kdump

%addon com_redhat_kdump --enable --reserve-mb=auto
%end

另见

有关 kickstart 文件的更多详细信息,请参考网站github.com/rhinstaller/pykickstart/blob/master/docs/kickstart-docs.rst

关于一致的网络设备命名,请参考access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/Networking_Guide/ch-Consistent_Network_Device_Naming.html

使用 httpd 发布你的 kickstart 文件

你可以将 kickstart 文件保存到 USB 驱动器(或任何其他介质)中,但如果你需要在不同位置安装多个系统,这就变得有些麻烦。

在安装过程中,通过内核行从网络加载 kickstart 文件仅支持 NFS、HTTP 和 FTP。

在这个方法中,我选择了 HTTP,因为它是公司中常用的技术,且易于保证安全。

操作方法…

让我们先从安装 Apache httpd开始,步骤如下:

  1. 通过以下命令安装 Apache httpd

    ~]# yum install -y httpd
    
    
  2. 启用并启动httpd守护进程,如下所示:

    ~]# systemctl enable httpd
    ln -s '/usr/lib/systemd/system/httpd.service' '/etc/systemd/system/multi-user.target.wants/httpd.service'
    ~]# systemctl start httpd
    
    
  3. 通过运行以下命令创建一个目录来存放 kickstart 文件:

    ~]# mkdir -p /var/www/html/kickstart
    ~]# chown apache:apache /var/www/html/kickstart
    ~]# chmod 750 /var/www/html/kickstart
    
    
  4. 将你的 kickstart 文件复制到此新位置:

    ~]# cp kickstart.ks /var/www/html/kickstart/
    
    
  5. 在浏览器中,浏览到你的网站服务器上的 kickstart 目录,如下图所示:操作方法…

还有更多内容…

这样,你可以创建多个 kickstart 文件,并且它们将可以从你网络中的任何地方访问。

此外,你还可以使用 CGI-BIN、PHP 或任何其他具有 Apache 模块的技术,根据你在 URL 中指定的参数动态创建 kickstart 文件。

创建自己的动态 kickstart 文件解决方案的替代方法是 Cobbler。

另请参见

有关 Cobbler 的更多信息,请访问cobbler.github.io/

使用 PXE 部署系统

PXE(Preboot eXecution Environment,预启动执行环境)允许你通过网络资源指示计算机启动。这样,你可以通过单一来源来控制安装服务器,而无需物理插入笨重的 DVD 或 USB 驱动器。

准备工作

对于此方法,你将需要一个完全可用的 RHEL 7 仓库。

操作方法…

使用此方法,我们将从 RHEL 7 安装介质安装并配置 PXE 引导,步骤如下:

  1. 使用以下命令安装必要的软件包:

    ~]# yum install -y dnsmasq syslinux tftp-server
    
    
  2. 通过编辑/etc/dnsmasq.conf来配置 DNSMASQ 服务器,具体如下:

    # interfaces to bind to
    interface=eno1,lo
    # the domain for this DNS server
    domain=rhel7.lan
    # DHCP lease range
    dhcp-range= eno1,192.168.0.3,192.168.0.103,255.255.255.0,1h
    # PXE – the address of the PXE server
    dhcp-boot=pxelinux.0,pxeserver,192.168.0.1
    # Gateway
    dhcp-option=3,192.168.0.254
    # DNS servers for DHCP clients(your internal DNS servers, and one of Google's DNS servers)
    dhcp-option=6,192.168.1.1, 8.8.8.8
    # DNS server to forward DNS queries to
    server=8.8.4.4
    # Broadcast Address
    dhcp-option=28,192.168.0.255
    pxe-prompt="Press F1 for menu.", 60
    pxe-service=x86_64PC, "Install RHEL 7 from network", pxelinux
    enable-tftp
    tftp-root=/var/lib/tftpboot
    
  3. 使用以下命令启用并启动dnsmasq

    ~]# systemctl enable dnsmasq
    ~]# systemctl start dnsmasq
    
    
  4. 现在,通过运行以下命令启用并启动xinet守护进程:

    ~]# systemctl enable xinetd
    ~]# systemctl start xinetd
    
    
  5. 启用tftp服务器的xinet守护进程,如下所示:

    ~]# sed -i '/disable/ s/yes/no/' /etc/xinetd.d/tftp
    
    
  6. 通过执行以下命令,将syslinux引导加载程序复制到tftp服务器的引导目录:

    ~]# cp -r /usr/share/syslinux/* /var/lib/tftpboot
    
    
  7. 接下来,使用以下命令创建 PXE 配置目录:

    ~]# mkdir /var/lib/tftpboot/pxelinux.cfg
    
    
  8. 然后,创建 PXE 配置文件,路径如下:/var/lib/tftpboot/pxelinux.cfg/default

    default menu.c32
    prompt 0
    timeout 300
    ONTIMEOUT local
    menu title PXE Boot Menu
    label 1
      menu label ¹ - Install RHEL 7 x64 with Local http Repo
      kernel rhel7/vmlinuz
      append initrd=rhel7/initrd.img method=http://repo.critter.be/rhel/7/os/x86_64/ devfs=nomount ks=http://kickstart.critter.be/kickstart.ks
    label 2
      menu label ² - Boot from local media
    
  9. initrdkernel 从 RHEL 7 安装介质复制到 /var/lib/tftpboot/rhel7/,并运行以下命令:

    ~]# mkdir /var/lib/tftpboot/rhel7
    ~]# mount -o loop /dev/cdrom /mnt
    ~]# cp /mnt/images/pxeboot/{initrd.img,vmlinuz} /var/lib/tftpboot/rhel7/
    ~]# umount /mnt
    
    
  10. 使用以下命令打开服务器上的防火墙(但这可能不是必需的):

    ~]# firewall-cmd --add-service=dns --permanent
    ~]# firewall-cmd --add-service=dhcp --permanent
    ~]# firewall-cmd --add-service=tftp --permanent
    ~]# firewall-cmd --reload
    
    
  11. 最后,启动客户端,配置其从网络引导,并选择下图中显示的第一个选项:如何操作…

它是如何工作的…

DNSMASQ 通过在 dnsmasq 配置文件中提供 enable-tftp 选项,负责将启动系统指向 tftp 服务器。

需要 Syslinux 提供必要的二进制文件,以便通过网络启动。

tftp 服务器本身提供对 syslinux 文件、RHEL 7 内核和 initrd 的访问,以便系统从中引导。

PXE 配置文件提供必要的配置来启动系统,包括一个 kickstart 文件,自动安装你的系统。

还有更多内容…

本教程的基本前提是你没有安装 DHCP 服务器。在大多数公司,通常已经有 DHCP 服务。

如果你有 ISC-DHCP 服务器,那么这是你需要添加到想要允许 PXE 启动的子网定义中的内容:

  next-server <ip address of TFTP server>;
  filename "pxelinux.0";

另见

查看第八章,Yum 和仓库,以从安装介质设置 RHEL 7 仓库。

使用自定义引导 ISO 文件部署系统

PXE 是一种广泛使用的系统部署方式,ISO 也不例外。由于安全性、硬件可用性等原因,PXE 可能并不总是可用的。

许多硬件厂商提供远程访问其未安装操作系统的系统。HP 提供 iLO,Dell 提供 RIB。这些“远程”控制解决方案的优点是,它们还允许你以 ISO 的形式挂载“虚拟”媒体。

如何操作…

Red Hat 提供引导介质作为 ISO 映像,你可以使用它们来启动你的系统。我们将创建一个自定义 ISO 映像,这样可以以类似的方式引导系统。

让我们创建一个 ISO,你可以将其挂载为虚拟媒体,写入 CD-ROM,或通过以下步骤使用 dd 将其内容写入 USB 闪存盘/硬盘:

  1. 安装创建 ISO9660 映像所需的包,如下所示:

    ~]# yum install -y genisoimage
    
    
  2. 通过执行以下命令挂载 RHEL 7 DVD 的 ISO 映像:

    ~]# mount -o loop /path/to/rhel-server-7.0-x86_64-dvd.iso /mnt
    
    
  3. 通过以下命令从 RHEL 7 安装介质复制所需文件以创建自定义 ISO:

    ~]# mkdir -p /root/iso
    ~]# cp -r /mnt/isolinux /root/iso
    ~]# umount /mnt
    
    
  4. 现在,通过运行以下命令卸载 RHEL 7 DVD 的 ISO 映像:

    ~]# umount /mnt
    
    
  5. 接下来,使用以下命令删除 isolinux.cfg 文件:

    ~]# rm -f /root/iso/isolinux/isolinux.cfg
    
    
  6. 创建一个新的 isolinux.cfg 文件,如下所示:

    default vesamenu.c32
    timeout 600
    display boot.msg
    menu clear
    menu background splash.png
    menu title Red Hat Enterprise Linux 7.0
    menu vshift 8
    menu rows 18
    menu margin 8
    menu helpmsgrow 15
    menu tabmsgrow 13
    menu color sel 0 #ffffffff #00000000 none
    menu color title 0 #ffcc000000 #00000000 none
    menu color tabmsg 0 #84cc0000 #00000000 none
    menu color hotsel 0 #84cc0000 #00000000 none
    menu color hotkey 0 #ffffffff #00000000 none
    menu color cmdmark 0 #84b8ffff #00000000 none
    menu color cmdline 0 #ffffffff #00000000 none
    label linux
      menu label ^Install Red Hat Enterprise Linux 7.0
      kernel vmlinuz
      append initrd=initrd.img ks=http://kickstart.critter.be/kickstart.ks text
    
    label local
      menu label Boot from ^local drive
      localboot 0xffff
    
    menu end
    
  7. 现在,通过执行以下命令创建 ISO:

    ~]# cd /root/iso
    ~/iso]# mkisofs -o ../boot.iso -b isolinux/isolinux.bin -c isolinux/boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table -J -r .
    
    

    有关 mkisofs 命令所用选项的更多信息,可以在 mkisofs(1) 的手册页中找到。

    以下图像显示了创建自定义 ISO 的进度:

    如何操作…

  8. 然后,使用 ISO 在 KVM 服务器上安装来宾操作系统,如下所示:

    ~]# virsh vol-create-as --pool localfs-vm --name rhel7_guest-da.qcows2 --format qcows2 –capacity 10G
    ~]# virt-install \
    --hvm \
    --name rhel7_guest \
    –-memory 2G,maxmemory=4G \
    --vcpus 2,max=4 \
    --os-type linux \
    --os-variant rhel7 \
    --boot hd,cdrom,network,menu=on \
    --controller type=scsi,model=virtio-scsi \
    --disk device=cdrom,vol=iso/boot.iso,readonly=on,bus=scsi \
    --disk device=disk,vol=localfs-vm/rhel7_guest-vda.qcow2,cache=none,bus=scsi \
    --network network=bridge-eth0,model=virtio \
    --graphics vnc \
    --graphics spice \
    --noautoconsole \
    --memballoon virtio
    
    

    以下截图显示了使用自定义 ISO 镜像启动后的控制台:

    如何操作……

它是如何工作的……

使用 RHEL 7 安装介质,我们创建了一个新的启动 ISO,使我们能够安装新的系统。该 ISO 可以用来烧录 CD,使用dd工具复制到 USB 闪存驱动器,或者作为虚拟介质挂载。将此 ISO 作为虚拟介质挂载的方法在不同硬件平台上有所不同,因此本教程展示了如何使用 KVM 进行安装。

第三章. 配置你的网络

本章我们将涵盖以下配方:

  • 创建 VLAN 接口

  • 创建一个聚合接口

  • 创建一个桥接

  • 配置 IPv4 设置

  • 配置你的 DNS 解析器

  • 配置静态网络路由

介绍

本章将尝试解释如何使用 NetworkManager,它是 RHEL 7 中的默认网络配置工具和守护进程。这是一组工具,可以简化和直接地进行网络配置。

配置你的网络有时可能很困难,尤其是当你使用较为复杂的配置选项并结合著名的配置脚本时。NetworkManager 允许你轻松配置网络,而无需手动编辑配置文件。

提示

你仍然可以使用你喜欢的编辑器编辑位于 /etc/sysconfig/network-scripts 的网络配置文件;然而,默认情况下,NetworkManager 不会察觉你所做的任何更改。你需要在编辑完这些文件后执行以下命令:

~]# nmcli connection reload

这还不足以立即应用更改。你需要关闭并重新启动连接,或者重启系统。

另外,你可以编辑 /etc/NetworkManager/NetworkManager.conf 并在 [main] 部分添加 monitor-connection-files=yes。这将导致 NetworkManager 立即应用这些更改。

在这些配方中,你将了解如何使用 NetworkManager 工具(nmclinmtui)以及 Kickstart 文件来配置你的网络。

创建 VLAN 接口

VLAN 是在单个物理网络上运行的隔离广播域。它们允许你将本地网络分段,并且可以将 LAN 跨多个物理位置“扩展”。大多数企业在其网络交换环境中实现了这一点,但在某些情况下,标记的 VLAN 会到达你的服务器。

准备就绪

为了配置 VLAN,我们需要在本地网络接口上建立一个已连接的网络。

如何操作…

为了方便起见,我们的物理网络接口命名为 eth0。VLAN 的 ID 为 1,IPv4 地址为 10.0.0.2,子网掩码为 255.0.0.0,默认网关为 10.0.0.1

使用 nmcli 创建 VLAN 连接

使用 nmcli,我们需要先创建连接,然后激活它。请执行以下步骤:

  1. 使用以下命令创建 VLAN 接口:

    ~]# nmcli connection add type vlan dev eth0 id 1 ip4 10.0.0.2/8 gw4 10.0.0.1
    Connection 'vlan' (4473572d-26c0-49b8-a1a4-c20b485dad0d) successfully added.
    ~]#
    
    
  2. 现在,通过此命令激活连接:

    ~]# nmcli connection up vlan
    Connection successfully activated (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/7)
    ~]#
    
    
  3. 检查你的网络连接,如下所示:

    ~]# nmcli connection show
    ~]# nmcli device status
    ~]# nmcli device show eth0.1
    
    

    这是前述命令的示例输出:

    使用 nmcli 创建 VLAN 连接

使用 nmtui 创建 VLAN 连接

nmtui 工具是一个文本用户界面,用于操作 NetworkManager,可以通过在终端中执行以下命令启动:

~]# nmtui

这将打开以下基于文本的界面:

使用 nmtui 创建 VLAN 连接

导航通过使用Tab键和箭头键来完成,选择则通过按Enter键来进行。现在,你需要做以下操作:

  1. 转到编辑连接并选择。以下屏幕将会显示:创建 VLAN 连接(使用 nmtui)

  2. 接下来,选择并选择VLAN选项。确认选择创建 VLAN 连接(使用 nmtui)

  3. 在以下表单中输入所请求的信息,并通过选择提交:创建 VLAN 连接(使用 nmtui)

你的新VLAN接口现在将显示在连接列表中:

创建 VLAN 连接(使用 nmtui)

使用 kickstart 创建 VLAN 连接

让我们探索一下你需要在 kickstart 脚本中添加哪些内容,以便实现与前面章节相同的结果:

  1. 使用以下命令在你的 kickstart 文件中查找配置参数:

    ...
    network --device=eth0
    ...
    
  2. 用以下配置参数替换它:

    network --device=eth0 --vlanid=1 --bootproto=static --ip=10.0.0.2 --netmask=255.0.0.0 --gateway=10.0.0.1
    

还有更多……

使用 nmcli 创建 VLAN 的命令行非常基础,它会为缺失的每项信息使用默认值。为了确保所有内容都按你的要求创建,最好使用 con-nameifname。这两个选项分别用于命名你的连接和你正在创建的设备。请看以下命令:

~]# nmcli connection add type vlan con-name vlan1 ifname eth0.1 dev eth0 id 1 ip4 10.0.0.2/8 gw4 10.0.0.1

这将创建 vlan.1 连接,eth0 作为父接口,eth0.1 作为目标设备。

nmclinmtui 一样,你可以在 kickstart 中为你的 VLAN 连接命名;只需要指定 --interfacename 选项。如果在你的 kickstart 文件中找不到任何之前的网络配置,只需将代码添加到你的 kickstart 文件中。

另见

nmcli 工具没有 man 页面,但可以执行以下命令以获得更多选项来创建 VLAN 连接:

~]# nmcli con add help

获取更多关于网络的 kickstart 信息,请查看以下网址:access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/Installation_Guide/sect-kickstart-syntax.html

创建一个团队接口

接口团队、接口绑定和链路聚合都是相同的。它已经通过 bonding 驱动程序在内核中实现。团队驱动程序提供了一种与绑定不同的机制,将多个网络接口合并为一个逻辑接口。

准备工作

要设置团队接口,我们需要多个网络接口。

如何操作…

为了简便起见,我们的物理网络接口分别称为 eth1eth2。团队接口的 IPv4 地址为 10.0.0.2,子网掩码为 255.0.0.0,默认网关为 10.0.0.1

使用 nmcli 创建团队接口

使用这种方法,我们需要创建团队连接和两个团队从接口,并激活该连接,具体步骤如下:

  1. 使用以下命令行创建团队连接:

    ~]# nmcli connection add type team ip4 10.0.0.2/8 gw4 10.0.0.1
    Connection 'team' (cfa46865-deb0-49f2-9156-4ca5461971b4) successfully added.
    ~]#
    
    
  2. 通过执行以下命令将 eth1 添加到团队中:

    ~]# nmcli connection add type team-slave ifname eth1 master team
    Connection 'team-slave-eth1' (01880e55-f9a5-477b-b194-73278ef3dce5) successfully added.
    ~]#
    
    
  3. 现在,通过运行以下命令将 eth2 添加到团队中:

    ~]# nmcli connection add type team-slave ifname eth2 master team
    Connection 'team-slave-eth2' (f9efd19a-905f-4538-939c-3ea7516c3567) successfully added.
    ~]#
    
    
  4. 按如下方式启用团队接口:

    ~]# nmcli connection up team
    Connection successfully activated (master waiting for slaves) (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/12)
    ~]#
    
    
  5. 最后,通过以下命令检查您的网络连接:

    ~]# nmcli connection show
    ~]# nmcli device status
    ~]# nmcli device show nm-team
    
    

    以下是前面命令的示例输出:

    使用 nmcli 创建聚合接口

使用 nmtui 创建聚合接口

让我们启动 nmtui 并通过以下步骤添加连接:

  1. 首先,通过选择 创建团队连接:使用 nmtui 创建聚合接口

  2. 在以下表单中输入所需的信息,并对每个接口点击 以添加:使用 nmtui 创建聚合接口

  3. 接下来,在团队从属项中选择 添加接口,填写表单并选择 。对每个物理接口重复此操作:使用 nmtui 创建聚合接口

  4. 现在,选择 创建团队接口:使用 nmtui 创建聚合接口

    您的新团队接口现在将在连接列表中列出,如下所示的截图所示:

    使用 nmtui 创建聚合接口

使用 kickstart 创建聚合接口

使用您喜欢的编辑器打开 kickstart 文件,并执行以下步骤:

  1. 通过运行以下命令,在您的 kickstart 文件中查找网络配置参数:

    ...
    network --device=eth0
    ...
    
  2. 接下来,添加以下配置参数:

    network --device=team0 --teamslaves="eth1,eth2" --bootproto=static --ip=10.0.0.2 --netmask=255.0.0.0 --gateway=10.0.0.1
    

还有更多…

团队化包含运行器——一种负载共享备份方法,您可以将其分配给团队:

  • active-backup:在此模式中,使用一个物理接口,其他接口保持为备份

  • broadcast:在此模式中,数据通过所有物理接口的选择器进行传输

  • LACP:实现 802.3ad 链路聚合控制协议

  • loadbalance:执行主动的 Tx 负载均衡,并使用基于 BPF 的 Tx 端口

  • round-robin:数据依次通过所有物理接口传输

这些也可以在创建时通过这里提供的任一选项进行定义:

nmcli

team.config "{\"runner\":{\"name\": \"activebackup\"}}" 添加到您的命令中以创建团队接口,并将 activebackup 替换为您希望使用的运行器。

nmtui

填写团队接口的 JSON 配置字段 {"runner": {"name": "activebackup"}},并将 activebackup 替换为您希望使用的运行器。

nmtui

kickstart

--teamconfig="{\"runner\":{\"name\": \"activebackup\"}}" 添加到您的团队设备行中,并将 activebackup 替换为您希望使用的运行器。

使用 nmcli 创建团队接口时,提供的选项是基础的。如果您希望添加连接和接口名称,可以分别使用 con-nameifname,如下所示:

~]# nmcli connection add type team con-name team0 ifname team0 ip4 10.0.0.2/8 gw4 10.0.0.1
Connection 'team0' (e1856313-ecd4-420e-96d5-c76bc00794aa) successfully added.
~]#

添加团队从属设备时也需要类似的操作,唯一不同的是需要指定正确的接口名ifname

~# nmcli connection add type team-slave con-name team0-slave0 ifname eth1 master team0
Connection 'team0-slave0' (3cb2f603-1f73-41a0-b476-7a356d4b6274) successfully added.
~# nmcli connection add type team-slave con-name team0-slave1 ifname eth2 master team0
Connection 'team0-slave1' (074e4dd3-8a3a-4997-b444-a781114c58c9) successfully added.
~#

另请参见

如需了解有关网络团队守护进程和“运行器”的更多信息,请参考以下网址:

access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/Networking_Guide/sec-Understanding_the_Network_Teaming_Daemon_and_the_Runners.html

如需了解更多关于使用nmcli创建团队接口的信息,请查看以下链接:

access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/Networking_Guide/sec-Configure_a_Network_Team_Using-the_Command_Line.html

如需了解更多使用nmtui创建团队接口的信息,请访问以下链接:

access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/Networking_Guide/sec-Configure_a_Network_Team_Using_the_Text_User_Interface_nmtui.html

有关在 kickstart 脚本中创建团队接口的更多信息,请参考以下链接:

access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/Installation_Guide/sect-kickstart-syntax.html

创建桥接

网络桥接是一个逻辑设备,它根据 MAC 地址在连接的物理接口之间转发流量。这种桥接可以在虚拟化应用程序(如 KVM)中用来模拟硬件桥接,从而使多个虚拟网络接口共享网卡。

准备就绪

要桥接两个物理网络,我们需要两个网络接口。你的物理接口不应配置任何地址,因为桥接将配置 IP 地址。

如何做…

为了简便起见,我们将桥接的物理网络接口为eth1eth2。IPv4 地址为10.0.0.2,子网掩码为255.0.0.0,默认网关为10.0.0.1

使用 nmcli 创建桥接

配置桥接和接口后,确保激活桥接!以下是需要执行的步骤:

  1. 首先,使用以下命令创建桥接连接:

    ~]# nmcli connection add type bridge ip4 10.0.0.2/8 gw4 10.0.0.1
    Connection 'bridge' (36e40910-cf6a-4a6c-ae28-c0d6fb90954d) successfully added.
    ~]#
    
    
  2. eth1添加到桥接中,如下所示:

    ~]# nmcli connection add type bridge-slave ifname eth1 master bridge
    Connection 'bridge-slave-eth1' (6821a067-f25c-46f6-89d4-a318fc4db683) successfully added.
    ~]#
    
    
  3. 接下来,使用以下命令将eth2添加到桥接中:

    ~]# nmcli connection add type bridge-slave ifname eth2 master bridge
    Connection 'bridge-slave-eth2' (f20d0a7b-da03-4338-8060-07a3775772f4) successfully added.
    ~]#
    
    
  4. 通过执行以下命令来激活桥接:

    ~# nmcli connection up bridge
    Connection successfully activated (master waiting for slaves) (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/30)
    ~]#
    
    
  5. 现在,通过运行以下命令检查你的网络连接:

    ~]# nmcli connection show
    ~]# nmcli device status
    ~]# nmcli device show bridge
    
    

    以下是前面命令的示例输出:

    使用 nmcli 创建桥接

使用 nmtui 创建桥接

启动nmtui并选择Edit a connection。接下来,按照这些步骤使用nmtui创建桥接:

  1. 通过从连接列表中选择Bridge,然后点击来创建桥接连接:使用 nmtui 创建桥接

  2. 填写所呈现的表单并提供所需的信息:使用 nmtui 创建桥接

  3. 接下来,通过选择并为每个接口提供所需的信息,添加两个网络接口:使用 nmtui 创建桥接

  4. 最后,选择来创建桥接:使用 nmtui 创建桥接

现在,您的新桥接将显示在连接列表中:

使用 nmtui 创建桥接

使用 kickstart 创建桥接

通过以下步骤使用您喜欢的编辑器编辑kickstart文件:

  1. 使用以下命令行查找kickstart文件中的配置参数:

    ...
    network --device=eth0
    ...
    
  2. 现在,添加以下配置参数:

    network --device=bridge0 --bridgeslaves="eth1,eth2" --bootproto=static --ip=10.0.0.2 --netmask=255.0.0.0 --gateway=10.0.0.1
    

还有更多……

使用nmcli创建桥接时,所提供的选项非常简单。如果您希望添加连接和接口名称,可以分别使用con-nameifname,如以下方式:

~# nmcli connection add type bridge con-name bridge0 ifname bridge0 ip4 10.0.0.2/8 gw4 10.0.0.1
Connection 'bridge0' (d04180be-3e80-4bd4-a0fe-b26d79d71c7d) successfully added.
~#

添加桥接从属接口时也是一样的,唯一不同的是需要使用ifname来指定正确的接口:

~]# nmcli connection add type bridge-slave con-name bridge0-slave0 ifname eth1 master bridge0
Connection 'bridge0-slave0' (3a885ca5-6ffb-42a3-9044-83c6142f1967) successfully added.
~]# nmcli connection add type team-slave con-name team0-slave1 ifname eth2 master team0
Connection 'bridge0-slave1' (f79716f1-7b7f-4462-87d9-6801eee1952f) successfully added.
~]#

另请参见

有关使用nmcli创建网络桥接的更多信息,请访问以下 URL:

access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/Networking_Guide/sec-Network_Bridging_Using_the_NetworkManager_Command_Line_Tool_nmcli.html

有关使用nmtui创建网络桥接的更多信息,请访问以下网站:

access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/Networking_Guide/ch-Configure_Network_Bridging.html

有关 kickstart 和桥接的更多信息,请访问以下网站:

access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/Installation_Guide/sect-kickstart-syntax.html

配置 IPv4 设置

在旧的ifcfg样式文件中更改 IP 地址非常直接,使用NetworkManager工具时也很简单。

由于 kickstart 仅用于设置系统,因此在本教程中不涉及深入讨论此问题。

如何操作…

现在,让我们将当前eth1的 IPv4 地址和网关更改为10.0.0.3/8,并将默认网关设置为10.0.0.2

使用 nmcli 设置 IPv4 配置

执行以下步骤:

  1. 通过执行以下命令行设置 ipv4 信息:

    ~]# nmcli connection modify eth0 ipv4.addresses 10.0.0.3/8 ipv4.gateway 10.0.0.2
    
    
  2. 现在,运行以下命令来验证信息:

    ~]# nmcli connection show eth0
    
    

    这是前述命令的示例输出:

    使用 nmcli 设置 IPv4 配置

使用 nmtui 设置您的 IPv4 配置

nmtui工具需要更多工作,但最终结果仍然相同。执行以下步骤:

  1. 启动nmtui,选择要修改的接口,然后单击<编辑...>使用 nmtui 设置 IPv4 配置

  2. 现在,根据您的喜好修改 IPv4 配置,然后单击

还有更多...

管理 IPv6 IP 地址与配置 IPv4 对应项一样简单。

您需要在 kickstart 中使用的选项来设置您的 IP 地址和网关是:

  • --ip:用于设置系统的 IPv4 地址

  • --netmask:用于子网掩码

  • --gateway:用于设置 IPv4 网关

配置您的 DNS 解析器

DNS 服务器存储在/etc/resolv.conf中。您也可以使用NetworkManager管理此文件。

与之前的配方一样,出于同样的原因,本配方不会涉及kickstart选项。

如何做...

让我们将eth1的 DNS 解析器设置为指向 Google 的公共 DNS 服务器:8.8.8.88.8.4.4

使用 nmcli 设置您的 DNS 解析器

执行以下步骤:

  1. 通过以下命令设置 DNS 服务器:

    ~]# nmcli connection modify System\ eth1 ipv4.dns "8.8.8.8,8.8.4.4"
    
    
  2. 现在,使用以下命令检查您的配置:

    ~]# nmcli connection show System\ eth1
    
    

    这是前述命令的示例输出:

    使用 nmcli 设置 DNS 解析器

使用 nmtui 设置您的 DNS 解析器

使用nmtui工具需要更多工作来设置 DNS 解析器,如下所示:

  1. 启动nmtui,选择要修改的接口,然后单击<编辑...>使用 nmtui 设置 DNS 解析器

还有更多...

nmcli工具支持通过分号分隔添加多个 DNS 服务器。使用空值("")将删除此连接的所有 DNS 服务器。

类似地,您可以为您的环境设置 DNS 搜索域。使用nmcli时,您需要指定ipv4.dns-search属性。

Kickstart 允许您使用--nameserver选项为每个 DNS 服务器指定 DNS 服务器。如果您不希望指定任何 DNS 服务器,请使用--nodns。不幸的是,没有原生方法可以使用kickstart设置 DNS 域搜索。您将不得不在kickstart脚本的%post部分中使用nmcli,例如。

提示

在为多个网络接口设置 DNS 配置时要小心。NetworkManager将所有名称服务器添加到您的resolv.conf文件中,但 libc 可能不支持超过六个名称服务器。

配置静态网络路由

在某些情况下,需要在系统上设置静态路由。由于静态路由在kickstart中不受原生支持,因此本配方不涵盖此内容。

如何做...

通过10.0.0.1添加静态路由到192.168.0.0/24192.168.1.0/24网络。

使用 nmcli 配置静态网络路由

以下是你需要做的:

  1. 使用以下命令设置路由:

    ~]# nmcli connection modify eth0 ipv4.routes "192.168.0.0/24 10.0.0.1,192.168.1.0/24 10.0.0.1"
    
    
  2. 现在,执行以下命令行来验证配置:

    ~]# nmcli connection show eth0
    
    

    下面是前述命令的示例输出:

    使用 nmcli 配置静态网络路由

使用 nmtui 配置网络路由

以下是此过程的步骤:

  1. 启动nmtui,选择你希望修改静态路由的接口,然后点击<编辑...>使用 nmtui 配置网络路由

  2. 现在,选择<编辑...>,位于IPv4 配置 - 路由条目旁边,输入你的路由信息。选择<确定>确认:使用 nmtui 配置网络路由

  3. 最后,点击<确定>以确认更改并保存。

第四章:配置你的新系统

这是我们将在本章中涵盖的所有配方概览:

  • systemd服务和设置运行级别

  • 启动和停止systemd服务

  • 配置systemd日志以实现持久化

  • 使用journalctl监控服务

  • 配置logrotate

  • 管理时间

  • 配置你的启动环境

  • 配置smtp

介绍

一旦你的系统安装完成并且网络配置好,就可以开始配置其他内容了。

RHEL 7 配备了systemd init守护进程,负责处理守护进程或服务的管理等任务,取代了旧的 SysV(UNIX System V)初始化系统。

它的主要优点是自动处理依赖关系、并行启动服务,并能够监控启动的服务并重启崩溃的服务。

要深入了解systemd及其内部工作原理,请访问n0where.net/understanding-systemd

systemd服务和设置运行级别

systemd服务不像 SysV 或 Upstart 那样使用运行级别。systemd的替代方案叫做目标(targets)。它们的目的是通过依赖链来组织一组systemd单元(不仅仅是服务,还包括套接字、设备等)。

如何操作……

使用systemd管理目标非常简单,如下所示:

  1. 列出所有目标单元,如下所示:

    ~]# systemctl list-unit-files --type target
    UNIT FILE                 STATE 
    anaconda.target           static 
    basic.target              static 
    bluetooth.target          static 
    cryptsetup.target         static 
    ctrl-alt-del.target       disabled
    default.target            enabled
    ...
    
    sysinit.target            static 
    system-update.target      static 
    time-sync.target          static 
    timers.target             static 
    umount.target             static 
    
    58 unit files listed.
    ~]#
    
    

    此列表显示所有可用的目标单元,并提供目标是否已启用的信息。

  2. 现在,显示当前加载的目标单元。

    systemd目标可以像 SysV 运行级别一样串联使用,因此你不仅会看到一个目标,还会看到一大堆目标,如下所示:

    ~]# systemctl list-units --type target
    UNIT                  LOAD   ACTIVE SUB    DESCRIPTION
    basic.target          loaded active active Basic System
    cryptsetup.target     loaded active active Encrypted Volumes
    getty.target          loaded active active Login Prompts
    local-fs-pre.target   loaded active active Local File Systems (Pre)
    local-fs.target       loaded active active Local File Systems
    multi-user.target     loaded active active Multi-User System
    network-online.target loaded active active Network is Online
    network.target        loaded active active Network
    nfs-client.target     loaded active active NFS client services
    paths.target          loaded active active Paths
    remote-fs-pre.target  loaded active active Remote File Systems (Pre)
    remote-fs.target      loaded active active Remote File Systems
    slices.target         loaded active active Slices
    sockets.target        loaded active active Sockets
    swap.target           loaded active active Swap
    sysinit.target        loaded active active System Initialization
    time-sync.target      loaded active active System Time Synchronized
    timers.target         loaded active active Timers
    
    LOAD   = Reflects whether the unit definition was properly loaded.
    ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
    SUB    = The low-level unit activation state, values depend on unit type.
    
    18 loaded units listed. Pass --all to see loaded but inactive units, too.
    To show all installed unit files use 'systemctl list-unit-files'.
    ~]#
    
    
  3. 接下来,通过运行以下命令更改默认的systemd目标:

    ~]# systemctl set-default graphical.target
    rm '/etc/systemd/system/default.target'
    ln -s '/usr/lib/systemd/system/graphical.target' '/etc/systemd/system/default.target'
    ~]#
    
    

还有更多内容……

有时,你可能希望像以前使用 runlevel 或 telinit 那样动态地更改目标。在systemd中,可以通过以下方式实现:

~]# systemctl isolate <target name>

这里是一个例子:

~]# systemctl isolate graphical.target

让我们通过以下表格概览以前的运行级别与systemd目标之间的关系:

运行级别 目标单元 描述
0 runlevel0.targetpoweroff.target 用于关闭并关闭系统电源
1 runlevel1.targetrescue.target 用于进入抢救模式外壳
2 runlevel2.targetmulti-user.target 用于设置命令行多用户系统
3 runlevel3.targetmulti-user.target 用于设置命令行多用户系统
4 runlevel4.targetmulti-user.target 用于设置命令行多用户系统
5 runlevel5.targetgraphical.target 用于设置图形化多用户系统
6 runlevel6.targetreboot.target 用于重启系统

另见

要了解有关 RHEL 7 和 systemd 目标的更多详细信息,请参考以下链接:access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/System_Administrators_Guide/sect-Managing_Services_with_systemd-Targets.html

启动和停止 systemd 服务

尽管这个示例使用的是服务的基本名称,但它们也可以通过完整的文件名来表示。例如,sshd可以替换为sshd.service

如何操作…

成功启动或停止systemd服务需要执行以下步骤:

  1. 列出所有可用的systemd服务,如下所示:

    ~]# systemctl list-unit-files --type service
    UNIT FILE                                   STATE 
    atd.service                                 enabled
    auditd.service                              enabled
    auth-rpcgss-module.service                  static 
    autovt@.service                             disabled
    avahi-daemon.service                        disabled
    blk-availability.service                    disabled
    brandbot.service                            static 
    
    ...
    
    systemd-udev-trigger.service                static 
    systemd-udevd.service                       static 
    systemd-update-utmp-runlevel.service        static 
    systemd-update-utmp.service                 static 
    systemd-user-sessions.service               static 
    systemd-vconsole-setup.service              static 
    tcsd.service                                disabled
    teamd@.service                              static 
    tuned.service                               enabled
    wpa_supplicant.service                      disabled
    xinetd.service                              enabled
    
    161 unit files listed.
    
    

    这将显示所有可用的服务单元,后面跟着关于服务是否启用的信息。

  2. 现在,列出所有已加载的systemd服务及其状态,如下所示:

    ~]# systemctl list-units --type service --all
    UNIT                        LOAD   ACTIVE   SUB     DESCRIPTION
    atd.service                 loaded active   running Job spooling tools
    auditd.service              loaded active   running Security Auditing Service
    auth-rpcgss-module.service  loaded inactive dead    Kernel Module supporting RPC
    brandbot.service            loaded inactive dead    Flexible Branding Service
    cpupower.service            loaded inactive dead    Configure CPU power related
    crond.service               loaded active   running Command Scheduler
    cups.service                loaded inactive dead    CUPS Printing Service
    dbus.service                loaded active   running D-Bus System Message Bus
    ...
    
    systemd-...es-setup.service loaded active   exited  Create Volatile Files and Di
    systemd-...-trigger.service loaded active   exited  udev Coldplug all Devices
    systemd-udevd.service       loaded active   running udev Kernel Device Manager
    systemd-update-utmp.service loaded active   exited  Update UTMP about System Reb
    systemd-...sessions.service loaded active   exited  Permit User Sessions
    systemd-...le-setup.service loaded active   exited  Setup Virtual Console
    tuned.service               loaded active   running Dynamic System Tuning Daemon
    xinetd.service              loaded active   running Xinetd A Powerful Replacemen
    LOAD   = Reflects whether the unit definition was properly loaded.
    ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
    SUB    = The low-level unit activation state, values depend on unit type.
    
    103 loaded units listed.
    To show all installed unit files use 'systemctl list-unit-files'.
    ~]#
    
    
  3. 接下来,获取服务的状态。

    要获取特定服务的状态,执行以下命令,将 <service> 替换为服务的名称:

    ~]# systemctl status <service>
    
    

    这里是一个示例:

    ~]# systemctl status sshd
    sshd.service - OpenSSH server daemon
     Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled)
     Active: active (running) since Fri 2015-07-17 09:13:55 CEST; 1 weeks 0 days ago
     Main PID: 11880 (sshd)
     CGroup: /system.slice/sshd.service
     └─11880 /usr/sbin/sshd -D
    
    Jul 22 12:07:31 rhel7.mydomain.lan sshd[10340]: Accepted publickey for root...
    Jul 22 12:12:29 rhel7.mydomain.lan sshd[10459]: Accepted publickey for root...
    Jul 22 12:13:33 rhel7.mydomain.lan sshd[10473]: Accepted publickey for root...
    Jul 24 21:27:24 rhel7.mydomain.lan sshd[28089]: Accepted publickey for root...
    Hint: Some lines were ellipsized, use -l to show in full.
    ~]#
    
    
  4. 现在,启动和停止systemd服务。

    要停止systemd服务,执行以下命令,将 <service> 替换为服务的名称:

    ~]# systemctl stop <service>
    
    

    这里是一个示例:

    ~]# systemctl stop sshd
    
    

    要启动systemd服务,执行以下命令,将 <service> 替换为服务的名称:

    ~]# systemctl start <service>
    
    

    这里是一个示例:

    ~]# systemctl start sshd
    
    
  5. 接下来,启用和禁用systemd服务。

    要启用systemd服务,执行以下命令,将 <service> 替换为服务的名称:

    ~]# systemctl enable <service>
    
    

    这里是一个示例:

    ~]# systemctl enable sshd
    ln -s '/usr/lib/systemd/system/sshd.service' '/etc/systemd/system/multi-user.target.wants/sshd.service'
    ~]#
    
    

    要禁用systemd服务,执行以下命令,将 <service> 替换为服务的名称:

    ~]# systemctl disable <service>
    
    

    这里是一个示例:

    ~]# systemctl disable sshd
    rm '/etc/systemd/system/multi-user.target.wants/sshd.service'
    ~]#
    
    
  6. 现在,配置服务在崩溃时重新启动。

    如果ntpd服务在 1 分钟后崩溃,让我们使其重新启动。

    1. 首先,创建目录,如下所示:/etc/systemd/system/ntpd.service.d

      ~]# mkdir -p /etc/systemd/system/ntpd.service.d
      
      
    2. 在该目录中创建一个名为restart.conf的新文件,并将以下内容添加到文件中:

      [Service]
      Restart=on-failure
      RestartSec=60s
      
    3. 接下来,使用以下命令重新加载单元文件并重新创建依赖关系树:

      ~]# systemctl daemon-reload
      
      
    4. 最后,执行以下命令重启ntpd服务:

      ~]# systemctl restart ntpd
      
      

还有更多…

当请求服务的状态时,如果以 root 身份执行,还会显示最新的日志条目。

以下表格可以查看服务状态信息:

字段 描述
Loaded 提供关于服务是否已加载和启用的信息,还包括服务文件的绝对路径。
Active 提供服务是否正在运行的信息,后面跟着服务启动的时间。
Main PID 提供相应服务的 PID,后面跟着服务的名称。
Status 提供有关相应服务的信息。
Process 提供关于相关进程的信息。
Cgroup 提供关于相关控制组的信息。

在某些(罕见)情况下,您可能希望防止某个服务启动,无论是手动启动还是由另一个服务启动;可以通过以下方式屏蔽该服务:

~]# systemctl mask <service>

要取消屏蔽,请执行以下命令:

~]# systemctl unmask <service>

修改服务单元文件时(这不仅限于服务),最佳实践是复制原始服务文件,该文件位于 /lib/systemd/system,然后将其放到 /etc/systemd/service。或者,您可以在 /etc/systemd/service 中创建一个以 .d 结尾的目录,在其中创建包含您希望添加或更改的指令的 conf 文件,如上例所示。后者的优点是,您无需跟踪原始服务文件的更改,因为它会与 service.d 目录中的内容“同步”更新。

另见

有关管理 systemd 服务的更多信息,请访问 access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/System_Administrators_Guide/sect-Managing_Services_with_systemd-Services.html

配置 systemd 日志以实现持久化

默认情况下,日志不会存储在磁盘上,只会保存在内存或 /run/log/journal 目录中。这对于最近的日志历史(使用日志)是足够的,但如果您决定只使用日志而不使用其他 syslog 解决方案,则不足以进行长期日志保留。

如何操作…

配置 journald 保留比内存允许的更多日志非常简单,如下所示:

  1. 使用 root 权限通过以下命令打开 /etc/systemd/journald.conf 文件,使用您喜欢的文本编辑器:

    ~]# vim /etc/systemd/journald.conf
    
    
  2. 确保包含 Storage 的行被注释掉或设置为 autopersistent,并保存,示例如下:

    Storage=auto
    
  3. 如果选择 auto,日志目录需要手动创建。以下命令可以帮助完成此操作:

    ~]# mkdir -p /var/log/journal
    
    
  4. 现在,执行以下命令重启日志服务:

    ~]# systemctl restart systemd-journald
    
    

还有更多内容…

还有许多其他选项可以为日志守护进程设置。

默认情况下,journald 存储的所有数据都是压缩的,但您可以通过设置 Compress=no 来禁用此功能。

建议通过指定最大保留时间(MaxRetentionSec)、全局最大大小使用(SystemMaxUse)或每个文件的最大大小使用(SystemMaxFileSize)来限制日志文件的大小。

另见

有关在 RHEL 7 中使用日志的更多信息,请访问 access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/System_Administrators_Guide/s1-Using_the_Journal.html

查看 journald (5) 的手册页,了解更多可以配置的内容。

使用 journalctl 监控服务

Systemd 的日志有一个额外的优点,它的控制选项允许你轻松缩小范围,只查看由特定服务生成的消息。

如何操作……

这是你在此食谱中需要执行的步骤:

  1. 首先,显示系统生成的所有消息。

    这将显示系统上生成的所有消息;运行以下命令:

    ~]# journalctl
    -- Logs begin at Fri 2015-06-26 23:37:30 CEST, end at Sat 2015-07-25 00:30:01 CEST. --
    Jun 26 23:37:30 rhel7.mydomain.lan systemd-journal[106]: Runtime journal is using 8.0M (max 396.0M, leaving 594.0M of free 3.8G, current limit 396.0M).
    Jun 26 23:37:30 rhel7.mydomain.lan systemd-journal[106]: Runtime journal is using 8.0M (max 396.0M, leaving 594.0M of free 3.8G, current limit 396.0M).
    Jun 26 23:37:30 rhel7.mydomain.lan kernel: Initializing cgroup subsys cpuset
    ...
    ~]#
    
    
  2. 现在,显示所有与系统相关的消息。

    此命令显示与系统相关的所有消息,而不包括用户相关的消息:

    ~]# journalctl –-system
    -- Logs begin at Fri 2015-06-26 23:37:30 CEST, end at Sat 2015-07-25 00:30:01 CEST. --
    Jun 26 23:37:30 rhel7.mydomain.lan systemd-journal[106]: Runtime journal is using 8.0M (max 396.0M, leaving 594.0M of free 3.8G, current limit 396.0M).
    Jun 26 23:37:30 rhel7.mydomain.lan systemd-journal[106]: Runtime journal is using 8.0M (max 396.0M, leaving 594.0M of free 3.8G, current limit 396.0M).
    Jun 26 23:37:30 rhel7.mydomain.lan kernel: Initializing cgroup subsys cpuset
    ...
    ~]#
    
    
  3. 显示当前用户的所有消息。

    此命令显示与你登录的用户相关的所有消息:

    ~]# journalctl --user
    No journal files were found.
    ~]#
    
    
  4. 接下来,使用以下命令行显示由特定服务生成的所有消息:

    ~]# journalctl --unit=<service>
    
    

    以下是一个示例:

    ~]# journalctl --unit=sshd
    -- Logs begin at Fri 2015-06-26 23:37:30 CEST, end at Sat 2015-07-25 00:45:01 CEST. --
    Jun 26 23:40:18 rhel7.mydomain.lan systemd[1]: Starting OpenSSH server daemon...
    Jun 26 23:40:18 rhel7.mydomain.lan systemd[1]: Started OpenSSH server daemon.
    Jun 26 23:40:20 rhel7.mydomain.lan sshd[817]: Server listening on 0.0.0.0 port 22.
    Jun 26 23:40:20 rhel7.mydomain.lan sshd[817]: Server listening on :: port 22.
    Jun 27 11:30:08 rhel7.mydomain.lan sshd[4495]: Accepted publickey for root from 10.0.0.2 port 42748 ssh2: RSA cf:8a:a0:b4:4c:3d:d7:4d:93:c6:e0:fe:c0:66:e4
    ...
    ~]#
    
    
  5. 现在,按优先级显示消息。

    可以通过关键字或数字指定优先级,例如 debug (7)、info (6)、notice (5)、warning (4)、err (3)、crit (2)、alert (1) 和 emerg (0)。指定优先级时,这也包括所有更低的优先级。例如,err 表示 critalertemerg 也会显示。看看以下命令行:

    ~]# journalctl -p <priority>
    
    

    以下是一个示例:

    ~]# journalctl -p err
    -- Logs begin at Fri 2015-06-26 23:37:30 CEST, end at Fri 2015-07-24 22:30:01 CEST. --
    Jun 26 23:37:30 rhel7.mydomain.lan kernel: ioremap error for 0xdffff000-0xe0000000, requested 0x10, got 0x0
    Jun 26 23:38:49 rhel7.mydomain.lan systemd[1]: Failed unmounting /usr.
    ...
    ~]#
    
    
  6. 接下来,按时间显示消息。

    你可以通过以下命令显示从当前启动以来的所有消息:

    ~]# journalctl -b
    -- Logs begin at Fri 2015-06-26 23:37:30 CEST, end at Sat 2015-07-25 00:45:01 CEST. --
    Jun 26 23:37:30 rhel7.mydomain.lan systemd-journal[106]: Runtime journal is using 8.0M (max 396.0M, leaving 594.0M of free 3.8G, current limit 396.0M).
    Jun 26 23:37:30 rhel7.mydomain.lan systemd-journal[106]: Runtime journal is using 8.0M (max 396.0M, leaving 594.0M of free 3.8G, current limit 396.0M).
    Jun 26 23:37:30 rhel7.mydomain.lan kernel: Initializing cgroup subsys cpuset
    Jun 26 23:37:30 rhel7.mydomain.lan kernel: Initializing cgroup subsys cpu
    Jun 26 23:37:30 rhel7.mydomain.lan kernel: Initializing cgroup subsys cpuacct
    Jun 26 23:37:30 rhel7.mydomain.lan kernel: Linux version 3.10.0-229.4.2.el7.x86_64 (gcc version 4.8.2 20140120 (Red Hat 4.8.2-
    Jun 26 23:37:30 rhel7.mydomain.lan kernel: Command line: BOOT_IMAGE=/vmlinuz-3.10.0-229.4.2.el7.x86_64 root=/dev/mapper/rhel7_system-root ro vconsole.keymap=
    Jun 26 23:37:30 rhel7.mydomain.lan kernel: e820: BIOS-provided physical RAM map:
    ~]# 
    
    

    你甚至可以通过运行以下命令,显示特定时间范围内的所有消息:

    ~]# journalctl --since="2015-07-24 08:00:00" --until="2015-07-24 09:00:00"
    -- Logs begin at Fri 2015-06-26 23:37:30 CEST, end at Sat 2015-07-25 00:45:01 CEST. --
    Jul 24 08:00:01 rhel7.mydomain.lan systemd[1]: Created slice user-48.slice.
    Jul 24 08:00:01 rhel7.mydomain.lan systemd[1]: Starting Session 3331 of user apache.
    J
    ...
    Jul 24 08:45:01 rhel7.mydomain.lan systemd[1]: Starting Session 3335 of user apache.
    Jul 24 08:45:01 rhel7.mydomain.lan systemd[1]: Started Session 3335 of user apache.
    Jul 24 08:45:01 rhel7.mydomain.lan CROND[22909]: (apache) CMD (php -f /var/lib/owncloud/cron.php)
    ~]#
    
    

还有更多内容……

本食谱中的示例都可以组合使用。例如,如果你想显示 2015-07-24 8:00 到 9:00 之间的所有错误消息,你的命令将是:

~]# journalctl -p err --since="2015-07-24 08:00:00" --until="2015-07-24 09:00:00"

很多人倾向于“跟踪”日志文件,以确定发生了什么,试图找出任何问题。journalctl 是一个可执行文件,因此无法使用传统的“跟踪”技术,如 tail -f 或使用 less 并按 CTRL + F。编写 systemdsystemctl 的好心人提供了一个解决方案:只需在 journalctl 命令中添加 -f--follow 参数。

尽管大多数环境习惯于创建 syslog 消息来进行故障排除,但日志系统提供了额外的价值,它能创建简单的过滤器,让你实时监控消息。

另见

关于在 RHEL 7 中使用日志系统的更多信息,请访问 access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/System_Administrators_Guide/s1-Using_the_Journal.html

查看 journalctl (1) 的手册页,了解可以配置的更多信息。

配置 logrotate

logrotate 工具允许你旋转由应用程序和脚本生成的日志文件。

它能保持你的日志目录整洁,并在正确配置时最小化磁盘使用。

如何操作……

logrotate 工具默认已安装,但为了完整性,我将包括安装说明。此教程将向你展示如何为 rsyslog 轮换日志。我们将每日轮换日志,基于日期添加扩展名,延迟一天压缩,并将其保存 365 天。请执行以下步骤:

  1. 首先,安装 logrotate,请执行以下命令:

    ~]# yum install -y logrotate
    
    
  2. 确保通过以下方式启用:

    ~]# systemctl restart crond
    
    
  3. 使用你喜欢的编辑器打开 /etc/logrotate.d/syslog。默认情况下,这个文件的内容如下:

    /var/log/cron
    /var/log/maillog
    /var/log/messages
    /var/log/secure
    /var/log/spooler
    {
        sharedscripts
        postrotate
            /bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true
        endscript
    }
    
  4. 现在,将其替换为以下代码:

    /var/log/cron
    /var/log/maillog
    /var/log/messages
    /var/log/secure
    /var/log/spooler
    {
        compress
        daily
        delaycompress
        dateext
        missingok
        rotate 365
        sharedscripts
        postrotate
            /bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true
        endscript
    }
    
  5. 最后,保存文件。

它是如何工作的…

logrotate 工具是一个由 cron 每天启动的脚本。

默认的 logrotate 定义中添加的指令有 compressdailydelaycompressdateextmissingokrotate

compress 指令使用 gzip 压缩旧版本的日志文件。通过指定 delaycompress,这种行为有所变化。这样可以确保我们始终能够得到最新的轮换日志文件且未压缩。

daily 指令使得 logrotate 每天执行一次定义。rotate 指令在删除最旧的日志文件之前,只保留 x 个已轮换的日志文件。在此例中,我们将其指定为 365,意味着在每日轮换的同时,日志文件将保留 365 天。

missingok 指令允许 syslog 不创建文件,虽然这种情况很少发生,但它是可能的。

dateext 指令将日期以 yyyymmdd 格式附加到轮换文件上,而不是默认的数字形式。

还有更多…

/etc/logrotate.conf 文件包含了所有定义的默认指令。如果在文件定义中没有特别使用某个指令,则会使用此文件中指定的值(如果有)。

修改此文件中的设置使所有定义都受影响是有意义的,但这并不实际;并非所有日志文件都相同。syslog 服务会生成大量消息,可能会很快让你的系统变得杂乱无章。然而,像 yum 这样的服务并不会生成很多消息,它可以保持日志文件的可读性,远比 syslog 文件长时间有效。顺便提一下,这在 yum 的定义中有所体现。

如果你想调试新的配置,可以通过执行以下命令测试单个配置:

~# /usr/sbin/logrotate -v /etc/logrotate.d/<config file>

或者,你可以使用以下命令测试所有配置:

~]# /usr/sbin/logrotate -v /etc/logrotate.conf

这是一个示例:

~]# /usr/sbin/logrotate -v /etc/logrotate.d/syslog
reading config file /etc/logrotate.d/syslog

Handling 1 logs

rotating pattern: /var/log/cron
/var/log/maillog
/var/log/messages
/var/log/secure
/var/log/spooler
 1048576 bytes (no old logs will be kept)
empty log files are rotated, old logs are removed
considering log /var/log/cron
 log does not need rotating
considering log /var/log/maillog
 log does not need rotating
considering log /var/log/messages
 log does not need rotating
considering log /var/log/secure
 log does not need rotating
considering log /var/log/spooler
 log does not need rotating
not running postrotate script, since no logs were rotated
~]#

另见

查看 logrotate (8) 的手册页,了解更多关于配置 logrotate 的信息。

管理时间

RHEL 7 默认安装了 Chrony。虽然每个人都知道 Ntpd,但 Chrony 是时间同步领域的“新手”。

Chrony 是一套程序,通过使用不同的时间源(如 NTP 服务器、系统时钟,甚至是自定义脚本/程序)来保持计算机的时间。它还会计算计算机丧失或增加时间的速率,以便在没有外部参考的情况下进行补偿——例如,如果你的 NTP 服务器出现故障。

Chrony 是一个适合那些间歇性断开和重新连接到网络的系统的好解决方案。

对于通常长时间保持开启的系统,应考虑使用ntpd

如何操作…

在谈到 RHEL 中管理时间时,可以通过以下方式进行:

  • Chrony

  • Ntpd

我们将分别查看每种方法。

通过chrony管理时间

确保已安装并启用chrony,并执行以下步骤:

  1. 首先,通过以下命令安装chrony

    ~]# yum install -y chrony
    
    
  2. 启用chrony,如下所示:

    ~]# systemctl enable chrony
    ~]# systemctl start chrony
    
    
  3. 现在,使用你喜欢的编辑器打开/etc/chrony.conf,并使用以下命令查找以server指令开头的行:

    server 0.rhel.pool.ntp.org iburst
    server 1.rhel.pool.ntp.org iburst
    server 2.rhel.pool.ntp.org iburst
    server 3.rhel.pool.ntp.org iburst
    
  4. 接下来,用你附近的 NTP 服务器替换这些行并保存文件:

    server 0.pool.ntp.mydomain.lan iburst
    server 1.pool.ntp.mydomain.lan iburst
    

    iburst选项会使 NTP 在下次轮询时发送八个数据包,而不是仅发送一个,如果时间主服务器不可用,从而加快 NTP 守护进程的时间同步速度。

  5. 最后,通过执行以下命令重新启动chrony

    ~]# systemctl restart chrony
    
    

通过ntpd管理时间

确保已安装并启用ntpd,并执行以下步骤:

  1. 首先,通过以下命令安装ntpd

    ~]# yum install -y ntpd
    
    
  2. 通过以下命令启用ntpd

    ~]# systemctl enable ntpd
    
    
  3. 使用你喜欢的编辑器打开/etc/ntp.conf,并查找以server指令开头的行。运行以下命令:

    server 0.rhel.pool.ntp.org iburst
    server 1.rhel.pool.ntp.org iburst
    server 2.rhel.pool.ntp.org iburst
    server 3.rhel.pool.ntp.org iburst
    
  4. 用你附近的 NTP 服务器替换这些行并保存文件:

    server 0.pool.ntp.mydomain.lan iburst
    server 1.pool.ntp.mydomain.lan iburst
    
  5. 用你的所有 NTP 服务器替换/etc/ntp/step-tickers文件的内容,每行一个:

    0.pool.ntp.mydomain.lan
    1.pool.ntp.mydomain.lan
    
  6. 现在,通过执行以下命令重新启动ntpd

    ~]# systemctl restart ntpd
    
    

还有更多内容…

虽然ntpd是时间同步的明显选择,但它在时间主服务器间歇性可访问的环境中表现不佳(无论什么原因)。在这些环境中,chronyd表现优异。而且,ntpd的配置较为复杂,而chronyd稍微简单一些。

在使用ntpd文件时修改/etc/ntp/step-tickers的原因是为了服务的启动。它使用ntpdate在实际启动 NTP 守护进程之前进行一次同步,这比 NTP 守护进程本身同步时间要快。

要检查你的系统是否已同步,可以使用以下命令:

  • 对于chrony,使用以下命令:

    ~]# chronyc sources
    
    
  • 对于ntpd,运行以下命令:

    ~]# ntpq -p
    
    

你的输出将类似于:

remote       refid      st t when poll reach   delay   offset  jitter
=====================================================================
 LOCAL(0)    .LOCL.      5 l  60m   64    0    0.000    0.000   0.000
*master.exam 178.32.44.208 3 u  35 128 377     0.214   -0.651  14.285

在条目前面的星号(*)表示你的系统与该远程系统的时钟已同步。

另请参见

有关如何为 RHEL 7 配置chrony的更多信息,请访问access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/System_Administrators_Guide/ch-Configuring_NTP_Using_the_chrony_Suite.html

有关如何为 RHEL 7 配置ntpd的更多信息,请访问access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/System_Administrators_Guide/ch-Configuring_NTP_Using_ntpd.html

配置你的启动环境

GRUB2 是 RHEL 7 的默认引导加载程序。默认情况下,它不使用任何复杂的配置选项,但至少保护你的 grub 引导加载程序是明智的。

如何操作…

在企业环境中,将 grub 和启动环境输出到串口控制台有许多优点。许多供应商在他们的远程控制系统中集成了虚拟串口,KVM 也不例外。这允许你连接到串口,并轻松地获取在文本编辑器中显示的内容。

在 GRUB2 引导加载程序上设置密码可以减轻当物理访问服务器或控制台时可能发生的黑客攻击。请按照以下步骤进行此操作:

  1. 首先,使用你喜欢的编辑器编辑/etc/sysconfig/grub文件。

  2. 现在,通过执行以下命令行,修改GRUB_TERMINAL_OUTPUT行,以同时包括控制台和串口访问:

    GRUB_TERMINAL_OUTPUT="console serial"
    
  3. 添加GRUB_SERIAL_COMMAND条目,如下所示:

    GRUB_SERIAL_COMMAND="serial --speed=9600 --unit=0 --word=8 --parity=no –stop=1"
    
  4. 现在,保存文件。

  5. 创建/etc/grub.d/01_users文件,内容如下:

    cat << EOF
    set superusers="root"
    password root SuperSecretPassword
    EOF
    
    
  6. 接下来,通过运行以下命令来更新你的grub配置:

    ~]# grub2-mkconfig -o /boot/grub2/grub.cfg
    Generating grub configuration file ...
    Found linux image: /boot/vmlinuz-3.10.0-229.4.2.el7.x86_64
    Found initrd image: /boot/initramfs-3.10.0-229.4.2.el7.x86_64.img
    Found linux image: /boot/vmlinuz-3.10.0-229.1.2.el7.x86_64
    Found initrd image: /boot/initramfs-3.10.0-229.1.2.el7.x86_64.img
    Found linux image: /boot/vmlinuz-0-rescue-fe045089e49942cb97db675892395bc8
    Found initrd image: /boot/initramfs-0-rescue-fe045089e49942cb97db675892395bc8.img
    done
    ~]#
    
    

它是如何工作的…

grub2-mkconfig的行为由/etc/grub.d中的文件指令定义。这些文件基于/etc/sysconfig/grub中的配置,自动生成grub.cfg文件中的所有菜单项。你可以通过在此目录中添加包含 bash 代码的文件来修改其行为。

例如,你可以添加一个脚本,用于将一个菜单项添加到从 CD/DVD ROM 驱动器启动。

被添加到/etc/grub.d/01_users中的用户 root 是唯一被允许从控制台编辑菜单项的用户,这可以缓解 GRUB 的弱点,即通过在kernel行的末尾添加1rescue来强制进入恢复模式。

还有更多内容……

grub2-mkconfig命令是特定于 BIOS 系统的。为了在 UEFI 系统上执行相同操作,请按如下方式修改命令:

~]# grub2-mkconfig -o /boot/efi/EFI/redhat/grub.cfg

为了通过相同的串口连接访问 GRUB 终端,你需要指定一个额外的内核选项:console=ttyS0,9600n8

你可以修改/boot/grub2/grub.cfg中的内核行(或者手动修改/boot/efi/EFI/redhat/grub.cfg,但你有可能在内核更新时丢失更改),或者使用grub2-mkconfig手动重新生成文件。

最好将其添加到/etc/sysconfig/grub中的GRUB_CMDLINE_LINUX指令,并重新生成grub.cfg文件。

GRUB 用户的密码可以使用grub2-mkpasswd-pbkdf2命令进行加密,如下所示:

~]# grub2-mkpasswd-pbkdf2
Enter password:
Reenter password:
PBKDF2 hash of your password is grub.pbkdf2.sha512.10000.C208DD5E318B1D6477C4E51035649C197411259C214D0B83E3E83753AD58F7676B62CDF48E31AF0E739844A5CF9A95F76AF5008AF340336DB50ECA23906ECC13.9D20A66F0CADA12AA617B293B5BBF7AAD44423ECA513F302FEBF5CB92A0DC54436E16D7CD6E09685323084A27462C2A981054D52F452F5C2F71FBACD2C31AEFA
~]#

然后,你可以将/etc/grub.d/01_users中的明文密码替换为生成的哈希值。以下是一个示例:

password root grub.pbkdf2.sha512.10000.C208DD5E318B1D6477C4E51035649C197411259C214D0B83E3E83753AD58F7676B62CDF48E31AF0E739844A5CF9A95F76AF5008AF340336DB50ECA23906ECC13.9D20A66F0CADA12AA617B293B5BBF7AAD44423ECA513F302FEBF5CB92A0DC54436E16D7CD6E09685323084A27462C2A981054D52F452F5C2F71FBACD2C31AEFA

所有自动生成的条目都是可引导的,但不能从控制台编辑,除非你知道用户名和密码。如果你有自定义菜单条目并希望以类似方式保护它们,可以在菜单条目定义之前加上--unrestricted。以下是一个示例:

menuentry 'My custom grub boot entry' <options> --unrestricted {

另见

有关使用 GRUB2 引导加载程序的更多信息,请访问access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/System_Administrators_Guide/ch-Working_with_the_GRUB_2_Boot_Loader.html

配置 smtp

许多程序使用(或可以配置为使用)SMTP 来发送关于其状态等的消息。默认情况下,Postfix 配置为将所有消息本地发送,并且不响应传入邮件。如果你的环境中有多个服务器,那么每次都登录到每个服务器检查新邮件可能会变得非常麻烦。本教程将展示如何将邮件转发到使用 SMTP 的中央邮件中继或消息存储。

在 RHEL 7 上,Postfix 默认已安装。

如何操作…

在这个教程中,我们将结合多个选项:

  • 我们将允许服务器接受传入邮件。

  • 我们只允许服务器转发来自mydomain.lan域的收件人的邮件。

  • 我们将所有邮件转发到mailhost.mydomain.lan邮件服务器。

完成此教程,请执行以下步骤:

  1. 使用你喜欢的编辑器编辑/etc/postfix/main.cf文件。

  2. 修改inet_interface,通过以下命令使邮件能够在任何接口上接受:

    inet_interface = all
    
  3. smtpd_recipient_restrictions指令添加到配置文件中,仅允许来自mydomain.lan域的传入邮件,如下所示:

    smtpd_recipient_restrictions =
        check_sender_access hash:/etc/postfix/sender_access,
        reject
    

    如你所见,最后两行是缩进的。postfix会将这个块视为一行,而不是三行。

  4. relayhost指令添加到配置文件中,指向mailhost.mydomain.lan,如下所示:

    relayhost = mailhost.mydomain.lan
    
  5. 现在,保存postfix文件。

  6. 创建/etc/postfix/sender_access并添加以下内容:

    mydomain.lan OK
    
  7. 接下来,使用以下命令对/etc/postfix/access文件进行哈希处理:

    ~]# postmap /etc/postfix/access
    
    
  8. 最后,按如下方式重新启动postfix

    ~]# systemctl restart postfix
    
    

还有更多…

要监控系统上的邮件队列,请执行以下命令:

~]# postqueue -p

当你的邮件中继无法转发邮件时,它会将邮件存储在本地,并尝试稍后重新发送。恢复邮件流后,你可以通过执行以下操作来刷新队列并尝试投递:

~]# postqueue -f

本文档中展示的设置非常简单,假设你的网络中没有恶意用户。有一些软件可以帮助你减少垃圾邮件和病毒。常见的解决方案包括 spamassassinamavis

另请参见

有关在 RHEL 7 中使用 postfix 的更多信息,请访问 access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/System_Administrators_Guide/s1-email-mta.html#s2-email-mta-postfix

有关 postfix 的更多信息,请查看 postfix rpm(rpm -ql postfix)或访问 www.postfix.org/。该站点提供了良好的文档和如何做指南,涵盖了大量场景。

第五章:使用 SELinux

本章介绍的配方概览:

  • 更改文件上下文

  • 配置 SELinux 布尔值

  • 配置 SELinux 端口定义

  • 排错 SELinux

  • 创建 SELinux 策略

  • 应用 SELinux 策略

简介

SELinux 是一个 Linux 内核模块,支持 强制访问控制(MAC)安全策略。Red Hat 对 SELinux 的实现将 基于角色的访问控制RBAC)与 类型强制TE)相结合。可选地,多级安全MLS)也可以使用,但它并不广泛应用,因为它实现的策略比默认的 Red Hat SELinux 策略少。

SELinux 在 RHEL 7 中默认启用,并且支持所有由 Red Hat 打包的软件。

本章中的配方不仅会为您提供一个坚实的基础,以便排查 SELinux 问题并解决它们,还将带您一窥如何创建您自己的 SELinux 策略。

更改文件上下文

文件和进程会被标记上 SELinux 上下文,其中包含有关 SELinux 用户、角色类型和级别的附加信息。这些信息由 SELinux 内核模块提供,用于做出访问控制决策。

SELinux 用户是一个在 SELinux 策略中已知的唯一身份,并且被授权担任多个角色。

如前所述,SELinux 角色是 SELinux 用户的属性,并且是 RBAC SELinux 策略的一部分。SELinux 角色被授权用于 SELinux 域。

SELinux 类型定义了文件的类型和进程的域。SELinux 策略定义了类型与其他文件和进程之间的访问。默认情况下,如果 SELinux 策略中没有特定规则,访问会被拒绝。

SELinux 级别仅在 SELinux 类型设置为 MLS 时使用,且应避免在除服务器之外的任何设备上使用。这套策略不覆盖与默认 Red Hat SELinux 策略中定义的相同的域。SELinux 级别是 MLS 和 多类别安全MCS)的属性。

准备工作

系统上的所有文件和进程都被标记上用于表示安全相关信息的标签,这些信息被称为 SELinux 上下文。要查看文件(和目录)的上下文,请执行以下命令:

~# ls -Z
-rw-r--r--. root root unconfined_u:object_r:admin_home_t:s0 file
~#

如何操作……

您可以暂时更改文件(或多个文件)的上下文,也可以永久更改它们的上下文。第一个选项允许在需要确定更改上下文是否解决问题时进行轻松排错。持久性更改通常用于当您的应用程序引用不在标准位置的数据时——例如,如果您的 Web 服务器从 /srv/www 提供数据。

临时上下文更改

临时 SELinux 上下文更改将在文件或文件所在的文件系统重新标记时失效。

要更改文件的 SELinux 用户,请执行以下命令:

~# chcon --user <SELinux user> <filename>

要更改文件的 SELinux 角色,请执行以下命令:

~# chcon --role <SELinux role> <filename>

要更改文件的 SELinux 类型,请执行以下命令:

~# chcon --type <SELinux typs> <filename>

持久文件上下文更改

改变应用程序数据位置不会自动修改 SELinux 上下文,以允许你的应用程序访问这些数据。

要永久重新标记文件或目录,请执行以下操作:

  1. 通过此命令更改文件或目录的 SELinux 用户:

    ~# semanage fcontext -a --seuser <SELinux user> <filename|dirname>
    
    
  2. 通过运行以下命令更改文件或目录的 SELinux 类型:

    ~# semanage fcontext -a --type <SELinux type> <filename|dirname>
    
    
  3. 使用此命令行并应用指令到 files/directories

    ~# restorecon <filename|dirname>
    
    

还有更多内容…

要显示所有可用的 SELinux 用户,请执行以下命令:

~# semanage user -l

更多内容…

或者,你可以安装 setools-console 包并运行以下命令:

~# seinfo -u

更多内容…

要显示所有可用的 SELinux 类型,请安装 setools-console 包并运行以下命令:

~# seinfo -t

更多内容…

要显示可用的 SELinux 角色,请安装 setools-console 包并运行以下命令:

~# seinfo -r

更多内容…

semanage 工具没有包含所有文件递归操作的选项,但有一种解决方法。你指定的文件名或目录名实际上是一个正则表达式过滤器。例如,如果你想递归包含 /srv/www 中的所有文件,你可以指定 "/srv/www(/.*)?"

提示

目前,无法通过 semanage 更改 SELinux 角色。解决方法是通过 semanage 更改 SELinux 用户或类型,然后进行编辑,方法如下:/etc/selinux/targeted/contexts/files/file_contexts.local

以下是 audit.log 文件中找到的一个错误的 SELinux 上下文示例,涉及 AVC 拒绝报告:

type=AVC msg=audit(1438884962.645:86): avc:  denied  { open } for  pid=1283 comm="httpd" path="/var/www/html/index.html" dev="dm-5" ino=1089 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:user_home_t:s0 tclass=file

该命令可以解释如下:

命令 描述
type=AVC 这是日志类型
msg=audit(1438884962.645:86) 这是日志条目的时间戳
avc 这是日志类型的重复
denied 该字段表示是否启用了强制执行
{ open } 这是导致 AVC 拒绝的权限
for pid=1283 这是进程 ID
comm="httpd" 这是进程命令
path="/var/www/html/index.html" 这是被访问的路径
dev="dm-5" 这是阻止前述文件所在设备的设备
ino=1089 这是前述文件的 inode
scontext=system_u:system_r:httpd_t:s0 这是源 SELinux 上下文
tcontext=system_u:object_r:user_home_t:s0 这是目标 SELinux 上下文
tclass=file 这是目标 SELinux 类

另见

有关更多信息,请参考 chcon (1)semanage-fcontext (8) 的手册页。

配置 SELinux 布尔值

SELinux 布尔值允许你在运行时更改 SELinux 策略,无需编写额外的策略。这使你可以在无需重新编译的情况下更改策略,例如允许服务访问 NFS 卷。

如何操作…

这是临时或永久更改 SELinux 布尔值的方法。

列出 SELinux 布尔值

要获取所有布尔值及其作用的列表,请执行以下命令:

~# semanage boolean -l

列出 SELinux 布尔值

现在,让我们尝试获取特定 SELinux 布尔值的值。无需使用其他工具,如 grepawk,即可获取单个 SELinux 布尔值的值。只需执行以下命令:

~# getsebool <SELinux boolean>

这将显示布尔值是否已设置。以下是一个示例:

~# getsebool virt_use_nfs
virt_use_nfs --> off
~#

更改 SELinux 布尔值

要将布尔值设置为特定值,请使用以下命令:

~# setsebool <SELinux boolean> <on|off>

以下是一个示例命令:

~# setsebool virt_use_nfs on

该命令允许您更改布尔值的值,但在重启后不会保留。如果希望保持更改,添加 -P 选项到命令行,如下所示:

~# setsebool -P virt_use_nfs on

还有更多…

如果您希望查看所有 SELinux 布尔值及其值的列表,getsebool -a 是一种替代方法,如下所示:

~# getsebool -a

更多…

管理 SELinux 布尔值可能相当复杂,因为有很多布尔值,并且它们的名称并不总是容易记住。因此,setseboolgetseboolsemanage 工具都支持 Tab 键自动补全。因此,每当您输入布尔值名称时,您可以使用 tab 键完成或显示可能的选项。

这是一个在 audit.log 文件中找到的 AVC 拒绝报告示例,通过启用布尔值可以解决该问题:

type=AVC msg=audit(1438884483.053:48): avc:  denied  { open } for  pid=1270 comm="httpd" path="/nfs/www/html/index.html" dev="0:38" ino=2717909250 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:nfs_t:s0 tclass=file

这是一个服务(此处为 httpd)访问位于 NFS 共享上的文件的示例,默认情况下此操作被禁用。

通过将 httpd_use_nfs 布尔值设置为 "on" 可以允许此操作。

配置 SELinux 端口定义

SELinux 还控制对 TCP/IP 端口的访问。如果您的应用程序受到 SELinux 限制,它在启动时也会拒绝访问您的端口。

本教程将展示如何检测特定 SELinux 类型使用的端口并进行更改。

如何操作…

让我们通过以下步骤允许 HTTP 守护进程在非标准端口 82 上监听:

  1. 首先,通过以下命令查找 HTTP 访问的端口:

    ~# 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
    pegasus_http_port_t            tcp      5988
    pegasus_https_port_t           tcp      5989
    ~#
    
    

    我们要查找的 SELinux 端口分配是 http_port_t。如您所见,只有显示的端口(80814434888008800984439000)被允许用于任何被允许使用 http_port_t 类型的进程进行监听。

  2. 将端口 82 添加到允许的端口列表中,如下所示:

    ~# semanage port -a -t http_port_t -p tcp 82
    ~#
    
    
  3. 接下来,验证端口分配,如下所示:

    ~# semanage port -l |grep ^http_port_t
    http_port_t                    tcp      82, 80, 81, 443, 488, 8008, 8009, 8443, 9000
    ~#
    
    

还有更多…

在这个示例中,提到 HTTP 守护进程,因为 SELinux 策略不仅适用于 Apache Web 服务器,还适用于 Nginx。因此,只要您使用的是 Red Hat 提供的包,SELinux 策略将被正确使用。

请查看以下在 audit.log 文件中找到的 AVC 拒绝报告示例,该报告表明由于域不被允许访问某个端口而导致问题:

type=AVC msg=audit(1225948455.061:294): avc: denied { name_bind } for pid=4997 comm="httpd" src=82 scontext=unconfined_u:system_r:httpd_t:s0 tcontext=system_u:object_r:port_t:s0 tclass=tcp_socket

该 AVC 拒绝显示 httpd 守护进程尝试在端口 82 上监听(name_bind),但被 SELinux 阻止。

SELinux 故障排除

SELinux 故障排除并不像看起来那么简单,因为在撰写本书时,与 SELinux 的集成没有将 SELinux 相关事件返回给应用程序。通常情况下,您会发现拒绝访问,并且日志文件中没有进一步的描述。

准备工作

通过执行以下命令确保已安装setroubleshoot-serversetools-console

~# yum install -y setroubleshoot-server setools-console

如果您的系统安装了 X 服务器,还可以安装 GUI,如下所示:

~# yum install -y setroubleshoot

在重现问题之前,请确保已安装并运行auditdrsyslogsetroubleshootd

如何操作…

有几种方法可以检测 SELinux 问题。

这是一个典型问题,文件的 SELinux 上下文不正确,导致尝试访问该文件的应用程序失败。

在这种情况下,/var/www/html/index.html 的上下文设置为system_u:object_r:user_home_t:s0而不是system_u:object_r:httpd_sys_content_t:s0,导致httpd报错404。查看以下命令:

# ls -Z /var/www/html/index.html
-rw-r--r--. apache apache system_u:object_r:user_home_t:s0 /var/www/html/index.html
~#

审计日志

使用以下命令查找审核日志中的拒绝或失败条目:

~# egrep 'avc.*denied' /var/log/audit/audit.log
ype=AVC msg=audit(1438884962.645:86): avc:  denied  { open } for  pid=1283 comm="httpd" path="/var/www/html/index.html" dev="dm-5" ino=1089 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:user_home_t:s0 tclass=file
~#

系统日志

您可以通过以下命令在/var/log/messages中查找 SELinux 消息:

~# grep 'SELinux is preventing' /var/log/messages
Aug  6 20:16:03 localhost setroubleshoot: SELinux is preventing /usr/sbin/httpd from read access on the file index.html. For complete SELinux messages., run sealert -l dc544bde-2d7e-4f3f-8826-224d9b0c71f6
Aug 6 20:16:03 localhost python: SELinux is preventing /usr/sbin/httpd from read access on the file index.html.
~#

ausearch

使用审核搜索工具查找 SELinux 错误,如下所示:

~# ausearch -m avc
time->Thu Aug  6 20:16:02 2015
type=SYSCALL msg=audit(1438884962.645:86): arch=c000003e syscall=2 success=yes exit=25 a0=7f1bcfb65670 a1=80000 a2=0 a3=0 items=0 ppid=1186 pid=1283 auid=4294967295 uid=48 gid=48 euid=48 suid=48 fsuid=48 egid=48 sgid=48 fsgid=48 tty=(none) ses=4294967295 comm="httpd" exe="/usr/sbin/httpd" subj=system_u:system_r:httpd_t:s0 key=(null)
type=AVC msg=audit(1438884962.645:86): avc:  denied  { open } for  pid=1283 comm="httpd" path="/var/www/html/index.html" dev="dm-5" ino=1089 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:user_home_t:s0 tclass=file
type=AVC msg=audit(1438884962.645:86): avc:  denied  { read } for  pid=1283 comm="httpd" name="index.html" dev="dm-5" ino=1089 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:user_home_t:s0 tclass=file
~#

一旦我们将/var/www/html/index.html的上下文恢复到原始状态,文件将再次可访问。查看以下命令:

~# restorecon /var/www/html/index.html
~# ls -Z /var/www/html/index.html
-rw-r--r--. apache apache system_u:object_r:httpd_sys_content_t:s0 /var/www/html/index.html
~#

还有更多…

要确定文件是否具有正确的上下文并查看实际的 SELinux 上下文并与不修改任何内容的预期进行比较,执行以下命令:

~# matchpathcon -V index.html
index.html has context system_u:object_r:user_home_t:s0, should be system_u:object_r:httpd_sys_content_t:s0
~#

这告诉您当前的上下文是什么以及它应该是什么。

正如您在前述系统日志示例中所看到的那样,输出伴随以下命令而来:

... run sealert -l dc544bde-2d7e-4f3f-8826-224d9b0c71f6

此命令将为您提供更丰富的问题描述:

~# sealert -l dc544bde-2d7e-4f3f-8826-224d9b0c71f6
SELinux is preventing /usr/sbin/httpd from read access on the file index.html.

*****  Plugin catchall_boolean (89.3 confidence) suggests   ******************

If you want to allow httpd to read user content
Then you must tell SELinux about this by enabling the 'httpd_read_user_content' boolean.
You can read 'None' man page for more details.
Do
setsebool -P httpd_read_user_content 1

*****  Plugin catchall (11.6 confidence) suggests   **************************

If you believe that httpd should be allowed read access on the index.html file by default.
Then you should report this as a bug.
You can generate a local policy module to allow this access.
Do
allow this access for now by executing:
# grep httpd /var/log/audit/audit.log | audit2allow -M mypol
# semodule -i mypol.pp

Additional Information:
Source Context                system_u:system_r:httpd_t:s0
Target Context                system_u:object_r:user_home_t:s0
Target Objects                index.html [ file ]
Source                        httpd
Source Path                   /usr/sbin/httpd
Port                          <Unknown>
Host                          localhost.localdomain
Source RPM Packages           httpd-2.4.6-31.el7.rhel.x86_64
Target RPM Packages 
Policy RPM                    selinux-policy-3.13.1-23.el7_1.7.noarch
Selinux Enabled               True
Policy Type                   targeted
Enforcing Mode                Permissive
Host Name                     localhost.localdomain
Platform                      Linux localhost.localdomain
 3.10.0-229.4.2.el7.x86_64 #1 SMP Wed May 13
 10:06:09 UTC 2015 x86_64 x86_64
Alert Count                   1
First Seen                    2015-08-06 20:16:02 CEST
Last Seen                     2015-08-06 20:16:02 CEST
Local ID                      dc544bde-2d7e-4f3f-8826-224d9b0c71f6

Raw Audit Messages
type=AVC msg=audit(1438884962.645:86): avc:  denied  { read } for  pid=1283 comm="httpd" name="index.html" dev="dm-5" ino=1089 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:user_home_t:s0 tclass=file

type=AVC msg=audit(1438884962.645:86): avc:  denied  { open } for  pid=1283 comm="httpd" path="/var/www/html/index.html" dev="dm-5" ino=1089 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:user_home_t:s0 tclass=file

type=SYSCALL msg=audit(1438884962.645:86): arch=x86_64 syscall=open success=yes exit=ENOTTY a0=7f1bcfb65670 a1=80000 a2=0 a3=0 items=0 ppid=1186 pid=1283 auid=4294967295 uid=48 gid=48 euid=48 suid=48 fsuid=48 egid=48 sgid=48 fsgid=48 tty=(none) ses=4294967295 comm=httpd exe=/usr/sbin/httpd subj=system_u:system_r:httpd_t:s0 key=(null)

Hash: httpd,httpd_t,user_home_t,file,read
~#

这实际上将为您提供有关手头问题的更多详细信息,并提出一些建议。当然,在这种情况下,真正的解决方案是恢复文件的 SELinux 上下文。

如果您安装了图形桌面环境,每当系统遇到“AVC 拒绝”警报时,您将收到通知:

更多内容…

单击图标将呈现以下对话框:

更多内容…

点击故障排除按钮将为您提供额外信息和(一个或多个)可能的问题解决方案,如下截图所示:

更多内容…

在这种情况下,第一个选项(带有绿线标记的选项)是正确的解决方案。

当 SELinux 拒绝访问时,某些 AVC 拒绝消息可能不会被记录。应用程序和库经常会探测超出实际需要的更多访问权限。为了避免这些消息淹没审计日志,可以使用dontaudit规则使得没有权限的 AVC 拒绝不被记录。这样做的缺点是,可能会让故障排除 SELinux 拒绝变得更加困难。

要禁用dontaudit规则,请执行以下命令:

~# semanage dontaudit off

这将禁用dontaudit规则并重建 SELinux 策略。

在故障排除完成后,建议重新启用dontaudit规则,因为否则可能会导致磁盘空间被大量占用。您可以通过执行以下命令来实现:

~# semanage dontaudit on

要获取完整的dontaudit规则列表,请运行以下命令:

~# sesearch --dontaudit
Found 8361 semantic av rules:
 dontaudit user_ssh_agent_t user_ssh_agent_t : udp_socket listen ;
 dontaudit openshift_user_domain sshd_t : key view ;
 dontaudit user_seunshare_t user_seunshare_t : process setfscreate ;
 dontaudit ftpd_t selinux_config_t : dir { getattr search open } ;
 dontaudit user_seunshare_t user_seunshare_t : capability sys_module ;
 dontaudit xguest_dbusd_t xguest_dbusd_t : udp_socket listen ;
 dontaudit tuned_t tuned_t : process setfscreate ;
...
~#

如果您知道想要检查dontaudit规则的域,请添加-s参数并后跟该域,如下所示:

~# sesearch --dontaudit -s httpd_t
Found 182 semantic av rules:
 dontaudit httpd_t snmpd_var_lib_t : file { ioctl read write getattr lock open } ;
 dontaudit domain rpm_var_lib_t : file { ioctl read write getattr lock append } ;
 dontaudit httpd_t snmpd_var_lib_t : dir { ioctl read getattr lock search open } ;
 dontaudit domain rpm_var_lib_t : dir getattr ;
 dontaudit httpd_t snmpd_var_lib_t : lnk_file { read getattr } ;
...
~#

参见

查看ausearch (8)matchpathcon (8)sealert (8)的手册页以获取更多信息。

创建 SELinux 策略

在某些情况下,您可能需要创建新的 SELinux 策略——例如,安装来自源代码的软件。尽管我不建议在企业系统上从源代码安装软件,但在公司开发的软件中,有时这是唯一的选择。

然后是创建您自己的 SELinux 策略的时候。

准备工作

对于本食谱,您需要安装policycoreutils-python

如何操作……

我们将使用audit.log日志文件中的denied条目,通过audit2allow构建我们的 SELinux 策略。

在本食谱中,我们将使用与前一个食谱相同的示例:将/var/www/html/index.html的 SELinux 上下文更改为system_u:object_r:user_home_t:s0。请执行以下步骤:

  1. 首先,通过以下命令创建一个可供验证的人类可读的策略:

    ~# egrep 'avc.*denied' /var/log/audit/audit.log |audit2allow -m example_policy
    
    module example_policy 1.0;
    
    require {
     type httpd_t;
     type user_home_t;
     class file { read open };
    }
    
    #============= httpd_t ==============
    
    #!!!! This avc can be allowed using the boolean 'httpd_read_user_content'
    allow httpd_t user_home_t:file { read open };
    ~#
    
    
  2. 当该策略经过验证后,您可以创建一个编译后的 SELinux 策略文件,如下所示:

    egrep 'avc.*denied' /var/log/audit/audit.log |audit2allow -M example_policy
    ******************** IMPORTANT ***********************
    To make this policy package active, execute:
    
    semodule -i example_policy.pp
    ~#
    
    

它是如何工作的……

当您生成模块包时,会创建两个文件:一个类型强制文件(.te)和一个策略包文件(.pp)。te文件是通过audit2allow -m生成的人类可读的策略。

pp文件是 SELinux 策略模块包,稍后将用于启用新策略。

还有更多……

如果您认为已发现现有 SELinux 策略中的漏洞,您需要生成一个类型强制和策略包文件,报告给 Red Hat Bugzilla。

确保只用audit2allow解析正确的AVC 拒绝条目非常重要,因为这可能导致过多的访问权限。建议将AVC 拒绝条目输出到临时文件中,删除不需要的部分,再使用audit2allow解析该文件。

如果通过这种方式生成的策略不完全符合您的需求,您可以随时编辑生成的te策略文件,完成后使用该te策略文件编译一个新的策略文件。您可以按如下方式操作:

  1. 通过以下命令从策略文件构建二进制策略模块:

    ~# checkmodule -M -m -o example_policy.mod example_policy.te
    checkmodule:  loading policy configuration from example_policy.te
    checkmodule:  policy configuration loaded
    checkmodule:  writing binary representation (version 17) to example_policy.mod
    ~#
    
    
  2. 通过执行以下命令创建 SELinux 策略模块包:

    ~# semodule_package -o example_policy.pp -m example_policy.mod
    ~#
    
    

另见

查看 audit2allow(1) 的手册页,了解有关创建策略的更多选项。

若要报告错误,请访问bugzilla.redhat.com/

应用 SELinux 策略

在之前的食谱中,我们学习了如何创建 SELinux 策略。本食谱将向您展示如何应用新创建的 SELinux 策略。

准备就绪

要应用策略,我们需要一个策略包文件(pp)。可以通过解析 AVC 拒绝记录到audit2allow,或者按照创建 SELinux 策略食谱中的说明编译自己的策略包文件来获取此文件。

如何操作...

按照以下步骤操作:

  1. 通过运行以下命令激活策略(根据系统上应用的策略数量,这可能需要相当长的时间):

    ~# semodule -i example_policy.pp
    ~#
    
    
  2. 接下来,通过以下命令验证策略是否已被激活:

    ~# semodule -l |grep example_policy
    example_policy  1.0
    ~#
    
    

它是如何工作的…

执行semodule命令时,策略文件会被复制到/etc/selinux/targeted/modules/active/modules/,并且完整的 SELinux 策略将被重新编译并应用。

提示

在应用自定义策略时要小心,因为这些策略可能会允许比实际需求更多的访问权限!

还有更多…

要删除策略,请执行以下命令:

~# semodule -r example_policy
~#

这在您想要测试应用了策略和没有应用策略的效果时特别实用。

还有一种方法可以在不先删除模块的情况下升级它,具体如下:

~# semodule -u example_policy
~#

另见

请参阅 semodule (8) 的手册页以获取更多信息。

第六章. 使用 Ansible 编排

在本章中,将讨论以下食谱:

  • 安装 Ansible

  • 配置 Ansible 清单

  • 创建 Kickstart 文件的模板

  • 创建一个剧本,使用 Kickstart 部署一个新的虚拟机

  • 创建一个剧本来执行系统配置任务

  • 排查 Ansible 问题

介绍

Ansible 是一个易于使用的无代理系统配置管理工具。它允许我们在不需要复杂界面或语言的麻烦下,部署复杂的配置。

Ansible 使用剧本,它是任务集合,用于通过 SSH 以受控方式将配置和应用程序部署到多个节点。然而,它并不仅仅止步于此。

Ansible 的模块,用于执行任务,都是设计成在执行过程中具有幂等性的。

根据维基百科,幂等性的定义如下:

幂等性 (/ˌaɪdɨmˈpoʊtəns/ eye-dəm-poh-təns [citation needed]) 是数学和计算机科学中某些操作的属性,可以多次应用而不会改变结果,超出初次应用的效果。

简而言之,任何模块都会检测需要应用的更改并执行它们。如果没有任何更改,它将不会重新应用请求的更改,也不会干扰文件的元数据。

Ansible 公司还提供了 Tower,一个付费订阅服务,带有额外功能,作为 Ansible 的附加组件。Tower 提供了一个图形界面来控制你的 Ansible 编排工具。然而,这超出了本章的范围。

安装 Ansible

Ansible 不在默认的 RHEL 7 仓库中,但在本食谱中,我将展示如何以多种方式安装它。

准备工作

Ansible 需要安装以下软件包:

  • Python v2.7(Ansible 目前不支持 v3)

  • python-httplib2

  • python-jinja2

  • python-paramiko

  • python-setuptools

  • PyYAML

因此,为了实现这一点,执行以下命令:

~]# yum install -y python-httplib2 python-jinja2 python-keyczar python-paramiko python-setuptools PyYAML

由于 RHEL 7 和一些其他主要发行版预安装了 Python(yum 和大多数 Red Hat 工具都需要它),因此我们无需在上述命令中包含它。

如何做...

在本食谱中,我将介绍三种最常用的安装 Ansible 的方法。

安装最新的 tarball

这种方法非常简单,你只需要下载 tarball 并将其解压到你选择的位置。执行以下步骤:

  1. 通过以下命令获取位于 releases.ansible.com/ansible/ 的最新 tarball:

    ~]$ curl -o /tmp/ansible-latest.tar.gz http://releases.ansible.com/ansible/ansible-latest.tar.gz
     % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
     Dload  Upload   Total   Spent    Left  Speed
    100  905k  100  905k    0     0   870k      0  0:00:01  0:00:01 --:--:--  870k
    ~]$
    
    
  2. 将 tarball 解压到 /opt,如下所示:

    ~]# tar zxf /tmp/ansible-latest.tar.gz -C /opt/
    
    
  3. 现在,使用以下命令创建一个符号链接,便于访问:

    ~]# ln -s /opt/ansible-1.9.2 /opt/ansible
    
    
  4. 通过执行以下命令,将 Ansible 的二进制文件和手册页添加到环境的路径中:

    ~]# cat << EOF > /etc/profile.d/ansible.sh
    # Ansible-related stuff
    export ANSIBLE_HOME=/opt/ansible
    export PATH=\${PATH-""}:${ANSIBLE_HOME}/bin
    export MANPATH=\${MANPATH-""}:${ANSIBLE_HOME}/docs/man
    export PYTHONPATH=\${PYTHONPATH-""}:${ ANSIBLE_HOME}/lib
    EOF
    ~]#
    
    
  5. 接下来,通过运行此命令行来设置 Ansible 的 PATH 和 MANPATH:

    ~]# . /etc/profile.d/ansible.sh
    
    
  6. 最后,使用以下命令重新生成手册页:

    ~]# /etc/cron.daily/man-db.cron
    
    

从 Git 安装最新版本

Git 使得保持本地 Ansible 副本的更新变得非常简单。

它会自动更新/删除需要的文件。执行以下步骤:

  1. 确保已安装git,使用以下命令:

    ~]# yum install -y git
    
    
  2. 将 Ansible 的git仓库克隆到/opt,方法如下:

    ~]# cd /opt
    ~]# git clone git://github.com/ansible/ansible.git --recursive
    
    

    从 Git 安装前沿版本

  3. 通过以下命令将 Ansible 二进制文件和 man 页添加到环境路径中:

    ~]# cat << EOF > /etc/profile.d/ansible.sh
    # Ansible-related stuff
    export ANSIBLE_HOME=/opt/ansible
    export PATH=\${PATH-""}:${ANSIBLE_HOME}/bin
    export MANPATH=\${MANPATH-""}:${ANSIBLE_HOME}/docs/man
    export PYTHONPATH=\${PYTHONPATH-""}:${ ANSIBLE_HOME}/lib
    EOF
    ~]#
    
    
  4. 现在,通过此命令设置 Ansible 的 PATH 和 MANPATH:

    ~]# . /etc/profile.d/ansible.sh
    
    
  5. 最后,使用以下命令重新生成 man 页:

    ~]# /etc/cron.daily/man-db.cron
    
    

从 EPEL 仓库安装 Ansible

从仓库安装的好处是,你可以使你的 Ansible 版本和系统保持同步更新。你需要执行的步骤如下:

  1. 通过以下命令从fedoraproject.org/wiki/EPEL安装企业 LinuxEPEL)仓库的额外软件包:

    ~]# yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
    
    
  2. 现在,通过 yum 安装 Ansible,方法如下:

    ~]# yum install -y ansible
    
    

还有更多…

如果你想保持 Git 克隆的更新,记住源代码树中还包含两个子树。你必须执行以下操作:

~]# git pull --release
~]# git submodule update --init --recursive

配置 Ansible 清单

Ansible 清单是该产品的核心,因为它提供了关于环境的大量变量给部署机制。这些变量被称为facts,为 Ansible 做决策、生成基于文本的文件等提供支持。

如何操作…

有几种方法可以将环境信息添加到清单中。

静态清单文件

静态清单基本上是一个小型格式化文件,包含主机和组的定义。你需要做的是:

  1. 创建/etc/ansible/hosts,并填入以下内容:

    ~]# cat << EOF >> /etc/ansible/hosts
    localhost         ansible_connection=local
    srv1.domain.tld   ansible_connection=ssh ansible_ssh_user=root
    
    [mail]
    mail[01..50].domain.tld
    
    [mail:vars]
    dns_servers=[ '8.8.8.8', '8.8.4.4' ]
    mail_port=25
    EOF
    ~]#
    
    

动态清单文件

动态清单文件必须是一个可执行文件,生成一个包含主机和组信息的 JSON 字符串。按以下步骤操作:

  1. 创建一个~/inventory.py脚本,内容如下:

    -]# cat << EOF >> ~/inventory.py
    #!/usr/bin/python -tt
    # -*- coding: utf-8 -*-
    # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
    import json
    
    def main():
     inventory = {
     '_meta': {
     'hostvars': {
     'localhost': {
     'ansible_connection': 'local' },
     'srv1.domain.tld': {
     'ansible_connection': 'ssh',
     'ansible_ssh_user': 'root' },
     }
     },
     'all': {
     'hosts': [
     'localhost',
     'srv1.domain.tld' ] },
     'mail': {
     'hosts': [],
     'vars': {
     'dns_servers': [ '8.8.8.8', '8.8.4.4' ],
     'mail_port': 25} }
     }
    
     for x in range(1,50):
     hostname = 'mail' + ('00%d' % x)[-2:] + '.domain.tld'
     inventory['_meta']['hostvars'].update({ hostname: {} })
     inventory['mail']['hosts'].append(hostname)
    
     print json.dumps(inventory, sort_keys=True, indent=4, separators=(',',': '))
    
    if __name__ == '__main__':
     main()
    ~]#
    
    
  2. 现在,使脚本可执行,方法如下:

    ~]# chmod +x ~/inventory.py
    
    

host_vars 文件

host_vars文件是一个yml格式的文件,包含额外的事实信息,这些信息只会应用于与文件名相同的主机。只需执行以下操作:

  1. 通过以下命令为srv1.domain.tld创建host_vars文件:

    ~]# cat << EOF >> ~/host_vars/srv1.domain.tld.yml
    ansible_connection: ssh
    ansible_ssh_user: root
    EOF
    ~]#
    
    

group_vars 文件

host_vars一样,group_vars文件也是yml格式的文件,包含额外的事实信息。这些信息将应用于与文件名相同的组。执行以下操作:

  1. 通过以下命令为邮件创建group_vars文件:

    ~]# cat << EOF >> ~/group_vars/mail.yml
    dns_servers: [ '8.8.8.8', '8.8.4.4' ]
    mail_port: 25
    EOF
    ~]#
    
    

它是如何工作的…

清单文件的位置在 Ansible 配置文件中设置—在defaults部分寻找以hostfile开头的行。此文件可以是静态文件,也可以是返回 JSON 格式的主机和组信息的脚本,正如前面示例中所展示的。Ansible 会自动检测文件是否是脚本,并按此方式处理以导入信息。

然而,有一个警告:脚本需要通过指定--list来显示 JSON 格式的信息。

如果 host_varsgroup_vars 目录与清单文件/脚本位于同一目录下,Ansible 可以自动将清单与这两个目录中的文件结合起来。看看以下内容:

/etc/ansible/hosts
/etc/ansible/host_vars
/etc/ansible/host_vars/srv1.domain.tld.yml
/etc/ansible/host_vars/...
/etc/ansible/group_vars
/etc/ansible/group_vars/mail.yml
/etc/ansible/group_vars/...

同样可以通过将 host_varsgroup_vars 目录放在与你执行的 playbook 相同的目录下实现。

提示

host_varsgroup_vars 中的事实优先于通过清单返回的变量。

还有更多…

Ansible 已经通过从主机本身获取的事实为清单提供了种子数据。你可以通过执行以下命令轻松查看 Ansible 为你准备了哪些事实:

~]# ansible -m setup <hostname>

这将产生一长串 JSON 格式的输出,包含 Ansible 所知道的有关目标主机的所有事实。

如果你想要更多信息,在 RHEL 系统上,你可以安装 redhat-lsb-core 以访问 LSB 特定的事实。

企业往往有包含其所有系统信息的数据库,用于变更管理。这是一个非常好的来源,可以供清单脚本获取其信息。

另见

如果你想获取有关 Ansible 清单的更详细信息,可以访问 docs.ansible.com/ansible/intro_inventory.html

这是对个人项目和一个自动化清单调用工具的无耻自我宣传,提及 github.com/bushvin/inventoryd/

创建一个 kickstart 文件的模板

template 是 Ansible 的核心模块之一。它用于根据一组共同的事实轻松生成文件(例如配置文件)。它使用 Jinja2 模板引擎来解释模板文件。

对于这个示例,我们将使用一个简单的 kickstart 脚本,它足够通用,可以部署任何主机。参考第二章,大规模部署 RHEL,了解更多关于 kickstart 文件的信息。

做好准备

我们需要的事实包括 repo_urlroot_password_hashntp_serverstimezoneipv4_addressipv4_netmaskipv4_gatewaydns_servers

如何操作…

在你的 playbook 模板文件夹中创建 kickstart 文件(~/playbooks/templates/kickstart/rhel7.ks),并使用以下内容:

install
url --url={{ repo_url }}
skipx
text
reboot
lang en_US.UTF-8
keyboard us
selinux --enforcing
firewall --enabled --ssh
rootpw –iscrypted {{ root_password_hash }}
authconfig --enableshadow --passalgo=sha512
timezone --utc --ntpservers {{ ntp_servers|join(',') }} {{ timezone }}
zerombr
clearpart --all
bootloader --location=mbr --timeout=5
part /boot --asprimary --fstype="xfs" --size=1024 --ondisk=sda
part pv.1   --size=1 --grow --ondisk=sda
volgroup {{ hostname }}_system pv.1
logvol / --vgname={{ inventory_hostname }}_system --size=2048 --name=root --fstype=xfs
logvol /usr --vgname={{ inventory_hostname }}_system --size=2048 --name=usr --fstype=xfs
logvol /var --vgname={{ inventory_hostname }}_system --size=2048 --name=var --fstype=xfs
logvol /var/log --vgname={{ inventory_hostname }}_system --size=2048 --name=varlog --fstype=xfs
logvol swap --vgname={{ inventory_hostname }}_system --recommended --name=swap --fstype=swap
network --device=eth0 --bootproto=static --onboot=yes --activate --ip={{ ipv4_address }} --netmask={{ ipv4_netmask }} --gateway={{ ipv4_gateway }} --nameserver={{ dns_servers|join(',') }}
%packages --excludedocs
@Core
vim-enhanced
%end

它是如何工作的…

Jinja2 引擎会将所有被 {{ }} 包围的变量替换为清单中指定主机的可用事实,从而生成正确的 kickstart 文件,前提是所有变量都已正确设置。

还有更多…

Jinja2 不仅仅是用来将变量替换为清单中的内容。它最初是作为一个功能丰富的网页模板语言开发的,支持条件、循环等主要特性。

使用 Jinja,你可以轻松地循环遍历清单中的列表或数组,并使用结果变量,甚至是字典和对象。例如,假设你的主机具有以下事实:

{ 'nics': [
    { 'device': 'eth0', 'ipv4': { 'address':'192.168.0.100', 'netmask':'255.255.255.0','gateway':'192.168.0.1'} },
    { 'device': 'eth1', 'ipv4': { 'address':'192.168.1.100', 'netmask':'255.255.255.0','gateway':'192.168.1.1'} } ] }

这将允许你用以下内容替换 kickstart 脚本中的网络部分:

{% for nic in nics %}
network –device={{ nic.device }} --bootproto=static --onboot=yes --activate --ip={{ nic.ipv4.address }} --netmask={{ nic.ipv4.netmask }} --gateway={{ nic.ipv4.gateway }}
{% endfor %}

使用这种方式配置新系统时,有一个需要考虑的问题:你只能使用自己引入的事实,而不能使用 Ansible 从系统中获取的事实。因为首先,它们还不存在,其次,任务是在不同的主机上执行的。

另见

有关使用 Ansible 模板的更多信息,请阅读 Jinja2 模板设计器文档:jinja.pocoo.org/docs/dev/templates/

有关 Ansible 模板模块的更多信息,请访问:docs.ansible.com/ansible/template_module.html

创建一个 playbook 以使用 kickstart 部署新的虚拟机

为 Ansible 创建 playbooks 是一项相对简单的任务,因为大多数考虑因素都由模块处理。所有模块都尽可能做到“幂等”,这意味着模块首先检查它应该做什么,与系统上已经做过的操作进行比较,只有在有差异时才应用更改。

准备就绪

对于这个食谱,我们不需要任何额外的事实。

为了使其工作,我们需要有一个 web 服务器和一个存储 kickstart 文件的位置,这些文件将由 web 服务器提供服务。

为了方便起见,我们的 web 服务器名为 web.domain.tld,该 web 服务器上的位置为 /var/www/html/kickstart,并且可以通过 http://web.domain.tld/kickstart 访问该目录。

我们还需要一个 KVM 主机(请参阅第一章,与 KVM 客户机合作,了解如何设置 KVM 服务器)。在此情况下,我们将我们的 KVM 服务器称为 kvm.domain.tld

如何操作…

让我们通过以下步骤来创建一个为新系统配置的 playbook:

  1. 创建一个 ~/playbooks/provisioning.yml playbook,内容如下:

    - name: Provision new machines
      hosts: all
      gather_facts: no
      tasks:
      - name: Publish kickstart template as new file to webserver
        action: template src=templates/kickstart/rhel7.ks dest=/var/www/html/kickstart/{{ inventory_hostname }}.ks
                         owner=apache group=apache mode=0644
                         seuser=system_u serole=object_r setype=httpd_sys_content_t selevel=s0
        delegate_to: web.domain.tld
    
      - name: Create new isolinux file to contain reference to the kickstart file
        action: template src=templates/isolinux/isolinux.cfg.el7 dest=/root/iso/isolinux/isolinux.cfg
        delegate_to: kvm.domain.tld
    
      - name: Create new iso boot media
        action: shell cd /root/iso; mkisofs -o /tmp/{{ inventory_hostname }}.iso -b isolinux/isolinux.bin -c isolinux/boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table -J -r .
        delegate_to: kvm.domain.tld
    
      - name: Create disk for the new kvm guest
        action: virsh vol-create-as --pool localfs-vm --name {{ hostname }}-vda.qcows2 --format qcows2 --capacity 15G
        delegate_to: kvm.domain.tld
    
      - name: Create new vm on KVM
        action: shell virt-install --hvm --name {{ inventory_hostname }} --ram 2048 --vcpus 2 --os-type linux  --boot hd,cdrom,network,menu=on --controller type=scsi,model=virtio-scsi --disk device=cdrom,path=/tmp/{{ inventory_hostname }}.iso,readonly=on,bus=scsi --disk device=disk,vol=localfs-vm/{{ inventory_hostname }}-vda.qcows2,cache=none,bus=scsi --network network=bridge-eth0,model=virtio --graphics vnc --graphics spice --noautoconsole --memballoon virtio
        delegate_to: kvm.domain.tld
    
  2. 你还需要为 ~/templates/isolinux/isolinux.cfg.el7 文件创建模板;你可以通过执行以下命令来完成:

    default vesamenu.c32
    timeout 600
    display boot.msg
    menu clear
    menu background splash.png
    menu title Red Hat Enterprise Linux 7.0
    menu vshift 8
    menu rows 18
    menu margin 8
    menu helpmsgrow 15
    menu tabmsgrow 13
    menu color sel 0 #ffffffff #00000000 none
    menu color title 0 #ffcc000000 #00000000 none
    menu color tabmsg 0 #84cc0000 #00000000 none
    menu color hotsel 0 #84cc0000 #00000000 none
    menu color hotkey 0 #ffffffff #00000000 none
    menu color cmdmark 0 #84b8ffff #00000000 none
    menu color cmdline 0 #ffffffff #00000000 none
    label linux
      menu label ^Install Red Hat Enterprise Linux 7.0
      kernel vmlinuz
      append initrd=initrd.img ks=http://web.domain.tld/kickstart/{{ inventory_hostname }}.ks text
    
    label local
      menu label Boot from ^local drive
      localboot 0xffff
    
    menu end
    
  3. 现在,使用以下命令执行 playbook:

    ~]# ansible-playbook --limit newhost ~/playbooks/provisioning.yml
    
    PLAY [Provision new machines] ********************************
    
    TASK: [Publish kickstart template as new file to webserver] **
    changed: [newhost -> web.domain.tld]
    
    TASK: [Create new isolinux file to contain reference to the kickstart file] ***
    changed: [newhost -> kvm.domain.tld]
    
    TASK: [Create new iso boot media] ****************************
    changed: [newhost -> kvm.domain.tld]
    
    TASK: [Create disk for the new kvm guest] ********************
    changed: [newhost -> kvm.domain.tld]
    
    TASK: [Create new vm on KVM] *********************************
    changed: [newhost -> kvm.domain.tld]
    
    PLAY RECAP ***************************************************
    newhost             : ok=5  changed=5  unreachable=0  failed=0
    ~]#
    
    

它是如何工作的……

playbook 开始时会有一个描述 playbook 的名称,每个任务也如此。就我个人而言,我认为为你的 playbook 和任务命名是个好主意,这将使你在排除任何问题时更加方便。

gather_facts: no 指令防止 playbook 实际尝试连接目标主机并收集信息。由于主机尚未构建,这没有用处,反而会导致 playbook 执行失败。

第一个任务使用模板(如前面的教程中创建的模板)生成一个新的kickstart文件。默认情况下,任务在命令行指定的主机上执行,但通过指定delegate_to指令,可以在 web 服务器上执行,并带有所选主机的事实。

同样适用于最后两个任务;这些任务使用kvm.domain.tld上的本地 shell 执行命令,并带有选定主机的事实。

还有更多内容…

如你所见,playbook 还利用了 Jinja,使我们能够创建动态 playbook,根据可用的事实执行不同的操作。

你在清单中拥有的事实越多,playbook 就能变得越动态。例如,你的源模板可以特定于操作系统版本,你可以在系统创建时一次性创建所有虚拟磁盘,并指定正确数量的 CPU 和 RAM。

另见

关于 playbooks 的更多信息,请访问docs.ansible.com/ansible/playbooks.html

关于 Ansible 模板的更多信息,请访问docs.ansible.com/ansible/modules_by_category.html

创建一个执行系统配置任务的 playbook

使用 Ansible 更改系统配置并不比为新系统配置提供更复杂。

准备工作

对于这个教程,我们需要以下新主机的事实:

  • ntp_servers

  • dns_servers

  • dns_search

我们还需要几个模板来配置以下文件:

  • /etc/logrotate.d/syslog

  • /etc/ntp.conf

  • /etc/ntp/step-tickers

  • /etc/resolv.conf

如何操作…

现在,我们将创建 playbook 来配置系统。执行以下步骤:

  1. 创建一个~/playbooks/config.yml的 playbook,内容如下:

    - name: Configure system
      hosts: all
    
      handlers:
      - include: networking.handlers.yml
      - include: ntp-client.handlers.yml
    
      tasks:
      - include: networking.tasks.yml
      - include: ntp-client.tasks.yml
      - include: logrotate.tasks.yml
    
  2. 创建一个~/playbooks/networking.handlers.yml文件,内容如下:

      - name: reset-sysctl
        action: command /sbin/sysctl -p
    
  3. 现在,创建一个~/playbooks/ntp-client.handlers.yml文件,内容如下:

      - name: restart-ntpd
        action: service name=ntpd state=restarted enabled=yes
    
  4. 创建一个~/playbooks/networking.tasks.yml文件,内容如下:

      - name: Set the hostname
        action: hostname name={{ inventory_hostname }}
    
      - name: Deploy sysctl template to disable ipv6
        action: template src=templates/etc/sysctl.d/ipv6.conf.el7 dest=/etc/sysctl.d/ipv6.conf
        notify: reset-sysctl
    
      - name: 'Detect if ::1 is in /etc/hosts'
        action: shell /bin/egrep '^\s*::1.*$' /etc/hosts
        register: hosts_lo_ipv6
        failed_when: false
        always_run: yes
    
      - name: 'Remove ::1 from /etc/hosts'
        action: lineinfile dest=/etc/hosts regexp='^\s*::1.*$' state=absent
        when: hosts_lo_ipv6.rc == 0
    
      - name: Configure DNS
        action: template src=templates/etc/resolv.conf.el7 dest=/etc/resolv.conf
    
  5. 接下来,创建一个~/playbooks/ntp-client.tasks.yml文件,内容如下:

      - name: "Install ntpd (if it's not installed already)"
        action: yum name=ntp state=present
        notify: restart-ntpd
    
      - name: Configure the ntp daemon
        action: template src=templates/etc/ntp.conf.el7 dest=/etc/ntp.conf
        notify: restart-ntpd
    
      - name: Configure the step-tickers
        action: template src=templates/etc/ntp/step-tickers.el7 dest=/etc/ntp/step-tickers
        notify: restart-ntpd
    
  6. 创建一个~/playbooks/logrotate.tasks.yml文件,内容如下:

      - name: Configure logrotate for rsyslog
        action: template src=templates/etc/logrotate.d/syslog.el7 dest=/etc/logrotate.d/syslog
    

就是这样,playbook 部分完成了。接下来,我们需要创建模板:

  1. 首先,创建一个~/playbooks/templates/etc/sysctl.d/ipv6.conf.el7文件,内容如下:

    # {{ ansible_managed }}
    net.ipv6.conf.all.disable_ipv6 = 1
    net.ipv6.conf.default.disable_ipv6 = 1
    net.ipv6.conf.lo.disable_ipv6 = 1
    
    
  2. 然后,创建一个~/playbooks/templates/etc/resolv.conf.el7文件,内容如下:

    # {{ ansible_managed }}
    search {{ dns_search|join(' ') }}
    {% for dns in dns_servers %}
    nameserver {{ dns }}
    {% endfor %}
    
    
  3. 创建一个~/playbooks/templates/etc/ntp.conf.el7文件,内容如下:

    # {{ ansible_managed }}
    
    driftfile /var/lib/ntp/drift
    
    restrict default nomodify notrap nopeer noquery
    
    restrict 127.0.0.1
    restrict ::1
    
    {% for ntp in ntp_servers %}
    server {{ ntp }} iburst
    {% endfor %}
    includefile /etc/ntp/crypto/pw
    
    keys /etc/ntp/keys
    
    disable monitor
    
    
  4. 接下来,创建一个~/playbooks/templates/etc/ntp/step-tickers.el7文件,内容如下:

    # {{ ansible_managed }}
    {% for ntp in ntp_servers %}
    {{ ntp }}
    {% endfor %}
    
    
  5. 创建一个~/playbooks/templates/etc/logrotate.d/syslog.el7文件,内容如下:

    # {{ ansible_managed }}
    /var/log/cron
    /var/log/maillog
    /var/log/messages
    /var/log/secure
    /var/log/spooler
    {
     daily
     compress
     delaycompress
     dateext
     ifempty
     missingok
     nocreate
     nomail
     rotate 365
     sharedscripts
     postrotate
     /bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true
     endscript
    }
    
    
  6. 然后,执行以下命令将 playbook 部署到新创建的主机上:

    ~]# ansible-playbook --limit newhost ~/playbooks/config.yml
    PLAY [Configure system] **************************************
    
    GATHERING FACTS **********************************************
    ok: [newhost]
    
    TASK: [Set the hostname] *************************************
    skipping: [newhost]
    ok: [newhost]
    
    TASK: [Deploy sysctl template to disable ipv6] ***************
    changed: [newhost]
    
    TASK: [Detect if ::1 is in /etc/hosts] ***********************
    changed: [newhost]
    
    TASK: [Remove ::1 from /etc/hosts] ***************************
    changed: [newhost]
    
    TASK: [Configure DNS] ****************************************
    changed: [newhost]
    
    TASK: [Install ntpd (if it's not installed already)] *********
    ok: [newhost]
    
    TASK: [Configure the ntp daemon] *****************************
    changed: [newhost]
    
    TASK: [Configure the step-tickers] ***************************
    changed: [newhost]
    
    TASK: [Configure logrotate for rsyslog] **********************
    changed: [newhost]
    
    NOTIFIED: [reset-sysctl] *************************************
    skipping: [newhost]
    ok: [newhost]
    
    NOTIFIED: [restart-ntpd] *************************************
    changed: [newhost]
    
    PLAY RECAP ***************************************************
    newhost            : ok=9  changed=8  unreachable=0  failed=0 
    ~]#
    
    

还有更多内容…

Ansible 的团队成员们是非常聪明的人,他们将 Ansible 打包了许多强大的工具。这里值得提及的两个工具,分别是 --check--diff,它们对于调试你的 playbook 非常有帮助。

ansible-playbook --check 工具允许你在系统上运行 playbook,而不实际更改任何内容。你可能会问,为什么这很重要?答案是,playbook 的输出将列出哪些操作会在目标系统上实际更改内容。

需要记住的一个重要点是,并非所有模块都支持此功能,但 Ansible 会告诉你哪个模块不支持。

shell 模块就是一个不支持干运行(dry run)的模块,它不会执行,除非你指定 always_run: yes 指令。使用这个指令时要小心,因为如果该操作会更改某些内容,即便指定了 --check,这个指令也会导致更改被应用。

我将 'Detect if ::1 is in /etc/hosts' 操作添加到了 networking.tasks.yml 文件,并且使用了 always_run: yes 指令。这个操作的作用就是检查该行是否存在。如果找到匹配,ergep 会返回代码 0,如果没有则返回 1。它将 shell 操作的结果注册到一个变量 (hosts_lo_ipv6) 中。

这个变量包含了操作结果的所有信息;在本例中,它包含 stdoutstderr 的值,以及(但不限于)我们需要用于 playbook 中下一任务 ('Remove ::1 from /etc/hosts') 决策的结果代码。通过这种方式,我们可以为那些由于某些限制无法处理幂等性的模块引入手动幂等性。

ansible-playbook --diff --check 工具与这里讨论的功能完全相同。但它有一个额外的好处:它会显示哪些内容会发生变化,并以 diff -u 的形式展示实际内容与预期内容之间的差异。当然,模块必须支持此功能。

如你在示例中所看到,Ansible 允许我们通过创建单独的任务和处理器 yml 文件来创建可重用的代码。这样,你可以创建其他的 playbook 来引用这些文件,而无需重新发明轮子。

一旦你开始使用角色来部署 playbook,这个功能就变得特别实用。

角色(Roles)允许你将 playbook 进行分组,并根据服务器的需求(即角色)进行部署。

例如,一个 "lamp" 角色将使用该角色中的 playbooks 来部署 Linux、Apache、MariaDB 和 PHP。角色可以定义依赖关系。这些依赖关系是其他角色,因此,"lamp" 角色可以拆分成三个更有用的独立角色:Linux、Dbserver 和 ApachePHP。

这是你在使用某些角色时需要的目录/文件结构分解:

文件结构 描述
roles/ 存放 Ansible 所有角色的容器。
roles/<role> 这是你的角色的容器。
roles/<role>/files 这包含要使用 copy 模块复制到目标主机的文件。
roles/<role>/templates 这包含要使用 template 模块部署的模板文件。
roles/<role>/tasks 这是放置执行所有必要操作任务的地方。
roles/<role>/tasks/main.yml 当这个角色应用到系统时,此 playbook 会自动添加到 play 中。
roles/<role>/handlers 这是你角色的处理程序所在的位置。
roles/<role>/handlers/main 这组处理程序会自动添加到 play 中。
roles/<role>/vars 该位置存放你角色的所有变量。
roles/<role>/vars/main.yml 这组变量会自动应用到 play 中。
roles/<role>/defaults 这是存放任何你可能需要的事实默认值的目录。以这种方式定义的事实/变量优先级最低,这意味着如果一个事实在两个地方都有定义,清单中的定义会优先。
role/<role>/defaults/main.yml 这组默认值会自动添加到 play 中。
role/<role>/meta 此目录包含该角色的所有依赖项。
role/<role>/meta/main.yml 这组依赖项会自动添加到 play 中。

为了处理这样创建的角色,你只需要创建一个包含以下内容的 playbook:

- name: Deploy LAMP servers
  hosts: lamp
  roles:
  - linux
  - DBserver
  - Apache-PHP

或者,你可以通过在meta/main.yml文件中创建以下内容,来创建一个包含 Linux、DBserver 和 ApachePHP 作为依赖的角色:

dependencies:
  - { role: linux }
  - { role: DBserver, db_type: mariadb }
  - { role: Apache-PHP }

另请参见

有关 Ansible 角色和包含的更多信息,请访问 docs.ansible.com/ansible/playbooks_roles.html

有关 playbooks 的更多信息,请访问 docs.ansible.com/ansible/playbooks.html

有关 Ansible 模板的更多信息,请访问 docs.ansible.com/ansible/modules_by_category.html

故障排除 Ansible

我之前写过,今天再说一遍:Ansible 团队真的是非常聪明,他们实际上将强大的工具都集成了进去。

我最喜欢的故障排除工具之一是--verbose-v。正如你在这个教程中会发现的,使用它不仅仅是为了在部署 playbook 时进行详细的日志记录。

准备就绪

让我们看看当指定最多 4 个-v工具时,~/playbooks/hello_world.yml playbook 会发生什么:

- name: Hello World test
  hosts: all
  tasks:
  - action: shell echo "Hello World"

如何操作…

Ansible 有多个详细程度级别,每个级别都会添加一层信息。理解每一层所添加的信息是很重要的。请按以下步骤操作:

  1. 首先,执行没有–v的 playbook,如下所示:

    ~]# ansible-playbook --limit <hostname> ~/playbooks/hello_world.yml
    PLAY [Hello World test] **************************************
    
    GATHERING FACTS **********************************************
    ok: [<hostname>]
    
    TASK: [shell echo "Hello World"] *****************************
    changed: [<hostname>]
    
    PLAY RECAP ***************************************************
    <hostname>        : ok=2  changed=1  unreachable=0    failed=0 
    ~]#
    
    
  2. 使用一个–v执行 playbook,如下所示:

    ~]# ansible-playbook --limit <hostname> ~/playbooks/hello_world.yml -v
    PLAY [Hello World test] **************************************
    
    GATHERING FACTS **********************************************
    ok: [<hostname>]
    
    TASK: [shell echo "Hello World"] *****************************
    changed: [<hostname>] => {"changed": true, "cmd": "echo \"Hello World\"", "delta": "0:00:00.003436", "end": "2015-08-18 23:35:26.668245", "rc": 0, "start": "2015-08-18 23:35:26.664809", "stderr": "", "stdout": "Hello World", "warnings": []}
    
    PLAY RECAP ***************************************************
    <hostname>        : ok=2  changed=1  unreachable=0    failed=0
    
    
  3. 现在,使用两个–v工具执行 playbook;运行以下命令:

    ~]# ansible-playbook --limit <hostname> ~/playbooks/hello_world.yml -vv
    PLAY [Hello World test] **************************************
    
    GATHERING FACTS **********************************************
    <hostname_fqdn> REMOTE_MODULE setup
    ok: [<hostname>]
    
    TASK: [shell echo "Hello World"] *****************************
    <hostname_fqdn> REMOTE_MODULE command echo "Hello World" #USE_SHELL
    changed: [<hostname>] => {"changed": true, "cmd": "echo \"Hello World\"", "delta": "0:00:00.004222", "end": "2015-08-18 23:37:56.737995", "rc": 0, "start": "2015-08-18 23:37:56.733773", "stderr": "", "stdout": "Hello World", "warnings": []}
    
    PLAY RECAP ***************************************************
    <hostname>        : ok=2  changed=1  unreachable=0    failed=0
    
    
  4. 接下来,通过以下命令使用三个–v工具执行 playbook:

    ~]# ansible-playbook --limit <hostname> ~/playbooks/hello_world.yml -vvv
    PLAY [Hello World test] **************************************
    
    GATHERING FACTS **********************************************
    <hostname_fqdn> ESTABLISH CONNECTION FOR USER: root
    <hostname_fqdn> REMOTE_MODULE setup
    <hostname_fqdn> EXEC ssh -C -tt -v -o ControlMaster=auto -o ControlPersist=60s -o ControlPath="/root/.ansible/cp/ansible-ssh-%h-%p-%r" -o StrictHostKeyChecking=no -o Port=22 -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 hostname_fqdn /bin/sh -c 'mkdir -p $HOME/.ansible/tmp/ansible-tmp-1439933893.82-159545120587420 && echo $HOME/.ansible/tmp/ansible-tmp-1439933893.82-159545120587420'
    <hostname_fqdn> PUT /tmp/tmpZgg_bx TO /root/.ansible/tmp/ansible-tmp-1439933893.82-159545120587420/setup
    <hostname_fqdn> EXEC ssh -C -tt -v -o ControlMaster=auto -o ControlPersist=60s -o ControlPath="/root/.ansible/cp/ansible-ssh-%h-%p-%r" -o StrictHostKeyChecking=no -o Port=22 -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 hostname_fqdn /bin/sh -c 'LANG=en_US.UTF-8 LC_CTYPE=en_US.UTF-8 /usr/bin/python /root/.ansible/tmp/ansible-tmp-1439933893.82-159545120587420/setup; rm -rf /root/.ansible/tmp/ansible-tmp-1439933893.82-159545120587420/ >/dev/null 2>&1'
    ok: [<hostname>]
    
    TASK: [shell echo "Hello World"] *****************************
    <hostname_fqdn> ESTABLISH CONNECTION FOR USER: root
    <hostname_fqdn> REMOTE_MODULE command echo "Hello World" #USE_SHELL
    <hostname_fqdn> EXEC ssh -C -tt -v -o ControlMaster=auto -o ControlPersist=60s -o ControlPath="/root/.ansible/cp/ansible-ssh-%h-%p-%r" -o StrictHostKeyChecking=no -o Port=22 -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 hostname_fqdn /bin/sh -c 'mkdir -p $HOME/.ansible/tmp/ansible-tmp-1439933894.43-112982528558910 && echo $HOME/.ansible/tmp/ansible-tmp-1439933894.43-112982528558910'
    <hostname_fqdn> PUT /tmp/tmp78xbMg TO /root/.ansible/tmp/ansible-tmp-1439933894.43-112982528558910/command
    <hostname_fqdn> EXEC ssh -C -tt -v -o ControlMaster=auto -o ControlPersist=60s -o ControlPath="/root/.ansible/cp/ansible-ssh-%h-%p-%r" -o StrictHostKeyChecking=no -o Port=22 -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 hostname_fqdn /bin/sh -c 'LANG=en_US.UTF-8 LC_CTYPE=en_US.UTF-8 /usr/bin/python /root/.ansible/tmp/ansible-tmp-1439933894.43-112982528558910/command; rm -rf /root/.ansible/tmp/ansible-tmp-1439933894.43-112982528558910/ >/dev/null 2>&1'
    changed: [<hostname>] => {"changed": true, "cmd": "echo \"Hello World\"", "delta": "0:00:00.002934", "end": "2015-08-18 23:38:14.674213", "rc": 0, "start": "2015-08-18 23:38:14.671279", "stderr": "", "stdout": "Hello World", "warnings": []}
    
    PLAY RECAP ***************************************************
    <hostname>        : ok=2  changed=1  unreachable=0    failed=0
    
    

它是如何工作的…

此表展示了显示哪些信息:

# of –v 显示的信息
0 我们获得了关于剧本的信息,收集的事实(如果未禁用)以及执行的任务,还概览了每台服务器上执行的任务及其数量。
1 此外,在这种情况下,每个任务都会显示与所使用模块相关的所有值。
2 这会额外显示一些使用信息。目前没有太多内容,但未来会有所扩展。
3 此外,这里显示了关于 SSH 操作的信息及其结果。

还有更多…

使用三个 v 工具时,你可以看到 Ansible 执行某个任务的过程,并且 SSH 选项将帮助你通过调试与某个主机的通信问题来入手。正如你所见,许多选项会随着 SSH 命令一起传递,而这些选项可能并非你的控制服务器的标准 SSH 配置的一部分。仅仅使用 SSH 命令来确认连接问题,并不等同于 Ansible 传递给目标主机的命令。

许多 SSH 问题是由于对端的配置文件有问题,因此,除了测试你的 SSH 连接,确保你的 .bashrc.bash_profile 文件正确也是一个好主意。

Ansible 有一个名为 debug 的模块,它允许你显示某个事实/变量或一组事实的值。看看以下代码:

- action: debug var=hostvars[inventory_hostname]

这将显示与目标主机相关的所有事实,而以下内容仅显示 inventory_hostname 事实的值:

- action: debug var=inventory_hostname

如果你希望某个剧本或任务不记录任何信息,使用 no_log: True 指令。

在剧本层面,考虑以下内容:

- name: playbook
  hosts: all
  no_log: True

然后,在任务层面,考虑以下内容:

- name: Forkbomb the remote host
  action: shell :(){ :|: & };:
  no_log: True

第七章。Puppet 配置管理

本章涵盖的教程有:

  • 安装和配置 Puppet Master

  • 安装和配置 Puppet 代理

  • 定义一个简单的模块来配置时间

  • 定义节点和节点分组

  • 将模块部署到单个节点和节点组

介绍

Puppet 是一个“老派”的配置管理工具。尽管它比 Ansible 更复杂,但它使你能够轻松执行配置。Puppet 的声明式语言可以与编程语言相提并论,掌握起来比较困难。然而,一旦你理解了它的工作原理,它就相对容易使用。

Puppet 非常擅长维护严格的配置集,但如果你打算在应用配置之前验证它们,你会发现 Puppet 并不是最锋利的工具。Puppet 确实有audit元参数,你可以在资源中使用它来跟踪更改,但它不允许你显示与清单的不同之处。事实上,它不允许你将audit元参数添加到你的“活动”模块或清单中。它位于一个单独的清单中,用于审计请求的资源。

本教程中使用的 Puppet 版本是 v3.8,并涵盖了社区版。

安装和配置 Puppet Master

Puppet Labs 的团队为 Puppet 提供了自己的仓库服务器,这在安装和维护服务器和代理时非常方便。尽管 EPEL 仓库也提供 Puppet 包,但它们往往比较旧或未更新。因此,我建议使用 Puppet Labs 的 yum 仓库。

如何做…

本教程涵盖了单体安装。执行以下步骤:

  1. 通过以下命令启用可选频道;你将需要此命令来安装 Puppet Server 组件:

    ~]# subscription-manager repos --enable rhel-6-server-optional-rpms
    
    
  2. 下载puppetlabs仓库安装程序,如下所示:

    ~]# curl -Lo /tmp/puppetlabs-release-el-7.noarch.rpm https://yum.puppetlabs.com/puppetlabs-release-el-7.noarch.rpm
    
    
  3. 现在,通过执行以下命令安装puppetlabs仓库:

    ~]# yum install -y /tmp/puppetlabs-release-el-7.noarch.rpm
    
    
  4. 通过输入以下命令安装puppet-server

    ~]# yum install -y puppet-server
    
    
  5. 通过将以下内容添加到/etc/puppet/puppet.conf[main]部分来设置 Puppet Master:

    dns_alt_names = puppetmaster.critter.be,rhel7.critter.be
    always_cache_features = true
    
  6. 接下来,通过以下命令验证puppet环境中 CA 证书的生成:

    ~]# puppet master --verbose --no-daemonize
    
    
  7. 当显示以下信息时,按CTRL + C

    Notice: Starting Puppet master version <version number>
    
    
  8. 现在,通过以下命令允许流量访问 Puppet Master 端口(8140/tcp):

    ~]# firewall-cmd --permanent –add-port=8140/tcp
    ~]# firewall-cmd --reload
    
    
  9. 通过执行以下命令启动 Puppet Master:

    ~]# systemctl start puppetmaster
    
    
  10. 最后,通过以下命令在启动时启用 Puppet Master:

    ~]# systemctl enable puppetmaster
    
    

还有更多…

Puppet Master 使用的基本 HTTP 守护进程并不适合为企业提供服务。Puppet Labs 建议使用 Apache 和 Passenger 来为更大范围的系统(超过 10 个)提供与 Puppet Master 相同的服务。

你可以自己编译 Passenger 模块,或者直接使用EPEL(用于rubygem(rack)包)和 Passenger 仓库。我选择后者。以下是你需要执行的步骤:

  1. 通过运行以下命令安装 Passenger 仓库:

    curl -Lo /etc/yum.repos.d/passenger.repo https://oss-binaries.phusionpassenger.com/yum/definitions/el-passenger.repo
    
    
  2. 现在,下载 EPEL 仓库安装程序,如下所示:

    ~]# curl -Lo /tmp/epel-release-latest-7.noarch.rpm https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
    
    
  3. 通过以下命令安装 rpm EPEL 仓库(使用 yum):

    ~]# yum install -y /tmp/epel-release-latest-7.noarch.rpm
    
    
  4. 接下来,安装 Puppet Web 界面所需的必要软件包。你可以执行以下命令行:

    ~]# yum install -y httpd mod_ssl mod_passenger
    
    
  5. 设置 Puppet Master 的虚拟主机目录及其所有权,如下所示:

    ~]# mkdir -p /var/www/puppetmaster/{public,tmp} -p && chown -R apache:apache /var/www/puppetmaster
    
    
  6. 使用以下命令将 rack 配置文件复制到 Puppet Master 的虚拟主机根目录:

    ~]# cp /usr/share/puppet/ext/rack/config.ru /var/www/puppetmaster/.
    
    
  7. 接下来,更改 config.ru 文件的所有权。这一点非常重要!你可以通过以下命令来执行:

    ~#] chown -R puppet:puppet /var/www/puppetmaster/config.ru
    
    
  8. 然后,在 /etc/httpd/conf.d/puppetmaster.conf 创建一个 Apache 虚拟主机配置文件,内容如下:

    # passenger performance tuning settings:
    # Set this to about 1.5 times the number of CPU cores in your master:
    PassengerMaxPoolSize 3
    # Recycle master processes after they service 1000 requests
    PassengerMaxRequests 1000
    # Stop processes if they sit idle for 10 minutes
    PassengerPoolIdleTime 600
    
    Listen 8140
    <VirtualHost *:8140>
        # Make Apache hand off HTTP requests to Puppet earlier, at the cost of
        # interfering with mod_proxy, mod_rewrite, etc. See note below.
        PassengerHighPerformance On
    
        SSLEngine On
    
        # Only allow high security cryptography. Alter if needed for compatibility.
        SSLProtocol ALL -SSLv2 -SSLv3
        SSLCipherSuite EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH:+CAMELLIA256:+AES256:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!IDEA:!ECDSA:kEDH:CAMELLIA256-SHA:AES256-SHA:CAMELLIA128-SHA:AES128-SHA
        SSLHonorCipherOrder     on
    
        SSLCertificateFile      /var/lib/puppet/ssl/certs/rhel7.critter.be.pem
        SSLCertificateKeyFile   /var/lib/puppet/ssl/private_keys/rhel7.critter.be.pem
        SSLCertificateChainFile /var/lib/puppet/ssl/ca/ca_crt.pem
        SSLCACertificateFile    /var/lib/puppet/ssl/ca/ca_crt.pem
        SSLCARevocationFile     /var/lib/puppet/ssl/ca/ca_crl.pem
        SSLCARevocationCheck   chain
        SSLVerifyClient         optional
        SSLVerifyDepth          1
        SSLOptions              +StdEnvVars +ExportCertData
    
        # Apache 2.4 introduces the SSLCARevocationCheck directive and sets it to none
        # which effectively disables CRL checking. If you are using Apache 2.4+ you must
        # specify 'SSLCARevocationCheck chain' to actually use the CRL.
    
        # These request headers are used to pass the client certificate
        # authentication information on to the Puppet master process
        RequestHeader set X-SSL-Subject %{SSL_CLIENT_S_DN}e
        RequestHeader set X-Client-DN %{SSL_CLIENT_S_DN}e
        RequestHeader set X-Client-Verify %{SSL_CLIENT_VERIFY}e
    
        DocumentRoot /var/www/puppetmaster/public
    
        <Directory /var/www/puppetmaster/>
          Options None
          AllowOverride None
          # Apply the right behavior depending on Apache version.
          <IfVersion < 2.4>
            Order allow,deny
            Allow from all
          </IfVersion>
          <IfVersion >= 2.4>
            Require all granted
          </IfVersion>
        </Directory>
    
        ErrorLog /var/log/httpd/puppetmaster_ssl_error.log
        CustomLog /var/log/httpd/puppetmaster_ssl_access.log combined
    </VirtualHost>
    

    提示

    确保将证书指令替换为你自己系统中的证书文件路径。

  9. 通过以下命令禁用 puppetmaster 服务:

    ~]# systemctl disable puppetmaster
    
    
  10. 使用以下命令行停止 puppetmaster 服务:

    ~]# systemctl stop puppetmaster
    
    
  11. 现在,启动 Apache,如下所示:

    ~]# systemctl start httpd
    
    
  12. 通过以下命令行在启动时启用 Apache:

    ~]# systemctl enable httpd
    
    
  13. 使用以下命令检查你的 HTTP 守护进程状态:

    ~]# systemctl status httpd
    
    

    这将导致以下(类似的)输出:

    还有更多内容…

Puppet 也可以在无主模式下运行。在这种情况下,你不需要安装服务器,只需在所有希望以这种方式进行管理的系统上安装客户端。

另见

有关在 RHEL 上安装 Puppet 的更多深入信息,请参考以下页面:

docs.puppetlabs.com/guides/install_puppet/install_el.html

安装和配置 Puppet agent

与 Ansible 不同,Puppet 需要一个代理来执行配置。本文将教你如何在系统上安装和配置 Puppet agent。大规模部署 Puppet agent 的唯一方法是通过自动化工具(如 Ansible)。

如何操作……

Puppet agent 可以使用与 Puppet 服务器相同的仓库进行安装和维护:Puppet Labs 仓库。请执行以下步骤:

  1. 通过以下命令下载 Puppet Labs 仓库安装程序:

    ~]# curl -Lo /tmp/puppetlabs-release-el-7.noarch.rpm https://yum.puppetlabs.com/puppetlabs-release-el-7.noarch.rpm
    
    
  2. 通过执行以下命令安装 Puppet Labs 仓库:

    ~]# yum install -y /tmp/puppetlabs-release-el-7.noarch.rpm
    
    
  3. 使用以下命令下载 EPEL 仓库安装程序:

    ~]# curl -Lo /tmp/epel-release-latest-7.noarch.rpm https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
    
    
  4. 现在,通过以下命令行安装 rpm EPEL 仓库(使用 yum):

    ~]# yum install -y /tmp/epel-release-latest-7.noarch.rpm
    
    
  5. 安装 Puppet agent;你可以运行以下命令:

    ~]# yum install -y puppet
    
    
  6. 接下来,配置代理,使其连接到你的 Puppet Master。

  7. 将你的 Puppet Master 添加到 /etc/puppet/puppet.conf[main] 部分,如下所示:

    server = rhel7.critter.be
    
  8. 通过执行以下命令启动 Puppet agent:

    ~]# systemctl start puppet
    
    
  9. 然后,通过运行以下命令启用 Puppet agent:

    ~]# systemctl enable puppet
    
    
  10. 最后,在 Puppet Master 上签署新节点的证书,如下所示:

    ~]# puppet cert sign rhel7-client.critter.be
    
    

还有更多内容……

你可以通过执行以下命令,为所有已注册到 Puppet Master 的系统签署证书,而无需单独为每个证书签名:

~]# puppet cert sign –all

如果你开始在 /lib/systemd/system 目录中查找 Puppet 单元文件,你还会发现一个 puppetagent.service 单元文件。puppetagent.service 单元文件实际上是指向 puppet.service 单元文件的软链接。

如果你不想在 /etc/puppet/puppet.conf 文件中设置服务器属性,你可以通过在所有 DNS 域区中定义指向 Puppet Master 的 puppet DNS 条目来实现这一点。

已知 Puppet 代理会消耗内存。为了减轻这一问题,可以将 Puppet 代理作为定时任务运行。这样可以释放一些内存,但你将失去从 Master 推送新配置的灵活性。

这将创建一个定时任务,每 30 分钟启动一次 Puppet 代理,如下所示:

~]# puppet resource cron puppet-agent ensure=present user=root minute=30 command='/usr/bin/puppet agent --onetime --no-daemonize --splay'

Puppet 代理也可以配置为在 Masterless 模式下运行。这意味着你将负责自己分发 Puppet 模块和类,而不是由 Puppet 来处理。这意味着你需要同步所有模块和类,即使是那些系统没有使用的,这可能会带来安全风险。

定义一个简单的模块来配置时间

模块是由清单和文件组成的集合,用于定义如何安装和配置各种组件。清单包含应用于系统配置的指令。在本篇教程中,我们将创建一个简单的模块,用于安装和配置 NTP 守护进程。

准备工作

Puppet 有一套严格的模块组织方式。你的模块应始终存储在 /etc/puppet/modules 目录中。每个模块都是该目录下的一个子目录,其中包含必要的子目录,这些子目录分别包含清单、文件、模板等。

如何操作...

在本篇教程中,我们将创建必要的目录结构、清单和文件,用于配置系统的时间。请按照以下步骤操作:

  1. 通过以下命令在 /etc/puppet/modules 目录中创建 ntp/manifests

    ~]# mkdir -p /etc/puppet/modules/ntp/manifests
    
    
  2. 通过以下方式在 /etc/puppet/modules/ntp 中创建 ntp/templates 目录,以存放所有由 Puppet 模块使用的模板:

    ~]# mkdir -p /etc/puppet/modules/ntp/templates
    
    
  3. 现在,在 /etc/puppet/modules/ntp/manifests 目录中创建 install.pp 文件,内容如下:

    class ntp::install inherits ntp {
      package { 'ntp':
        ensure => installed,
      }
    }
    
  4. /etc/puppet/modules/ntp/manifests 目录中创建 config.pp 文件,内容如下:

    class ntp::config inherits ntp {
      file { '/etc/ntp.conf':
        ensure  => file,
        owner   => 'root',
        group   => 'root',
        mode    => 0644,
        content => template("ntp/ntp.conf.erb"),
      }
    }
    
  5. 接下来,在 /etc/puppet/modules/ntp/templates 目录中创建 ntp.conf.erb 模板文件,内容如下:

    driftfile /var/lib/ntp/drift
    
    restrict default nomodify notrap nopeer noquery
    
    restrict 127.0.0.1
    restrict ::1
    
    server 0.be.pool.ntp.org iburst
    server 1.be.pool.ntp.org iburst
    server 2.be.pool.ntp.org iburst
    server 3.be.pool.ntp.org iburst
    
    includefile /etc/ntp/crypto/pw
    
    keys /etc/ntp/keys
    
    disable monitor
    
  6. /etc/puppet/modules/ntp/manifests 目录中创建 service.pp 文件,内容如下:

    class ntp::service inherits ntp {
      service { 'ntp':
        ensure     => running,
        enable     => true,
        hasstatus  => true,
        hasrestart => true,
        require => Package['ntp'],
      }
    }
    
  7. 最后,在 /etc/puppet/modules/ntp/manifests 目录中创建 init.pp 文件,将它们全部绑定在一起,内容如下:

    class ntp {
        include ntp::install
        include ntp::config
        include ntp::service
    }
    

工作原理...

在将模块应用到系统时,它会应用模块 init.pp 清单中找到的指令。

如你所见,我们创建了一个模板文件,它会被“自动”分发到客户端。Puppet 会自动为 templatesfiles 目录创建文件共享。

如你在config.pp文件中看到的,模板引用了ntp/ntp.conf.erb。Puppet 会自动将其解析为正确的位置(ntp/templates/ntp.conf.erb)。

还有更多…

我创建了四个清单来安装和配置 Puppet。通过创建一个包含其他三个文件内容的单一init.pp清单,这可以轻松实现。当你开始创建复杂的清单时,你会很高兴将它们拆分开来。

如果你想将所有模块中使用的资产(模板和文件)存放在一个位置,你需要在/etc/puppet/fileserver.conf文件中为该位置定义一个单独的文件共享,具体如下:

[mount_point]
    path /path/to/files
    allow *

另请参见

通过链接docs.puppetlabs.com/puppet/3.8/reference/modules_fundamentals.html了解 Puppet 模块。

定义节点和节点分组

为了将清单、类和资产推送到系统,它们需要被 Puppet Master 所识别。分组非常实用,如果你希望将一个清单推送到多个主机而不需要修改每个配置节点。

如何做…

与标题想让你相信的不同,你不能创建一个组并将节点添加进去。然而,你可以将节点分组,并使它们的行为类似于组。

节点和节点组在/etc/puppet/manifests/site.pp/etc/puppet/manifests/site.pp文件中定义。

创建配置节点

创建一个/etc/puppet/manifests/site.pp/rhel7-client.pp文件,内容如下:

node 'rhel7-client.critter.be' {
}

创建一个节点组

创建一个/etc/puppet/manifests/site.pp/rhel7-clientgroup.pp文件,内容如下:

node 'rhel7-client00.critter.be', 'rhel7-client01.critter.be', 'rhel7-client02.critter.be' {
}

还有更多…

如果你有严格的命名规范,你可以使用regular expressions来定义你的节点组。运行以下命令:

node /^www[0-9]+\.critter\.be$/ {
}
node /^repo[0-9]+\.critter\.be$/ {
}

默认情况下,节点名称由其证书名称定义,即我们用于在 Puppet Master 上注册的系统的FQDN完全限定域名)。

如果你不记得所有节点的名称,你可以轻松地在/var/lib/puppet/ssl/ca/signed/中找到它们。

将模块部署到单个节点和节点组

一旦定义了模块和节点,你就可以开始将模块部署到你的节点。你可以在不同级别上执行此操作,接下来的食谱将展示这一点。

如何做…

为了将模块(或清单)部署到一个节点,你必须在该节点的条目中进行配置,或者在该节点所属的节点组中配置,或者你也可以在基础级别定义它,以便应用于每个节点。

配置以将模块或清单部署到单个客户端

编辑前面步骤中的客户端配置节点,并添加一个include语句,引用你希望应用于客户端块的清单。你可以执行以下命令来完成:

node 'rhel7-client.critter.be' {
  include ntp
}

配置以将模块或清单部署到节点组

以您编辑单节点文件的相同方式,编辑节点组配置文件,并在节点组块中添加一个包含语句,引用您希望应用的清单。请查看以下命令:

node 'rhel7-client0.critter.be', 'rhel7-client1.critter.be', 'rhel7-client2.critter.be' {
  include ntp
}

配置以部署到所有注册的系统

通常会在 /etc/puppet/manifests/site.pp/ 内,或如果您使用一个单一的站点定义影响所有节点,/etc/puppet/manifests/site.pp 本身会有一个节点配置文件。编辑 /etc/puppet/manifests/site.pp/default.pp,并输入以下代码:

include ntp

部署到系统

在安装了 Puppet Agent 的系统上,执行以下操作:

~]# puppet agent –-test

执行时,以下内容将出现:

部署到系统

还有更多……

为了测试目的,定义节点和包含模块有一个替代方案。

将清单、文件和模板复制到您的测试机器(通常,您会在生产 Puppet Master 之外的地方进行开发),并以以下方式执行:

~]# puppet apply /path/to/manifest.pp

提示

默认情况下,Puppet 会应用 /etc/puppet/manifests/site.pp 中找到的所有清单。正如前一节所解释的,这不需要是一个包含所有指令的单一庞大文件。当作为一个目录使用时,它会使用该目录中找到的所有清单,或者如果某个子目录的名称以 .pp 结尾,它也会将该目录中的所有内容作为清单进行解析。它会按字母数字顺序解析所有文件。

第八章. Yum 和仓库

在本章中,我们将介绍以下内容:

  • 管理 yum 历史记录

  • 创建任何(RHN)仓库的副本(镜像)

  • 配置额外的仓库

  • 设置 yum 自动更新

  • 配置 logrotate 用于 yum

  • 从损坏的 RPM 数据库恢复

介绍

最初,你需要从源代码手动编译 GNU/Linux 系统,这通常是耗时且麻烦的,尤其是当你无法正确处理依赖关系时。1998 年,红帽公司创建了红帽包管理器RPM),旨在解决依赖问题并减少系统安装所需的时间(以及其他问题)。自那时以来,RPM 被开源社区不断改进,其中一个改进就是 yum。

Yellowdog Updater, Modifiedyum)是一个使用 RPM 的包管理工具。它允许 RPM 访问远程的 RPM 文件仓库,并会根据 RPM 提供的依赖信息自动下载所需的 RPM 文件。

如果没有 Red Hat Network 订阅,你将无法访问更新。

除了 Red Hat Network,你还可以购买 Red Hat Satellite,如果你需要更多的控制权来管理你的 Red Hat 系统。

管理 yum 历史记录

yum 的一个常被忽视的特性是历史记录。它允许你执行许多额外的功能,这些功能在企业环境中可以为你省去不少麻烦。

它允许你将“时间倒回”,恢复到应用程序的最后正常状态,万一包更新出现问题,你也不必担心依赖关系等问题。

如何操作…

在这篇文章中,我将向你展示一些最常用的 yum 历史记录功能。

你的 yum 历史记录

使用以下命令显示你的 yum 历史记录:

~]# yum history list

上述命令将列出输出,内容如下:

你的 yum 历史记录

关于 yum 事务或包的信息

执行以下命令显示 yum 事务的详细信息:

~]# yum history info 1

这将显示有关这个单个事务的所有信息:

关于 yum 事务或包的信息

使用以下命令显示通过 yum 安装的包的详细信息:

~]# yum history info ntp

这将显示所有以某种方式(安装/更新/删除)修改 ntp 包的事务信息:

关于 yum 事务或包的信息

撤销/重做某些 yum 事务

使用以下命令撤销特定的事务:

~]# yum history undo 7

这个命令撤销特定的事务(由 ID 定义),如下图所示:

撤销/重做某些 yum 事务

现在,你可以使用以下命令重做特定的事务:

~]# yum history redo 7

这个命令将重新执行特定的事务(由事务 ID 定义),如下所示:

撤销/重做某些 yum 事务

回滚到事务历史中的某个特定点

这允许你撤销直到指定事务 ID 之前的所有事务。运行以下命令:

~]# yum history rollback 6

这里,回滚到的事务 ID 是 6。你将得到以下输出:

回滚到事务历史中的某一点

还有更多…

使用历史选项,如撤销和回滚时需要小心。Yum 会尽力遵循这些操作,但它不能恢复配置,并且如果你已经编辑过配置文件,它不会恢复配置文件的先前版本。如果没有备份,这不是一个保险的选项。尽管这两个选项非常有用,但我建议你不要频繁使用它们。在使用时,尽量将事务的影响控制得越小越好。增量越小,撤销或回滚成功的机会就越大!

另见

请参考 yum(8) 手册页,了解更多关于 yum 历史选项的信息。

创建 RHN 仓库的副本

在本教程中,我将向你展示如何为基于 Red Hat Network 的 yum 仓库和“纯” yum 仓库进行设置。

准备工作

在你创建 RHN 仓库的副本之前,需要确保你已经拥有有效的订阅,以访问你想要复制的仓库。当这个前提条件满足时,你可以从使用该订阅的机器上执行本教程。

如何操作…

在能够创建 yum 仓库之前,我们需要通过以下步骤安装一些工具:

  1. 使用以下命令安装 createrepoyum-utils 包:

    ~]# yum install -y yum-utils createrepo
    
    
  2. 现在,安装 Apache Web 服务器,如下所示:

    ~]# yum install -y httpd
    
    

同步 RHN 仓库

你只能同步你有权限访问的 RHN 订阅。执行以下步骤:

  1. 创建一个目录来存放 RHN rhel7 仓库,如下所示:

    ~]# mkdir /var/www/html/repo/rhel/rhel-x86_64-server-7/packages
    
    
  2. 现在,通过执行以下命令创建 /mnt/iso 目录:

    ~]# mkdir -p /mnt/iso
    
    
  3. 通过以下方法挂载 RHEL 7 Server DVD:

    ~]# mount -o loop,ro /tmp/rhel-server-7.0-x86_64-dvd.iso /mnt/iso
    
    
  4. 现在,将 *-comps-Server.x86_64.xml 文件从 RHEL Server DVD 复制到你的 repo 目录。以下命令可帮助完成此操作:

    ~]# cp /mnt/iso/repodata/*-comps-Server.x86_64.xml /var/www/html/repo/rhel/comps-Server.x86_64.xml
    
    
  5. 卸载 RHEL Server DVD,如下所示:

    ~]# umount /mnt/iso
    
    
  6. 通过运行以下命令同步 RHEL 7 操作系统仓库:(这可能需要一段时间…我建议你一边等待,一边喝一杯新磨制的阿拉比卡咖啡!)

    ~]# reposync --repoid=rhel-7-server-rpms --norepopath –download_path=/var/www/html/repo/rhel/rhel-x86_64-server-7/packages
    
    
  7. 接下来,创建本地仓库(根据你的硬件配置,这可能需要很长时间),如下所示:

    ~]# cd /var/www/html/repo/rhel/rhel-x86_64-server-7/
    ~]# createrepo --groupfile=/var/www/html/repo/rhel/comps-Server.x86_64.xml .
    
    
  8. 最后,通过以下方法测试你的仓库:

    ~]# curl http://localhost/repo/rhel/rhel-x86_64-server-7/repodata/repomd.xml
    
    

让我们通过以下步骤创建 EPEL 仓库的副本:

  1. 首先,安装 EPEL 仓库,如下所示:

    ~]# yum install -y epel-release
    
    
  2. 通过执行以下命令创建一个目录来存放 EPEL 仓库:

    ~]# mkdir -p /var/www/html/repo/epel/7/x86_64
    
    
  3. 现在,将 *-comps-epel7.xml 文件下载到 /repo 目录并重命名为 comps-epel7.xml,如以下所示:

    ~]# curl -o /var/www/html/repo/epel/comps-epel7.xml http://mirror.kinamo.be/epel/7/x86_64/repodata/xxxxxxxxxxxxxxxxxxxx-comps-epel7.xml
    
    

你需要将多个 x 替换为 repodata 文件夹中找到的正确 MD5 哈希值。

  1. 接下来,执行以下命令同步 EPEL 仓库(这可能需要非常长的时间,具体取决于你的硬件和网络速度):

    ~]# reposync --repoid=epel --norepopath –download_path=/var/www/html/repo/epel/7/x86_64
    
    
  2. 创建本地仓库(根据你的硬件配置,这可能需要很长时间),如下所示:

    ~]# cd /var/www/html/repo/epel/7/x86_64
    ~]# createrepo --groupfile=/var/www/html/repo/epel/comps-epel7.xml .
    
    
  3. 最后,通过执行以下命令来测试您的仓库:

    ~]# curl http://localhost/repo/epel/7/x86_64/repodata/repomd.xml
    
    

还有更多……

在同步 RHEL 7 仓库时,您只能同步您有权限访问的仓库。要查看您在连接到 RHN 的系统上拥有的权限,请执行以下命令:

~]# cd /etc/yum/pluginconf.d/ && echo *.conf | sed "s/rhnplugin.conf//"|sed 's/\([0-9a-zA-Z\-]*\).conf/--disableplugin=\1/g'|xargs yum repolist && cd - >/dev/null

每次同步仓库时,尽量保持与原始仓库相同的目录结构。我发现,当你想重写 /etc/yum.repos.d 文件时,这会使生活更轻松。

在企业环境中,确保所有系统处于相同的 RPM 版本水平时,“冻结”您的 yum 仓库是非常有用的。默认情况下,任何仓库都是“活动”的,并会在添加新软件包时进行更新。这样做的好处是,您总是可以获得所有软件包的最新版本;但是缺点是,您的环境可能不统一,并且您可能会因同一软件包的不同版本而进行故障排除。

实现“冻结”仓库的最简单方法是创建一个中央位置,用于存放所有的 RPM 包,就像普通的 yum 镜像或副本一样。

每隔 x 时间(您预先定义的时间间隔),创建一个带有时间戳的新目录,在其中硬链接所有您镜像的 RPM 包。最后,创建该目录的硬链接,稍后将在您的 repo 配置中使用。

这是一个示例:

目录 描述
/rhel7/x86_64.all 此目录包含一个每天同步的镜像。RPM 包会被添加,但不会删除。
/rhel7/x86_64.20150701 此目录包含指向 /rhel7/x86_64 中 RPM 包的硬链接,所有这些包均于 2015 年 07 月 01 日同步,另外还包括 /rhel6/x86_64.20150701 目录的每月迭代版本。
/rhel7/x86_64 此目录包含指向每月迭代版本的硬链接,该版本被认为是生产中的版本。

当然,你需要确保为每次新的同步创建一个仓库!

另见

参考 createrepo(8) 手册页,获取更多有关创建仓库的信息。

另外,参考 reposync(1) 手册页,获取更多有关保持仓库最新的信息。

配置额外的仓库

无论是创建自己的镜像仓库,还是组织为您提供仓库中的软件,在 RHEL 系统上设置额外的仓库都非常简单。本教程将向您展示如何设置它们。许多仓库有自己的 repo 文件,甚至有自动安装仓库的 RPM。如果这些可用,不要犹豫,尽管使用它们!

准备工作

为了使其工作,您需要设置一个可以通过以下 URL 访问的仓库:http://repo.example.com/myrepo/7/x86_64

如何操作……

为了创建一个额外的仓库,请在 /etc/yum.repos.d 中创建一个名为 myrepo.repo 的文件,其中包含以下信息:

[myrepo]
name=My Personal Repository
baseurl=http://repo.example.com/myrepo/$releasever/$basearch
gpgcheck=0
enabled=1

还有更多……

gpgcheck=1 选项仅在您或仓库提供者已签署仓库中的所有 RPM 时有效。这通常是一个好做法,并为您的仓库提供额外的安全性。

$releasever$basearch 变量允许您创建一个可以在多个系统上使用的单一仓库文件,只要您有适当的 URL 仓库。$releasever 变量展开为操作系统的主要版本(在我们这里是 7),而 $basearch 会展开为 x86_64。在 i386 系统上(RHEL 7 仅提供 x86_64 架构),$basearch 会展开为 i386。

你可以在互联网上找到许多仓库,如 epelelrepo,但使用它们并不总是个好主意。Red Hat 标准仓库提供的任何软件都会得到 Red Hat 的支持,如果你开始使用通过其他仓库提供的相同软件,他们将不再为你提供支持。所以,最好确保你不关心支持,或者有其他愿意为你提供支持的方。

另见

尽管我不建议在生产环境中使用这些方法而不采取适当的支持措施,但这里有一些流行的仓库列表,您可以使用:

ELRepo 仓库可以在以下位置找到:

elrepo.org/tiki/tiki-index.php

EPEL 仓库位于:

fedoraproject.org/wiki/EPEL

Puppetlabs 的仓库可以在以下位置找到:

docs.puppetlabs.com/guides/puppetlabs_package_repositories.html

Zabbix 仓库位于以下链接:

www.zabbix.com/documentation/2.0/manual/installation/install_from_packages

对于 RepoForge 仓库,请参考以下网站:

repoforge.org/use/

Remi 的仓库可以在以下位置找到:

rpms.famillecollet.com/

Webtatic 的仓库位于:

webtatic.com/projects/yum-repository/

设置 yum 自动更新

在企业中,自动化更新 RHEL 系统非常重要。你希望走在黑客的前面,或者总的来说,避免那些通过利用你环境中的弱点来伤害你的人。

尽管我不推荐将此方案应用于企业中的所有系统,但它对于确保某些系统在 Red Hat(及其他)仓库中应用补丁和修复后能够保持最新非常有用。

准备工作

为了使此方案生效,您需要确保所使用的仓库已正确设置,并且您已正确配置邮件系统(例如使用 Postfix 或 Sendmail)。

如何操作…

我们将设置 yum 每周自动更新一次系统(在 03:00),如有必要,重启系统,步骤如下:

  1. 按如下方式安装 yum cron 插件:

    ~]# yum install -y yum-cron
    
    
  2. 然后,通过以下命令禁用每小时和每天的 yum cron 任务:

    ~]# echo > /etc/cron.dhourly/0yum-hourly.cron
    ~]# echo > /etc/cron.daily/0yum-daily.cron
    
    
  3. 通过以下方式创建每周 yum 更新的 cron 任务配置文件:

    ~]# cp /etc/yum/yum-cron.conf /etc/yum/yum-cron-weekly.conf
    
    
  4. 修改创建的配置文件,通过设置以下值来应用更新并通过电子邮件发送通知:

    apply_updates = yes
    emit_via = email
    email_to = <your email address>
    
    
  5. 接下来,通过将以下内容添加到 /etc/cron.weekly/yum-weekly.cron,创建一个每周的 cron 任务:

    #!/bin/bash 
    
    # Only run if this flag is set. The flag is created by the yum-cron init
    # script when the service is started -- this allows one to use chkconfig and
    # the standard "service stop|start" commands to enable or disable yum-cron.
    if [[ ! -f /var/lock/subsys/yum-cron ]]; then
     exit 0
    fi
    
    # Action!
    exec /usr/sbin/yum-cron /etc/yum/yum-cron-weekly.conf
    if test "$(yum history info |egrep '\skernel'|wc -l)" != "0"; then
    
    /sbin/shutdown --reboot +5 "Kernel has been upgraded, rebooting the server in 5 minutes. Please save your work."
    fi
    
    
  6. 最后,通过执行以下命令使 cron 任务可执行:

    ~]# chmod +x /etc/cron.weekly/yum-weekly.cron
    
    

它是如何工作的……

默认情况下,yum-cron 会设置一个 cron 任务,每小时运行一次(/etc/cron.dhourly/0yum-hourly.cron)和每天运行一次(/etc/cron.daily/0yum-daily.cron)。

还有更多内容……

这个步骤将升级你所有的包,当有更新时。如果你只想应用安全修复,请按以下方式修改你的 yum cron 配置文件中的 update_cmd 值:

update_cmd = security

或者,如果你只想应用关键修复,可以使用以下配置:

update_cmd = security-severity:Critical

另见:

查看 yum cron(8) 手册页或位于 /etc/yum/yum-cron.conf 的默认 yum-cron.conf 文件,了解更多信息。

配置 yum 的 logrotate

每次使用 yum 安装和/或更新包时,它都会记录到 /var/log/yum.log。很多人不希望频繁轮换该文件,因为他们错误地认为这是唯一的 yum 任务历史记录来源。他们甚至可能认为它提供了一种在 RPM 数据库损坏时恢复数据库的方式——实际上并不是。

我确实建议保留完整的 yum 历史记录,因为它的增长并不大,除非你经常重新安装包。

为了更好地管理你的 yum 历史记录,我建议你使用 yum history。

默认情况下,你的 yum 日志文件是按年轮换的,甚至只有在日志文件大小超过 30 KB 时才会轮换,而且日志只保留 4 年。通常,在物理环境中,这已经足够,因为物理服务器通常每 3-4 年就会被替换。然而,虚拟服务器有可能超过这 3-4 年仍然“存活”。

如何操作……

/etc/logrotate.d/yum 修改为如下内容:

/var/log/yum.log {
    missingok
    notifempty
    size 30k
    rotate 1000
    yearly
    create 0600 root root
}

它是如何工作的……

该配置只会在 yum 日志文件大小超过 30 KB 时每年轮换一次日志,并且会保留 1000 个已轮换的日志文件,相当于保留了 1000 年的日志!

另见:

如需了解更多关于如何使用和配置 logrotate 的信息,请参阅 logrotate(8) 手册页。

从损坏的 RPM 数据库恢复

尽管已做出一切确保你的 RPM 数据库完好无损,但你的 RPM 数据库可能会损坏并无法使用。这通常发生在 rpm db 所在的文件系统突然无法访问时(例如文件系统满、只读、重启等情况)。

这个步骤将向你展示恢复 RPM 数据库的两种方式。

准备工作:

确保你的系统已经以某种方式备份。

如何操作……

我们将从最简单且成功率最高的选项开始:

  1. 首先创建一个损坏的 rpm db 的备份,步骤如下:

    ~]# cd; tar zcvf rpm-db.tar.gz /var/lib/rpm/*
    
    
  2. 如果存在过时的锁文件,请通过以下命令将其删除:

    ~]# rm -f /var/lib/rpm/__db*
    
    
  3. 现在,通过以下命令验证 Packages 数据库的完整性:

    ~]# /usr/lib/rpm/rpmdb_verify /var/lib/rpm/Packages; echo $?
    
    

    如果前一步输出 0,请继续进行第 7 步。

  4. 重命名 Packages 文件(不要删除它,我们还需要它!),步骤如下:

    ~]# mv /var/lib/rpm/Packages  /var/lib/rpm/Packages.org
    
    
  5. 接下来,执行以下命令从原始的 Packages db 中转储 Packages db

    ~]# cd /usr/lib/rpm/rpmdb_dump Packages.org | /usr/lib/rpm/rpmdb_load Packages
    
    
  6. 验证新创建的 Packages 数据库的完整性。执行以下操作:

    ~]# /usr/lib/rpm/rpmdb_verify /var/lib/rpm/Packages; echo $?
    
    

    如果退出代码不是 0,则需要从备份中恢复数据库。

  7. 重新构建 rpm 索引,步骤如下:

    ~]# rpm -vv --rebuilddb
    
    
  8. 接下来,使用以下命令通过 yum 检查 rpm db 是否存在其他问题(此操作可能需要较长时间):

    ~]# yum check
    
    
  9. 通过以下命令恢复 rpm 数据库的 SELinux 上下文:

    ~]# restorecon -R -v /var/lib/rpm
    
    

    如何操作…

还有更多…

如果由于某种原因,你无法恢复 RPM 数据库,还有最后一个选择。企业通常有标准化的构建,许多服务器安装了相同的软件包,因此可以从另一台拥有相同软件包集的健康服务器复制 /var/lib/rpm 目录到损坏的服务器,并执行前面步骤中的操作,确保一切正常。

虽然你会找到一些额外的工具可以救急(例如 RPM cron),但通常拥有一个良好的备份更为实际。

第九章:加固 RHEL 7

在本章中,您将学习以下内容:

  • 安装和配置 IPA

  • 加强系统登录安全

  • 配置 sudo 提权

  • 使用 firewalld 加强网络安全

  • 使用 kdump 和 SysRq

  • 使用 ABRT

  • 审计系统

介绍

安全性是您环境中的一个重要方面。本章提供的示例并不是一套完整的操作指南,而是为环境中的安全性提供了一个起点,因为每个环境都不同。本章旨在让您了解如何使用 Red Hat Enterprise Server 7 中包含的简单工具来提升安全性。

在本章中,我不会尝试解释系统如何存储 syslog 消息以及它们的含义,因为这是一个相当复杂的话题。最重要的与安全相关的 syslog 消息可以在 /var/log/secure/var/log/audit/audit.log 中找到。

安装和配置 IPA

IPA身份策略审计)服务器允许您在一个中心位置管理您的 Kerberos、DNS、主机、用户、sudo 规则、密码策略和自动挂载。IPA 是一组软件包的组合,包括但不限于 bindldappam 等。它将这些功能结合起来,为您的环境提供身份管理。

准备工作

在本示例中,我将选择集成的 DNS 设置,尽管也可以使用现有的 DNS 基础设施。

如何操作……

首先,我们将安装服务器组件,然后进行 IPA 客户端的配置。

安装 IPA 服务器

按照以下说明安装 IPA 服务器:

  1. 通过以下命令安装必要的软件包:

    ~]# yum install -y ipa-server bind bind-dyndb-ldap
    
    
  2. 安装软件包后,按照如下方式调用 ipa 安装程序:

    ~]# ipa-server-install
    
    

在此阶段,您将被问及一些关于如何设置 IPA 服务器的问题。

  1. 按如下方式配置集成的 DNS:

    Do you want to configure integrated DNS (BIND)? [no]: yes
    
    
  2. 按如下方式覆盖现有的 /etc/resolv.conf

    Existing BIND configuration detected, overwrite? [no]: yes
    
    
  3. 提供 IPA 服务器的主机名,如下所示:

    Server host name [localhost.localdomain]: master.example.com
    
    
  4. 现在,确认 IPA 服务器的 DNS 域名,如下所示:

    Please confirm the domain name [example.com]:
    
    
  5. 提供 IPA 服务器的 IP 地址,如下所示:

    Please provide the IP address to be used for this host name: 192.168.0.1
    
    
  6. 接下来,提供一个 Kerberos realm 名称,如下所示:

    Please provide a realm name [EXAMPLE.COM]:
    
    
  7. 创建目录管理员的密码并确认,如下所示:

    Directory Manager password:
    
    
  8. 创建 IPA 管理员的密码并确认,如下所示:

    IPA admin password:
    
    
  9. 现在,按如下方式配置 DNS 转发器:

    Do you want to configure DNS forwarders? [yes]: no
    
    
  10. 最后,按如下方式配置反向 DNS 区域:

    Do you want to configure the reverse zone? [yes]:
    Please specify the reverse zone name [0.168.192.in-addr.arpa.]:
    
    

    安装程序现在将提供类似于以下的概述:

    The IPA Master Server will be configured with:
    Hostname:      master.example.com
    IP address:    192.168.0.1
    Domain name:   example.com
    Realm name:    EXAMPLE.COM
    
    BIND DNS server will be configured to serve IPA domain with:
    Forwarders:    No forwarders
    Reverse zone:  0.168.192.in-addr.arpa.
    
    
  11. 现在,通过输入 "yes" 来确认信息,如下所示:

    Continue to configure the system with these values? [no]: yes
    
    

此时,您将看到屏幕上滚动大量信息,指示安装程序正在执行的操作:安装或配置 NTP、LDAP、BIND、Kerberos、HTTP、证书服务器以及前面示例中的 IPA 相关修改。

安装和配置过程可能需要一些时间,请耐心等待。

安装 IPA 客户端

执行以下步骤以在系统上安装和配置 IPA 客户端:

提示

确保你的系统主机名不同于 localhost.localdomain。如果不是,客户端配置将失败。

  1. 通过以下命令安装必要的软件包:

    ~]# yum install -y ipa-client
    
    
  2. 确保通过以下方式将 IPA 服务器用作 DNS 服务器:

    ~]# cat /etc/resolv.conf
    search example.com
    nameserver 192.168.0.1
    
    
  3. 通过运行此命令行来调用 IPA 客户端配置:

    ~]# ipa-client-install --enable-dns-updates
    
    

安装程序现在将显示检测到的 IPA 服务器概览,并要求提供一个用户(IPA 管理员)和密码来注册你的系统,如下图所示:

安装 IPA 客户端

还有更多…

安装后,你可以使用命令行工具 IPA 或通过 Web 界面管理 IPA 环境,该界面可以通过在浏览器中访问你的 IPA 主服务器的 HTTPS 地址来访问。在这种情况下,URL 是 https://master.example.com

默认情况下,IPA 客户端不会在用户第一次登录时为新用户创建 homedirs。如果你想启用此功能,可以使用 --mkhomedir 参数与 ipa-client-install 一起使用。如果你不小心忘记了这一步,没必要重新安装 IPA 客户端。你只需要执行以下命令重新配置它:

~]# authconfig --enablemkhomedir --update

另请参见

如需关于安装和配置 IPA 服务器的更深入信息,请访问 access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/Linux_Domain_Identity_Authentication_and_Policy_Guide/installing-ipa.html

如需了解通过命令行管理 IPA 环境的更多信息,请阅读 ipa (1) 手册页。

保护系统登录

应用到系统登录的默认设置是基于 Red Hat 认为的基本安全性。如果由于某种原因你想更改这些设置,本文将展示几个示例。Authconfig 有两个工具可用于配置身份验证:authconfigauthconfig-tui

这两个工具会为你配置 pam,以确保在 rpm 更新中这些更改是一致的。

authconfig-tui 工具的功能不如计划中的 authconfig 工具丰富,我个人建议你使用 authconfig,因为它允许你做更多的操作。

如果你知道自己在做什么,你可以手动编辑位于 /etc/pam.d 中的文件,但不建议这样做。

如何操作…

执行以下步骤:

首先,将 /etc/shadow 中存储的密码哈希加密更改为 sha512,如下所示:

~]# authconfig --passalgo=sha512 --update

通过以下命令启用 NIS 身份验证:

~]# authconfig --enablenis –nisdomain=NISDOMAIN --nisserver=nisserver.example.com --update

现在,通过以下命令将密码的最小长度要求设置为 16

~]# authconfig --passminlen=16 --update

密码中至少需要包含一个小写字母,你可以通过运行以下命令来设置此要求:

~]# authconfig --enablereqlower --update

此外,密码中至少需要包含一个大写字母,你可以运行以下命令来实现:

~]# authconfig --enablerequpper --update

现在,密码中要求至少包含一个数字。为此执行以下命令:

~]# authconfig --enablereqdigit --update

最后,用户的密码至少需要包含一个非字母数字字符,你可以通过以下命令设置:

~]# authconfig --enablereqother --update

工作原理…

authconfigauthconfig-tui 是用于修改多种文件的包装脚本,包括但不限于 /etc/nsswitch.conf/etc/pam.d/*/etc/sssd.conf/etc/openldap/ldap.conf/etc/sysconfig/network

该工具的优点是它使用正确的语法,这有时可能有些棘手,尤其是对于 /etc/pam.d 中的文件。

还有更多…

该工具的一个有趣特点是备份和恢复功能。如果你没有使用任何集中式身份验证和认证基础设施(例如 IPA),你可以使用此功能备份正确配置的机器,并通过你选择的任何方式分发该备份。

要备份你的 authconf 配置,请执行以下命令:

~]# authconfig --savebackup=/tmp/auth.conf

这将创建一个 /tmp/auth.conf 目录,其中包含 authconfig 修改的所有文件。

将该目录复制到另一台服务器并通过执行以下命令恢复配置:

~]# authconfig –-restorebackup=/tmp/auth.conf

你通过 authconfig 应用的所有安全更改也可以通过 IPA 管理。

另见

有关更多信息和更多配置选项,请查看 authconfig (8) 手册页。

你也可以在 Red Hat 的认证页面找到更多信息:access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/System-Level_Authentication_Guide/Configuring_Authentication.html

使用 sudo 配置特权提升

Sudo 允许用户以其他用户的安全权限运行应用程序和脚本。

准备工作

在允许某人提高特定应用程序或脚本的安全上下文之前,你需要弄清楚要提升的用户或组、使用的应用程序/脚本以及在哪些系统上运行它们。

sudo 条目的默认语法如下:

who where = (as_whom) what

如何操作…

这五个简单的步骤将指导你完成特权提升的设置:

  1. 通过以下命令在 /etc/sudoers.d/ 中创建一个新的 sudoers 定义文件,命名为 clustering:

    ~]# visudo -f /etc/sudoers.d/clustering
    
    
  2. 通过执行以下命令,为最常用的集群工具创建一个命令别名,命名为 CLUSTERING

    Cmnd_Alias CLUSTERING = /sbin/ccs, /sbin/clustat, /sbin/clusvcadm
    
  3. 现在,创建一个名为 CLUSTERS 的主机别名组,包含所有集群,如下所示:

    Host_Alias CLUSTERS = cluster1, cluster2
    
  4. 接下来,通过执行以下命令,为所有集群管理员创建一个用户别名,命名为 CLUSTERADMINS

    User_Alias CLUSTERADMINS = spalpatine, dvader, okenobi, qjinn
    
  5. 现在,让我们创建一个 sudo 规则,允许 CLUSTERADMINS 中的用户在 CLUSTERS 组内的所有服务器上执行来自 CLUSTERING 的命令,如下所示:

    CLUSTERADMINS CLUSTERS = (root) CLUSTERING
    

还有更多…

要编辑 sudoers 文件,你可以使用文本编辑器编辑 /etc/sudoers,或者使用 visudo 工具,它会在退出时自动检查你的语法。

最好不要动原始的/etc/sudoers文件,而是修改位于/etc/sudoers.d/目录下的文件。这样可以在必要时由 sudo rpm 更新sudoers文件。

另请参阅

要了解有关 sudo 的更多信息,请查看sudoers(5)手册页面。

使用firewalld保护网络

firewalld是一组脚本和守护程序,用于管理您的 RHEL 系统上的netfilter。它旨在为系统上的防火墙创建一个简单的命令行界面。

如何做…

默认情况下,firewalld包含在“core”rpm 组中,但由于某些原因(如在 kickstart 中遗漏),可能未安装。执行以下步骤:

  1. 通过以下命令行安装firewalld

    ~]# yum install -y firewalld
    
    
  2. 现在,通过以下步骤启用firewalld

    ~]# systemctl enable firewalld
    
    
  3. 最后,请执行以下命令行确保firewalld已启动:

    ~]# systemctl restart firewalld
    
    

显示当前在系统上允许的服务和端口

使用以下命令列出所有允许的服务:

~]# firewall-cmd –list-services

您可以查看以下输出,其中列出了所有允许的服务:

显示系统上当前允许的服务和端口

现在,使用以下命令显示防火墙允许的tcp/udp端口:

~]# firewall-cmd --list-ports

输出应如下所示:

显示系统上当前允许的服务和端口

允许 NFS(v4)的传入请求

执行以下步骤允许系统上的 NFSv4 流量:

  1. 首先,通过此命令允许nfs流量:

    ~]# firewall-cmd --add-service nfs –-permanent
    success
    ~]#
    
    
  2. 然后,按以下方式重新加载配置:

    ~]# firewall-cmd --reload
    success
    ~]#
    
    
  3. 现在,通过执行以下命令行检查新应用的规则:

    ~]# firewall-cmd –-list-services
    nfs
    ~]#
    
    

允许任意端口的传入请求

执行以下步骤以允许通过tcpudp上的1234端口的传入流量:

  1. 首先,通过运行以下命令允许tcpudp上的1234端口流量:

    ~]# firewall-cmd --add-port 1234/tcp --permanent
    success
    ~]# firewall-cmd --add-port 1234/udp --permanent
    success
    ~]#
    
    
  2. 通过执行以下命令重新加载配置:

    ~]# firewall-cmd –-reload
    success
    ~]#
    
    
  3. 通过以下命令检查新应用的规则:

    ~]# firewall-cmd –-list-ports
    1234/tcp 1234/udp
    ~]#
    
    

这里还有…

firewalld提供了一组预定义的端口配置,如 HTTP 和 HTTPS。您可以在/lib/firewalld/services中找到所有这些定义。当创建自己的端口定义或修改现有定义时,应在/etc/firewalld/services中创建新的端口定义文件。

当创建新的“规则”(如添加端口、服务等)时,需要添加--permanent选项,否则在系统重新启动或重新加载firewalld策略时,更改将会丢失。

另请参阅

要了解有关配置防火墙的更多信息,请查看firewall-cmd(1)的 man 页面。

使用 kdump 和 SysRq

kdump 机制是 Linux 内核的一个功能,允许您在内核崩溃时创建转储。它生成内存的精确副本,可用于分析崩溃的根本原因。

SysRq 是 Linux 内核支持的一项功能,允许您即使在系统无响应时也能向其发送键组合。

如何操作……

首先,我们将设置 kdump 和 SysRq,之后,我会向您展示如何使用它来调试转储。

安装和配置 kdump 和 SysRq

让我们看看如何安装和配置:

  1. 通过执行以下命令安装 kdump 所需的包:

    ~]# yum install -y kexec-tools
    
    
  2. 使用此命令确保crashkernel=auto出现在/etc/sysconfig/grub文件中的GRUB_CMDLINE_LINUX变量声明中:

    GRUB_CMDLINE_LINUX="rd.lvm.lv=system/usr rd.lvm.lv=system/swap vconsole.keymap=us rd.lvm.lv=system/root vconsole.font=latarcyrheb-sun16 crashkernel=auto"
    
  3. 通过执行以下命令启动kdump

    ~]# systemctl start kdump
    
    
  4. 现在,启用kdump在启动时自动启动,如下所示:

    ~]# sysctl enable kdump
    
    
  5. 通过以下命令配置 SysRq 接受所有命令:

    ~]# echo "kernel.sysrq = 1" >> /etc/sysctl.d/sysrq.conf
    ~]# systemctl -q -p /etc/sysctl.d/sysrq.conf
    
    
  6. 通过执行以下命令,重新生成您的intramfs初始 RAM 文件系统),以包含 kdump 所需的信息:

    ~]# dracut --force
    
    
  7. 最后,通过以下命令重启:

    ~]# reboot
    
    

使用 kdump 工具分析转储

尽管您可以在vmcore-dmesg.txt文件中找到大部分所需的信息,有时查看vmcore转储中的位和字节也是有用的,即使这只是为了了解 Red Hat 的技术人员在让您发送vmcore转储时会做什么。执行以下步骤:

  1. 通过以下命令安装调试vmcore转储所需的工具:

    ~]# yum install -y --enablerepo=\*debuginfo crash kernel-debuginfo
    
    
  2. 通过执行以下命令找到您的vmcore

    ~]# find /var/crash -name 'vmcore'
    /var/crash/127.0.0.1-2015.10.31-12:03:06/vmcore
    
    

    注意

    如果您没有核心转储,可以通过执行以下命令手动触发:

    ~]# echo c > /proc/sysrq-trigger
    
    
  3. 使用crash分析内容,如下所示:

    ~]# crash /var/crash/127.0.0.1-2015.10.31-12:03:06/vmcore /usr/lib/debug/lib/modules/<kernel>/vmlinux
    
    

    在这里,<kernel>必须与创建转储时使用的内核相同:

    使用 kdump 工具分析转储

  4. 通过执行以下命令显示内核消息缓冲区(这也可以在vmcore-dmesg.txt转储文件中找到):

    crash> log
    
    

    输出应该是这样的:

    使用 kdump 工具分析转储

  5. 通过以下命令显示内核堆栈跟踪:

    crash> bt
    
    

    输出应该是这样的:

    使用 kdump 工具分析转储

  6. 现在,展示核心转储时的进程,如下所示:

    crash> ps
    
    

    输出应该是这样的:

    使用 kdump 工具分析转储

还有更多内容……

默认的 kdump 配置使用/var/crash来转储内存。此路径必须位于根文件系统上。一些系统配置了单独的文件系统用于/var,因此您需要在/etc/kdump.conf中更改位置,或使用其他目标类型,如rawnfs等。如果您的崩溃目录位于非根文件系统上,kdump 服务将失败!

虽然 crash 工具可以提供有关崩溃的很多详细信息,但通常您只需要查看位于与vmcore文件相同目录中的vmcore-dmesg.txt文件的内容。因此,我建议您在深入分析内存转储的细节之前,先解析这个文件。

如前所述,SysRq 允许您在系统处于无法执行任何操作的状态下,依然能够控制系统。然而,它需要您可以访问系统的控制台。

默认情况下,kdump 会创建一个转储并重启系统。如果这没有发生,并且你不想按下(虚拟)系统上的电源按钮,SysRq 允许你通过控制台向内核发送命令。

发送信息所需的按键组合在不同架构间略有不同。请参考下表:

架构 按键组合
x86 <Alt><SysRq><command key>
Sparc <Alt><Stop><command key>
串口控制台(仅 PC 风格) 这会发送BREAK,并在 5 秒内发送命令键。发送两次BREAK会被解释为正常的BREAK
PowerPC <Alt><Print Screen>(或<F13><command key>

因此,在 x86 系统上,你可以通过执行以下命令尝试在重启系统之前同步磁盘:

<Alt><SysRq><s>
<Alt><SysRq><b>

或者,如果你仍然可以访问终端,可以通过将字符发送到/proc/sysrq-trigger来执行相同操作,如下所示:

~]# echo s > /proc/sysrq-trigger
~]# echo b > /proc/sysrq-trigger

以下是可用的按键命令:

命令键 功能
b 这会立即重启你的系统。它不会同步或卸载磁盘,这可能导致数据损坏!
c 这会通过NULL指针解引用执行系统崩溃。如果配置了 kdump,则会生成崩溃转储。
d 这会显示所有持有的锁。
e 这会向所有进程发送SIGTERM信号,init进程除外。
f 这会调用oom_kill来终止任何占用内存的进程。
g 这由内核调试器kgdb)使用。
h 这会显示帮助信息。(记住这个选项!)
i 这会向所有进程发送SIGKILL信号,init进程除外。
j 这会通过FIFREEZE ioctl 冻结你的文件系统。
k 这会终止当前虚拟控制台上的所有程序。它可以通过终止所有试图获取键盘输入的恶意软件,确保安全登录。
l 这会显示所有活动 CPU 的堆栈跟踪。
m 这会将当前内存信息转储到控制台。
n 你可以用这个命令将实时任务设置为可调度状态。
o 这会关闭你的系统并将其关机(如果已配置并且受支持)。
p 这会将当前寄存器和标志转储到你的控制台。
q 这会转储每个 CPU 上所有已激活的hrtimers(不包括timer_list计时器)的列表,并附带所有时钟事件设备的详细信息。
r 这会关闭键盘的原始模式并将其设置为XLATE
s 这会尝试同步所有已挂载的文件系统,将未写入的数据提交到其中。
t 这会将当前任务及其信息转储到控制台。
u 这会尝试将所有文件系统重新挂载为只读卷。
v 这会导致 ETM 缓冲区转储(这是 ARM 特定的)。
w 这会转储所有处于不可中断(阻塞)状态的任务。
x 这用于 ppc/powerpc 平台上的 xmon。它显示 SPARC64 上的全局 PMU 寄存器。
y 显示全局 CPU 寄存器(这是 SPARC64 特有的)。
z 转储 ftrace 缓冲区。
0 - 9 设置控制台的日志级别,控制哪些消息会被打印。数字越高,输出越多。

另见…

关于 SysRq 和 systemd 的更多信息,请参阅以下页面:github.com/systemdaemon/systemd/blob/master/src/linux/Documentation/sysrq.txt

Red Hat 提供了完整的崩溃转储指南,参见 access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/Kernel_Crash_Dump_Guide/index.html

使用 ABRT

ABRT自动错误报告工具)是一套帮助用户检测和分析应用程序崩溃的工具。

如何操作…

首先,我们将安装必要的包,然后了解如何使用这些工具。

安装和配置 abrtd

让我们安装 abrt 并让它运行起来:

  1. 通过以下命令行安装 abrt 守护进程和工具:

    ~]# yum install -y abrt-cli
    
    
  2. 现在,通过以下命令启用并启动 abrt 守护进程:

    ~]# systemctl enable abrtd
    ~]# systemctl restart abrtdThere's more...
    
    

使用 abrt-cli

执行以下命令列出所有检测到的分段错误:

~]# abtr-cli list

以下是输出应呈现的样式:

使用 abrt-cli

显示的位置信息包含有关分段错误的所有信息。你可以使用这些信息分析出错原因,如果需要 Red Hat 的帮助,可以使用 abrt-cli report 向 Red Hat 支持团队报告。

还有更多内容…

当你的 RHEL 7 系统注册到卫星时,所有错误将自动报告到卫星系统。

你可以安装额外的插件,以自动报告以下方式的错误:

  • 到 Bugzilla (libreport-plugin-bugzilla)

  • 通过 FTP 上传 (libreport-plugin-reportuploader)

  • 到 Red Hat 支持(libreport-plugin-rhtsupport

  • 到一个 abrt 服务器(libreport-plugin-ureport

除了基本的错误报告外,你还可以通过安装 abrt-java-connector 包为 Java 创建自动错误报告。

另见

关于如何使用 abrt 工具的更多信息,请参阅 access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/System_Administrators_Guide/ch-abrt.html

审计系统

Linux 审计系统允许你跟踪系统的安全相关信息。它允许你监控安全事件、文件系统访问、网络访问、用户执行的命令和系统调用。

如何操作…

默认情况下,审计功能作为核心包的一部分安装。因此,无需单独安装。

配置一个集中式 syslog 服务器以接收审计日志

执行以下步骤以设置syslog服务器:

  1. syslog服务器上,创建一个/etc/rsyslog.d/audit_server.conf文件,内容如下:

    # Receive syslog audit messages via TCP over port 65514
    $ModLoad imtcp
    $InputTCPServerRun 65514
    $AllowedSender TCP, 127.0.0.1, 192.168.1.0/24
    $template HostAudit, "/var/log/audit/%$YEAR%%$MONTH%%$DAY%-%HOSTNAME%/audit.log"
    $template auditFormat, "%msg%\n" local6.*  ?HostAudit;auditFormat
    
  2. syslog服务器上,重新启动rsyslog,如下所示:

    ~]# systemctl restart rsyslog
    
    
  3. 在客户端上,创建一个/etc/rsyslog.d/audit_client.conf文件,内容如下:

    $ModLoad imfile
    $InputFileName /var/log/audit/audit.log
    $InputFileTag tag_audit_log:
    $InputFileStateFile audit_log
    $InputFileFacility local6
    $InputFileSeverity info
    $InputRunFileMonitor local6.* @@logserver.example.com:65514
    
  4. 接下来,在客户端上,重新启动rsyslog,如下所示:

    ~]# systemctl restart syslog
    
    

一些审计规则

你可以使用以下命令记录/etc/resolv.conf上的活动:

~]# auditctl -w /etc/resolv.conf -p w -k resolv_changes

你可以执行以下命令,记录 root 执行的所有命令:

~]# echo "session   required pam_tty_audit.so disable=* enable=root" >> /etc/pam.d/system-auth-ac
~]# echo "session   required pam_tty_audit.so disable=* enable=root" >> /etc/pam.d/password-auth-ac

显示前述规则的审计日志

你可以通过执行以下命令,搜索使用前述规则更改/etc/resolv.conf的审计事件:

~]# ausearch -k resolv_changes

下面是输出的示例:

显示前述规则的审计日志

若要检查今天由 root 执行的所有命令,可以运行以下命令:

~]# aureport --tty -ts today

下面是输出的示例:

显示前述规则的审计日志

另见

如需了解更多关于审计的深入信息,请参考access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/Security_Guide/chap-system_auditing.html

第十章:监控与性能调优

在本章中,我将探讨以下主题:

  • 调优系统性能

  • 设置 PCP – 性能共管程序

  • 监控基础系统性能

  • 监控 CPU 性能

  • 监控 RAM 性能

  • 监控存储性能

  • 监控网络性能

引言

监控基础设施是环境中的一个重要方面,因为它能帮助你了解环境的行为。它会告诉你瓶颈所在以及哪些地方有改进空间。在本章中,我们将监控性能,而不是在某些指标超过特定值时触发警报。

调优系统性能

企业购买了他们能买到的最好的硬件,他们希望能够优化地使用每一部分。然而,提升应用运行速度的不仅仅是硬件。你的操作系统在特定情况下的表现也会不同。

Tuned 是一组工具和守护进程,它会根据系统的使用情况自动调整系统设置。它通过插件定期收集组件的数据,并根据当前使用情况调整系统设置。

如何实现…

在这个方案中,我们将询问 tuned 使用哪个配置文件,并通过以下步骤应用它:

  1. 首先,运行以下命令安装所需的包:

    ~]# yum install -y tuned
    
    
  2. 通过执行以下命令启用并启动 tuned:

    ~]# systemctl enable tuned
    ~]# systemctl restart tuned
    
    
  3. 让 tuned 猜测使用哪个配置文件,方法如下:

    ~]# tuned-adm recommend
    virtual-guest
    
    
  4. 最后,通过以下方式将推荐的配置文件应用到 tuned 中:

    ~]# tuned-adm profile virtual-guest
    
    

还有更多…

你可以在/lib/tuned/中找到系统使用的配置文件。当你创建自己的配置文件时,应该将它们创建在/etc/tuned中,并按照/lib/tuned中的组织方式进行。 我不建议在/etc/tuned中创建与/lib/tuned中同名的配置文件,但如果你这么做,/etc/tuned目录中的文件将被使用。最好是创建一个新的文件,使用不同的名称,包括你想要修改的配置文件,然后在新配置文件中进行必要的修改。

每个配置文件都有一个目录,里面包含一组控制系统行为的文件。如果你查看这些目录中的tuned.conf文件,你会看到这些文件定义了其他工具(如cpufreq)所需配置的精确设置,并且某些配置文件包含其他配置文件。例如,如果你为一台笔记本电脑创建了一个配置文件,通过应用powersave CPU 调度器来优化电池使用,你可以在/etc/tuned/laptop/tuned.conf中创建一个新文件,内容如下:

#
# laptop tuned configuration
#

[main]
include=desktop

[cpu]
replace=1
governor=powersave

当你知道系统的瓶颈时,你就可以通过以特定方式配置系统来减轻这些瓶颈。Tuned 可以帮助你根据组件的性能监控来创建和应用配置文件。

另见

有关调优系统的更多信息,请参阅Red Hat 性能调优指南

查阅tuned (8)tuned-adm (8)tuned-main.conf (5)tuned.conf (5)的手册页获取更多信息。

设置 PCP – 性能协同工具

多年来,已经创建了许多工具来排查系统性能问题,例如topsariotopiostatiftopvmstatdstat等。然而,这些工具并未互相集成,有些是其他工具的扩展,等等。

PCP 似乎有几个优点:它监控系统的几乎所有方面,允许集中存储(重要的)性能数据,并允许您不仅使用实时数据,还可以使用保存的数据等。

如何操作…

在本指南中,我们将同时查看“默认”设置和“收集器”配置,后者允许您收集所需的所有性能数据。

默认安装

这是 PCP 的基本设置:

  1. 让我们安装所需的软件包;运行以下命令:

    ~]# yum install -y pcp
    
    
  2. 现在,启用并启动必要的守护进程,如下所示:

    ~]# systemctl enable pmcd
    ~]# systemctl enable pmlogger
    ~]# systemctl start pmcd
    ~]# systemctl start pmlogger
    
    
  3. 如果您希望通过中央收集器监控系统,请执行以下操作:

    ~]# firewall-cmd --add-service pmcd --permanent
    
    

中央收集器

每个作为收集器的主机都需要额外的配置。以下是配置方法:

  1. 每个系统添加一行,以便从/etc/pcp/pmlogger/control收集数据,如下所示:

    <hostname> n n PCP_LOG_DIR/pmlogger/<hostname> -r -T24h10m -c config.<hostname>
    

    这里,<hostname>是此主机的 FDQN。请查看以下示例:

    guest.example.com n n PCP_LOG_DIR/pmlogger/guest.example.com -r -T24h10m -c config.guest.example.com
    
  2. 以这种方式添加主机后,您需要重启pmlogger守护进程。执行以下命令:

    ~]# systemctl restart pmlogger
    
    

还有更多…

默认情况下,PCP 每 60 秒记录一次信息。如果您希望增加此时间间隔并每 30 秒收集一次性能统计信息,则需要修改以LOCALHOSTNAME开头的行,并在末尾添加-t 30s

修改您收集的统计信息稍微复杂一点。您可以在/var/lib/pcp/config/pmlogconf/中找到pmlogger的配置。该目录中的每个文件都包含有关要收集的指标的信息。语法并不难理解,但解释起来比较复杂。pmlogconf (1)手册页包含您需要了解的所有内容。

如果您希望在主机上可视化数据,您需要安装pcp-gui,如下所示:

~]# yum install -y pcp-gui dejavu-sans-fonts

该软件包附带一个名为pmchart的工具,允许您使用 PCP 收集的数据创建图形。字体是正确显示字符所必需的。

另见

有关 PCP 及其组件的更多信息,请参阅其在线手册,您可以在www.pcp.io/documentation.html找到。

监控基本系统性能

我们需要关注全局系统值。特别感兴趣的是以下内容:

  • kernel.all.pswitch

  • kernel.all.nprocs

  • kernel.all.load

如何做到…

我会向你展示一种同时显示文本和图形输出的方法。以下是步骤:

  1. 通过执行以下命令为 guest.example.com 主机的指标显示 1 秒间隔的实时数据:

    ~]# pmdumptext -H -t 1 -i -l kernel.all.pswitch kernel.all.nprocs kernel.all.load -h guest.example.com
    
    

    如何做到…

  2. 创建一个名为 system.confpmchart 配置文件来显示以下内容的实时数据:

    #kmchart
    version 1
    
    chart style plot antialiasing off
    
    plot color #ffff00 metric kernel.all.pswitch
    chart style plot antialiasing off
     plot color #ffff00 metric kernel.all.nprocs
    chart style plot antialiasing off
     plot color #ffff00 metric kernel.all.load instance "1 minute"
     plot color #ff924a metric kernel.all.load instance "5 minute"
     plot color #ff0000 metric kernel.all.load instance "15 minute"
    
    
  3. 接下来,使用以下命令通过 pmchartguest.example.com 绘制实时图表:

    ~]# pmchart -h guest.example.com -c system.conf
    
    

    如何做到…

还有更多内容…

上述示例基于“实时”数据;但您不限于实时数据。您可以增加 pmlogger 的间隔以获取有关问题系统的更多数据,然后查看生成的数据。使用其他工具,您需要通过 cronjob 等额外工具来执行,而 PCP 允许您同时执行这两种操作。

这里是如何做到的:

  1. 通过以下命令显示 guest.example.com 的 2015 年 11 月 1 日的数据,时间段为 15:3016:30,间隔为 5 分钟:

    ~]# pmdumptext -H -t 5m -i -l -S @15:30 -T @16:30 kernel.all.pswitch kernel.all.nprocs kernel.all.load -a /var/log/pcp/pmlogger/guest.example.com/20151101
    
    

    还有更多内容…

  2. 您也可以使用 pmchart 来完成同样的操作:

    ~]# pmchart -a /var/log/pcp/pmlogger/guest.example.com/20151101 -c system.conf -S @15:30 -T @16:30 -W -o output.png
    
    

    还有更多内容…

监控 CPU 性能

本文将向您展示如何使用 pmchart 和命令行工具来监视 CPU 的性能。我们将查看以下指标:

  • kernel.all.cpu.wait.total

  • kernel.all.cpu.irq.hard

  • kernel.all.cpu.irq.soft

  • kernel.all.cpu.steal

  • kernel.all.cpu.sys

  • kernel.all.cpu.user

  • kernel.all.cpu.nice

  • kernel.all.cpu.idle

如何做到…

这将向您展示如何创建性能数据的文本和图形表示。执行以下步骤:

  1. 通过以下命令为主机 localhost 的上述指标显示 1 秒间隔的实时数据:

    ~]# pmdumptext -H -t 1 -i -l kernel.all.cpu.wait.total kernel.all.cpu.irq.hard kernel.all.cpu.irq.soft kernel.all.cpu.steal kernel.all.cpu.sys kernel.all.cpu.user kernel.all.cpu.nice kernel.all.cpu.idle -h localhost
    
    

    如何做到…

  2. 创建一个名为 cpu_stack.confpmchart 配置文件来显示以下内容的实时数据:

    #kmchart
    version 1
    
    chart style stacking antialiasing off
     plot color #aaaa7f metric kernel.all.cpu.wait.total
    
    plot color #008000 metric kernel.all.cpu.irq.hard
     plot color #ee82ee metric kernel.all.cpu.irq.soft
     plot color #666666 metric kernel.all.cpu.steal
     plot color #aa00ff metric kernel.all.cpu.user
     plot color #aaff00 metric kernel.all.cpu.sys
     plot color #aa5500 metric kernel.all.cpu.nice
     plot color #0000ff metric kernel.all.cpu.idle
    
    

    您会注意到我在图表中没有使用所有指标,因为其中一些指标是彼此结合的。

  3. 使用以下命令为 guest.example.com 绘制实时图表:

    ~]# pmchart -h guest.example.com -c cpu_stack.conf
    
    

    如何做到…

监控 RAM 性能

为了监控 RAM 性能,我只关心几个指标,而不是所有与内存相关的指标。看看这个列表:

  • mem.util.used

  • mem.util.free

  • mem.util.bufmem

  • mem.util.cached

  • swap.free

  • swap.used

  • swap.pagesin

  • swap.pagesout

如何做到…

本文将解释如何创建文本和图形输出:

  1. 首先,通过以下命令显示上述指标的实时数据:

    ~]# pmdumptext -H -t 1 -i -l mem.util.used mem.util.free mem.util.bufmem mem.util.cached swap.free swap.used swap.pagesin swap.pagesout -h guest.example.com
    
    

    如何做到…

  2. 创建一个名为 memory.confpmchart 配置文件来显示以下内容的实时数据:

    #kmchart
    version 1
    
    chart style stacking
     plot color #ffff00 metric mem.util.used
     plot color #ee82ee metric mem.util.free
    chart style stacking
     plot color #ffff00 metric swap.used
     plot color #0000ff metric swap.free
    chart style plot antialiasing off
     plot color #19ff00 metric swap.pagesin
     plot color #ff0004 metric swap.pagesout
    
    
  3. 现在,使用pmchart通过执行以下命令行为guest.example.com绘制实时图表:

    ~]# pmchart -h guest.example.com -c memory.conf
    
    

    How to do it…

我没有在这个图表中包含缓冲区和缓存内存,因为它是内存使用指标的一部分。

监控存储性能

在这个教程中,我们将查看以下指标:

  • disk.all.read

  • disk.all.write

  • disk.all.read_bytes

  • disk.all.write_bytes

如何操作…

让我们通过以下步骤创建性能数据的文本和图形表示:

  1. 显示上述指标的实时数据;你可以使用以下命令来实现:

    ~]# pmdumptext -H -t 1 -i -l disk.all.read disk.all.write disk.all.read_bytes disk.all.write_bytes -h guest.example.com
    
    

    How to do it…

  2. 接下来,为pmchart创建一个名为disk.conf的配置文件,以显示实时数据,内容如下:

    #kmchart
    version 1
    
    chart style stacking
     plot color #ffff00 metric mem.util.used
     plot color #ee82ee metric mem.util.free
    chart style stacking
    
    plot color #ffff00 metric swap.used
     plot color #0000ff metric swap.free
    chart style plot antialiasing off
     plot color #19ff00 metric swap.pagesin
     plot color #ff0004 metric swap.pagesout
    
    
  3. 现在,使用pmchartguest.example.com绘制实时图表,方法如下:

    ~]# pmchart -h guest.example.com -c memory.conf
    
    

    How to do it…

监控网络性能

在这个教程中,我们将查看以下网络指标:

  • network.interface.collisions

  • network.interface.in.bytes

  • network.interface.in.packets

  • network.interface.in.errors

  • network.interface.in.drops

  • network.interface.out.bytes

  • network.interface.out.packets

  • network.interface.out.errors

  • network.interface.out.drops

如何操作…

现在,我们最后一次来看看如何创建数据的文本和图形表示。请按照以下步骤操作:

  1. 显示上述指标的实时数据;运行以下命令:

    ~]# pmdumptext -H -t 1 -i -l network.interface.collisions network.interface.in.bytes network.interface.in.packets network.interface.in.errors network.interface.in.drops network.interface.out.bytes network.interface.out.packets network.interface.out.errors network.interface.out.drops -h guest.example.com
    
    

    How to do it…

  2. pmchart创建一个名为network.conf的配置文件,以显示实时数据,内容如下:

    #kmchart
    version 1
    
    chart style plot antialiasing off
     plot color #ff0000 metric network.interface.collisions instance "eth0"
    chart style plot antialiasing off
     plot color #00ff00 metric network.interface.in.bytes instance "eth0"
     plot color #ff0000 metric network.interface.out.bytes instance "eth0"
    chart style plot antialiasing off
    
    plot color #00ff00 metric network.interface.in.packets instance "eth0"
     plot color #ff0000 metric network.interface.out.packets instance "eth0"
    chart style plot antialiasing off
     plot color #00ff00 metric network.interface.in.errors instance "eth0"
     plot color #ff0000 metric network.interface.out.errors instance "eth0"
    chart style plot antialiasing off
     plot color #00ff00 metric network.interface.in.drops instance "eth0"
     plot color #ff0000 metric network.interface.out.drops instance "eth0"
    
    
  3. 接下来,使用pmchart通过以下命令行为guest.example.com绘制实时图表:

    ~]# pmchart -h guest.example.com -c network.conf
    
    

    How to do it…

posted @ 2025-07-05 19:50  绝不原创的飞龙  阅读(56)  评论(0)    收藏  举报