CentOS-故障排除指南-全-
CentOS 故障排除指南(全)
原文:
annas-archive.org/md5/7b6e772fc80d2e15150201df989de650译者:飞龙
前言
CentOS(Community Enterprise Operating System)被认为是一款强大、稳定且通常没有问题的操作系统,尤其适合作为服务器使用。作为 RHEL 的忠实版本,CentOS 自 2004 年 5 月首次发布以来就一直陪伴我们。它被全球大量服务器使用,越来越多的个人和企业也在各种需求下选择它,并且在许多关键任务场景中都有它的身影。CentOS 被认为是 Linux 专业人士的最爱,如果配置正确、服务到位并进行妥善维护,通常情况下,基于 CentOS 的服务器不应产生任何重大问题。然而,也有可能出现故障,在这种情况下,当“重启机器”这种老掉牙的笑话并不适用时,你唯一的选择就是考虑进行系统故障排除。
本书以故障排除 CentOS 7 服务器为总体主题,旨在带领你走过一条涉及广泛问题解决方案的学习之路。你将遇到活跃进程、网络环境、包管理、用户、目录和文件、共享资源、安全性、数据库、基于 Web 的服务以及 DNS 等多个领域,最终目标是构建你的知识库,并帮助你发展一种全新的问题解决方法。
本书涵盖的内容
第一章,CentOS 故障排除基础,作为本书的引言,向你介绍了如何收集硬件信息、dmesg 的使用、处理日志文件,以及如何利用一系列命令行工具操作这些日志文件。
第二章,故障排除活跃进程,重点讨论了服务器性能调优、交换空间、内存管理、系统负载、磁盘 I/O 监控、系统巡检、发出 kill 信号以及使用更多命令行工具进行性能检查等内容。
第三章,故障排除网络环境,带你逐步诊断与网络环境相关的各种问题。ping、dig、host、traceroute、mtr、ss 和 tcpdump 只是一些工具,书中将讨论如何通过它们解决一系列网络相关的问题。
第四章,故障排除包管理和系统升级,将 yum(Yellowdog Updater, Modified)置于聚光灯下,目的是向你展示如何管理插件、添加额外的软件仓库、下载 RPM 包、恢复 RPM 数据库并收集通用的软件信息。
第五章,用户、目录和文件故障排除,着眼于持续维护,提供专业故障排除员可能面临的各种问题的信息。从用户管理到 login.defs,utmpdump 到一般的文件和目录审计。本章还建立在你现有的 XFS 文件系统知识基础上,展示如何使用 Scalpel 恢复丢失的数据。
第六章,共享资源故障排除,聚焦于 CentOS 7 中的 NFS,展示如何提供共享、管理导出,并通过客户端工作站访问它们,同时探讨 CIFS 和 autofs,提供一份全面的问题解决指南。
第七章,安全问题故障排除,在已有势头的基础上,讨论为什么你需要保持 SELinux,并展示如何使用 aureport 生成审计报告。从这一点开始,你将发现对 FirewallD 的全面回顾,并获得 Tripwire 安装指南,以便开发自己的入侵检测系统。
第八章,数据库服务故障排除,为故障排除人员和系统管理员提供帮助,通过解决 MariaDB、MySQL 和 PostgreSQL 的关键问题,提供如何处理丢失的 root 密码、数据库调优、数据库指标的概览,以及如何在 CentOS 7 上安装 MySQL 服务器。
第九章,Web 服务故障排除,从恢复问题中退后一步,探讨提高系统、网站或 Web 应用程序性能的需求。通过 cURL 的艺术,你不仅会发现如何审计你的服务器和访问 FTP,还会学到如何验证 Akamai 头部并管理 Varnish,整体目标是阐明 Dev/Ops 与故障排除之间的微妙界限。
第十章,DNS 服务故障排除,通过调查各种域名服务问题,完成我们的旅程。主机名、FQDN、BIND 和 iftop 都被深入探讨,我们将解决与带宽、缓存清除和如何进行 DNS 健康检查等相关的问题。
本书所需内容
本书的要求基于使用 CentOS 7,这是一个社区支持的发行版,源代码由 Red Hat 公开提供。因此,CentOS Linux 在功能上与 RHEL(红帽企业 Linux)兼容,尽管某些软件包名称可能已更改,以去除上游供应商的品牌和艺术设计。CentOS Linux 是免费的,无需付费,并且可以自由重新分发。
本书适合谁
本书是一本实际的指南,旨在解决 CentOS 7 社区版企业服务器的问题。假设你已经有一个运行中的服务器,具备一定的 CentOS 知识,并且能够熟悉地使用你的服务器所用的服务。我们并不要求你成为专家,但有远程管理服务器的经验会对你有所帮助。
约定
在本书中,你将看到多种文本样式,用来区分不同类型的信息。以下是这些样式的几个示例,并解释它们的含义。
文本中的代码词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 用户名如下所示:“了解如何使用lscpu和lspci收集硬件系统信息。”
代码块的设置如下:
/path/to/nfs/publication/directory XXX.XXX.XXX.XXX(rw,sync,root_squash,no_all_squash)
任何命令行输入或输出都如下所示:
# yum groupinstall "Base" "Development Libraries" "Development Tools"
注意
警告或重要的注意事项会以类似这样的框展示。
小贴士
小贴士和技巧以这种形式出现。
读者反馈
我们始终欢迎读者的反馈。告诉我们你对本书的看法——你喜欢什么,或者不喜欢什么。读者反馈对我们很重要,因为它帮助我们开发出你能够从中获得最大收益的书籍。
若要向我们发送一般反馈,只需发送电子邮件至<feedback@packtpub.com>,并在邮件主题中提到书名。
如果你在某个领域有专业知识,并且有兴趣写作或为书籍贡献内容,请查看我们的作者指南,网址为www.packtpub.com/authors。
客户支持
现在你已经是一本 Packt 书籍的骄傲拥有者,我们为你提供了一些帮助,以便你从购买中获得最大收益。
勘误
尽管我们已经尽力确保内容的准确性,但错误仍然可能发生。如果你在我们的书籍中发现错误——可能是文本或代码中的错误——我们将非常感激你能向我们报告。这样,你不仅能帮助其他读者避免困扰,还能帮助我们改进书籍的后续版本。如果你发现任何勘误,请访问www.packtpub.com/submit-errata报告,选择你的书籍,点击Errata Submission Form链接,并输入勘误的详细信息。一旦你的勘误被验证,通过审核后,勘误将被上传到我们的网站,或添加到该书籍勘误列表的 Errata 部分。
若要查看已提交的勘误,请访问www.packtpub.com/books/content/support,并在搜索框中输入书名。所需的信息将出现在Errata部分。
盗版
网络上盗版受版权保护的材料是一个持续存在的问题,涵盖了所有媒体。我们在 Packt 对版权和许可的保护非常重视。如果您在网络上发现我们作品的任何非法副本,请立即向我们提供位置地址或网站名称,以便我们采取措施。
如果您发现涉嫌盗版的内容,请通过 <copyright@packtpub.com> 联系我们,并提供涉嫌盗版材料的链接。
我们感谢您在保护我们的作者和帮助我们为您提供有价值内容方面的支持。
问题
如果您对本书的任何内容有疑问,可以通过 <questions@packtpub.com> 联系我们,我们将尽最大努力解决问题。
第一章:CentOS 故障排除基础
CentOS,即社区企业操作系统,以其强大、稳定和无故障的特性而闻名,特别适合作为服务器操作系统。被各类组织广泛使用,CentOS 在全球许多关键任务环境中都能找到其身影。然而,随着服务器需要按需运行且不中断地提供服务,某些时候,需要冷静但果断的手段来恢复服务,或对现有应用程序进行最后的调整,以确保能够尽快恢复到“正常工作状态”。
“服务器已经崩溃,所有的麻烦即将爆发。”
在一个不完美的世界里,事情可能会出错(并且不可避免地出错),但正是你对 CentOS 7 的整体理解以及它所提供的信心,构成了你故障排除技能的基础。记住,故障排除是一个调查过程,最终会得出诊断结果。所有系统都是不同的,对同一情况的处理方法也会根据系统的目的有所不同。因此,考虑到这一点,重要的是要意识到本书的前提并不是基于具体的操作步骤,而是更多地关注使用的工具和你将要遇到并与之互动的资源。
在本章中,我们将:
-
学习如何在 CentOS 上安装一些基本工具
-
探索如何使用
lscpu和lspci收集基于硬件的系统信息 -
进一步了解
dmesg的重要性及其与内核的交互 -
了解更常见的日志文件及其如何影响日志输出
-
学习如何使用
grep、tail、cat、less、truncate等命令行功能操作任何类型的文件
安装一些基本工具
本书假设你已经能够访问与服务器故障排除相关的基本工具。将提及一些较为冷僻的工具,并会提供相应的使用说明;然而,对于那些可能有或没有基本工具箱的读者,作为 root 用户,你可能想要从运行以下命令开始:
# yum groupinstall "Base" "Development Libraries" "Development Tools"
该操作(如果确认执行)将开始下载并安装 CentOS 服务器系统的常用开发工具、库和基础组件。它还包含 RPM 所需的相关工具、额外的文本编辑器以及编译自定义包所需的包。
注意
在开始时安装这些软件包是可选的,所有这些软件包都可以根据需要单独安装。然而,在灾难恢复规划至关重要的环境中,考虑到服务器在任何问题发生之前就应具备一切所需,值得一提。
所以,在为系统准备好必要的工具和实用程序后,我们将正式开始,仔细查看硬件。为了做到这一点,建议你继续以 root 权限访问相关系统。
收集硬件信息
从原则上讲,大多数人倾向于建议将所有系统信息分为硬件或软件两类。这种方法确实有助于简化问题,但在本章中,我将通过一些方式推测,在某些情况下,硬件和软件的相互作用可能是问题的根源。
因此,在开始故障排除之前,始终考虑收集系统信息是获得更多洞察和熟悉度的推荐方法。这样来看:收集硬件信息的实践并不是必须的,但这种类型的调查可能有助于你寻找最终的诊断结果。
首先,我们将通过以下命令运行一个简单的基于 CPU 的硬件报告:
# cat /proc/cpuinfo
如你所见,此命令的目的是输出与 CPU 型号、家族、架构、缓存等相关的所有信息。/proc 方法一直是一个不错的传统,但使用以下命令通常被认为是更好的做法,并且更易于使用:
# lscpu
此命令将查询系统,并以以下方式输出与 CPU 相关的所有信息:
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 2
On-line CPU(s) list: 0,1
Thread(s) per core: 1
Core(s) per socket: 2
Socket(s): 1
NUMA node(s): 1
Vendor ID: GenuineIntel
CPU family: 6
...
另一方面,与其查询所有内容,你可以使用 grep(这是我们稍后会回到的主题)来指定条件,从而获取任何相关信息,像这样:
# lscpu | grep op-mode
因此,完成这些操作并记录结果以备将来参考后,我们将继续进行调查,通过以下方式运行简单的硬件报告,使用 lspci 命令:
# lspci
该命令的输出可能类似于以下信息:
00:00.0 Host bridge: Intel Corporation 82P965/G965 Memory Controller Hub (rev 02)
00:01.0 PCI bridge: Intel Corporation 82G35 Express PCI Express Root Port (rev 02)
00:05.0 Ethernet controller: Red Hat, Inc Virtio network device
00:0a.0 PCI bridge: Digital Equipment Corporation DECchip 21150
00:0e.0 RAM memory: Red Hat, Inc Virtio memory balloon
00:1d.0 USB controller: Intel Corporation 82801FB/FBM/FR/FW/FRW (ICH6 Family) USB UHCI #1 (rev 02)
00:1d.7 USB controller: Intel Corporation 82801FB/FBM/FR/FW/FRW (ICH6 Family) USB2 EHCI Controller (rev 02)
00:1e.0 PCI bridge: Intel Corporation 82801 PCI Bridge (rev f2)
00:1f.0 ISA bridge: Intel Corporation 82801HB/HR (ICH8/R) LPC Interface Controller (rev 02)
lspci 命令提供有关服务器的 PCI 设备的所有相关信息,进一步的信息可以通过使用 -v 选项或其他 -vv / -vvv 选项来扩展,具体取决于你所需的详细程度:
# lspci -v
# lspci -vv
# lspci -vvv
默认情况下,上述命令将提供所有所需的信息,以便确认设备是否受到当前系统中任何模块的支持。预计你只需要在实施硬件升级后、新安装系统时,或者尝试熟悉新环境时执行此操作。然而,为了进一步简化此过程,你会高兴地知道,还可以使用“树状视图模式”。这个功能的目的是输出相关的设备 ID,并展示这些值如何与相应的总线相关联。
要做到这一点,输入以下命令:
# lspci -t
作为一名故障排除员,您会知道每个设备都必须维护一个唯一的标识符,因为 CentOS 与其他操作系统一样,将使用该标识符将驱动程序绑定到该设备。lspci命令通过扫描/sys树来检测所有连接的设备,这些设备可以包括连接端口、设备类型和类别,仅举几例。完成此操作后,lspci命令将查阅/usr/share/hwdata/pci.ids,以提供它所显示的可读条目。
例如,您可以通过输入以下带有-k选项的lspci命令来显示内核驱动程序/模块,像这样:
# lspci -k
自然,在任何基于硬件的故障排除调查中,您都会想查看系统日志以获取更多线索,但正如我们所看到的,lscpu和lspci命令在尝试发现系统中所需的硬件信息时尤其有用。
您可以随时通过查看相应的车载手册来了解更多关于这些命令的信息:
$ man lscpu
$ man lspci
同时,如果您想要更多练习,一个简单的测试就是插入一个 USB 闪存驱动器,并通过仔细查看/var/log/messages中的枚举信息来分析您自己得到的结果。
注意
请记住,如果您确实尝试了这个操作,您所看到的是系统在插入 USB 驱动器后的反应;您不一定是在查看 USB 驱动器本身;关于 USB 的信息可以通过lsusb获得。
另一方面,就像我们可以将grep与lscpu一起使用一样,如果您已经习惯了这种类型的调查,那么您可能会想知道,您还可以将grep与lspci命令一起使用,以下面这种方式来发现更多关于 RAID 控制器的信息:
# lspci | grep -i raid
现在,我相信您不会感到惊讶,知道还有许多与获取硬件信息相关的命令。这些包括(但不限于)lsmod、dmidecode、hdparm、df -h,甚至是lsblk,以及在本书中将提到的许多其他命令。它们都很有用,但对于那些不想记住它们的人,可以通过简单地阅读/proc和/sys目录中的文件找到大量信息,像这样:
# find /proc | less
# find /sys | less
因此,在我们继续之前,你现在应该知道,当你处理硬件分析时,提升你的技能是通过长时间接触服务器来实现的。我这么说的原因是基于这样一种观点:一个简单的安装过程几乎可以立即识别出这些问题,但没有这个便利的情况下,随着时间的推移,硬件可能需要更换或维护。RAID 电池组会故障,内存模块会故障,有时可能是某个特定驱动程序在最近一次重启时没有完全加载。在这种情况下,你可能会发现内核正以如此高的频率向系统发送随机消息,以至于它表明一个完全不同的问题导致了故障。所以,是的,硬件故障排除需要耐心和观察力,这也是为什么对lscpu和lspci命令的快速回顾成为我们故障排除 CentOS 7 的引言。
理解 dmesg
在我们深入探讨日志文件的主题之前,我想花几分钟时间讨论一下dmesg命令的重要性。
dmesg命令用于记录与硬件检测和配置过程相关的内核消息。我此时不打算深入讲解技术细节,但重要的是要意识到,这些信息来源于内核环形缓冲区;这个条件不仅在硬件故障排除时非常有帮助,而且也为理解系统硬件如何反映在可能的软件诊断上提供了证据,反之亦然。
dmesg文件位于/var/log/目录中,但与该目录中其他文件不同,查看dmesg文件内容的基本语法如下:
# dmesg | less
你可以像往常一样翻页查看结果,但如果你希望让时间戳更容易阅读,你可能希望像这样调用-T选项:
# dmesg -T | less
这些命令将向我们提供与启动过程中加载到内核中的所有硬件驱动程序相关的信息。这些信息将包括它们的状态(成功或失败),如果记录到失败,它甚至会提供一个错误消息,描述失败发生的原因。然而,由于该文件可能非常庞大,你应该使用grep查询dmesg以简化这些信息并简化输出。
为此,只需根据你的需求定制以下语法:
# dmesg -T | grep -i memory
这个命令将显示所有与服务器相关的总内存和共享内存细节的相关信息。当然,类似的方法也可以用来读取 USB 设备、直接内存访问(DMA)或甚至 tty 的具体信息。
例如,你可以查询 dmesg 来以以下方式显示与任何以太网端口相关的硬件信息:
# dmesg –T | grep -i eth0
根据你的系统配置,输出将类似于以下内容:
[Sun Apr 19 04:56:57 2015] IPv6: ADDRCONF(NETDEV_UP): eth0: link is not ready
为了扩展这一方法,你可以修改之前的命令,以发现内核是否已检测到特定的硬盘。为此,请输入:
# dmesg –T | grep sda
或者,你可以使用 -i 选项忽略搜索 tty 引用时的大小写敏感性:
# dmesg | grep -i tty
正如你将看到的,dmesg 文件的输出非常冗长,文件中包含的信息可以用于故障排除几乎任何问题,从网络卡到存储问题。dmesg 文件可能不会直接给出你想要的答案,但它提供了一个拼图的另一部分,当与一些常见的 CentOS 操作系统日志文件中的信息结合使用时,它会帮助你找到解决方案。
理解日志文件
默认情况下,所有 CentOS 系统日志文件都可以在 /var/log 中找到,可以通过输入以下命令获取当前服务器的完整清单:
# find /var/log
话虽如此,每个系统都是不同的,为了简化操作,你会发现一些常见的日志文件(与 CentOS 7 最小化安装相关的)包括:
-
/var/log/messages:该文件包含与 CentOS 使用的许多本地服务相关的信息。包括(但不限于)内核日志、网络管理器、引导过程、邮件服务、cron任务以及许多没有自己日志文件的其他服务。在许多方面,这个记录可以被认为是某种全球性日志文件,出于习惯,它可能会成为你在任何故障排除过程中首先访问的文件。 -
/var/log/boot.log:该文件包含系统启动时报告的信息。 -
/var/log/maillog:该文件包含由系统默认邮件服务器报告的信息。 -
/var/log/secure:该文件包含与认证和授权权限相关的信息。 -
/var/log/wtmp:该文件包含与用户登录记录相关的信息。 -
/var/log/btmp:该文件包含与登录失败尝试相关的信息。 -
/var/log/cron:该文件包含与 cron(和 anacron)相关的信息。 -
/var/log/lastlog:该文件包含与包含所有最后登录信息的二进制日志相关的信息。 -
/var/log/yum.log:该文件包含与 Yum 相关的信息,并报告与服务器包管理工具相关的任何活动。
现在,在继续之前,我想提醒你这些文件的重要性,因为通常建议将 /var/log 存储在与 /(根目录)不同的分区中。
一个完美的系统应为/tmp、/usr等目录维护单独的分区,但确实也有可能在某些情况下,日志文件不得不与/(根)分区存储在同一分区上。因此,请记住,如果有这样的机会,您可能需要考虑将这些目录存储在一个独立的文件系统和独立的物理卷上(如果可能),因为这被认为是保持系统安全性、完整性和性能的良好实践。
然而,话虽如此,仍然需要认识到,许多其他软件包会在其他位置创建和存储日志文件。您甚至可能需要自行指定这些位置,因此应该记住,并非所有日志都位于/var/log目录下。
例如,如果相关服务器托管一个或多个网站,并将所有相关的 Apache 虚拟主机信息存储在特定的/home目录中,那么相关的日志文件可能会存储在如下位置:
/path/to/virtualhost/domain1/log/access_log
/path/to/virtualhost/domain1/log/error_log
许多其他软件包也面临同样的问题,原因在于这些软件包可能没有写入该目录所需的权限,而其他软件包则设计为将所有日志活动保存在其自己的安装目录中。因此,根据您的系统特性,您可能需要花些时间分析服务器的安装结构,以便找到适当的日志文件。
阅读日志文件并影响输出
查看或读取日志文件非常容易,且根据个人偏好,查看这些文件的基本语法可以用以下任意一种格式表达:
# less /var/log/filename
# more /var/log/filename
# cat /var/log/filename
# cat /var/log/filename | less
# cat /var/log/filename | more
注意
请记住,根据系统配置,您可能需要根用户权限才能查看特定的日志文件。试图更改任何系统文件时,也可能需要类似的权限,因此,我们将继续以根用户身份操作。然而,使用sudo或su(切换用户)的用户应相应地调整指令。
日志文件在不同的应用程序和服务之间可能有所不同,但这些文件的主要目的是记录事件的时间和日期以及安全级别,并提供一条消息或一般描述。大多数消息将是某种类型的常规通知或警告,但在某些情况下,也会捕获错误。
例如,您可能会看到如下内容:
Dec 4 12:49:05 localhost postfix/postfix-script[1909]: starting the Postfix mail system
这样的消息很普通,仅仅解释发生了什么以及何时发生。是的,你可以放心地忽略它们,但由于你看到的消息数量较多,有些人可能会觉得系统对一些事情过于敏感,导致日志文件被低级信息淹没。对于很多人来说,这些信息可能没有实际用途,但在某些情况下,你可能会认为提供的信息不够详细,可能需要更多的信息。最终,只有你能决定最适合你的需求。所以,为了举个例子,假设我们要提高日志敏感度来排查系统问题。
为此,我们将首先运行以下命令:
# cat /proc/sys/kernel/printk
前面的命令输出允许你查看当前的内核设置,典型系统中会是如下所示:
4 4 1 7
这里存在一个关系,重要的是你理解printk维护着四个数值,这些数值控制与错误消息日志记录相关的多个设置,同时每个错误消息也有其专属的日志级别,用来定义该消息的重要性。
日志级别值可以总结如下:
-
0:内核紧急 -
1:内核警报;必须立即采取行动 -
2:内核状态被认为是关键的 -
3:一般内核,错误条件 -
4:一般内核,警告条件 -
5:内核正常但重要的情况通知 -
6:内核信息性消息 -
7:内核调试级别消息
所以,基于以上信息,4、4、1 和 7 的日志级别值告诉我们,接下来显而易见的是:
-
第一个值(
4)称为控制台日志级别。这个数值定义了打印到控制台的消息的最低优先级,意味着优先级越低,日志级别数字越高。 -
第二个值(
4)确定了所有没有专属日志级别的消息的默认日志级别。 -
第三个值(
1)确定了整体控制台日志级别的最低可能日志级别配置。优先级越低,日志级别数字越高。 -
第四个也是最后一个值(
7)确定了整体控制台日志级别的默认值。同样,优先级越低,日志级别数字越高。
因此,你现在可以考虑通过配置文件/etc/sysctl.conf来修改日志级别。这个文件使你能够对默认设置进行细微调整,并且可以通过你喜欢的文本编辑器以以下方式访问:
# nano /etc/sysctl.conf
要进行所需的更改,请使用以下语法:
kernel.printk = X X X X
这里,X的实际值是从前面描述的选项中获取的日志级别设置。
例如,你可以通过添加以下行来改变消息数量:
kernel.printk = 5 4 1 7
当然,这样的修改意味着对内核的更改,因此重启是必要的。所以,完成这一步后,你会发现运行cat /proc/sys/kernel/printk的输出现在应该反映新的值。然而,作为补充的警告,考虑到执行此操作(是的,你可以轻松地撤销任何已做的更改),重要的是要意识到关于更改这些设置的有效性存在许多问题。换个角度看:这可能完全不帮助你,因此在进行这些更改之前,你应始终阅读相关资料,以确认做出这一修改是否符合你的总体目的。
要查看内建的手册,只需使用以下命令:
$ man sysctl
另一方面,对于服务器上许多其他服务和应用程序,你将有额外的调查途径需要考虑,这些途径通常是由相关服务或应用程序本身设置的。
一个常见的例子是 Apache。因此,如果你在调试与该服务相关的 Web 问题时,你可能会倾向于打开httpd配置文件,如下所示:
# nano /etc/httpd/conf/httpd.conf
查找或搜索以下行:
LogLevel warn
然后,替换该指令为更合适的设置(在保存文件并重启服务之前)。在这种情况下,你可以使用:
LogLevel debug
幸运的是,知道大多数服务和应用程序确实支持一种调试模式,以改善日志输出,这是一件好事。这将使日志文件更加详细并且在排除服务器故障时更容易处理,但在我们结束这个话题之前,有一个小的注意事项……
当你处理日志文件时,应该意识到这些日志文件中包含的信息并不总是足以帮助你诊断当前的问题或发现问题的根本原因。日志文件不仅可能缺少必要的信息,还可能包含未知的错误和误导性的消息。毕竟,日志文件仅包含一系列(主要是)预定义的消息或包中的断点,这些消息是由程序员设计的,用于备注可能发生过或已经发生的已知事件。
注意
记住……
在影响日志文件输出时,详细的输出可能会引发性能或安全问题,而详细的日志记录还可能对 CPU 或磁盘 I/O 操作造成不必要的负担。
根据这些情况,没有固定的规则,因为我们也知道日志文件是有局限性的。所以,最终你将依赖于敏锐的观察力和大量的耐心,仅仅基于这些原因,你必须始终学会“整体倾听服务器”。
这样说吧:答案在那儿,但可能不在日志文件中。坚持不懈和冷静(但坚定)的态度将最终胜出,而这一点将贯穿本书的每一页。
使用 tail 监控日志文件
所以,掌握了之前的信息,并且知道日志文件通常通过指定事件发生的时间、严重程度和预定的消息来描述事件,成功的关键在于能够处理这些记录并以某种方式操作它们,使它们为我们提供完成任务所需的信息。
在故障排除过程中,你将使用的最有用的命令之一是 tail。以下是一个命令行表达式,可以用来读取日志文件的最后几行:
# tail -n 100 /var/log/maillog
同样,tail 也可以用来获取最近添加的行,像这样:
# tail -f /var/log/maillog
使用此命令不仅可以为你提供日志文件的最新视图,还能确保所有更新立即显示,这为你提供了一种在实时环境中阅读日志文件的即时方式。这种方法可以被描述为解决 Apache、Postfix、Nginx、MySQL 以及你的服务器可能使用的其他许多应用程序或服务故障的完美方式。
例如,你可以像这样查看 Apache 的 access_log:
# tail -f /var/log/httpd/access_log
为了进一步拓展这个功能,假设你想获取日志文件中的最后 3,000 行,知道它将无法适应你的 shell 窗口。为了满足这个需求,你可以像这样使用管道将结果与 less 命令结合:
# tail -n 3000 /var/log/messages | less
在这种情况下,你现在可以根据需要分页结果,但使用这种技术几次后,我想你会同意,它比使用通用的 cat 命令要灵活得多;除非,当然,你想做一些非常具体的事情。
使用 cat、less 和 more
cat 命令已经陪伴我们很长时间了,回到之前我们讨论的硬件和 /proc 目录的内容,你可以使用 cat 命令查看服务器 CPU 的详细信息:
# cat /proc/cpuinfo
如果你想了解更多关于服务器内存的信息,你可以使用:
# cat /proc/meminfo
然后,你总是可以通过输入以下命令来了解更多关于你的设备的信息:
# cat /proc/devices
尽管 cat 非常有用,但它也因将整个内容输出到屏幕上而闻名,如果文件超过 1,000 行,可能会显得有些笨拙。因此,在这种情况下,另一种选择是使用 less 和 more 命令,以分页的方式查看特定的(静态)文件,如下所示:
# less /var/log/messages
# more /var/log/messages
然而,由于 more 命令相对较旧,大多数人会认为 less 更加优越。less 命令类似于 more,但 less 允许你在分页结果之间前后导航。所以,是的,这是一个老笑话,但从现在起,并且在任何可能的情况下,始终记住,less 确实意味着 more。
例如,less 允许你搜索特定的字符串。为此,只需像这样使用 less 打开以下文件:
# less /var/log/messages
现在,在屏幕的左下角,输入 /,后面跟着一个字符串值,像这样:
/error
输出现在将调整为突出显示搜索结果,如果你想查看更多选项,只需在 less 打开时按 H 键。
使用 grep
现在,让我们考虑一下需要在服务器的日志文件中查找特定关键字的情况。
在这种情况下,你将使用名为 grep 的命令,这也是当你想对服务器上的几乎任何文件执行高级基于字符串的搜索时,非常有用的技巧。
假设你想在邮件日志文件中查找一个特定的电子邮件地址。为此,你可以如下使用 grep 命令:
# grep "user@domain.tld" /var/log/maillog
更进一步,grep 还可以用于递归地搜索一个或多个文件中的内容。
例如,如果你想要在日志文件目录中查找一个 IP 地址(XXX.XXX.XXX.XXX),你可以将 grep 命令与 -R 选项结合使用,如下所示:
# grep -R "XXX.XXX.XXX.XXX" /var/log/
类似地,你可以通过 -n 选项为输出添加行号,如下所示:
# grep -Rn "XXX.XXX.XXX.XXX" /var/log/
此外,你还会注意到,在多文件搜索时,每个搜索结果都会显示文件名,但通过使用 -h 选项,你可以禁用此功能,如下所示:
# grep -Rh "XXX.XXX.XXX.XXX" /var/log/
你可以通过 -i 选项忽略大小写,如下所示:
# grep -Ri "XXX.XXX.XXX.XXX" /var/log/
更进一步,grep 还可以用来对搜索结果的内容进行排序,只需在原始命令末尾添加 sort 命令即可实现按字母顺序(从 a 到 z)排序,如下所示:
# grep -R "XXX.XXX.XXX.XXX" /var/log/ | sort
通过添加 -r 选项,你可以实现反向字母排序(从 z 到 a),如下所示:
# grep -R "XXX.XXX.XXX.XXX" /var/log/ | sort -
最后,如果你希望搜索多个值,你可以像这样使用 –E 参数(但不要在管道符之间包含不必要的空格):
# grep -E "term 1|term 2|term 3" /var/log/messages
当然,grep 的功能远不止这些,但为了故障排除的目的,我现在想要引起你注意的最后一个命令,diff 命令,在确定两个文件之间的差异时非常有用。
使用 diff
diff 命令通常不被认为是与日志文件相关的工具,除非你是在为特定目的比较备份文件。然而,diff 命令在比较应用程序的变化时非常有用。
例如,diff 命令可以让你比较两个 Apache 配置文件之间的差异,但通过使用 -u 选项,你还可以包含额外的信息,比如时间和日期:
# diff -u /etc/httpd/conf/httpd.conf /etc/httpd/conf/httpd.conf.backup
现在,根据文件的大小和服务器的速度,任务可能需要几秒钟(甚至几分钟)才能完成。是的,我知道我们有点偏离了日志文件的主题,但我相信随着时间的推移,你会发现这个命令非常有用。
例如,你可能想要使用 –rq 选项来比较两个文件夹的内容,这样可以让比较变得递归,如下所示:
# diff –rq /path/to/folder1 /path/to/folder2
要了解更多关于 diff 命令的信息,只需输入以下命令查看手册:
$ man diff
使用截断
因此,既然我们已经展示了处理日志文件的简便性,我们应该始终记住,像这样的记录会随着时间的推移而增长,正因如此,它们可能会变得难以处理。事实上,你应该意识到,过大的日志文件可能会影响系统性能。考虑到这一点,监控任何日志轮换过程并根据需要定期调整是一个好主意。
此外,考虑到日志轮换在中高负载环境中的重要性,我建议你有效地管理这个过程。然而,在这种过程中影响较小的情况下,下面的防护技术将允许你通过键入以下任一命令来清理日志文件:
# cat /dev/null > /path/to/file
或者更准确地说,你可以像这样使用truncate命令:
# truncate --size 0 /path/to/file
这个过程被称为截断,如前所述,这应该是最后的手段,因为之前的命令会删除文件中包含的所有数据。所以记住,如果文件包含你未来可能需要查看的重要信息,请在使用truncate之前先进行备份。
总结
本章旨在介绍故障排除 CentOS 7 的主题,目的是让你了解这一主题,而不是让你背负一堆不适合你当前情况或需求的规则、指令或流程。我们知道,故障排除是一个过程,第一章已经帮助你了解了一些概念和方法,接下来的每一页都会确保你更接近于轻松应对你即将诊断和修复的服务器。所以,是的,旅程刚刚开始,我们现在将讨论如何排查正在运行的进程。
参考资料
-
Red Hat 客户门户:
access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/ -
Syslog 严重性级别:
en.wikipedia.org/wiki/Syslog#Severity_levels -
Dmesg 维基页面:
en.wikipedia.org/wiki/Dmesg -
Cat 维基页面:
en.wikipedia.org/wiki/Cat_(Unix) -
Grep 维基页面:
en.wikipedia.org/wiki/Grep -
Diff 维基页面:
en.wikipedia.org/wiki/Diff_utility -
Tail 维基页面:
en.wikipedia.org/wiki/Tail -
Less 维基页面:
en.wikipedia.org/wiki/Less_(Unix)
第二章:故障排除活动进程
对 CentOS 7 中底层活动进程的深入理解是任何故障排除人员的必要技能。从高负载平均值到响应时间缓慢,从系统过载到死掉或将死的进程,每台服务器都会经历开始变得迟缓、表现不佳或无法响应的时刻,因此,它将需要你立即关注。
在本章中,我们将:
-
了解内存管理、交换空间、交换性和抖动
-
了解如何使用
vmstat、top和ps命令分析活动进程 -
了解如何使用
iotop、iostat和lsof监控服务器 -
了解系统负载和
systemd -
了解如何查找进程 ID、识别父进程 ID 和孤儿进程,并启动各种类型的
kill信号
通过内存管理和交换空间调整服务器性能
无论你怎么看,内存使用问题始终是系统生命周期中的关键问题。无论你是在维护系统健康状态还是排除特定服务或应用程序的故障,你都需要记住,内存的使用是系统的关键资源。基于这一原因,我们将首先通过以下方式调用free命令:
# free -m
前面命令的主要元素看起来将类似于以下内容:
Total used free shared buffers cached
Mem: 1837 274 1563 8 0 108
-/+ buffers/cache: 164 1673
Swap: 2063 0 2063
在所示示例中,我使用了-m选项来确保输出的结果以兆字节为单位进行格式化。这样可以更容易阅读,但为了排除故障,我们不需要尝试理解每个显示的数字值,而是将原始输出的范围缩小,突出显示相关问题区域:
-/+ buffers/cache: 164 1673
这一行的重要性在于,它考虑了相关的缓冲区和缓存,以说明当前使用了多少内存以及多少内存被保留。第一个值表示使用的内存量,第二个值则告诉我们应用程序可用的内存量。在所示示例中,这意味着使用了 164 MB 内存,剩余 1673 MB 内存可用。
记住这一点,我请你注意最后一行,以便我们可以研究交换空间的重要性:
Swap: 2063 0 2063
交换通常发生在内存使用影响性能时。正如我们从前面的示例中看到的,第一个值告诉我们系统交换总量为 2063 MB,第二个值表示使用了多少交换空间(0 MB),而第三个值显示系统整体上还有多少交换空间可用(2063 MB)。因此,是的,基于此示例数据,我们可以得出结论:这是一个健康的系统,当前没有使用交换空间,但在这里,我们利用这段时间来进一步了解系统的交换空间。
首先,我们将重新访问proc目录,并通过输入以下命令来揭示交换空间的总大小和已用大小:
# cat /proc/swaps
假设你理解了显示的输出,那么你可以通过以下命令来调查系统使用的交换性水平:
# cat /proc/sys/vm/swappiness
完成后,你现在应该会看到一个介于 0 到 100 之间的数字值。该数字值是百分比,意味着例如如果你的系统值为 30,它将在 RAM 占用率达到 70%时开始使用交换内存。
所有 Linux 系统的默认值通常设置在 30 到 60 之间,但你可以使用以下命令中的任何一个来临时更改和修改系统的交换性。
你可以通过输入以下命令,将X的值替换为 1 到 100 之间的数字值来实现:
# echo X > /proc/sys/vm/swappiness
或者,更具体地说,也可以通过以下方式实现:
# sysctl -w vm.swappiness=X
如果你在任何时候改变主意,你有两个选项来确保没有做出永久更改。你可以重复执行前面两条命令中的任何一条,将值恢复到原来的状态,或者进行一次完整的系统重启。
另一方面,如果你想让更改生效并持久化,那么你应该编辑/etc/sysctl.conf文件,并以如下方式添加你的交换性偏好:
vm.swappiness=X
完成后,只需保存并关闭文件,以确保更改生效。
交换性值控制内核将进程从物理 RAM 移到交换磁盘的倾向。这是内存管理的一部分,但需要意识到,交换并不会立即发生,因为交换性值实际上是以百分比的形式表示的。因此,交换的过程应该更多地视为在使用缓存时的偏好度量,正如每个管理员都知道的那样,你可以通过使用命令swapoff -a和swapon -a来清除交换,以达到所需的效果。
黄金法则是要意识到,系统的交换性(swappiness)接近最大值(100)时,它会倾向于开始交换不活跃的页面。这是因为值为 100 代表着 RAM 的占用率为 0%。相比之下,系统的交换性越接近最低值(0),发生交换的可能性就越小,因为 0 代表着 RAM 的占用率为 100%。
一般来说,我们大多数人可能都会同意,拥有大量 RAM 的系统并不需要激进的交换。但为了让事情变得更加复杂,让我们换个角度来看。我们都知道,桌面电脑会从较低的交换性值中受益,但在某些情况下,你可能也会发现,拥有大量 RAM 的系统(运行批处理作业)也可能受益于适度到激进的交换,这与一个尝试做很多事情但仅使用少量 RAM 的系统类似。所以,实际上,并没有硬性规定;交换的使用应根据具体系统的需求,而不是寻找一个可以普遍适用的单一解决方案。
更进一步,在修改交换值时应特别小心,因为未被应用程序使用的内存会作为磁盘缓存使用。在这种情况下,通过减少交换性,你实际上是在增加该应用程序不被交换出去的概率,从而减少磁盘缓存的整体大小,这可能会导致磁盘访问变慢。然而,如果增加交换的优先级,由于硬盘比内存模块慢,它可能会导致整个系统响应时间变慢。交换操作可能会令人困惑,但了解这些之后,我们也能体会到交换性的隐含讽刺。正如牛顿的第三定律所说,每一个动作都会有一个相等且相反的反应,而找到最优的交换性值可能需要一些额外的实验。
使用 vmstat 管理内存
另一种内存管理的方式可以通过使用vmstat命令来实现。vmstat被认为是与内存、进程和分页相关的摘要报告功能,输入以下命令即可看到其运行:
# vmstat -a
使用-a选项调用所有活动和非活动内存时,vmstat输出中最有意义的列可以描述如下:
-
si: 该列显示从磁盘交换进来的值 -
so: 该列显示交换到磁盘的值 -
bi: 该列显示发送到块设备的值 -
bo: 该列显示从块设备接收的值 -
us: 该列显示用户时间 -
sy: 该列显示系统时间 -
id: 该列显示空闲时间
显示刚开始看起来可能会有些困惑,但对于我们的目的来说,我们需要集中注意以下在交换列下的几列:
free si so
1645452 0 0
其中free显示当前的空闲内存分配,si显示页面调入,而so提供页面调出。遗憾的是,单纯通过这种方式查看它,发现它对我们的需求有些局限,因此最有效的查看方法是通过在原始命令中添加延迟选项来管理输出,如下所示:
# vmstat X N
在这里,X是以秒为单位的数字时间值,N表示我们希望调用vmstat的次数;此代码格式的工作示范如下:
# vmstat 3 5
在这个示例中,我添加了值3和5,其中第一个数字表示延迟的秒数,第二个数字表示调用的结果次数。在这种情况下,vmstat 3 5将以3秒的延迟运行vmstat,并将显示5次更新,如下所示:
free si so
1645452 0 0
1645452 0 0
1645452 0 0
1645452 0 0
1645452 0 0
或者,你可以通过简化命令格式,减少复杂性,保持vmstat每N秒运行一次:
# vmstat N
所以,通过运行vmstat 10,vmstat会每10秒刷新一次所有活动的报告。然而,如果你需要了解事件发生的时间,可以使用-t选项,如下所示,调用一个带有时间戳的类似报告:
# vmstat -t X N
最后,由于默认的vmstat命令会以千字节为单位生成报告,为避免混淆,通常最好使用以下表达式让vmstat以兆字节为单位显示报告:
# vmstat -S M X N
当你启动一个应用程序并且信息被“调入”时,通常会发生页面调入(si)。然而,偶尔或间歇性的页面调出(so)也会发生,尤其是在内核释放内存的时期。定期的页面调出(so)或页面调出的增长是我们不希望看到的。如果这些事件的频率呈指数增长,那么这些事件就会表现为通常称为“抖动”的行为。
抖动是指系统在管理页面调度的时间超过了为应用程序或服务提供支持的时间。这不一定是一个严重的事件,但它表明故障排除人员应重新评估某些操作的价值,并考虑将它们分散到工作日的不同时间段进行处理。你总是可以为系统购买更多的 RAM,这可能在短期内有所帮助,但这并不能缩小问题的根源,也无法阻止事件的重复发生。因此,为了让我们的工作稍微轻松一点,下一步是使用top命令。
使用top命令检查系统负载
可以随时通过输入以下命令调用top命令:
# top
top命令是检查系统负载(RAM/MEM 和 CPU)的标准命令。它包含许多与内核相关的任务信息;显示内容会实时更新,最高负载因素以 CPU 或 MEM 的百分比表示。然而,重要的是要意识到,top可能会将这些值显示为超过预期的百分位范围。这是因为所有单独的核心都以百分比表示,且这些核心的多个实例会被加总。例如,一个双核系统可能会显示第一个核心为 70%,第二个核心为 60%,在这种情况下,top可能会显示合计 130%的结果,但你将无法得知每个核心的具体值。
你可以使用M键按内存对top进行排序,但正如你所见,top不仅会显示空闲内存的数量(如通过free命令看到的那样),它还会提供你在做某些操作和任务判断时可能需要的交换区细节。此外,你还可以通过定制输出内容来扩展top的功能,以显示特定用户,如下所示:
# top -u <username>
正如你所注意到的,top 会自动刷新;因此,在做出任何决定之前,尝试观察它几分钟。为了帮助这个过程,你可以要求 top 在 10 次循环后退出,如下所示:
# top -n 10
使用 top 时,你应该始终注意某些进程是由 child-processes(子进程)生成的,这些进程往往会单独显示(httpd 和 php-fpm 是这方面的典型例子),你可以预期这些服务会消耗最多的内存。
尽管可以看到一系列子进程使用了大量的内存,但你应该避免将 %MEM 列的数值相加,因为这些进程通常使用共享内存。因此,在很多情况下,你应该注意到所显示的值可能会具有误导性,出于这个原因,top 提供的结果不应作为你在做出最终决定之前唯一的依据。
你可以通过查看手册来了解更多关于 top 命令的信息,如下所示:
$ man top
使用 iotop 监控磁盘 I/O
每个管理员都知道,系统可能因为磁盘 I/O 活动过于繁重而开始变慢。然而,作为故障排除人员,你可能希望知道是哪些进程或(在多用户系统中)哪些用户是罪魁祸首,正因如此,你会想要使用 iotop——一个实时显示最消耗 I/O 的进程列表的工具,它以类似 top 的界面呈现。
首先,你需要通过输入以下命令来安装 iotop:
# yum install iotop
下载非常小,要开始一个发现会话,只需使用以下命令:
# iotop
运行没有任何参数的 iotop 会列出所有现有的进程,无论它们是否有磁盘 I/O 活动,因此,如果你只希望 iotop 报告那些有磁盘 I/O 活动的进程,你应该改用以下命令:
# iotop –o
输出非常详细,因为它的工作方式类似于 top 命令,所以熟悉后你会感到得心应手。然而,与 top 不同,iotop 显示了所有进程和线程的列表,以及磁盘活动的测量(总磁盘读取和实际磁盘读取),以便你可以快速识别哪些进程正在影响服务器上的当前 I/O 活动。
你可以通过查看手册了解更多关于 iotop 的信息,如下所示:
$ man iotop
使用 ps 命令检查进程
对于大多数希望更全面了解其系统中运行的进程的故障排除人员,我们可以使用 ps 命令,如下所示:
# ps aux | less
另外,信息可以以用户友好的树状视图模式显示,如下所示:
# ps axjf | less
如果你希望获得更少的细节,可以尝试:
# ps auxf | less
当然,我们可以在ps命令中使用更多的选项。例如,命令可以通过管道传输并与grep或tail结合使用,你还可以使用诸如ps -e这样的显式语句(显示系统中的所有进程)。或者,你也可以通过输入以下命令来定位特定进程:
# ps aux | grep <process_name>
此外,你甚至可以扩展其用法,显示所有进程(除了以 root 身份运行的进程),通过以下变化:
# ps -U root -u root -N
对于特定用户,你可以使用:
# ps -u <username> u
最后,你可以获得更多的安全信息,并将结果输出到文本文件中,方式如下:
# ps axZ > /path/to/filename.txt
基于这一点,我想你会同意说ps不仅有用,而且它的灵活性和可定制性使其成为故障排除工具箱中一个重要的工具。ps命令可以用于显示系统当前进程的快照,但对于本章来说,我们更关心的是ps命令还能为我们提供相关的进程 ID。通常简化称为PID,这个关键信息将在我们稍作岔开后重新提到,我们将深入了解系统负载。
使用 iostat 和 lsof 检查性能
在已经发现vmstat可以用于提供与内存管理相关的统计信息后,解决与性能相关的问题时,过载的 CPU 是另一个需要关注的领域。为此,我们可以像下面这样使用iostat命令:
# iostat
然而,要显示更互动的 CPU 利用率报告,你可以使用–c选项(并提供一个以秒为单位的数值,如 5 秒),像这样:
# iostat –c 5
大多数列应该是自解释的,但如果系统变得繁忙,你会看到%iowait的增加,这用于报告任何 I/O 请求完成等待时间的增加。基于此,如果服务器正在传输或复制大量文件,你可能还会注意到额外的时间花费在系统级别,因为文件将被移动进出相关的磁盘分区。在尝试监控存储设备以寻找可能的瓶颈时,iostat与数值参数结合使用是特别有用的,如下所示:
# iostat 5
正如你所看到的,要检查读/写操作,我们只是简单地为iostat添加了一个轮询选项。当然,你可以将这些知识与运行vmstat –d或vmstat –p <partition_name>命令获得的见解结合使用,但通过使用–t选项,你还可以为该命令添加时间戳,像这样:
# iostat –t 5
你应该知道iostat报告会持续运行,直到该进程被取消。然而,通过这些观察,现在使用top和其他所有命令应该会让你感到更加满意。使用以下命令的技巧特别受欢迎,因为你可以通过lsof命令查看打开的文件列表:
# lsof | less
注意
使用 lsof 时,重要的是要注意,第一列将显示使用相关文件的命令、该命令的进程 ID(PID)、用户以及打开的文件名。
因此,考虑到这一点,并意识到本章中讨论的每个命令都是相互关联的,我们回到系统负载这一重要话题。
计算系统负载
系统负载是衡量计算机系统当前正在执行的处理量的指标。它不是衡量计算机性能的完美方式,但它确实为故障排除人员提供了修复系统所需的附加证据。
与负载计算最常相关的表达式是:
实际负载 = 总负载(运行时间)/ CPU 数量
如你所知,CPU 数量已知,你可以通过查看 top 命令的结果或输入以下命令来计算运行时间:
# uptime
前述命令的输出可能如下所示:
09:59:41 up 2:36, 1 user, load average: 0.01, 0.02, 0.05
服务器负载是基于 1 分钟、5 分钟和 15 分钟的读取时间表示的数值。因此,通过查看前述输出中的最后三个值,我们可以看到,对于该系统,平均负载为 0.01(1 分钟时),0.02(5 分钟时)和 0.05(15 分钟时)。
当前,示例系统没有出现疲劳的迹象,但由于高负载的原因可能各异,这并不意味着该机器的当前状态在工作日内不会发生变化。高负载可能是数据库连接、磁盘输入输出、编码不良、网站访问频率、电力消耗大的应用程序或电子商务网站、脚本攻击、垃圾邮件、批处理作业等原因引起的。如果你遇到这种情况,只需运行 top 命令,并按常规方式开始排查系统。大多数情况下,可以找到短期解决方案(尤其是在网站在高峰时段接收到大量访问时),但只有长期计划才能防止这种情况再次发生。
在故障排查负载时,重要的是要知道,当负载增加时,处理器会排队,如果有多个处理器,负载会均匀分布到服务器的各个核心上以平衡工作负载。通常认为,服务器的理想负载值应设置为 1\。这并不意味着一旦达到或超过此值就需要立即按下“紧急按钮”,但如果你在一段时间内开始看到双位数的响应,那么是的,期望服务器(负载值 > 1)可能会在工作负载(负载值 > 10)的压力下开始出现问题。
因此,考虑到这一点,我们回到进程 ID 的话题。
使用 pgrep 和 systemctl 查找进程 ID
与其使用 ps,另一种查找特定进程 ID 的方法是使用 pgrep 命令,如下所示:
# pgrep <servicename>
在大多数情况下,使用此命令将显示进程 ID 或PID。但是,采用这种方法时,输出也可能提供多个值。所以请记住,如果某个应用程序(如httpd或ssh)提供了一个或多个进程 ID,你可以安全地假设最小的数字(代表系统生成的第一个PID)是最重要的。这个值被称为PPID或父进程 ID。
另一方面,一种更简洁的方法可以通过利用systemd,使用以下命令:
# systemctl status <service_name>.service
前述命令的输出将类似于以下示例,正如我们所见,Apache 的主PID是2413:
httpd.service - The Apache HTTP Server
Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled)
Active: active (running) since Sun 2014-12-14 01:26:37 GMT; 2min 56s ago
Main PID: 2413 (httpd)
Status: "Total requests: 0; Current requests/sec: 0; Current traffic: 0 B/sec"
CGroup: /system.slice/httpd.service
├─2413 /usr/sbin/httpd -DFOREGROUND
├─2414 /usr/sbin/httpd -DFOREGROUND
├─2415 /usr/sbin/httpd -DFOREGROUND
├─2416 /usr/sbin/httpd -DFOREGROUND
├─2417 /usr/sbin/httpd -DFOREGROUND
└─2418 /usr/sbin/httpd -DFOREGROUND
Linux 注重选项,没错,有许多方法可以获取所需的进程 ID(PID)或父进程 ID(PPID),但我们不会遍历所有选项(包括旧的和新的)。单就速度而言,我想你会同意,利用systemd命令有其自身的优势。
更多关于 systemd 的信息
systemd系统和服务管理器负责控制 CentOS 7 上如何管理服务。现在的情况发生了很大变化,结果是,你需要认识到,脚本的位置已经更改为/usr/lib/systemd/systemd,而旧的命令将被弃用到一定程度(最终)它们将被彻底移除。
例如,当使用systemd检查状态或启动或停止服务时,你可以使用以下命令之一:
# systemctl status <service_name>.service
# systemctl stop <service_name>.service
# systemctl start <service_name>.service
此外,与其使用chkconfig来启用和禁用引导序列中的服务,现在你应该使用:
# systemctl enable <service_name>.service
# systemctl disable <service_name>.service
你可能对这种方法持有不同意见,但与其纠结于变化的主题,不如考虑如何利用新命令让故障排除变得更加轻松。为此,我们将从一个简单的方法开始:列出当前所有服务,使用以下命令:
# systemctl list-units --type service
现在,一切都被称为单元,认识到这一点后,相同的命令还可以修改为显示所有挂载:
# systemctl list-units --type mount
与此同时,调用以下命令可以列出所有服务的依赖项:
# systemctl list-dependencies <service_name>.service
此外,systemd还自带了自己的top版本,若要查看与特定服务相关的进程,可以使用system-cgtop命令,如下所示:
# systemd-cgtop
正如你会注意到的,这个命令提供了所有相关进程的总结,并显示了路径、任务数量、CPU 使用百分比、内存分配以及相对的输入和输出。它的工作方式类似于top,但不同的是,它的使用可以修改为输出递归的服务内容列表,如下所示:
# systemd-cgls
输出将类似于以下内容:
├─smb.service
│ ├─2472 /usr/sbin/smbd
│ └─2473 /usr/sbin/smbd
├─httpd.service
│ ├─2394 /usr/sbin/httpd -DFOREGROUND
│ ├─2395 /usr/sbin/httpd -DFOREGROUND
│ ├─2396 /usr/sbin/httpd -DFOREGROUND
│ ├─2397 /usr/sbin/httpd -DFOREGROUND
│ ├─2398 /usr/sbin/httpd -DFOREGROUND
│ └─2399 /usr/sbin/httpd -DFOREGROUND
├─polkit.service
│ └─875 /usr/lib/polkit-1/polkitd --no-debug
├─auditd.service
│ └─672 /sbin/auditd -n
所以,正如我们所看到的,在许多方面,systemd虽然冗长,但它确实在试图获取有关活动进程的某些信息时节省了我们的时间。在这个阶段,重要的是要意识到,我们只触及了systemd的皮毛,但就本章的目的而言,我相信你继续使用它的过程将会既富有成效又愉快。
发出终止信号
想要了解进程 ID 的最常见原因是将这些信息传递给kill命令。进程 ID 确实有其他用途,但我们的主要关注点是通过发出终止信号(SIGTERM)来移除有问题的服务或应用程序,如下所示:
# kill pid_of_process
kill信号指示进程终止,从而使相关进程能够执行一些基本的清理操作,并以有序的方式退出。这种方法被称为“安全终止”。然而,根据你的具体情况,更好的解决方案可能是强制让服务或应用程序挂起,从而启用守护进程的自动重新加载,如下所示:
# kill -1 pid_of_process
这个命令被称为SIGHUP或挂起命令。另一方面,如果进程似乎崩溃了,并且安全终止或重新加载操作无法产生任何效果,那么通过传递以下命令,你将能够直接终止该进程:
# kill -9 pid_of_process
在此命令中使用选项9表示发出一个信号终止(SIGKILL),与原始的终止命令(SIGTERM)不同,这个替代版本直接发给内核,从而以更为突然的方式终止进程。此命令没有清理操作或安全退出,因此它被称为“强制终止”。
最后,为了进一步解决“强制终止”问题,使用pkill命令也是完全合适的,语法如下:
# pkill -9 httpd
另外,你可以使用pgrep命令确保所有与相关搜索词相关的进程被移除:
# pgrep httpd
所以,涵盖了kill命令的最常见用法后,剩下的技巧之一是基于需要处理孤儿进程。
处理孤儿进程
孤儿进程并不是常见的问题,但它们确实会发生,解决这些问题的第一步是通过匹配显示的PID或PPID与init进程本身使用的 ID。使用ps命令可以显示,二者的PPID都等于1。说实话,你可能会意识到孤儿进程和守护进程之间几乎没有区别,唯一的区别是孤儿进程是由于错误产生的。因此,这里的黄金法则是记住,通过一个相对简单的技巧可以识别孤儿进程,并且它可以通过标准方式终止。
孤儿进程可能由多种原因引起,尽管它们已经被 init 进程采纳,你仍然会发现它们在执行命令。因此,孤儿进程是潜在的危险,因为它们会继续占用系统资源,导致系统资源短缺。在某些情况下,过多的孤儿进程可能会导致 init 进程过载,并造成系统挂起。虽然这种情况不常见,但删除这些错误的守护进程对于故障排除人员来说是一个重要任务,如果你的系统容易发生这种情况,那么你应该时刻关注它。
总结
本章的目的是阐明一些关于故障排除活动进程的概念,在这方面,我们已经涵盖了 swap、vmstat、top、ps、进程 ID、kill 和 pkill 等内容。当然,除了这些工具,你还可以使用更多其他工具,但对于大多数故障排除人员(无论是初学者还是有经验的),了解如何监控和测量内存使用情况;确定服务器负载;关注耗电的应用程序、服务或用户;删除孤儿进程;以及使用 systemd,这将对你大有帮助,之后我们可以继续考虑如何故障排除网络问题。
参考资料
-
Red Hat Enterprise Linux 7 系统管理员指南:
access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/System_Administrators_Guide/chap-Managing_Services_with_systemd.html -
Swappiness 维基百科页面:
en.wikipedia.org/wiki/Swappiness -
vmstat命令维基百科页面:en.wikipedia.org/wiki/Vmstat -
iostat命令维基百科页面:en.wikipedia.org/wiki/Iostat -
lsof命令维基百科页面:en.wikipedia.org/wiki/Lsof -
kill命令维基百科页面:en.wikipedia.org/wiki/Kill_(command) -
pkill命令维基百科页面:en.wikipedia.org/wiki/Pkill -
SysVinit 到 Systemd 备忘单:
fedoraproject.org/wiki/SysVinit_to_Systemd_Cheatsheet -
孤儿进程维基百科页面:
en.wikipedia.org/wiki/Orphan_process
第三章:网络环境故障排除
从幽灵连接到数据包错误,从流失败到连接错误,再到缺少路由,故障排除网络环境可能是一个缓慢且艰难的过程,通常从物理层开始。然而,一旦你确认物理节点正常工作,下一步就是考虑和查阅你系统中可用的各种工具。
在本章中,我们将:
-
了解一些基本工具,这些工具将帮助你排查与网络环境相关的各种问题。本讨论将涵盖
ping、dig、host、traceroute和mtr的详细使用。 -
了解如何使用
ss命令监控网络连接。 -
学习如何使用
tcpdump检查数据包传输。
使用 ping、dig、host、traceroute 和 mtr
故障排除员最常用的一些工具有 ping、dig、host、traceroute 和 mtr。将这些工具一起使用,可以为故障排除员提供做出判断所需的证据,几乎可以解决任何网络相关的问题。这是网络工具包的基础,但需要强调的是,这些命令用于不同的目的,因此我们将分别介绍它们。
ping 命令
ping 命令是一个小型工具,可以用来确定是否可以访问特定的 IP 地址。ping 命令在大多数计算机系统中都是常见的,它允许你查询 IP 地址或完全限定的域名,以检查是否有可用的连接。
ping 命令的基本语法如下:
# ping <ip_address>
# ping <domain_name>
ping 命令通过向指定的目标发出 ICMP 回显请求来验证和检查网络连接,正是这一简单的命令使其成为诊断任何基于网络的连接问题时非常有用的工具。
例如,如果你向 Google 发出 ping 请求(# ping google.com),那么根据你的网络环境和条件,输出将类似于以下内容:
PING google.com (216.58.210.14) 56(84) bytes of data.
64 bytes from lhr08s06-in-f14.1e100.net (216.58.210.14): icmp_seq=1 ttl=55 time=10.5 ms
64 bytes from lhr08s06-in-f14.1e100.net (216.58.210.14): icmp_seq=2 ttl=55 time=10.9 ms
64 bytes from lhr08s06-in-f14.1e100.net (216.58.210.14): icmp_seq=3 ttl=55 time=36.2 ms
64 bytes from lhr08s06-in-f14.1e100.net (216.58.210.14): icmp_seq=4 ttl=55 time=11.0 ms
64 bytes from lhr08s06-in-f14.1e100.net (216.58.210.14): icmp_seq=5 ttl=55 time=10.1 ms
64 bytes from lhr08s06-in-f14.1e100.net (216.58.210.14): icmp_seq=6 ttl=55 time=32.0 ms
64 bytes from lhr08s06-in-f14.1e100.net (216.58.210.14): icmp_seq=7 ttl=55 time=10.6 ms
这些结果展示了一个成功的 ping,可以描述为一个本地计算机系统向 google.com (216.58.210.14) 发出的回显请求的旅程。
请求从主机计算机发起,然后通过本地网络传送,最后经过互联网。一旦请求成功接收,目标将进行响应,并且测量完成此过程所需的时间,以生成平均响应或延迟时间。但是,如果没有响应,则很可能是网络本身存在物理问题,或者是一些基本问题,如位置不正确或不可用,目标计算机未响应 ping 请求,或者主机路由表错误。
注意
在在线游戏中,ping 请求(也称为“高 ping”或“低 ping”)通常与从本地机器到外部游戏服务器的速度测量相关。例如,一个低 ping(例如 10 毫秒)的玩家会比一个 180 毫秒 ping 的玩家拥有更好的游戏体验。
此外,你还应该意识到,如果你的 ping 值超过 500 毫秒,则意味着任何请求需要超过半秒才能到达服务器并返回。这个条件很明显,因为你可能会经历“帧抖动”或“帧跳跃”——在在线游戏中被称为“橡皮带现象”。
ping 命令很简单易用,但在其默认形式下,它会一直执行,直到被取消。在某些情况下,这可能会很有用,但通常更容易使用 -c 选项,以减少回显请求的次数,并获取事件的总结。
例如,如果你想将回显请求的数量限制为 4 次,你需要输入以下命令:
# ping -c 4 google.com
在前面的例子中,ping 命令将在 4 次循环后停止发出回显请求,基于我们之前的例子,输出会类似于此:
PING google.com (216.58.208.78) 56(84) bytes of data.
64 bytes from lhr14s27-in-f14.1e100.net (216.58.208.78): icmp_seq=1 ttl=55 time=11.9 ms
64 bytes from lhr14s27-in-f14.1e100.net (216.58.208.78): icmp_seq=2 ttl=55 time=16.7 ms
64 bytes from lhr14s27-in-f14.1e100.net (216.58.208.78): icmp_seq=3 ttl=55 time=35.4 ms
64 bytes from lhr14s27-in-f14.1e100.net (216.58.208.78): icmp_seq=4 ttl=55 time=15.1 ms
--- google.com ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3005ms
rtt min/avg/max/mdev = 11.985/19.827/35.462/9.187 ms
在我们结束对 ping 命令的介绍之前,有几点关于任何 ping 请求需要考虑的事项。这些点可能不一定表示问题,但它们会影响 ping 测试的结果:
-
与目标的距离:假设你住在美国,并尝试连接到欧洲的服务器。在这种情况下,你应该预期 ping 值会高于你尝试连接的另一台距离你更近的美国服务器。此外,你还应该预期,不同地理位置之间的速度可能会有所不同。
-
互联网连接速度:如果你的网络带宽较低(即上传和下载速度差),则 ping 请求的响应时间会比高速带宽的宽带连接(即上传和下载速度较好)更长。
-
跳数:跳数是一个通用术语,指的是 ping 请求必须经过的路线和服务器,以便到达目标并返回。因此,就像在现实生活中一样,如果你住得离主要火车线路较远,你就需要做更多的“连接”或“跳跃”,才能到达最终目的地。
基本原则始终表明,低 ping 始终是可取的,因为它对基于时间的指令至关重要。然而,在进行 ping 测试时,你不仅要考虑实际到达目标站点的 ping 总数,还要仔细记录相关 ping 的平均值和标准差。
从这个角度看:如果 ping 请求没有到达,这可能表明由于你计算机和目标之间的互联网连接不稳定,可能会出现数据包丢失的情况。然而,如果 ping 率较低,但在特定时间段内显示出一个逐渐增大的变化率,那么在某些情况下,这种环境并不总是比同一时间段内的恒定速率更可取。
dig和host命令
dig命令可以用来验证 DNS 映射、互联网连接、主机地址和 MX 记录,并且可以帮助发现与潜在的反向 DNS 问题相关的信息,这些问题可能导致垃圾邮件和被列入黑名单。通过bind-utils包提供的dig命令,返回的信息分为四个主要部分,包括:头部部分(使用的选项列表)、问题部分(查询类型)、答案部分(相关位置的地址)、查询部分(包含关于查询时间、名称服务器等的统计信息)。dig命令是为了替代nslookup而推出的,基本语法如下:
# dig google.com
结果将如下所示:
; <<>> DiG 9.9.4-RedHat-9.9.4-18.el7_1.1 <<>> google.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 18657
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;google.com. IN A
;; ANSWER SECTION:
google.com. 299 IN A 216.58.210.78
;; Query time: 100 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Sat Apr 25 13:45:02 EDT 2015
;; MSG SIZE rcvd: 55
你会注意到,这种输出中包含了大量信息,因此让我们从全局选项部分开始逐步解析:
; <<>> DiG 9.9.4-RedHat-9.9.4-18.el7_1.1 <<>> google.com
;; global options: +cmd
然后是一个输出,报告查询的答案:
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 18657
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
紧接着,dig会重复原始问题:
;; QUESTION SECTION:
;google.com. IN A
答案如下所示:
;; ANSWER SECTION:
google.com. 299 IN A 216.58.210.78
最后,我们将看到一些关于查询本身的一般统计数据:
;; Query time: 100 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Sat Apr 25 13:45:02 EDT 2015
;; MSG SIZE rcvd: 55
同样,通过将XXX.XXX.XXX.XXX替换为相关的 IP 地址,你可以像这样查询特定的名称服务器:
# dig google.com @XXX.XXX.XXX.XXX
所以,如果你运行以下命令:
# dig google.com @8.8.8.8
你可以期望看到以下结果:
; <<>> DiG 9.9.4-RedHat-9.9.4-18.el7_1.1 <<>> google.com @8.8.8.8
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 5496
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;google.com. IN A
;; ANSWER SECTION:
google.com. 299 IN A 216.58.210.78
;; Query time: 92 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Sat Apr 25 13:46:54 EDT 2015
;; MSG SIZE rcvd: 55
此外,dig命令的默认操作是查找A记录,你可以通过调整dig语法来获取基于特定记录类型的信息,方法如下:
# dig google.com MX
# dig google.com TXT
# dig google.com NS
# dig google.com SOA
作为替代方法,并为了使结果更具普适性,你可以通过输入ANY查询来尽可能多地获取信息:
# dig google.com ANY
此外,dig命令还可以用来执行反向查找,以根据特定的 IP 地址获取相关的 DNS 信息。
这可以通过输入以下命令来实现:
# dig -x 8.8.8.8
前述命令随后会以以下方式响应:
; <<>> DiG 9.9.4-RedHat-9.9.4-18.el7_1.1 <<>> -x 8.8.8.8
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 34651
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;8.8.8.8.in-addr.arpa. IN PTR
;; ANSWER SECTION:
8.8.8.8.in-addr.arpa. 21599 IN PTR google-public-dns-a.google.com.
;; Query time: 35 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Sat Apr 25 13:49:13 EDT 2015
;; MSG SIZE rcvd: 93
如你所见,dig是一个灵活的命令行工具,它可以让你执行有效的 DNS 查询。它的输出非常详细,但可以通过+short开关来简化并提供一个简洁的答案,像这样:
# dig -x 209.132.183.81 +short
上述命令应该以以下方式响应:
www.redhat.com.
dig命令是一个极其有用的网络故障排除工具,它的成功主要归功于它能够返回问题、答案、权威和附加部分的能力。
然而,话虽如此,另一种选择是使用host命令,方法如下:
# host –a google.com
host 命令的工作方式与 dig 命令类似,但其输出如下所示:
Trying "google.com"
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 60735
;; flags: qr rd ra; QUERY: 1, ANSWER: 14, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;google.com. IN ANY
;; ANSWER SECTION:
google.com. 299 IN A 216.58.210.78
google.com. 299 IN AAAA 2a00:1450:4009:801::200e
google.com. 21599 IN NS ns3.google.com.
google.com. 21599 IN TYPE257 \# 19 0005697373756573796D616E7465632E636F6D
google.com. 599 IN MX 20 alt1.aspmx.l.google.com.
google.com. 21599 IN NS ns4.google.com.
google.com. 21599 IN SOA ns1.google.com. dns-admin.google.com. 2015041501 7200 1800 1209600 300
google.com. 3599 IN TXT "v=spf1 include:_spf.google.com ip4:216.73.93.70/31 ip4:216.73.93.72/31 ~all"
google.com. 599 IN MX 40 alt3.aspmx.l.google.com.
google.com. 21599 IN NS ns1.google.com.
google.com. 599 IN MX 30 alt2.aspmx.l.google.com.
google.com. 599 IN MX 50 alt4.aspmx.l.google.com.
google.com. 21599 IN NS ns2.google.com.
google.com. 599 IN MX 10 aspmx.l.google.com.
如你所见,host 命令与 dig 的作用类似,但它更加简洁。
例如,一个基本的 host 查询如下所示:
# host www.google.com
返回的输出将如下所示:
www.google.com has address 216.58.210.68
www.google.com has IPv6 address 2a00:1450:4009:801::2004
另外,你也可以通过以下方式指定第三方 DNS 服务器:
# host www.redhat.com 8.8.8.8
这将报告使用替代 DNS 服务器的情况,并显示如下内容:
Using domain server:
Name: 8.8.8.8
Address: 8.8.8.8#53
Aliases:
www.redhat.com is an alias for wildcard.redhat.com.edgekey.net.
wildcard.redhat.com.edgekey.net is an alias for wildcard.redhat.com.edgekey.net.globalredir.akadns.net.
wildcard.redhat.com.edgekey.net.globalredir.akadns.net is an alias for e1890.b.akamaiedge.net.
e1890.b.akamaiedge.net has address 23.195.127.72
最后,host 可以执行反向查找,如下所示:
# host XXX.XXX.XXX.XXX
所以,假设你对 Red Hat 的 Akamai Edge 服务器进行反向查找,使用以下命令:
# host 23.195.127.72
输出将如下所示:
72.127.195.23.in-addr.arpa domain name pointer a23-195-127-72.deploy.static.akamaitechnologies.com.
那么从这个角度来看:为了故障排除网络,你可以使用 dig 或 host。这两个命令在用途和功能上是相似的,但 host 提供了简单性,而 dig 则提供了更高级的、适合脚本使用的选项。
traceroute 命令
traceroute 命令旨在显示到远程目的地的路径,以及每个停靠点发生的延迟。大多数管理员都熟悉 traceroute,它有三个主要目标,可以总结如下:
-
提供数据包将要经过的整个路径的详细信息
-
提供路径上找到的设备和路由器的名称及其身份
-
报告网络延迟的情况,评估在给定路径上向每个设备发送和接收数据所花费的时间
简单来说,traceroute 命令是一个工具,用于验证数据将要经过的路径,而不会使用任何数据,所使用的语法基于以下内容:
# traceroute google.com
输出将提供指定的主机、该域的 IP 地址、所需的最大跳数以及将使用的包大小。随后的行将报告跳数、主机名、IP 地址和数据包的往返时间。你当然也可以使用 -n 选项以以下方式避免反向 DNS:
# traceroute -n google.com
traceroute 命令每次发送三个包,带有每个 TTL,并将显示往返时间 (RTT),这表示从发出探测到接收到响应包之间的时间差。这对于发现网络瓶颈非常有用,如果你开始看到星号(*),则表明路由到该主机可能存在问题,因为星号可能表示数据包丢失或丢弃数据包。然而,也需要认识到,解释 traceroute 结果需要理解并接受它固有的特点。
traceroute命令被认为是 TCP/IP 故障排除的基石。它开始时会发出一个基于 UDP 的数据包,TTL 值为 1。如果数据包到达目标,网关会发送响应包并报告其结果。然而,如果数据包没有到达目标,那么接收网关会将 TTL 值减少 1。如果 TTL 值为 0,则网关会丢弃数据包,并在发出一个增加了 TTL 值的新数据包后报告结果,以绕过下一个阶段的同一网关。这个过程会一直重复,直到到达目标主机或达到最大 TTL 值为止。
有三种不同类型的traceroute实现,分别涵盖 UDP、TCP 和 ICMP。
例如,如果你想使用 ICMP 变种,你可以输入:
# traceroute –I google.com
同样,你可以像这样使用–n选项绕过 DNS:
# traceroute -I -n 8.8.8.8
这种变种的工作方式与之前使用 UDP 的示例类似,traceroute程序将发送回显请求,途中经过的每一跳都会做出回应。然而,与 UDP 版本不同的是,这个过程将使用 ICMP。
最终的方法是使用以下方式的 TCP 变种:
# traceroute -T google.com
在许多方面,TCP 选项可能是最有效的方法,因为大多数网络都会允许这种流量。如果你的目标是 80 端口,尤其如此。然而,没有硬性规定来确定你可以或想要使用哪种版本的traceroute。这些规则将由网络配置设定,因为某些网络默认会阻止 UDP 请求(通常是 33434 到 33534 端口)。所以,基于这一点,为什么不尝试所有版本,看看哪个最适合你的环境呢?
让我们这样来看:了解traceroute的工作原理仅仅是赢得了半场胜利。如果traceroute可以到达主机,但无法到达目标,那么问题很可能出在目标上。然而,如果traceroute无法到达主机,那么问题可能出在路由本身,这不仅涉及到一些路由器拒绝traceroute数据包,还有其他一些路由器在带宽和延迟上表现出显著的差异、防火墙,以及过滤traceroute数据包的其他各种陷阱。在这种情况下,应选择多个目标(你还应该考虑使用 UDP、ICMP 和 TCP 发送请求,以绕过任何网络问题),并且考虑到互联网本质上是非对称的,通常最好在两个方向上执行traceroute操作,以便评估整体网络效率。
总的来说,traceroute是一个很好的工具,但它可能会误导你,因此在分析结果时要小心,并始终用额外的调查来补充你的工作。
mtr 命令
作为traceroute的替代方案,有mtr命令。在某些 Linux 系统上,你需要以 root 用户身份运行此命令,或者与sudo一起使用,但无论你使用哪种方法,该命令的语法非常简单,并按如下方式工作:
# mtr google.com
输出可能类似于traceroute,但显示是实时的,从而使你能够监控趋势和平均值,反映网络性能随时间的变化。因此,与traceroute不同,mtr通过收集更长时间的数据,不仅能简单地拍摄一次旅程的快照,还能检查间歇性的数据包问题。此外,作为实时更新的替代方案,mtr还将提供一个报告选项,向每个遇到的跳点发出 10 个数据包的结果:
# mtr --report google.com
所以,经过反思,可以认为mtr在监控网络连接方面优于traceroute。它确实有许多优点,并且可以提供大量细节,但考虑到你无法控制外部网络的工作方式,经验丰富的故障排除人员应始终保持警觉,并选择检查所有可用的工具。
使用ss命令监控网络连接
套接字统计命令(ss)是netstat的继任者;它不仅更快,而且能够显示更多的信息。然而,与通过/proc目录中的各种文件获取信息的netstat不同,ss命令直接从内核空间获取信息。
ss命令的基本语法如下:
# ss | less
使用这种语法,我们只是调用了所有 TCP、UDP 和 Unix 套接字连接的输出,并可选择通过管道将其发送到less,以确保结果可以在屏幕上查看。当然,您可以将此命令与-t、-u或-x选项结合使用,以限制输出仅显示 TCP、UDP 或 Unix 套接字连接,但为了使输出更加信息丰富,你可能想要将这些附加选项与-a选项结合使用,以报告连接和监听套接字,如下所示:
# ss -ta
正如你所注意到的,在前面的例子中,我们只报告了当前的 TCP 环境,可以通过类似的方式将其更改为适用于 UDP(ss -ua)或 Unix 套接字连接(ss -xa)。然而,如果你喜欢一定程度的精确性,你会欣慰地知道,ss命令可以通过使用–A选项与查询结合使用,如下所示:
# ss -a -A tcp
限制输出确实能使信息更加简洁,但要进一步提升,可以使用以下语法应用附加的过滤器:
# ss [ OPTIONS ] [ STATE-FILTER ] [ ADDRESS-FILTER ]
例如,考虑到所有标准的 TCP 状态,你可以以下列方式显示所有已建立的 IPv4 TCP 套接字:
# ss -t4 state established
你可以像这样显示所有关闭的 TCP 状态:
# ss -t4 state closed
现在,可以说使用ss命令的效果与使用netstat -a类似。部分是正确的,但(记住你可以将-t替换为-u或-x)考虑到通过不解析主机名来提高执行速度(ss -nt),只显示监听套接字(ss -ltn),显示套接字内存使用情况(ss -t -m),显示使用特定套接字的进程(ss -t -p),打印进程名称(ss -ltp),显示 IPv4 或 IPv6(ss -tl4或ss -tl6),并显示时间信息(ss -tn -o),你会发现我们才刚刚触及ss命令的表面。
例如,你甚至可以运行查询,通过使用以下语法来发现谁在使用端口 22(SSH):
# ss -lpn | grep 22
另外,你可以使用以下语法来显示从远程 IP 地址连接的所有端口:
# ss dst XXX.XXX.XXX.XXX
然后使用以下变体将查询过滤到特定端口:
# ss dst XXX.XXX.XXX.XXX:22
记住,熟悉你的网络环境总是会有所帮助,掌握了这个命令后,你应该能在问题连接发生之前就能识别它们。
使用 tcpdump 进行数据包分析
tcpdump命令是一种数据包分析工具,它能够捕获并提供通过网络接口传输的流量描述。它是大多数 Linux 发行版的标准工具,提供了一个独特的网络数据包层级视图,在网络故障排除时非常有用。
使用tcpdump的基本语法如下:
# tcpdump -i <device_name>
你还可以像这样指定协议:
# tcpdump -i <device_name> tcp
端口值可以按以下方式使用:
# tcpdump -i <device_name> port 22
可以使用-v或-vv选项发出详细信息选项,而通过使用-n选项可以避免 DNS 解析。然而,由于tcpdump会一直运行,直到请求被取消,因此最好使用-c选项来捕获预定数量的事件,像这样:
# tcpdump -c 10 -i <device_name>
更进一步,你可以通过调用src选项(源)或dst选项(目的地)来从特定 IP 地址捕获10个数据包,像这样:
# tcpdump -c 10 -i <device_name> src XXX.XXX.XXX.XXX
设备名称本身可以通过运行以下选项获取:
# tcpdump -D
tcpdump命令可以在读取模式和写入模式下运行。然而,后者意味着使用-w选项,这会导致tcpdump将数据包数据保存到文件中以供后续分析,而前者,通过使用-r选项,意味着tcpdump只会从已保存的数据包文件中读取。如你所知,在写入模式下你应该指定相关的设备名称(即eth0),但在这两种情况下,只有匹配表达式的数据包才会被匹配并显示出来。
例如,在读取模式下,这个命令的基本语法如下:
# tcpdump -r <file_name>
在写入模式下,你可以以以下方式发送整个以太网帧进行进一步分析:
# tcpdump -w /path/to/file -i <device_name>
如你所见,tcpdump最常见的应用是验证双向通信是否正常。tcpdump命令可以用来记录网络片段,在认识到这一点后,我们仅仅触及了它灵活性的表面。
因此,我希望你能已经看到,当排查你的网络环境问题时,这个小工具可以成为一个重要的工具。
总结
本章的目的是提供一个起点,以便在尝试排查网络环境中的问题时使用。当然,学习的内容总是有更多,而了解这些将带你踏上远超dig、ping甚至tcpdump基本语法的旅程。然而,通过学习多个命令和工具,你现在可以看到,成为一个有效的故障排除者正变成一个可以实现的目标。为了进一步推动这一目标,我们将把注意力转向包管理的故障排除需求。
参考文献
-
TCP 的维基百科页面:
en.wikipedia.org/wiki/Transmission_Control_Protocol -
Ping 的维基百科页面:
en.wikipedia.org/wiki/Ping_(networking_utility) -
Traceroute 的维基百科页面:
en.wikipedia.org/wiki/Traceroute -
ss命令的官方页面:www.cyberciti.biz/files/ss.html -
ARP 的维基百科页面:
en.wikipedia.org/wiki/Address_Resolution_Protocol -
dig命令的维基百科页面:en.wikipedia.org/wiki/Dig_(command) -
tcpdump的维基百科页面:en.wikipedia.org/wiki/Tcpdump
第四章。解决包管理和系统升级问题
Yellowdog Updater, Modified (Yum) 已经存在一段时间了。它易于使用,并在安装或升级 CentOS 软件包时减少了依赖管理的复杂性。更常被称为 Yum,本章将假设您已经精通其基本用法(包括安装软件包、更新软件包、删除软件包和搜索软件包),因为我们的目的是通过接近包管理和系统升级的主题来继续本书的总体前提。
在本章中,我们将:
-
学习如何使用 RPM 和 YUM 收集软件信息
-
学习如何使用 Yum 插件使故障排除过程更轻松
-
故障排除与包安装及更新相关的问题
-
发现如何扩展系统并安装额外的 Yum 仓库
-
学习如何使用 Yum 下载 RPM 软件包
-
学习如何恢复 RPM 数据库
-
讨论管理小系统升级的复杂性
收集软件信息
在开始解决 YUM 之前,我们将稍微偏离一下,把注意力转向收集必要的软件信息,以便更多地了解系统整体情况。
为此,我们将从运行以下命令开始:
# cat /etc/redhat-release; lscpu | grep -i arch; yum repolist all; ls -alsh /etc/yum.repos.d;
在这个阶段,我不会解释上面示例中显示的每个命令,但您会注意到输出内容冗长,并详细描述了 CentOS 的发布信息。显示的信息包括服务器的整体架构、域、时间和日期信息,以及 Yum 使用的仓库列表的范围、状态和权限。
到目前为止一切顺利,但是如果我需要了解服务器上已安装的基于 RPM 的软件包呢?与其浏览整个系列的配置文件(甚至是做一个有根据的猜测),为什么不简单地使用以下命令:
# rpm -qa | sort | less
如您所见,根据服务器上安装的内容,上述命令将输出大量(或者相对较少)基于 RPM 的软件包列表。如果这显得太详细,而您只是想快速了解安装历史,您可以输入以下命令来显示基于 RPM 的软件包总数:
# rpm -qa | wc -l
正如我们使用了wc命令,输出将被限制为表示所请求信息的数字值。对于您的确切需求来说,这可能过于简单或模糊,但它将为您提供关于所讨论的服务器当前使用情况的坚实基础(特别是如果此任务在特定时间段内重复执行)。
那么,为什么要止步于此?如果您感到更加好奇,那么您还可以通过输入以下命令来请求关于安装的 Yum 软件包的信息:
# yum list installed | sort | less
注意
在这个阶段,你可能会问,yum list installed 和之前提到的 rpm –qa 命令有什么区别?简单来说,前者是基于 Yum 的命令,它还会列出包依赖关系,因此你应该在输出中看到更多的细节。
再次说明,这个列表的内容可能会根据所涉及服务器的用途而有所不同,但对于那些喜欢良好管理的人来说,这个功能可以通过将输出打印到你选择的文件中来加以改进,命令如下:
# yum list installed | sort > /path/to/filename.txt
再次说明,在这个阶段并没有什么复杂的内容,但在我们完成这些初步步骤之前,需要意识到,我们刚刚揭开了一个以前未知的 CentOS 服务器的一些秘密。我们对系统的熟悉程度正在不断提高,随着我们活动的进行,你现在会对新环境感到更加舒适和自如。毕竟,当服务器宕机,其他人都在惊慌失措时,这里获得的信心将有助于你最终的成功。
使用 Yum 插件
Yum 是最广泛使用的包管理工具之一,但许多管理员并不知道它自带一个插件系统,可以用来扩展其功能。可以说,许多插件是默认安装的,但由于假设你对当前系统一无所知(这对于任何故障排除人员来说都是常见的情况),我们将从安装 yum-skip-broken 包开始。
那么,我们从输入以下命令开始:
# yum install yum-skip-broken
完成了这个步骤(并确认该套包现在已被系统识别),我们可以使用 --skip-broken 插件来处理任何想要更新或升级某个包,但由于报告依赖关系损坏而被拒绝的情况。
为此,可以使用以下命令的组合:
# yum update --skip-broken && yum upgrade --skip-broken
当然,你可以简化上述命令,以便符合自己的需求(例如将命令分成两行),但需要注意的是,这些情况下发生错误的原因通常与混合(不兼容的)第三方仓库有关。在这方面,为了实现长期解决方案,你需要减少使用的第三方仓库的数量。然而,在尝试这一操作之前,你应该回顾 Yum 过去的事务,以了解这会如何影响系统。
这可以通过输入以下命令来实现:
# yum history
上述命令现在将生成一个包含 Yum 所有历史操作的列表,从而提供一个非常有用的详细信息层级,当你尝试调试一个故障服务、修正包依赖或协助减少对第三方仓库的依赖时,这个信息会非常有用。此外,在这个命令生成的列表中,你还会注意到每个事务都有一个唯一的标识符。
唯一标识符可以用来获取有关特定事件的更多信息,输入以下命令:
# yum history info <unique_identifier>
或者,在不需要如此详细信息的情况下,你可以通过输入以下命令始终获得所有最近事件的摘要:
# yum history summary
话虽如此,既然我们谈论到了 Yum 插件,你还应该知道,changelog信息并不是直接可以通过 Yum 包管理器获得的。同样,这类信息可能很有用,但为了进一步了解,你需要通过输入以下命令安装changelog插件:
# yum install yum-plugin-changelog
完成此操作后,你就能够像这样查询 Yum 的changelog:
# yum changelog all <package_name>
由于此输出可能会让人感到有些不知所措,因此知道你可以通过简单地将all替换为表示要显示记录数量的数字值来限制显示的信息,这一点非常有帮助。所以,如果你想查看 Postfix 的5个最近更新,你可以输入:
# yum changelog 5 postfix
此外,安装了这个插件后,你可以通过输入以下命令来查看任何包安装之前的相关changelog信息:
# yum update --changelog
这是一个小巧但有趣的功能,可以通过输入以下命令来扩展显示所有最近的changelog信息:
# yum changelog all recent
或者,你可以通过输入以下命令查看所有过时的包:
# yum changelog all obsoletes
最后,在我们结束关于使用 Yum 插件的讨论之前,可能会有一种情况需要使用yum-utils,如果它当前没有在系统中安装,你可以通过输入以下命令来安装:
# yum install yum-utils
这一补充使得包管理变得更加轻松,考虑到需要解决的一系列问题,包括删除孤立包或重复包,以及包清理操作的执行。
例如,要删除孤立包,可以输入:
# package-cleanup --orphans
要删除重复项,可以使用:
# package-cleanup --dupes
为了方便删除旧内核,你可以输入:
# package-cleanup --oldkernels
参考上述示例,如果你的系统维护着多个旧的内核,可以通过运行命令rpm -q kernel来查询它们。正如你所看到的,这个简单的操作可以提供你所需的信息,从而决定是否可以释放磁盘空间。如果看到旧的内核,你可以按照常规方式将其删除。然而,我并不建议你非得这么做,我揭示这个功能的目的是证明yum-utils有许多有趣的功能,值得探索,因为它是 Yum 中一个被低估的方面,在故障排除包管理时能发挥重要作用。
修复 Yum 操作
现在,需要意识到的是,在许多情况下,Yum 出错的普遍原因可能与网络环境、磁盘空间、混合仓库或系统的 DNS 设置有关。然而,也有一些情况,常见的操作错误需要通过刷新 Yum 本身来解决,可以使用以下命令中的一个或多个:
要清除旧的包信息,您应使用:
# yum clean headers
要清除所有缓存的包,请使用以下命令:
# yum clean packages
要清除所有缓存的基于 XML 的数据,请使用以下命令:
# yum clean metadata
然而,如果您希望完全刷新 Yum 缓存(包括所有头信息、元数据、下载的包等),您可以随时使用以下命令完成此过程:
# yum clean all
安装额外的 Yum 仓库
安装额外的仓库不一定被视为故障排除任务,但它确实有助于缓解许多与包依赖性相关的问题,并尽量保持您的系统在 Dev/Ops 环境中具有相关性。
在接下来的文本中,我已包含一些最流行的仓库的安装说明。然而,您应该意识到,这些仓库的位置在 CentOS 的不同版本中会有所不同,并且这些链接会随着时间的推移而更新。更多信息可以在本章末尾找到,供日后参考。
EPEL
企业 Linux 附加软件包(EPEL)仓库提供了官方 CentOS Linux 仓库中未包含的有用软件包,其中一些将在本书的后续章节中介绍。它也是许多其他第三方仓库的依赖项。
对于 CentOS 7,您应按照此过程安装 EPEL 仓库:
# cd /root
# wget https://dl.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-7-5.noarch.rpm
# yum install epel-release-7-5.noarch.rpm
完成相关步骤后,只需确认是否继续安装,然后输入以下命令以确保其已启用:
# yum repolist all
EPEL 通常被认为是一个基础仓库,许多其他仓库也常常依赖它。鉴于我们希望保持系统的更新,我已包含了安装 Remi 和 IUS 仓库的程序。然而,带着强烈的警告,我建议只使用其中一个,以避免在同一系统上使用它们可能引发的冲突。
Remi
Remi 仓库依赖于 EPEL 仓库,并向 CentOS 核心 Linux 仓库提供软件的新版本;因此,安装了此仓库后,您可以预期在下次运行 yum update 时,CentOS 系统会进行多次更新。
对于 CentOS 7,您应按照此过程安装 Remi 仓库:
# cd /root
# wget http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
# rpm -Uvh remi-release-7*.rpm
默认情况下,Remi 仓库是禁用的;要启用它,我们需要更新配置文件并将其标记为活动状态。
要执行此操作,请在您喜欢的文本编辑器中打开以下文件:
# nano /etc/yum.repos.d/remi.repo
现在,改变:
enabled = 0
阅读:
enabled = 1
此外,如果您想使用 PHP 5.5 库,只需在同一文件 remi.repo 中取消注释 [remi-php55] 引用。完成后,保存并关闭文件,然后输入以下命令以确保其已启用:
# yum repolist all
IUS 仓库
作为 Remi 的替代方案,IUS 仓库也向核心 CentOS Linux 仓库提供更新的版本,但开发人员强调,IUS 通常使用不同的包名,以避免软件版本更新时可能出现的冲突。这个简单的包名方法在 CentOS 社区中得到了广泛支持,因为这种控制级别在关键任务环境中非常有用。IUS 仓库依赖于 EPEL 仓库,但再次强调,我建议不要将这个仓库与其他来源混合使用。
对于 CentOS 7,你应该按照以下步骤安装 IUS 仓库:
# cd /root
# wget http://dl.iuscommunity.org/pub/ius/stable/CentOS/7/x86_64/ius-release-1.0-13.ius.centos7.noarch.rpm
# rpm -Uvh ius-release*.rpm
此外,鉴于 IUS 仓库的工作方式独特,你应该知道有一个叫做 yum-plugin-replace 的包,它用于帮助从默认包升级到 IUS packageXY 风格的包。
再次,我在本章结尾提供了一个关于如何使用这个工具的链接(预计这些指令可能会随时间改变),但目前,你可以通过输入以下命令开始:
# yum install yum-plugin-replace
总体而言,无论你是使用 Remi 还是 IUS,请记住,黄金法则是不混合使用它们,但无论你选择哪个仓库,预期它们都会对你有帮助。
使用 Yum 下载 RPM 包
如果有需要下载一个包但不安装它的情况,可以通过 Yum 来实现。然而,在开始这个过程之前,你需要确保你的系统已经安装了以下工具:
# yum install yum-plugin-downloadonly
在大多数情况下,它可能已经被安装(因为它是之前提到的 yum-utils 包的一部分),但完成这个任务后(或者确认它已经存在),你可以通过自定义以下命令,将所需的包下载到你选择的目录:
# yum install <package_name> --downloadonly --downloaddir=/path/to/folder
例如,为了理解之前的命令,你可以通过输入以下命令,将 Samba 及其所有依赖项下载到用户目录中:
# yum install samba --downloadonly --downloaddir=/home/username
或者,你也可以调用以下变体,尽管这个版本的命令假设下载的文件会存储在你当前的目录:
# yumdownloader <package_name>
完成这一步后,接下来的步骤是提取使用 yumdownloader 下载的包内容,以便通过以下命令访问相关的 RPM:
# rpm2cpio <package_name> | cpio -idmv
cpio 命令通常用于备份,其功能是便于将文件进出 cpio 压缩包。它的工作方式类似于 tar,但与 tar 不同,cpio 可以与 find 命令结合使用。
例如,要进行备份,你可以通过以下方式访问相关目录:
# cd /path/to/directory
列出目录内容,确保所有内容都在:
# ls -altr
现在,以以下方式运行备份目录的命令:
# find . -print | cpio -ocv > /path/to/backup-name.cpio
所以,通过几步简单的操作,我们已经学会了如何通过 Yum 下载一个软件包,并使用cpio命令提取相关的包数据。这个过程在排查特定服务或应用程序的依赖问题时可能会非常有用。这可能是你第一次接触cpio命令,也许你不会感到惊讶,因为我们仅仅触及了它的一小部分功能。因此,我鼓励你深入学习它,因为你会发现它在未来某些时候会非常有用。
关于cpio命令的更多信息可以在本章末尾找到,但作为参考,你可以通过输入以下命令开始你的探索:
$ man cpio
诊断损坏的 RPM 数据库
RPM 是一个包管理工具,它将软件包的信息存储在位于/var/lib/rpm的数据库中,但有时会观察到该数据库可能会失败。如果发生这种情况,rpm命令将无法使用,在这种情况下,系统可能会开始出现与任何基于 Yum 或 RPM 的进程相关的故障迹象。
例如,在进行典型的 Yum 更新过程时,你可能会看到以下消息:
"error: cannot open Packages database in /var/lib/rpm"
在此,我不得不强调良好备份策略的重要性,但作为故障排查人员,这可能超出你的控制范围。因此,在这种情况下,可以通过完成以下步骤来诊断恢复 RPM 数据库的基本过程:
# cd /var/lib/rpm
# rm -rf __db*
# rpm -v --rebuilddb
完成上述步骤后,你应该能够运行各种健康检查,以确认是否没有段错误,可以通过以下命令之一或多个进行检查:
# db_verify Packages
# db_stat -CA
# rpm -qa
# rpm -Va
# yum update
例如,运行命令db_verify Packages后,你应该看到以下类型的输出:
BDB5105 Verification of Packages succeeded.
希望这个过程能够解决问题。然而,需要认识到,这个过程并不是绝对的,它可能会失败。换个角度来看,为了避免这种情况,定期备份/var/lib/rpm应视为所有 CentOS/RHEL 系统的常规操作。如果包验证过程失败,你需要考虑从最近的备份中进行完全恢复。
小版本升级
对于 CentOS 7 用户,完成小版本升级的简便方法只是使用 Yum,但和往常一样,在继续操作之前,你应该进行完整备份。
你应该备份的文件类型因系统而异,但通常包括配置文件、重要的系统文件、用户数据、数据库、网站版本控制和应用程序文件。此外,如果你使用的是专有软件,在进行更新之前,你应与原开发者确认任何升级的可行性。
因此,在考虑了所有这些措施之后,如果可能的话,我建议您在操作前备份整个系统,您可以放心,备份中会有所有内容。
要开始进行小幅升级,您可以通过输入以下命令查看当前 CentOS 版本信息:
# cat /etc/redhat-release
然后,您可以通过以下命令查看 Linux 信息:
# uname -mrs
现在,在您调用 Yum 获取更新包列表之前,通常最好先输入以下命令:
# yum clean all
然后,按照以下说明清除 Yum:
# yum check-update
现在,您将看到所选系统的更新列表。这些待更新的内容将以常见的格式显示,详细列出包名和版本信息。
如果您希望更新系统,请使用以下命令:
# yum update
任何更新所需的时间可能会有所不同,因此您可能需要耐心等待。然而,在成功完成此步骤后,您可能想考虑重新启动系统。如果更新需要在启动阶段对内核进行任何更改,重启系统尤为有利。
要执行此操作,请输入:
# reboot
最后,在重新启动完成后,您可以使用以下命令验证系统更新:
# uname -a
现在,运行以下一个或多个命令以确保所有服务和应用程序都正常运行:
# tail -f /var/log/messages
# netstat -tulpn
# ps aux | less
摘要
在本章中,我们迅速了解了包管理故障排除的细节。虽然还有很多内容可以进一步学习,但作为系统管理员,您不仅发现了一系列可以用来解决 Yum 相关常见问题的工具,还讨论了通过各种插件扩展 Yum、安装第三方仓库、启用 Yum 下载 RPM 包以及恢复 RPM 数据库的能力。
如您所见,在我们继续讨论用户、目录和文件之前,通过一些 lateral thinking(横向思维)和一点练习,您现在应该能够排除大量问题,并将几乎所有的包管理问题抛诸脑后。
参考资料
-
CentOS 升级工具:
wiki.centos.org/TipsAndTricks/CentOSUpgradeTool -
如何从 Enterprise Linux 6 升级到 Red Hat Enterprise Linux 7?:
access.redhat.com/solutions/637583 -
CPIO 的维基百科页面:
en.wikipedia.org/wiki/Cpio -
EPEL/epel7beta-faq:
fedoraproject.org/wiki/EPEL/epel7beta-faq -
EPEL/epel7:
fedoraproject.org/wiki/EPEL/epel7 -
/pub/epel/7/x86_64/e 的索引:
dl.fedoraproject.org/pub/epel/7/x86_64/e/ -
Les RPM de Remi - 博客:
blog.famillecollet.com/pages/Config-en -
Remi 索引:
rpms.famillecollet.com/enterprise/ -
/pub/ius/stable/CentOS 的索引:
dl.iuscommunity.org/pub/ius/stable/CentOS/ -
ATrpms 仓库:
atrpms.net/about/ -
Nux 仓库:
li.nux.ro/repos.html -
RPM 首页:
rpm.org -
RPM 恢复诊断:
www.rpm.org/wiki/Docs/RpmRecovery
第五章:故障排除用户、目录和文件
与之前讨论的主题不同,故障排除用户、目录和文件的过程可以看作是一个持续的过程,需要在服务器的生命周期中不断关注。它将成为日常事务,因此,我们将从用户管理的基本原则开始,目的是向你展示如何恢复默认的文件和文件夹权限,恢复丢失的文件,并带你走过许多相关主题,为你准备应对专业故障排除人员可能遇到的各种问题。
在本章中,我们将:
-
了解如何有效管理添加、删除、修改用户的过程,并使用
login.defs实现系统范围的更改 -
了解如何使用
utmpdump监控用户活动 -
了解如何重置 root 密码并启动基于 root 的日志记录,以实现更好的命令行安全审计
-
了解如何使用 Scalpel 恢复丢失的数据
-
了解如何恢复默认的权限和所有权
-
通过了解如何进行持续修复和检查碎片整理,进一步探索 XFS 文件系统
-
了解如何审计目录和文件
-
了解如何可视化目录和文件
用户
用户管理是与管理服务器相关的基础技能,在这方面,它无疑是解决任何系统问题时的一个里程碑。因此,考虑到这一点,我们将快速分析管理用户的过程,以消除任何困惑。
添加用户并强制密码更改
你可以使用以下命令添加新用户(并为他们创建主目录):
# adduser <username>
你可以这样为新用户提供密码:
# passwd <username>
或者,如果你想强制重置密码,意味着用户必须重置其密码,那么以下命令就足够了:
# chage -d 0 <username>
此外,你可以通过输入以下命令为特定用户取消密码:
# usermod -p "" <username>
但是,如果你想授予新用户使用sudo的权限,那么请输入以下命令:
# gpasswd -a <username> wheel
最后,如果你想了解更多关于用户的信息,使用以下命令将显示他们当前的属性:
# id <username>
删除用户
删除用户账户的操作通常是直接的,但它可能涉及多个容易被忽视的步骤。因此,为了避免在大规模用户系统中出现任何未来的问题,在删除用户之前,应先按以下方式锁定账户:
# passwd -l <username>
然后,你需要使用tar备份用户的主目录,并通过输入以下命令来确认是否存在与该账户关联的活动进程:
# ps aux | grep -i <username>
完成这些后,你现在可以通过以下命令结束与该账户关联的任何活动进程:
# pkill -u <username>
或者,你可以像这样删除单独的进程 ID:
# kill -9 <pid>
通过使用pkill,您调用了SIGTERM命令,这将简化移除与该账户关联的任何活动进程的任务。因此,在这个阶段,您应该考虑移除任何文件、打印作业,并重新分配或删除与该账户关联的任何cron作业。
您可以通过键入以下命令来执行此操作:
# find / -user <username> -print
完成这些操作后,您可以安全地删除用户:
# userdel -r <username>
使用-r选项还会删除与该账户关联的主目录,但如果您希望删除用户、其主目录并移除任何SELinux映射,您应该使用:
# userdel -rZ <username>
然而,如果遇到任何困难,您可以始终以以下方式使用强制选项:
# userdel -rfZ <username>
最后,您需要考虑移除与该用户关联的任何 SSH 密钥。确保该账户没有启用sudo或su,然后逐一处理您的应用程序和服务(包括数据库、电子邮件、文件共享、htaccess、网页目录、CGI 文件等),同时为系统可能使用的任何公共账户重新分配新的设置。
修改用户
对于故障排除人员来说,用户管理的一个最有用的方面是能够修改现有的用户账户。可能有许多原因需要执行此任务,但最好的说明这种技能的方法是从修改以下文件中的默认adduser属性开始:
# nano /etc/default/useradd
从这里,您可以重新定义使用的 shell、主目录的默认位置以及是否设置默认的邮件队列。
例如,您可以使用此技术将主目录的默认位置从/home更改为/home/<公司名>。然而,如果您更倾向于手动操作(逐个案例处理),为了更改主目录的位置,您需要使用usermod命令结合-d选项(新目录的路径)和-m选项(移动当前主目录的内容),如下所示:
# usermod -m -d /path/to/new/home/directory <username>
在运行上述命令时,重要的是要意识到,如果该用户正在使用系统,控制台上将显示一个 PID,在进行任何修改之前,必须终止该进程。
最后,如果需要将现有用户转移到不同的组,可以通过调用-g选项来实现,如下所示:
# usermod -g <new_group_name> <username>
然而,完成这些操作后,就像删除用户一样,您必须手动更改任何crontab文件或任务的所有权,并通过对任何剩余(相关/现有)服务进行必要的修改来完成该过程。
了解 login.defs
在管理用户时,另一种替代方法或长期方法是考虑修改/etc/login.defs中找到的默认设置,这样您就可以更改删除命令的行为。
例如,假设您发现以下行被注释掉,如下所示:
#USERDEL_CMD /usr/sbin/userdel_local
取消注释这一行,它将确保移除所有at/cron/print任务。此外,你还可以使用login.defs文件来确定分配给用户邮件目录、密码加密方式、密码过期周期、userid、groupid等的默认值。
使用 utmpdump 监控用户活动
跟踪用户活动是任何 Linux 管理员最基本的技能之一。在需要解决与用户管理相关的故障排除问题时,我们可以使用utmpdump。
用户历史通常存储在以下位置:
-
/var/run/utmp:这个二进制文件的目的是记录打开的会话。你可以使用utmpdump /var/run/utmp查看该文件的内容。 -
/var/run/wtmp:这个二进制文件的目的是记录连接历史。你可以使用utmpdump /var/log/wtmp查看该文件的内容。 -
/var/log/btmp。这个二进制文件的目的是记录失败的登录尝试。你可以使用utmpdump /var/log/btmp查看该文件的内容。
更进一步,你还可以通过输入以下命令来查看/var/run/wtmp中当前记录的会话历史:
# last
你可以通过输入以下命令查看/var/run/btmp中当前记录的会话历史:
# lastb
然而,鉴于对这些文件的简单查看对于我们的需求来说有些冗余,你可以使用以下命令查看这些文件的当前状态:
# stat /var/run/utmp
# stat /var/log/wtmp
# stat /var/log/btmp
这些命令的输出可能类似于以下内容:
Access: 2015-04-26 07:29:13.143818061 -0400
Modify: 2015-04-26 06:24:02.444728081 -0400
Change: 2015-04-26 06:24:02.444728081 -0400
由于二进制文件无法通过基本的阅读命令如cat、less和more进行查看,因此,除了简单依赖last、who、lastb等基本命令外,另一种方法是使用utmpdump命令,方式如下:
# utmpdump /path/to/binary
如前所述,如果你想读取/var/run/utmp,可以使用以下命令:
# utmpdump /var/run/utmp
而其余的文件可以通过以下方式访问:
# utmpdump /var/log/wtmp
# utmpdump /var/log/btmp
使用完这三个命令后,你会注意到输出格式是熟悉的,最明显的区别是wtmp的结果按逆序显示,而utmp和btmp则按时间顺序显示。
utmpdump的结果格式如下:
-
第一列显示会话标识符;值 7 通常与新登录事件关联,而值 8 则与登出事件关联。
-
第二列显示 PID。
-
第三列可以根据以下任一条件包含一个相对变量:
-
~~,表示运行级别或系统重启变化 -
bw,或称为启动等待进程 -
一个数字或 TTY 值
-
一个字符/数字,表示 PTY 值(伪终端)。
-
-
第四列有时可能为空,或者保留一个关联的用户名、运行级别或重启值。
-
第五列(如果该信息可用)将显示 TTY 或 PTY 值。
-
第六列将显示远程主机的身份。在大多数本地情况下,你最多只会看到一个运行级别信息,但对于远程访问,你会看到 IP 地址或名称。
-
第七列将显示远程主机的 IP 地址,或者如果是本地访问,则显示 0.0.0.0。
-
第八列(最后一列)将指示记录创建的时间和日期信息。
你还应该注意,如果没有进行 DNS 解析,第六列和第七列将显示相同的信息。
所以,考虑到前述信息,通过一点练习,并使用我们在前几章中发现的技巧,utmpdump可以用来执行广泛的查询,例如显示像这样的常规访问信息:
# utmpdump /var/log/wtmp
此外,你可以使用grep显示特定记录的详细信息。
例如,如果你想显示某个特定用户的wtmp记录,你可以输入:
# utmpdump /var/log/wtmp | grep <username>
进一步来说,你可以使用grep以以下方式识别来自特定 IP 地址的登录次数:
# utmpdump /var/log/wtmp | grep XXX.XXX.XXX.XXX
或者使用以下语法检查 root 访问系统的次数:
# utmpdump /var/log/wtmp | grep root
然后使用以下命令来监视失败登录尝试的次数:
# utmpdump /var/log/btmp
请记住,btmp的输出应该是最小化的,因为这个二进制文件将显示与使用错误密码或尝试使用未知用户名登录相关的各种问题。特别是当 tty1 被显示为正在使用时,后者尤其重要,因为这表示一个未知的人访问了你机器上的终端。从这个角度来看,注意到这样一个重要问题可能会激发你运行安全审计,检查访问权限和密钥,通过以下命令创建一个基本的基于文本的输出文件:
# utmpdump /var/log/btmp > btmp-YYYY-MM-DD.txt
重置 root 密码并增强日志记录
随着 CentOS 7 的发布,你可能会发现重置 root 密码的过程发生了变化。所以,如果你忘记了 root 密码,你需要按照这些重要步骤进行操作。
启动计算机,并在内核屏幕阶段按E键。在下一个屏幕上,滚动文本并查找以下行:
root=/dev/mapper/centos-root ro
现在,替换字母ro为以下内容:
rw init=/sysroot/bin/sh
它应该看起来像这样:
root=/dev/mapper/centos-root rw init=/sysroot/bin/sh
完成后,按Control + X 或 Ctrl + X 以使用 bash shell /sysroot/bin/sh进入单用户模式。
在单用户模式下,输入:
# chroot /sysroot
在井号(#)后,输入:
# passwd root
按照屏幕上的指示进行操作,并继续重置密码,但如果你确实需要更新SELINUX,在做任何操作之前,使用命令touch /.autorelabel。
当你准备好完成时,输入以下命令以按通常的方式访问机器:
# exit
现在,以通常的方式重新启动你的系统:
# reboot
做得好!你现在应该能够使用新的 root 密码完全访问系统。然而,如果你决定更新所有系统命令的日志记录,只需在你喜欢的文本编辑器中打开以下文件:
# nano /etc/bashrc
向下滚动到文件底部并添加以下行:
readonly PROMPT_COMMAND='history -a >(logger -t "$USER[$PWD] $SSH_CONNECTION")'
完成这一步后,你会发现所有基于 SSH 的命令行活动都被记录在/var/log/messages中,如下所示:
Jan 11 11:38:14 centurion1 journal: root[/root] 192.168.1.17 53421 192.168.1.183 22: last
Jan 11 11:38:26 centurion1 journal: root[/var/log] 192.168.1.17 53421 192.168.1.183 22: cd /var/log
Jan 11 11:38:32 centurion1 journal: root[/var/log] 192.168.1.17 53421 192.168.1.183 22: cat messages
Jan 11 11:38:49 centurion1 journal: root[/var/log] 192.168.1.17 53421 192.168.1.183 22: last
使用 Scalpel 恢复丢失或删除的文件
如果文件不小心从系统中删除,你可以使用一个名为 Scalpel 的小工具来恢复它。Scalpel 是 Foremost 的一个更快的替代工具,Foremost 最初由美国空军特种调查办公室和信息系统安全研究中心开发。如今,它是一个通常与数字取证调查和文件恢复相关的工具,你可以通过键入以下命令来安装它:
# yum install scalpel
你需要 EPEL 仓库来完成这个过程(这在前一章中讨论过),但是当你准备好时,只需更新以下配置文件,以确定你希望搜索哪些类型的文件:
# nano /etc/scalpel.conf
完成这一步后,你应该创建一个恢复目录,然后转到/etc目录以使用scalpel.conf,如图所示:
# cd /etc
你可以通过定制以下命令来扫描相关设备:
# scalpel /path/to/device -o /path/to/recovery/directory
上述命令的示例看起来像这样:
# scalpel /dev/sda1 -o /tmp/recovery-session1
Scalpel 将通过创建工作队列来开始,但请注意,整个操作需要一定的时间才能完成。简单来说,完成扫描所需的实际时间将取决于磁盘大小、删除文件的数量、机器的性能以及系统当前正在执行的其他活动。
你可以使用ls命令像这样查看结果:
# ls -la /path/to/recovery/directory
最后,在开始之前,你需要注意,每次运行 Scalpel 时都必须创建一个新的恢复目录(所以你可能需要考虑使用一个备用硬盘),因为结果将由一个单一的审计文件维护。
可以通过键入以下命令来查看这个特定文件:
# less /path/to/recovery/directory/audit.txt
记住,Scalpel 可以与各种文件系统格式或原始分区一起工作,从这个角度来看,它可以视为一个非常有用的故障排除工具。
你可以通过查看手册来了解更多关于 Scalpel 的内容,方法如下:
# man scalpel
恢复文件和目录权限
文件和目录权限非常重要,要查看特定目录中所有文件的当前状态,可以运行以下命令:
# ll
或者,你可以通过运行以下命令来定位特定目录:
# ll /path/to/directory
然而,在某个系统文件或文件夹的权限被误改的情况下,可以通过以下基于 RPM 的命令来修复这一灾难性情况:
# rpm --setugids PACKAGENAME
# rpm --setperms PACKAGENAME
另一方面,如果整个目录被错误地使用 chown 或 chmod 命令更新,那么以下命令会更加有用:
# for package in $(rpm -qa); do rpm --setugids $package; done
# for package in $(rpm -qa); do rpm --setperms $package; done
根据前面显示的命令,第一个命令将重置所有文件和文件夹的所有权值到默认状态,而第二个命令将重置相对的文件权限。因此,在运行这些命令后,你可能会看到以下消息:
chgrp: cannot access '/usr/share/man/zh_TW/man5x': No such file or directory
chown: cannot access '/usr/share/man/zh_TW/man6': No such file or directory
chgrp: cannot access '/usr/share/man/zh_TW/man6': No such file or directory
chown: cannot access '/usr/share/man/zh_TW/man6x': No such file or directory
不用担心!无论列出的是哪个文件或目录,这些通知都可以安全忽略。
使用和扩展 XFS 文件系统
XFS 最早于 1993 年由 Silicon Graphics 开发,其主要目的是不仅支持创建能够进行元数据日志记录的大型文件系统,还提供一种可以在挂载和活动状态下进行碎片整理和扩展的技术。作为故障排除者,这些信息对你可能没什么用,但你应该知道,最新版本的 CentOS 默认使用的文件系统就是 XFS。如果你没有对分区进行过大的自定义,那么你可能会发现 XFS 是你需要处理的文件系统。
你可以通过以下命令快速确认系统的结构:
# df -Th
上述命令(忽略磁盘大小和分区)可能会产生类似于以下输出的结果:
Filesystem Type Size Used Avail Use% Mounted on
/dev/mapper/centos-root xfs 42G 1.5G 40G 4% /
devtmpfs devtmpfs 913M 0 913M 0% /dev
tmpfs tmpfs 919M 0 919M 0% /dev/shm
tmpfs tmpfs 919M 8.4M 911M 1% /run
tmpfs tmpfs 919M 0 919M 0% /sys/fs/cgroup
/dev/sda1 xfs 494M 139M 356M 29% /boot
/dev/mapper/centos-home xfs 21G 33M 21G 1% /home
在标记为 type 的列下,如果出现 xfs,那就是我们要找的。如果发现服务器确实使用了 XFS 文件系统,那么可以使用以下命令安装 XFS 工具和实用程序文件 xfsprogs.x86_64:
# yum install xfsprogs
一般来说,你应该了解,如果服务器系统相对较小,XFS 可能会导致性能轻微下降。在这些情况下,ext4 在一些单线程和元数据密集型工作负载下通常会更快。此外,由于 XFS 不支持缩小,你应该知道,即使在未挂载时,该技术也不允许文件系统缩小。因此,当不需要大文件系统或大文件时,你可能会选择继续使用 ext4。
从更广泛的角度来看,你会感到宽慰,因为创建 XFS 所需的基本语法与其他文件系统相似:
# mkfs.xfs /dev/device
所以,没什么意外的,而且由于与其他文件系统的相似性,我假设你可以舒适地完成这整个过程。然而,在你开始之前,应该始终了解服务器的硬件配置,因为在开始操作之前,可能会有一些你需要注意的显著问题。
例如,假设服务器超过了 2 TB。所以,在完成初步的 fdisk 操作以构建文件系统布局后(挂载之前),你可能会决定对系统进行基准测试,因为每个优秀的故障排除者都知道 XFS 启用了写入屏障,以确保文件系统的完整性。
你可以通过输入以下命令来完成这个简单的操作:
# mount -o inode64 /dev/device /mount/point
默认情况下,写入屏障将有助于保护文件系统免受电源故障、重置和系统崩溃等问题的影响,但如果你的硬件具有良好的写入缓存,可能更明智的做法是禁用写入屏障,以减少对性能的影响。
在这方面,你可以通过以下方式挂载设备:
# mount -o nobarrier /dev/device /mount/point
完成后,你可以始终使用以下语法请求有关特定卷的更多信息:
# xfs_info /mount/point
正如我们所看到的,XFS 确实有许多优秀的功能和工具,但在排查服务器问题时,正是这些差异可能会成为问题的根源。
在这方面,正如我们现在看到的,XFS 应该与类似的基于 ext3 或 ext4 的系统有所不同对待。然而,如果你需要扩展文件系统,那么你会高兴地发现,XFS 配备了一种名为 xfs_growfs 的标准工具,可以通过以下方式使用:
# xfs_growfs -d /mount/point
假设你已经查看了 man 页,显然可以指出,你的语法会使用 -d 选项来将文件系统扩展到设备所支持的最大大小。
对 XFS 进行修复
XFS 是为了支持极大的文件系统而创建的。在高负载下,它表现得非常出色,并且能够扩展大文件,但也因此更容易受到损坏。正因为如此,我们现在考虑一组工具,帮助我们排查服务器问题并恢复文件系统。
这个被称为 xfs_repair 的工具,用于确认文件系统的一致性并修复发现的问题。这个过程不会恢复丢失的数据,但应该可以恢复相关设备上的文件系统。
xfs_repair 使用的基本语法如下:
# xfs_repair /mount/point
然而,为了避免任何错误信息,该过程需要你首先 umount 相关设备。整个过程如下所示:
# umount /mount/point
# xfs_repair /mount/point
结果输出将继续经过一系列阶段,并确认相关事件。完成后,只需按常规方式重新挂载设备以完成任务。然而,如果 xfs_repair 失败,请再次重复此过程,并对相关错误信息进行研究。
如果 xfs_repair 第三次未能修复一致性问题,依据错误信息,你可能需要考虑为服务器制定一个替代的救援计划,因为应该假设数据恢复只能通过备份来完成。
注意
话虽如此,你也可以考虑采取额外的步骤来恢复相关设备。
在当前阶段,你应该假设数据恢复只能通过备份进行,你的计划现在是基于仅恢复文件系统。然而,值得记住的是,你不应采取任何可能影响生产环境的操作。
通过备份和恢复文件系统上的文件,可能能够从磁盘恢复文件。要做到这一点,请以只读模式挂载文件系统,然后使用xfsdump进行备份。从此以后,你需要重新创建分区并使用xfsrestore恢复文件。有关详细信息,请查阅man xfsdump和man xfsrestore。
或者,如果日志恢复失败,可能可以通过以只读模式挂载文件系统,并使用no recover选项来恢复部分数据。这将避免运行日志恢复过程,但使用这种方法,文件系统可能不一致,并且无法保证所有数据都会恢复。
xfs_repair工具用于修复文件系统。它与文件系统的大小无关(无论大文件系统还是小文件系统都一样处理),但与其他修复工具不同,它不会在启动时运行,并且只会在挂载时启动日志记录,以确保文件系统的一致性。如果xfs_repair遇到损坏的日志文件,它将无法修复文件系统,因此如果发生这种情况,你需要清除相关日志,挂载然后卸载 XFS 文件系统,这可以通过添加-L选项来强制清零日志,如下所示:
# xfs_repair -L /mount/point
请记住,重置日志可能会导致文件系统处于不一致状态。这通常会导致数据丢失和/或数据损坏。因此,只应在仅打算恢复文件系统的情况下应用这些方法。记住,xfs_repair命令并非用于恢复该文件系统上的数据。
调查 XFS 上的碎片化
在文件系统运行缓慢的情况下,可能是碎片化影响了你的服务器。在这种情况下,如果你怀疑发生了或正在发生碎片化,可以在相关设备上运行以下命令:
# xfs_db -c frag -r /mount/point
使用此命令时,我们让xfs_db以只读模式(-r选项)打开文件系统,并传递一个命令(-c选项)来获取该设备的文件碎片数据(frag)。当我们使用frag命令时,它只会返回与文件数据相关的信息,而不会关注空闲空间的碎片化。因此,根据系统的具体情况,输出结果可能如下所示:
fragmentation factor 0.31%
在更严重的情况下,它可能会报告以下输出:
fragmentation factor 93.39%
通过将你的注意力引导到前面示例中的碎片因素(以百分比表示),你可能已经找到了至少一个需要故障排除的原因。修复这种情况只需要调用文件系统重组工具,也就是 xfs_fsr。我们只需要系统重组我们的分区或设备,以类似于 Microsoft Windows 桌面的方式优化磁盘使用。在这方面,使用 xfs_fsr 的最基本语法如下:
# xfs_fsr /path/to/device
而对于单个文件,你可以使用:
# xfs_fsr /path/to/file
然而,考虑到这些事件完成的时间可能相当长,这个命令的更简洁用法是指定一个要重组的文件系统列表(-m),一个以秒为单位计算的时间选项 -t,以及一个详细选项 -v,以清晰指示发生的情况,如下所示:
# xfs_fsr -m /etc/mtab -t 7200 -v
对应的输出将显示 inode 前后范围的数量。默认情况下,xfs_fsr 会在完成过程之前执行十次遍历,除非你决定使用选项 -p 来减少遍历次数,如下所示:
# xfs_fsr -m /etc/mtab -t 7200 -v -p 2
你应该知道,xfs_fsr 不应被用来碎片整理整个系统,因为这通常被认为是不必要的,它可能导致空闲空间碎片化,因此你可以分阶段完成此任务,并知道操作可以被干净地中断。这样将保持文件系统的一致性。如果你中断了过程(使用 Ctrl + C),xfs_fsr 会将碎片整理过程保存到以下位置:
# /var/tmp/.fsrlast_xfs
然而,在你深入了解之前,真正需要注意的问题是,应该小心谨慎地在实时系统上处理碎片问题,因为在高负载期间对设备或分区进行碎片整理将给你的服务器带来不必要的负担。因此,在这种情况下,最好的做法是在相关设备或分区未满载或在较轻工作负荷期间运行 xfs_fsr。
最后,在完成碎片整理过程后,你可以使用以下命令确认已完成的工作量:
# xfs_db -c frag -r /mount/point
因此,在完成这些简单操作后,或需要未来的(并可能是重复的)定时任务,你应该能立即注意到文件和文件夹移动及传输速度的改善。
审计目录和文件
处理故障排除的一个重要任务可以来自于对与文件读写操作相关的活动的理解。CentOS 7 提供了一个简单的实用工具。这个工具称为 auditd,它在启动过程中启动。事件会记录到一个关联的日志文件,位于 /var/log/audit,并且由于它在后台运行,你可以通过以下命令检查当前服务状态:
# systemctl status | grep audit
审计服务是可以自定义的,你可以通过访问以下文件,并使用你喜欢的文本编辑器,直接管理日志文件的大小、位置和相关属性:
# nano /etc/audit/auditd.conf
此外,如果你不希望丢失任何审计数据,你可以在无法执行审计时禁用机器。为此,打开配置文件 auditd.conf,并添加或修改以下几行:
max_log_file_action = keep_logs
space_left_action = email
action_mail_acct = root
admin_space_left_action = halt
这个操作很严重,在没有做好充分准备的情况下不建议贸然进行,但它会移除旋转日志文件的默认操作,并用发送电子邮件给 root 用户的指令来替代。
最后,如果你希望对每个进程利用审计服务标志,只需打开 /etc/default/grub 并将以下参数添加到内核行:
audit=1
记得使用以下命令重新生成 grub 并重启:
# grub2-mkconfig -o /boot/grub2/grub.cfg
这将确保在启动序列启动后,每个进程都设置一个可审计的标志,为了更简便,我们可以通过编辑以下文件来构建一套独特的规则:
# nano /etc/audit/rules.d/audit.rules
为了简化操作,最好的方法是找到服务器的 stig.rules 文件,路径为 /usr/share/doc/audit-X.X.X/stig.rules,并将其复制到 /etc/audit/rules.d/audit.rules。根据当前的包版本(以我为例),stig.rules 文件可以在 /usr/share/doc/audit-2.3.3/stig.rules 找到。因此,我运行了以下命令来创建默认规则集:
# cp /usr/share/doc/audit-2.3.3/stig.rules /etc/audit/rules.d/audit.rules
因此,在自定义规则并重启 auditd 服务后,你会发现可以使用以下语法发起查询:
# ausearch -f /path/to/directory/or/file
# ausearch -f /path/to/directory/or/file | less
# ausearch -f /path/to/directory/or/file -i | less
作为替代方案,你可以使用 aureport 以以下方式生成一系列审计:
要监控异常行为,可以使用:
# aureport --key --summary
要构建用户登录报告,可以使用:
# aureport -l -i -ts yesterday -te today
要审查访问违规行为,可以尝试:
# ausearch --key access --raw | aureport --file --summary
最后,要查看异常情况,可以使用:
# aureport --anomaly
当然,我们没有涵盖审计服务的每个方面,但前面的示例应该能帮助你入门。记住,所有示例都可以添加到 cron 作业中,如果你想了解更多内容,可以随时通过输入以下命令查看 aureport 手册:
# man ausearch
# man aureport
可视化目录和文件
良好的管理始于良好的家务处理,因此,维护关于服务器布局的详细记录通常被认为是任何 Linux 管理员的良好起点。这项任务不仅能让你随时了解系统整体所做的更改,还可以作为调试的有效方法。此外,因为你可能继承了这个系统,或者和其他管理员共享访问权限,因此考虑运行一次最新的更改清单可能是个好主意。
所有可以访问的目录、文件夹和文件都会以树状结构排列在一个特定的基于 Linux 的系统中。从根目录 (/) 开始,这个层次结构可能包含本地或远程文件、本地或远程文件系统,以及本地或远程块设备。
要查看此树,只需确保你已经安装了以下软件包:
# yum install tree
默认情况下,tree 命令将从当前位置开始索引,因此首先,只需将位置更改为启动目录,如下所示:
# cd /boot
现在,运行以下命令:
# tree
tree 命令在技术上被描述为 递归目录列表命令,它以树状格式显示服务器的内容。它高度可定制,因此如果你希望从当前位置指定一个特定目录,可以使用:
# tree /path/to/folder
你可能已经注意到,tree 命令默认不会显示隐藏文件。因此,为了查看所有文件(包括所有隐藏文件),请使用 -a 选项,如下所示:
# tree -a /path/to/folder
然而,如果你希望 tree 功能仅显示文件夹名称,你应该使用 -d 选项,如下所示:
# tree -d /path/to/folder
如果一切看起来有些平凡无奇,你可以通过 -C 选项为输出添加一些颜色,如下所示:
# tree -C /path/to/folder
最后,你可以将之前的选项组合起来,通过输入以下命令将输出打印到文本文件中:
# tree > /folder/name/filename.txt
例如,如果你想维护一个列出当前权限的文件清单,可以使用 -p 选项,如下所示:
# tree -p > /folder/name/filename.txt
或者,如果你更愿意显示嵌入了 HTML 代码的输出以便导出,可以尝试:
# tree -H /path/to/folder
因此,无论你是采用了新服务器,还是被访问并写入文件的用户数量所困扰,tree 功能提供了一个相对的解决方案,可以通过输入以下命令来保持对你的服务器或设备的可视化审计:
# tree -d /sys/devices
那为什么不把它与定时任务(cron job)结合使用呢?这样你就可以定期监控潜在问题的出现,甚至保持一个视觉记录,了解这些变化何时发生。从这个角度看,你可以断言 tree 软件包是一个非常有用的工具,要了解更多,你可以随时通过输入以下命令查看手册:
# man tree
总结
在本章中,我们讨论了与用户、目录和文件相关的多个主题,同时介绍了与 XFS 文件系统发布相关的一些主题。从强制更改密码到可视化目录结构,从恢复 root 密码到理解磁盘碎片整理的必要性,我们对 CentOS 7 故障排除的探索表明,解决系统基础问题所获得的知识与持续的人为问题密切相关。可以说,你永远无法预演一个灾难性场景,因为每个事件可能是独特的,可能仅适用于一个或多个系统,但正如我们所看到的,无论你是在监控用户、修改用户、恢复数据,还是在维护整个文件系统,通过遵循一些简单的步骤,许多与文件、目录和用户相关的问题都可以快速有效地解决;这也自然引导我们进入了共享资源故障排除的话题。
参考资料
-
Red Hat 客户门户:
access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/ -
Tree 项目主页:
mama.indstate.edu/users/ice/tree/ -
XFS 常见问题解答:
xfs.org/index.php/XFS_FAQ -
XFS 用户指南:
xfs.org/docs/xfsdocs-xml-dev/XFS_User_Guide//tmp/en-US/html/index.html -
Red Hat XFS 指南:
access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/Storage_Administration_Guide/ch-xfs.html -
XFS 维基页面:
en.wikipedia.org/wiki/XFS
第六章. 故障排除共享资源
在当今世界,共享信息的需求无处不在。从家庭办公室到小型办公室,再到公司和企业办公室以及公共场所,保持协作信息的能力是解决故障排除角色的重要组成部分。毫无疑问,共享资源或提供对远程位置的访问现在被视为一种普遍期望,本章的目的是讨论并强调与通过网络访问共享资源相关的若干问题。
在本章中,我们将:
-
发现如何在 CentOS 7 服务器上提供 NFS 共享
-
了解更多关于 NFS 导出的信息
-
学习如何在 CentOS 7 客户端工作站上访问 NFS 共享资源
-
学习如何使用 CIFS 挂载外部驱动器
-
学习如何使用
autofs来提供持久挂载
在 CentOS 7 服务器上提供 NFS 共享
NFS 共享已经存在一段时间,正如大多数此类问题一样,故障排除文件共享服务的基本方法是基于您对安装过程的了解,因为您将花费大量时间审查权限和网络环境,并诊断服务启动失败的原因。
首先,您应该确保客户端工作站和服务器能够互相 ping 通:
# ping -c 4 XXX.XXX.XXX.XXX
如果ping命令在服务器和客户端工作站上都成功,为继续操作,您需要在服务器上安装nfs-utils包,如下所示:
# yum install nfs-utils
安装完成后,我们现在需要以以下方式创建一个永久的发布目录:
# mkdir /path/to/nfs/publication/directory
例如,一种方法是使用/home目录,如下所示:
# mkdir /home/nfs-share
由于此位置将存储客户端文件,因此您需要通过输入以下命令确保权限正确:
# chmod -R 775 /path/to/nfs/publication/directory
提示
请记住,如果您打算使用服务器上的/home目录,在修改/home目录的权限时要小心,并直接定位到适当的子目录,因为您不想影响其他文件夹。
下一步是启动相关服务,方法如下:
# systemctl enable rpcbind
# systemctl enable nfs-server
# systemctl enable nfs-lock
# systemctl enable nfs-idmap
# systemctl start rpcbind
# systemctl start nfs-server
# systemctl start nfs-lock
# systemctl start nfs-idmap
此时,我们将决定通过对以下文件进行一些修改,在网络上共享 NFS 目录:
# nano /etc/exports
在XXX.XXX.XXX.XXX为客户端工作站的 IP 地址的地方,按以下方式添加您的网络共享点:
/path/to/nfs/publication/directory XXX.XXX.XXX.XXX(rw,sync,root_squash,no_all_squash)
自然地,您可以根据需要为一个或多个用户添加多个发布目录;每个用户可以根据其 IP 地址拥有一个独特的目录。但是,如果您希望创建一个全局发布目录——即一个为所有客户端工作站服务的单一目录——那么您应该使用以下语法:
/path/to/nfs/publication/directory *(rw,sync,no_root_squash,no_all_squash)
请注意,星号符号(*)已替代了 IP 地址。在生产服务器或类似环境中,您应该避免这种做法,改用您尝试共享的网络/子网。这是一个特别需要排错人员注意的问题,但为了便于解释安装过程,我们将使用这种方法,原因是它是一种常见的做法。
因此,根据我们在这里详细描述的原始工作示例,条目可能如下所示:
/home/nfs-share *(rw,sync,no_root_squash,no_all_squash)
最后,您可能需要考虑所需的防火墙更改。为此,请逐个添加以下行:
# firewall-cmd --permanent --zone=public --add-service=nfs
# firewall-cmd --reload
然后,按照以下方式重新启动 NFS 服务:
# systemctl restart nfs-server
关于 NFS 导出
在此阶段,我想讨论一下 CentOS 7 上的 NFS 导出问题。如前面的示例中所述,我们使用了以下语法:
(rw,sync,root_squash,no_all_squash)
在这里,大部分选项对您来说应该是显而易见的;root_squash 将允许客户端的 root 用户以 root 身份访问和创建 NFS 服务器上的文件。技术上讲,此选项将强制 NFS 将客户端的 root 更改为匿名 ID,实际上,通过防止系统间 root 账户所有权迁移,这将增加安全性。如果您在 NFS 服务器上托管 root 文件系统(尤其是对于无盘客户端),则需要此设置;考虑到这一点,它可以(适度)用于选定的主机,但除非您了解其后果,否则不应使用 no_root_squash。
注意
其他基本的导出选项包括:
-
no_all_squash:此选项禁用所有的 squashing(压缩)。 -
rw:此选项使 NFS 服务器能够在 NFS 卷上同时进行读写请求。 -
ro:此选项使 NFS 服务器在 NFS 卷上使用只读请求。 -
sync:此选项使 NFS 服务器仅在更改已提交到稳定存储后才回复请求。 -
async:此选项使 NFS 服务器违反 NFS 协议,在任何更改提交到稳定存储之前就回复请求。 -
secure:此选项要求请求来源于一个互联网端口。 -
insecure:此选项接受任何或所有端口。 -
wdelay:此选项使 NFS 服务器在怀疑另一个相关的写请求可能正在进行或即将到来时,延迟提交写请求到磁盘。 -
no_wdelay:此选项使 NFS 服务器允许多个写请求在单次操作中提交到磁盘。此功能可以提高性能,但如果 NFS 服务器接收到许多小请求,这种行为可能会降低性能。您应该知道,如果同时设置了async,此选项将没有任何效果。 -
subtree_check:此选项启用subtree(子树)检查。 -
no_subtree_check:此选项禁用subtree(子树)检查,虽然它带有一些隐含的安全问题,但它可以提高可靠性。 -
anonuid=UID:这些选项明确设置匿名账户的uid和gid;当你希望所有请求看起来都来自同一个用户时,这个选项很有用。 -
anongid=GID:此选项将禁用anonuid=UID。
在 CentOS 客户端上挂载 NFS 共享
假设你的服务器当前正在提供 NFS 共享,我们现在将检查客户端工作站,以确保一切正常工作。这是每个故障排除人员都需要掌握并完善的任务。
首先,客户端必须像这样使用nfs-utils包:
# yum install nfs-utils
完成nfs-utils包的安装后,你现在必须按照以下方式创建挂载点:
# mkdir -p /path/to/mount/point
例如,为了满足你的需求,前面的命令可能如下所示:
# mkdir -p /mnt/nfs/home
现在可以像这样启动相关服务:
# systemctl enable rpcbind
# systemctl enable nfs-server
# systemctl enable nfs-lock
# systemctl enable nfs-idmap
# systemctl start rpcbind
# systemctl start nfs-server
# systemctl start nfs-lock
# systemctl start nfs-idmap
最后,我们可以通过以下方式在客户端工作站上挂载 NFS 共享:
# mount -t nfs XXX.XXX.XXX.XXX:/path/to/folder /path/to/mount/point
这里,XXX.XXX.XXX.XXX是 NFS 服务器的 IP 地址,:/path/to/folder是共享资源的位置。/path/to/mount/point部分表示共享资源在客户端工作站上应找到的位置。
这个命令的工作示例如下所示:
# mount -t nfs 192.168.1.100:/home /mnt/nfs/home/
为了确认一切正常工作,你可能需要运行以下命令:
# df -h
根据此处提供的工作示例,命令输出应显示一个或多个文件系统的添加,类似如下:
192.168.1.100:/home 21G 33M 21G 1% /mnt/nfs/home
然后,你可以通过以下方式轻松确认 NFS 资源的读写权限,通过创建一个新的文本文件:
# touch /path/to/mount/point/nfs-test.txt
使用ls命令,你应该能够在服务器和客户端工作站上看到这个文件。然而,由于这只是一个临时解决方案,如果你决定将其设置为永久或持久挂载,那么你应该打开以下文件:
# nano /etc/fstab
现在为每个挂载点添加一个条目,如下所示:
XXX.XXX.XXX.XXX:/path/to/folder /path/to/mount/point nfs defaults 0 0
完成这些步骤后,你现在可以重新启动客户端机器,并且完全知道 NFS 服务将始终可用。
使用 CIFS 挂载外部驱动器
在 CentOS 7 工作站或服务器上挂载外部驱动器被认为是一个相对简单的过程,在很多方面,这将是一个资深故障排除人员的日常任务。然而,在某些情况下,整个过程确实会引起很多关于需要哪些步骤的困惑,鉴于此,我们的目标是提供一些急需的清晰指导。
我们将首先确认cifs是否已安装。为此,输入以下命令:
# rpm -q cifs-utils
CIFS,即通用互联网文件系统,是一种文件共享协议,它为跨多个文件系统的远程文件访问提供了一种标准。基于服务器消息块(SMB)并通过 TCP/IP 运行,cifs提供了典型的文件操作,如打开、关闭、读取、写入、安全缓存和查找。它支持扩展的非文件系统属性、批量请求和分布式复制虚拟卷。然而,如果系统以以下方式回应,您就知道cifs当前没有安装:
package cifs-utils is not installed
要解决此问题,只需输入以下命令来安装cifs软件包:
# yum install cifs-utils
目前,您需要决定将设备挂载到哪里,这是一个可以通过以下方式实现的简单过程:
# mkdir /path/to/mount/folder
然后使用cifs-utils软件包通过输入以下命令来挂载外部驱动器:
# mount -t cifs //XXX.XXX.XXX.XXX/path/to/folder /path/to/mount/folder
然而,如果您希望传递一个字符串或一系列变量,如用户名和密码,那么完整的命令应该调用-o选项,像这样:
# mount -t cifs //XXX.XXX.XXX.XXX/path/to/folder /path/to/mount/folder -o user=<username> password=<password>
需要注意的是,这个过程也可以用来挂载许多不同类型的共享资源,并且如果外部资源的相关文件夹名称中包含空格,那么可以按照常规方式处理:
# mount -t cifs //XXX.XXX.XXX.XXX/path/to/folder\ name /path/to/mount/folder -o user=<username>,password=<password>
您使用的字符串类型还可以利用手册中提到的其他功能。然而,重要的一点是要记住,前述解决方案只会保持挂载的驱动器,直到该驱动器被卸载、断开连接或重启。因此,当前阶段的任何设置都不是永久的或持久的。
使用 autofs 挂载外部驱动器
如果您希望使连接外部驱动器(通过cifs)的过程永久(持久化),那么您需要先按照以下方式安装autofs软件包:
# yum install autofs
安装好该软件包后,您需要确保像这样启动并启用autofs服务:
# systemctl start autofs
# systemctl enable autofs
完成此操作后,假设我们将使用本文讨论的相同挂载点,您应该开始配置autofs服务,通过输入以下命令,在您喜欢的文本编辑器中创建一个凭据文件:
# nano /path/to/credentials.txt
现在,像这样添加所需的网络凭证:
username=<access_username>
password=<access_password>
保存并关闭此文件后,请确保修改权限以确保系统安全:
# chmod 600 /path/to/credentials.txt
这个过程的下一阶段是打开autofs配置文件:
# nano /etc/auto.master
在此文件末尾添加以下行,但请确保根据您的需求自定义这里显示的值:
/path/to/mount/folder /etc/auto.cifs --timeout=600 --ghost
如您所见,我们使用了各种选项,其中--timeout选项设置了未访问共享时卸载前的空闲时间(以秒为单位,默认时间为 10 分钟)。建议使用--ghost选项,因为它在挂载点未挂载期间创建一个ghost或空的持有文件夹。
现在,创建并编辑以下挂载文件:
# nano /etc/auto.cifs
添加并自定义以下行以满足您的需求:
<Local-Name> -fstype=cifs,rw,noperm,credentials=/path/to/credentials.txt ://XXX.XXX.XXX.XXX/path/to/share/folder
使用的Local-Name将显示在挂载点目录中(/path/to/mount/point/Local-Name),而随后的参数只是调用文件系统类型,无论您是否提供读写访问权限以及预期的访问凭证。因此,如果您计划提供只读访问权限,请记得将rw替换为ro。此外,鉴于所做的自定义结构,您可以看到如何以以下方式添加多个位置(这也意味着可以调用多个凭证):
<Local-Name> -fstype=cifs,rw,noperm,credentials=/path/to/credentials1.txt ://XXX.XXX.XXX.XXX/path/to/share/folder1
<Local-Name> -fstype=cifs,rw,noperm,credentials=/path/to/credentials2.txt ://XXX.XXX.XXX.XXX/path/to/share/folder2
<Local-Name> -fstype=cifs,rw,noperm,credentials=/path/to/credentials3.txt ://XXX.XXX.XXX.XXX/path/to/share/folder3
最后,如果您希望避免使用 IP 地址,那么您应该确保通过/etc/hosts或 DNS 将主机名映射到您的系统,以便使用以下语法更改:
<Local-Name> -fstype=cifs,rw,noperm,credentials=/path/to/credentials.txt ://hostname/path/to/share/folder
完成这些步骤后,下一步是重启您的系统,但作为替代,您也可以简单地重新启动autofs服务,以便享受您工作的成果:
# systemctl restart autofs
总结
在本章中,我们考虑了通过网络提供和访问共享资源的独特方法。从 NFS 到cifs,从fstab到autofs,我们已经覆盖了使挂载点临时或永久的过程,并确保我们论证了 CentOS 可以支持所有操作系统。然而,与迄今为止的其他章节不同,我们没有直接诊断问题,而是将故障排除者的角色定义为对安装过程的回顾,以便您的理解和对共享资源常见问题的认识是基于初始安装,而不是安装后发生的事件。通过这种方式,并且通过了解安装过程,您也将知道如何修复与该服务相关的任何问题。考虑到这一点,我们将继续讨论安全问题的故障排除。
参考资料
红帽客户门户:access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/
第七章:故障排除安全问题
在本章中,我们将讨论 CentOS 7 的安全问题。然而,我们不会采用传统的服务器加固方法,而是通过以另一种方式回顾 SSH、SELinux、HIDS 和 Firewalld,鼓励你更全面地探索系统。
在本章中,我们将:
-
了解如何使用
aureport生成审计报告并使用setroubleshoot审计SELinux -
学习如何添加和管理
SSH横幅,并使用FIGlet创建自定义横幅 -
了解更多关于调整
SSH服务的基本知识 -
学习如何安装
Tripwire并为系统提供入侵检测系统 -
了解更多关于 Firewalld、区域管理以及如何添加/删除接口、端口和伪装基础设施的内容
-
学习如何移除 Firewalld 并返回到 iptables
使用 aureport 和 setroubleshoot 审计 SELinux
禁用 SELinux 是一个相当常见的操作。通常在使用托管控制面板时,或者当某些特定应用程序似乎因 SELinux 启用而无法运行时,禁用 SELinux 是一个常见的做法。在这种情况下,禁用 SELinux 是一种经过验证的技术,能够为系统管理员节省大量时间。对于许多人来说,这是一个自动反应,而其他人则认为与 SELinux 相关的工具更适合用于桌面、工作站、带有 GUI 的服务器或受控网络环境。然而,事实很简单,禁用 SELinux 会移除一个关键的安全组件,从而使系统暴露。我同意,SELinux 是一个复杂的系统,对于那些希望享受它所提供保护的人来说,通过像这样运行 aureport 选项,生活可以变得更简单:
# aureport --avc | tail -n 10
这将提供一个 avc 消息的列表,其输出可能类似于以下内容:
AVC Report
========================================================
# date time comm subj syscall class permission obj event
========================================================
1\. 04/18/2015 13:50:53 ? system_u:system_r:init_t:s0 0 (null) (null) (null) unset 384
2\. 04/18/2015 13:55:49 ? system_u:system_r:init_t:s0 0 (null) (null) (null) unset 789
aureport 工具旨在创建基于列的报告,显示审计日志文件中记录的事件,进一步来说,你还可以使用相同的工具创建一个可执行文件的列表,具体变化如下:
# aureport -x
其输出结果根据你系统的不同,可能会类似于以下内容:
5988\. 05/03/2015 12:40:01 /usr/sbin/crond cron ? 0 773
5989\. 05/03/2015 12:40:01 /usr/sbin/crond cron ? 0 774
5990\. 05/03/2015 12:50:01 /usr/sbin/crond cron ? -1 775
5991\. 05/03/2015 12:50:01 /usr/sbin/crond cron ? -1 776
5992\. 05/03/2015 12:50:01 /usr/sbin/crond cron ? 0 778
5993\. 05/03/2015 12:50:01 /usr/sbin/crond cron ? 0 779
5994\. 05/03/2015 12:50:01 /usr/sbin/crond cron ? 0 780
5995\. 05/03/2015 12:50:01 /usr/sbin/crond cron ? 0 781
5996\. 05/03/2015 13:00:01 /usr/sbin/crond cron ? -1 782
5997\. 05/03/2015 13:00:01 /usr/sbin/crond cron ? -1 783
5998\. 05/03/2015 13:00:01 /usr/sbin/crond cron ? 0 785
5999\. 05/03/2015 13:00:01 /usr/sbin/crond cron ? 0 786
6000\. 05/03/2015 13:00:01 /usr/sbin/crond cron ? 0 787
6001\. 05/03/2015 13:00:01 /usr/sbin/crond cron ? 0 788
6002\. 05/03/2015 13:01:01 /usr/sbin/crond cron ? -1 789
6003\. 05/03/2015 13:01:01 /usr/sbin/crond cron ? -1 790
6004\. 05/03/2015 13:01:01 /usr/sbin/crond cron ? 0 792
6005\. 05/03/2015 13:01:01 /usr/sbin/crond cron ? 0 793
6006\. 05/03/2015 13:01:01 /usr/sbin/crond cron ? 0 794
6007\. 05/03/2015 13:01:01 /usr/sbin/crond cron ? 0 795
其他人可能希望使用这个工具来生成完整的身份验证报告,方法如下:
# aureport -au -i
其输出结果类似于以下内容:
Authentication Report
============================================
# date time acct host term exe success event
============================================
1\. 04/18/2015 12:40:57 root 192.168.1.17 ssh /usr/sbin/sshd yes 343
2\. 04/18/2015 12:40:57 root 192.168.1.17 ssh /usr/sbin/sshd yes 346
3\. 04/18/2015 19:28:26 root 192.168.1.17 ssh /usr/sbin/sshd yes 1099
4\. 04/18/2015 19:28:26 root 192.168.1.17 ssh /usr/sbin/sshd yes 1102
5\. 04/19/2015 04:57:06 root 192.168.1.17 ssh /usr/sbin/sshd yes 345
要生成失败身份验证事件的摘要报告,请使用以下命令:
# aureport -au --summary -i --failed
你可以使用以下语法创建一个成功身份验证事件的相对摘要报告:
# aureport -au --summary -i --success
因此,鉴于您可以获得的报告深度,当您处理运行SELinux的系统时,作为故障排除者,您的首要任务是考虑在审计系统时aureport的好处。作为补充,您还需要考虑一个名为setroubleshoot的工具。
setroubleshoot工具可以通过以下语法安装:
# yum install setroubleshoot setools
完成此操作后,您现在已经为系统配备了一个工具,它将主动从位于/var/log/audit/audit.log的日志文件中返回公告,并将其转化为更“人性化”的形式。这个工具叫做sealert,其目的是发布关于与SELinux相关的任何问题的报告和解决方案。
通过调用以下命令,可以启动一个进程:
# sealert -a /var/log/audit/audit.log
然而,如果您预计会返回大量数据,那么以下变体可能更适合您的需求:
# sealert -a /var/log/audit/audit.log | less
然而,在我们结束关于审计SELinux的讨论之前,对于那些运行无头服务器并希望接收电子邮件警报的用户,可能需要进行最终的配置更改。
为此,我们将打开我们喜欢的文本编辑器中的以下文件:
# nano /etc/setroubleshoot/setroubleshoot.conf
向下滚动该文件,找到[email]部分,并通过替换相关文本来添加您的电子邮件地址:
from_address = SELinux_Troubleshoot
现在,通过自定义以下命令,创建相关的收件人列表:
echo "email@domain.com" >> /var/lib/setroubleshoot/email_alert_recipients
setroubleshoot命令可能并不是适合每个人和每个环境的完美解决方案,但使用此包的效果是,无论您是运行无头服务器、带 GUI 的服务器,还是桌面工作站,SELinux Alert都是一种解决方案,使您能够继续使用并享受SELinux的好处,而不会牺牲您的安全性。
鉴于此主题的重要性,关于SELinux和setroubleshoot的进一步阅读可以在本章末尾找到。
SSH 横幅
使用 SSH 横幅并不完全是纯粹的故障排除(是的,我们确实涉及了硬化的主题)。然而,由于通常认为所有服务器应该携带某种形式的法律横幅、通知或安全警告,这些内容应在 SSH 认证过程开始和结束之前展示给用户,因此这是我们应当探索的一个领域。故障排除者并不负责构建系统,但他们负责修复系统,因此这是您需要了解的内容。而且,作为进入 SSH 世界的一个入口,学习如何开发您自己的(并且独特的)SSH 登录横幅将是一个不错的起点。
要在 SSH 认证之前显示一个横幅,您需要在您喜欢的编辑器中打开以下文件:
# nano /etc/issue.net
现在,按照需要添加所需的消息、通知或安全警告,但请记住,尽量保持简短和简洁。
例如,您可能想说:
Warning! You are entering a secure area. This service is restricted to authorized users only. All activities on this system are logged. Any unauthorized access will be fully investigated and reported to the appropriate law enforcement agencies.
完成此操作并保存文件后,你应该像这样在你最喜欢的文本编辑器中打开 SSH 的主配置文件:
# nano /etc/ssh/sshd_config
然后向下滚动,直到找到以下这一行:
#Banner
取消注释并将正确的路径添加到 issue.net,如下所示:
Banner /etc/issue.net
现在保存并关闭文件,然后按照以下方式重启 SSH 服务:
# systemctl restart sshd
此时,你应该随时通过输入以下命令检查 SSH 服务的状态:
# systemctl status sshd
你可以通过以下方式限定 SSH 使用的横幅设置:
# grep -i banner /etc/ssh/sshd_config
但是,假设你想提供一条独特的消息,将纯文本转换为一个大型 ASCII 横幅。
为此,我们需要安装一个名为 FIGlet 的小工具:
# yum install figlet
要使用 FIGlet,你只需使用以下语法:
# figlet "My Message Here"
然而,出于 SSH 横幅的目的,我们希望创建一个存储在本地文件中的消息,如下所示:
# figlet "My Message Here" > /path/to/banner.txt
完成此操作后,只需返回以下文件:
# nano /etc/ssh/sshd_config
现在找到你之前取消注释的这一行:
Banner /etc/issue.net
用 FIGlet 创建的新横幅文件的目标路径替换成以下路径:
Banner /path/to/banner.txt
最后,保存并关闭文件,然后像这样重启 SSH 服务:
# systemctl restart sshd
你可以说到此为止,但如果你希望提供一个额外的登录后消息,可以通过编辑以下文件来实现:
# nano /etc/motd
同样,简单地在保存并关闭文件之前添加所需的消息。完成这些步骤后,下次用户完成 SSH 身份验证时,他们将不仅看到服务器消息,还会看到一个附加的消息,从而为你提供充足的机会,在需要时向系统用户提供适当的指示和报告。
请记住,登录横幅对于两个主要原因非常有用。它们不仅在用户访问系统之前提供一条小消息,还可以警告未授权访问,同时向系统管理员提供重要信息,而无需他们主动请求。
调整 SSH
SSH 是与系统通信的最终方式。它是系统生命线中的一个重要服务,并且它维护着一个系统范围的配置文件,使得系统管理员能够修改守护进程的操作。
SSH 访问通常使用以下语法:
# ssh username@ipaddress
然而,如果系统特别慢,排查问题的第一步是使用替代的调试模式,如下所示:
# ssh username@ipaddress -vvv
既然如此,让我们更仔细地查看这个文件,以帮助你排查 sshd 守护进程的整体问题。
我们将开始打开以下文件,在我们最喜欢的文本编辑器中:
# nano /etc/ssh/sshd_config
当处理字典攻击、扫描器或机器人时,作为一种良好的实践,你可以通过简单地将 #Port 22 替换为完全不同的值,例如 Port 2222 来更改 SSH 端口。
你还可以通过更新以下值来限制 root 登录(这总是被推荐的):
PermitRootLogin no
要禁用隧道式明文密码,您应该取消注释以下行:
PermitEmptyPasswords no
SSH 日志有时可能会很难解读,因此,在我们结束对 SSH 的简要回顾之前,如果系统正处于一个难以诊断的阶段,通常可以通过简单地取消注释并更新日志记录参数来解决,方法如下:
#LogLevel INFO
修改为:
LogLevel VERBOSE
否则,如有必要,可以通过以下方式启用更高级别的日志记录:
LogLevel DEBUG
现在,最后的修改可能无法防止攻击,但通过要求 SSH 通过正向和反向 DNS 查找远程主机名,将在系统日志文件中生成适当的警告。为此,只需找到以下行:
#UseDNS yes
更新此行使其读取:
UseDNS yes
然而,如果 SSH 仍然有些迟缓,那么确保 SSH 不需要进行反向 DNS 查找可以大大改善这个情况。为此,只需将前面一行更改为:
UseDNS no
此外,也有可能由于使用了GSSAPI认证而引发问题。这种情况并不常见,因为这是 SSH 的一项功能,当需要GSSAPI服务器验证相关用户凭据时才会调用。为了避免这种情况,您应添加或编辑以下行,使其读取:
GSSAPIAuthentication no
此外,您还可能希望考虑超时的问题。这个常见问题可以通过配置正确的ServerAliveInterval、ServerAliveCountMax和TCPKeepAlive值来解决。我在这里给出一个简单的建议,但您应该记得确保这些值适合您的需求。
例如,以下规则表示每 60 秒会发送一个数据包:
ServerAliveInterval 15
ServerAliveCountMax 3
TCPKeepAlive yes
调整以下值可以提供更稳定的连接:
ClientAliveInterval 30
ClientAliveCountMax 5
最后,为了让 SSH 服务更安全一些,滚动到主配置文件的底部,添加以下行以维护一个允许进行 SSH 认证的用户名列表:
AllowUsers <username1> <username2>
或者,您也可以通过这种方式简化身份管理过程,而不是按用户逐个启用访问权限:
AllowGroup <groupname>
您的工作几乎完成,但话说回来,根据您故障排除 SSH 守护进程的原因,您必须记住,完成工作后,SSH 服务必须确保不受到攻击的可能性。因此,请始终记住,一个成功的故障排除会话不仅会修复问题,还将确保服务器的安全和稳定运行。
例如,对于那些没有使用SELinux、fail2ban或其他类似安全措施的用户,您可以随时通过输入以下命令来查看登录记录:
# cat /var/log/secure | grep 'sshd'
输出将如下所示:
May 3 13:57:24 centos7 sshd[2479]: pam_unix(sshd:session): session closed for user root
May 3 13:57:28 centos7 sshd[3313]: Accepted password for root from 192.168.1.17 port 51093 ssh2
May 3 13:57:28 centos7 sshd[3313]: pam_unix(sshd:session): session opened for user root by (uid=0)
如果您希望查看失败的登录尝试列表,可以尝试以下方法:
# cat /var/log/secure | grep 'sshd.*Failed'
可以通过以下方式查看接受的登录尝试:
# cat /var/log/secure | grep 'sshd.*Accepted'
使用 Tripwire 进行入侵检测
Tripwire 是一个 基于主机的入侵检测系统 (HIDS)。它通过收集配置和文件系统的详细信息,利用这些信息提供一个参考点,用于比较系统的先前状态和当前状态,这一过程通过监控哪些文件或目录最近被添加或修改,谁修改了它们,做了哪些更改,以及何时进行了更改来实现。
如前一章所讨论的,你需要访问 EPEL 仓库才能获得 Tripwire。当你准备好时,可以像这样安装:
# yum install tripwire
要开始使用 Tripwire,你需要使用以下语法创建适当的本地和站点密钥:
# tripwire-setup-keyfiles
当提示时,为站点和本地密钥文件添加一个密码短语。Tripwire 会建议你使用大写字母、小写字母、数字和标点符号的组合,完成后,你将被要求使用先前创建的站点密码短语签署配置文件。
一旦此过程完成,你可以通过修改以下文件来自定义 Tripwire:
# nano /etc/tripwire/twpol.txt
在开始之前,建议你先阅读 twpol.txt,因为许多默认的目录未必在你的系统上可用。这些额外的行不会引发特定问题,但如果你希望避免无意义的错误消息,应将它们注释掉。
你可以通过注释掉以下行来实现这一点:
### Filename: /root/.Xauthority
### No such file or directory
### Continuing...
此外,你还应该花一些时间查看以下文件,以便为适当的用途定制 Tripwire:
# nano /etc/tripwire/twcfg.txt
所以,在做出相关更改后,你现在应该通过以下方式更新 Tripwire 策略文件:
# tripwire --update-policy --secure-mode low /etc/tripwire/twpol.txt
Tripwire 现在将通过各种屏幕阶段来引用你的更改;完成后,你现在应该能够像这样初始化 Tripwire 数据库:
# tripwire --init
Tripwire 现在将开始扫描系统,但根据系统的整体大小,这可能需要一些时间:
Wrote database file: /var/lib/tripwire/server1.server1.com.twd
The database was successfully generated.
完成后,你可以使用以下语法运行 Tripwire 报告:
# tripwire --check --interactive
通过运行上述命令,Tripwire 将自动在 vi 中打开报告,从此以后,所有后续报告都将在比较模式下进行。因此,完成此操作后,何不利用这个机会在你的主文件夹中创建一些简单的文本文件或目录,然后重新运行报告,这样 Tripwire 的发现会变得更加明显。
请记住,如果对文件系统的任何更改被认为是系统入侵的结果,管理员将会收到通知,他们需要使用可以信任的文件和目录来恢复系统。因此,所有系统更改必须通过 Tripwire 进行验证。
你可以通过运行以下命令来验证当前的策略文件:
# tripwire --check
你可以通过像 mutt 这样的工具,通过电子邮件发送 Tripwire 报告,方法如下:
# yum install mutt
# tripwire --check | mutt -s "Tripwire report" email@domain.com
或者通过修改每日 cron 作业的后续部分:
# nano /etc/cron.daily/tripwire-check
通过添加以下行:
test -f /etc/tripwire/tw.cfg && /usr/sbin/tripwire --check | /bin/mail -s "Tripwire File Integrity Report" emailaddress@domain.com
当然,在短短的几段话中,我们已经迈出了构建全面主机入侵系统的一小步。它并不是纯粹意义上的故障排除,但在未来某个时刻,它将帮助您诊断问题。而且,从现在到那时,您可以通过查看手册来进一步了解Tripwire,例如这样:
# man tripwire
然而,在我们结束之前,此时我建议您确保twpol.txt和twcfg.txt文件的安全。充分意识到 Tripwire 的策略文件比这里建议的要更加可扩展,为了帮助您持续学习,我在本章的结尾提供了该项目主页的链接。
Firewalld – 区域、服务和端口管理
Firewalld 的目的是替代 iptables,并通过允许配置更改而不停止当前连接来改善安全管理。Firewalld 作为守护进程运行,允许规则即时添加和更改,并使用网络区域来定义与所有关联网络连接的信任级别。对于故障排除人员来说,这提供了多种灵活的选项,但更重要的是,必须理解,虽然一个连接只能属于单一的一个区域,但一个区域可以跨多个网络连接使用。
要了解 Firewalld 当前是否正在运行,您可以输入:
# firewall-cmd --state
要列出预定义的区域,您可以使用:
# firewall-cmd --get-zones
注意
这些区域可以定义为:
-
drop:在此区域,传入的网络数据包会被丢弃(没有回复),仅允许发起外出的网络连接 -
block:在此区域,只有在本系统内发起的网络连接才是可能的,因为所有传入的网络连接都会被以icmp-host-prohibited消息拒绝 -
public:此区域用于您不信任其他计算机的区域;仅接受选定的传入连接 -
external:此区域用于启用了伪装的外部网络,仅接受选定的传入连接 -
dmz:这是非军事区 -
work/home/internal:此区域用于大多数信任网络中其他计算机的环境;同样,只有选定的传入连接被接受 -
trusted:此区域接受所有网络连接
然而,通过扩展此命令,我们还可以通过输入以下命令来发现默认区域:
# firewall-cmd --get-default-zone
这个值可以使用以下语法进行更新:
# firewall-cmd --set-default-zone=<new-zone-name>
更进一步,我们可以扩展此命令,不仅提供区域的列表,还能提供类似以下的网络接口信息:
# firewall-cmd --get-active-zones
在这种情况下,网络接口可以使用以下语法进行管理:
# firewall-cmd --zone=<zone-name> --add-interface=<device-name>
# firewall-cmd --zone=<zone-name> --change-interface=<device-name>
# firewall-cmd --zone=<zone-name> --remove-interface=<device-name>
我们可以使用以下命令更改网络接口的分配,并将其绑定到不同的区域:
# firewall-cmd --permanent --zone=<zone-name> --change-interface=<device-name>
最后,您可以通过输入以下命令获取关于任何特定区域的所有相关信息:
# firewall-cmd --zone=<zone-name> --list-all
您可以列出所有支持的服务,使用:
# firewall-cmd --get-services
然后,你可以使用以下命令管理某一区域内的附加服务:
# firewall-cmd --zone=<zone-name> --add-service=<service-name>
# firewall-cmd --zone=<zone-name> --remove-service=<service-name>
否则,使用以下命令列出特定区域内的所有开放端口:
# firewall-cmd --zone=<zone-name> --list-ports
你可以像这样管理 TCP/UDP 端口的添加或移除:
# firewall-cmd --zone=<zone-name> --add-port=<port-number/protocol>
# firewall-cmd --zone=<zone-name> --remove-port=<port-number/protocol>
最后,在不试图使命令数组过于复杂的情况下,你可以按以下方式配置地址伪装:
# firewall-cmd --zone=<zone-name> --add-masquerade
# firewall-cmd --zone=<zone-name> --remove-masquerade
然后像这样查询它:
# firewall-cmd --zone=<zone-name> --query-masquerade
你可以使用这些命令管理端口转发:
# firewall-cmd --zone=<zone-name> --add-forward-port=<port-number>
# firewall-cmd --zone=<zone-name> --remove-forward-port=<port-number>
例如,在典型配置中,如果你想将所有面向端口 22 的数据包转发到端口 2222,你可以使用以下语法:
# firewall-cmd --zone=external --add-forward-port=22:proto=tcp:toport=2222
如你所见,Firewalld 是全面的,但考虑到有许多命令可以讨论,本书的目的是展示故障排除人员能够动态管理防火墙架构,而无需停止或重启防火墙服务。这是 iptables 无法实现的;在许多方面,基于相关的学习曲线和大量新命令,这一特性可能会成为一种划时代的成功。
有关 Firewalld 的更多信息可以在本章的最后找到。
移除 Firewalld 并回到 iptables
Firewalld 可能并不适合每个人,你可能更喜欢 iptables。所以,最后,如果你发现自己不想使用 Firewalld,你可以轻松地回到 iptables。
首先,你应该通过以下方式禁用 Firewalld:
# systemctl disable firewalld
# systemctl stop firewalld
然后,你应该通过输入以下命令安装和配置 iptables:
# yum install iptables-services
# touch /etc/sysconfig/iptables
# touch /etc/sysconfig/ip6tables
现在,使用以下命令启动 iptables 服务:
# systemctl start iptables
# systemctl start ip6tables
# systemctl enable iptables
# systemctl enable ip6tables
从此以后,你将以 iptables 作为你首选的防火墙服务。然而,在离开之前,最好重启服务器,以便内核能处理新的配置。
为此,输入以下命令:
# reboot
总结
从 SSH 横幅和通知的更被动的定位,到构建基于主机的入侵检测系统的严格方法,本章介绍了多种方法,旨在提供解决安全问题的前进方向。我们不仅讨论了 Firewalld 的发布,以及它如何在不中断服务的情况下动态重新设计整个防火墙环境,还讨论了 OpenSSH,并展示了如何回归使用 iptables。
我相信大家都会同意,安全是一个大主题,其方法和途径贯穿了本书的每一页。然而,在浏览了本章之后,我希望这块小小的垫脚石能在未来为你提供帮助,接下来我们将讨论如何解决数据库服务的故障。
参考文献
-
红帽客户门户:
access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/ -
Fedora 项目 – SELinux 故障排除工具 (setroubleshoot):
fedorahosted.org/setroubleshoot/wiki/SETroubleShoot%20Overview -
Oracle – 配置和使用 SELinux:
docs.oracle.com/cd/E37670_01/E36387/html/ol_selinux_sec.html -
Fedora 项目 – 文档/草稿/SELinux/SETroubleShoot/开发者常见问题:
fedoraproject.org/wiki/Docs/Drafts/SELinux/SETroubleShoot/DeveloperFAQ -
FIGlet 主页:
www.figlet.org -
Tripwire 项目主页:
sourceforge.net/projects/tripwire/ -
SSH 维基百科页面:
en.wikipedia.org/wiki/Secure_Shell -
SSH 项目主页:
www.openssh.com -
FirewallD Fedora 项目:
fedoraproject.org/wiki/FirewallD -
RHEL – 使用防火墙:
access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/Security_Guide/sec-Using_Firewalls.html
第八章:数据库服务故障排除
数据库服务在当今企业基础设施中起着至关重要的作用,然而本章并非面向程序员、数据库管理员或开发人员。相反,接下来的内容将采用另一种视角,专门为主要处理 CentOS 7 的系统管理员和故障排除人员提供帮助。因此,让我们从探讨数据库常见问题开始,提供一个 MariaDB、MySQL 和 PostgreSQL 故障排除指南。
在本章中,我们将:
-
学习如何在 CentOS 7 上快速启动并运行 MariaDB
-
学习如何使用 MariaDB 重置和恢复 root 用户的丢失密码
-
学习如何使用
mysqltuner调优 MariaDB 和 MySQL 服务器 -
了解如何在 MariaDB 和 MySQL 服务器之间运行指标
-
学习如何卸载 MariaDB 并恢复 MySQL 服务器
-
学习如何在 CentOS 7 上安装和配置 PostgreSQL
启动并运行 MariaDB
在 CentOS 的最新版本中,你会发现 MariaDB 已经取代了 MySQL。虽然可以说这两种数据库系统之间有相似之处,但同样重要的是要认识到它们是截然不同的系统。在这个前提下,通常会在安装阶段遇到问题,可能会出现以下令人不适的消息:
Redirecting to /bin/systemctl start mysqld.service.
Failed to issue method call: Unit mysqld.service failed to load: No such file or directory.
在这种情况下,你的第一步是验证当前已安装的内容。这可以通过运行以下一个或多个命令来实现:
# which mysql
# ls -la /bin/my*
# ps -ef | grep mysql
然而,由于输出可能会让未经训练的眼睛感到困惑,这个问题会带来一定的混淆,且它是尝试运行 MySQL 安装和启动命令时发生的。是的,这确实是一个容易犯的错误,而解决此问题的最有效方法是探索正确的 MariaDB 安装方式。
要安装 MariaDB,你应该使用以下命令:
# yum install mariadb mariadb-server
要启动 MariaDB 服务,只需执行以下命令:
# systemctl start mariadb.service
# systemctl enable mariadb.service
其输出结果将如下所示:
ln -s '/usr/lib/systemd/system/mariadb.service' '/etc/systemd/system/multi-user.target.wants/mariadb.service'
为完成安装,现在应运行以下命令:
# mysql_secure_installation
请记住,此时你尚未设置密码。因此,当系统提示时,只需按 回车 键表示当前没有密码,并按照提示完成安全安装过程。作为补充,你也可能会看到以下错误消息:
/usr/bin/mysql_secure_installation: line 379: find_mysql_client: command not found
此消息可以安全忽略,因为它表示 Fedora 19 相关的一个已知错误(有关 Red Hat Bugzilla - Bug 1020055 的更多信息,请参见本章末尾的参考资料)。
完整的 mysql_secure_installation 过程如下所示:
NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MariaDB. SERVERS IN PRODUCTION USE! PLEASE READ EACH STEP CAREFULLY!
In order to log into MariaDB to secure it, we'll need the current
password for the root user. If you've just installed MariaDB, and
you haven't set the root password yet, the password will be blank,
so you should just press enter here.
Enter current password for root (enter for none): type enter
OK, successfully used password, moving on...
Setting the root password ensures that nobody can log into the MariaDB root user without the proper authorisation.
Set root password? [Y/n] <Y>
New password: your-password
Re-enter new password: your-password
Password updated successfully!
Reloading privilege tables..
... Success!
By default, a MariaDB installation has an anonymous user, allowing anyone to log into MariaDB without having to have a user account created for them. This is intended only for testing, and to make the installation go a bit smoother. You should remove them before moving into a production environment.
Remove anonymous users? [Y/n] <Y>
... Success!
Normally, root should only be allowed to connect from 'localhost'. This ensures that someone cannot guess at the root password from the network.
Disallow root login remotely? [Y/n] <Y>
... Success!
By default, MariaDB comes with a database named 'test' that anyone can access. This is also intended only for testing, and should be removed before moving into a production environment.
Remove test database and access to it? [Y/n] <Y>
- Dropping test database...
... Success!
- Removing privileges on test database...
... Success!
Reloading the privilege tables will ensure that all changes made so far will take effect immediately.
Reload privilege tables now? [Y/n] <Y>
... Success!
Cleaning up...
All done! If you've completed all of the above steps, your MariaDB
installation should now be secure.
Thanks for using MariaDB!
从此时起,一切应重新变得熟悉,你可以随时通过以下命令检查 MariaDB 的状态:
# systemctl status mariadb.service
使用 MariaDB 重置和恢复 root 密码
重置 root 密码的操作对系统故障排除人员而言至关重要。它确实会发生——没错,比你想象的要多得多——但按照接下来的步骤操作,可以避免危机的发生。
首先,您需要像这样停止 MariaDB 服务:
# systemctl stop mariadb.service
下一步是以以下方式激活“安全模式”:
# mysqld_safe --skip-grant-tables --skip-networking
现在,运行以下序列以访问 MySQL 控制台并连接到数据库:
# mysql -u root
# use mysql;
此时,我们需要为 root 用户创建一个新密码,刷新新的权限,并像这样退出 MySQL 控制台:
# update user set password=PASSWORD("NEW_PASSWORD") where User='root';
# flush privileges;
# exit
完成这些步骤后,您可以选择重启服务器,或者以以下方式简单地停止并重新启动 MariaDB 服务:
# systemctl stop mariadb.service
# systemctl start mariadb.service
最后,您可以通过输入以下命令,使用新的 root 用户凭证访问数据库:
# mysql -u root -p
调优 MariaDB 和 MySQL
MYSQL tuner 是一个有用的工具,它可以连接到正在运行的数据库实例,并根据当前的工作负载提供一系列配置建议。当然,这类工具并不总能为您的系统提供完美的答案,但您应在典型负载下让数据库系统运行一两天后,再应用修改过的配置。
要安装 mysqltuner 包(这是 EPEL 仓库的一部分),请键入以下内容:
# yum install mysqltuner
若要从命令行运行 mysqltuner 包,您可以随时使用以下语法:
# mysqltuner
现在,根据您的系统配置和硬件,mysqltuner 的输出看起来会类似于以下内容:
>> MySQLTuner 1.2.0 - Major Hayden <major@mhtx.net>
>> Bug reports, feature requests, and downloads at http://mysqltuner.com/
>> Run with '--help' for additional options and output filtering
Please enter your MySQL administrative login: <username>
Please enter your MySQL administrative password: <password>
-------- General Statistics --------------------------------------
[--] Skipped version check for MySQLTuner script
[OK] Currently running supported MySQL version 5.5.41-MariaDB
[OK] Operating on 64-bit architecture
-------- Storage Engine Statistics -------------------------------
[--] Status: +Archive -BDB +Federated +InnoDB -ISAM -NDBCluster
[--] Data in PERFORMANCE_SCHEMA tables: 0B (Tables: 17)
[!!] InnoDB is enabled but isn't being used
[OK] Total fragmented tables: 0
-------- Security Recommendations -------------------------------
[OK] All database users have passwords assigned
-------- Performance Metrics -------------------------------------
[--] Up for: 1h 35m 23s (33 q [0.006 qps], 15 conn, TX: 16K, RX: 1K)
[--] Reads / Writes: 75% / 25%
[--] Total buffers: 288.0M global + 2.8M per thread (151 max threads)
[OK] Maximum possible memory usage: 708.0M (38% of installed RAM)
[OK] Slow queries: 0% (0/33)
[OK] Highest usage of available connections: 0% (1/151)
[OK] Key buffer size / total MyISAM indexes: 128.0M/99.0K
[!!] Key buffer hit rate: 73.3% (15 cached / 4 reads)
[!!] Query cache is disabled
[OK] Temporary tables created on disk: 0% (0 on disk / 2 total)
[!!] Thread cache is disabled
[OK] Table cache hit rate: 2700% (27 open / 1 opened)
[OK] Open file limit used: 2% (23/1K)
[OK] Table locks acquired immediately: 100% (59 immediate / 59 locks)
[!!] Connections aborted: 6%
-------- Recommendations -----------------------------------------
General recommendations:
Add skip-innodb to MySQL configuration to disable InnoDB
MySQL started within last 24 hours - recommendations may be inaccurate
Enable the slow query log to troubleshoot bad queries
Set thread_cache_size to 4 as a starting value
Your applications are not closing MySQL connections properly
Variables to adjust:
query_cache_size (>= 8M)
thread_cache_size (start at 4)
mysqltuner 包旨在帮助您对 MySQL 安装的性能和稳定性进行持续调整。它的输出内容较为冗长,展示了当前的配置变量,并附带一系列当前状态数据,总结了一些常见的性能建议。
建议在对数据库进行任何更改之前,让数据库在典型条件下运行至少 24 小时。然而,如果您希望利用这些建议中的一项或多项,您可以将它们添加到现有的 MySQL 配置文件中,或者与之集成:
# nano /etc/my.cnf
完成后,您需要重启相关的数据库服务,以便利用所做的更改。
您可以通过输入以下命令来执行此操作:
# systemctl restart mariadb.service
然后使用以下命令确认数据库的状态:
# systemctl status mariadb.service
其输出可能看起来像这样:
mariadb.service - MariaDB database server
Loaded: loaded (/usr/lib/systemd/system/mariadb.service; enabled)
Active: active (running) since Mon 2015-05-04 07:10:58 EDT; 9s ago
Process: 4756 ExecStartPost=/usr/libexec/mariadb-wait-ready $MAINPID (code=exited, status=0/SUCCESS)
Process: 4726 ExecStartPre=/usr/libexec/mariadb-prepare-db-dir %n (code=exited, status=0/SUCCESS)
Main PID: 4755 (mysqld_safe)
CGroup: /system.slice/mariadb.service
├─4755 /bin/sh /usr/bin/mysqld_safe --basedir=/usr
└─4911 /usr/libexec/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib64/mysql/plugin --log-error=/...
May 04 07:10:56 centos7 systemd[1]: Starting MariaDB database server...
May 04 07:10:56 centos7 mysqld_safe[4755]: 150504 07:10:56 mysqld_safe Logging to '/var/log/mariadb/mariadb.log'.
May 04 07:10:56 centos7 mysqld_safe[4755]: 150504 07:10:56 mysqld_safe Starting mysqld daemon with databases from /var/lib/mysql
May 04 07:10:58 centos7 systemd[1]: Started MariaDB database server.
记住,由于系统需求和数据库需求是不断变化的,您可以根据需要随时运行 mysqltuner,查看是否有新的建议。
从 MariaDB 和 MySQL 获取指标
指标不仅可以帮助您对数据库服务器进行性能分析,还能为异常行为提供证据。对于故障排除人员来说,这类数据非常重要,您可以通过运行以下命令来获取这些数据:
# mysqladmin -u root -p status
输出将提供以下信息:
-
运行时间: 该值表示数据库服务器已经运行的秒数。 -
线程: 该值表示当前连接的客户端数量。 -
问题: 该值表示自数据库服务器启动以来服务的查询数量。 -
慢查询: 该值表示超过long_query_time的查询数量。 -
打开: 该值表示已提供给客户端的表数量。 -
刷新表: 该值表示数据库服务器服务的刷新请求数量,包括flush、refresh和reload命令。 -
打开的表: 该值表示当前打开的表数量。 -
每秒查询平均: 该值表示数据库服务器每秒接收到的查询数量。
然而,由于前面的命令缺少详细信息,你可以通过使用以下语法获得更多细节:
# mysqladmin -u root -p extended-status
可以通过使用以下命令获得替代或实时方法:
# mysqladmin -i 10 -u root -p processlist
请注意使用了-i选项。这表示命令将在 10 秒后刷新。基于此,你可以建立数据库服务器事件的实时监控,从而识别、捕捉并终止可能导致系统整体变慢的查询。
返回 MySQL
在某些环境下,你可能希望 CentOS 7 使用 MySQL,而不是安装 MariaDB。为此,你需要确保 MariaDB 没有被安装,可以通过运行以下命令来实现:
# yum remove mysql-server mysql-libs mysql-devel mysql*
你现在应该检查是否已经卸载,使用以下命令确认:
# rpm -qa | grep mysql
要开始安装 MySQL,你应该从dev.mysql.com/downloads/repo/yum/下载 YUM 仓库配置文件。
现在,你不需要账户来下载这个文件,但对于那些不想浏览 Oracle 网站的人,在写这本书时,你可以跳过上述过程,使用以下语法:
# rpm -Uvh http://dev.mysql.com/get/mysql-community-release-el7-5.noarch.rpm
然后,你可以像这样运行适当的安装命令:
# yum install mysql-community-server
通过运行以下命令,确保 MySQL 守护进程在启动时自动启动:
# systemctl enable mysqld
现在,你可以启动服务器:
# systemctl start mysqld
然后,按常规方式运行 MySQL 安全安装程序:
# mysql_secure_installation
最后,重新运行以下命令将确认该过程是否成功:
# ps -ef | grep mysql
安装和配置 PostgreSQL 9
PostgreSQL 快速、强大、跨平台,并且具有优秀的血统。然而,为了在出现不规则或意外事件时进行故障排查,最好的方法是首先记住该数据库服务是如何安装的。
要开始这个过程,我们必须以以下方式添加相关仓库:
# rpm -iUvh http://yum.postgresql.org/9.3/redhat/rhel-7-x86_64/pgdg-centos93-9.3-1.noarch.rpm
你应始终通过访问仓库本身确认你正在下载正确的版本,但完成此步骤后,你现在可以像这样安装 PostgreSQL:
# yum install postgresql93-server
在这个阶段,你可能需要对 PostgreSQL 做一些配置更改。首先,像这样用你喜欢的文本编辑器打开以下文件:
# nano /var/lib/pgsql/9.3/data/postgresql.conf
前面的配置较为冗长,在大多数情况下,你只需取消注释相关行或替换相应的值以适应你的环境。例如,要让 PostgreSQL 数据库服务器监听特定的 IP 地址,你需要取消注释以下这一行:
#listen_addresses = 'localhost'
然后,你可以像这样更改为你选择的 IP 地址:
listen_addresses = 'XXX.XXX.XXX.XXX'
然而,取决于你使用的 Linux 版本,在你可能需要或不需要查找 tcpip_socket 参数的情况下,你应该改用以下语法:
listen_addresses = '*'
更进一步,你还应花时间对该文件中的其他设置进行相关修改。这些设置可以包括使用的端口、支持的最大连接数、身份验证超时、资源使用情况以及 PostgreSQL 提供的更多功能,在此之后再打开以下文件,以调整对数据库服务器的网络访问:
# nano /var/lib/pgsql/9.3/data/pg_hba.conf
例如,如果你想为整个 IP 范围(例如,192.168.1.0/24)提供本地网络访问,可以使用以下语法:
host all all 192.168.1.0 255.255.255.0 trust
另外,为了心安理得,你可以使用以下语法,通过稍少的输入实现类似的效果:
host all all 192.168.1.0/24 md5
所以,在完成前面的步骤以启用 PostgreSQL 启动时,你必须输入:
# systemctl enable postgresql-9.3
要初始化数据库服务器,你必须输入:
# /usr/pgsql-9.3/bin/postgresql93-setup initdb
# systemctl start postgresql-9.3
最后,如果你想访问数据库服务器,你必须切换到预定义的 PostgreSQL 用户帐户,像这样:
# su - postgres
然后,你可以按照以下方式连接到 PostgreSQL 数据库:
# psql
然后,使用以下表达式,你将能够查看你可以使用的所有 psql 命令,以便开始添加用户和模板,以及创建数据库:
# \?
例如,要随时退出 psql 控制台,可以使用以下语法:
# \q
最后,返回标准 bash 控制台后,你可以随时通过自定义以下命令来确认 PostgreSQL 的连接性:
# psql -h <database_hostname> -U <username> -d <database_name>
另外,你也可以使用 ps 命令,像这样:
# ps -ef | grep posgres
总结
从安装与优化,到恢复 root 用户的丢失密码,本章我们重点讨论了与 MariaDB 和 PostgreSQL 故障排除过程相关的一些问题。正如开头所提到的,本文并不打算处理具体的编程或开发问题,但由于这些数据库系统在企业中普遍存在,因此你将需要处理它们;在这方面,我们讨论了一系列的主题,为故障排除几乎任何数据库服务提供了一个有用的起点。
在下一章,我们将继续本书的主题,讨论一种独特的故障排除 Web 服务的方法。
参考文献
-
MySQL 项目主页:
dev.mysql.com/ -
MySQL YUM 下载:
dev.mysql.com/downloads/repo/yum/ -
MariaDB 项目首页:
mariadb.org/en/ -
MariaDB 常见问题解答:
mariadb.com/kb/en/mariadb/faq/ -
使用 Yum 安装 MariaDB:
mariadb.com/kb/en/mariadb/yum/ -
Red Hat Bugzilla – Bug 1020055,
bugzilla.redhat.com/show_bug.cgi?id=1020055 -
MySQLTuner 首页:
mysqltuner.com -
MySQLTuner GitHub 首页:
github.com/major/MySQLTuner-perl -
MariaDB-5.3.4 性能基准测试:
blog.mariadb.org/benchmarking-mariadb-5-3-4/ -
排查问题 – 启动 MySQL 服务器:
dev.mysql.com/doc/refman/5.1/en/starting-server.html -
MariaDB 与 MySQL – 兼容性:
mariadb.com/kb/en/mariadb/mariadb-vs-mysql-compatibility/ -
PostgreSQL 9.3.6 文档:
www.postgresql.org/docs/9.3/static/index.html -
PostgreSQL 客户端认证:
www.postgresql.org/docs/9.3/static/client-authentication.html -
PostgreSQL 数据库角色:
www.postgresql.org/docs/9.3/static/user-manag.html -
PostgreSQL 仓库:
yum.postgresql.org/repopackages.php
第九章:Web 服务故障排除
故障排除并不总是关于灾难恢复或修复损坏的系统。事实上,大多数故障排除者往往花时间发现不断改进系统的方法,或者协助其他同事充分利用现有技术。有些人会称之为 Dev/Ops,但无论你如何看待,基本原则始终不变。你是故障排除者,你是支持网络中至关重要的一部分;因此,考虑到这一点,我们将暂时放下“拯救世界”的任务,以更积极的方式来探讨 Web 服务的主题。
在本章中,我们将回顾调查 Web 服务的主题,目的是改进并扩展你作为故障排除者的知识。
在本章中,我们将:
-
学习如何使用 cURL 审核服务器
-
发现检查你的 Akamai 头信息的方法
-
学习如何在 Apache 上实现 Varnish
-
发现如何使用 cURL 验证你的 Varnish 安装
-
学习如何使用 cURL 访问 FTP 目录
-
学习如何通过安装
mod_status来监控 Apache
使用 cURL 审核服务器
当 Web 服务器开始出现问题时,可能有很多原因。然而,作为故障排除者,在遇到这个问题时,请记住,你并不是在看应用程序本身(这是程序员的领域,他们不会感谢你加入其中),而是看服务器的状态。
本质上,你可以说这是一个审查服务器及其提供网页或 Web 应用程序能力的过程。那么,让我们从检查确认 cURL 是否已安装开始。
为此,你应该使用以下语法:
# yum install curl
完成此步骤后,你现在可以运行你的第一个 cURL 命令了:
$ curl http://www.example.com
更具体地说,你可以通过以下方式选择特定的位置:
$ curl http://www.example.com/path/to/homepage.html
或者,你可以像这样传递一个字符串:
$ curl http://www.example.com/path/to/homepage.html?query=string
前面每个命令都会显示目标 URL 的全部 HTTP 内容;是的,这可能会让屏幕看起来有点乱。因此,你可以调用 tidy 选项,如下所示:
$ curl http://www.example.com | tidy -i
然而,如果你希望捕获数据并将输出保存到你选择的文件中,可以通过使用命令行重定向方法来实现,如下所示:
$ curl http://www.example.com > /path/to/folder/example.html
或者,你可以以以下方式使用-o选项:
$ curl -o /path/to/folder/example.txt http://www.example.com
请注意,通过调用-o选项的方法时,目标文件必须首先指定。然而,由于前面的示例表明我们将输出保存到文本文件中,你可以很高兴地将其更改为几乎任何类型的文件,如下所示:
$ curl -o /path/to/folder/example.html http://www.example.com
现在,假设网络连接良好,我们选择了 cURL,因为我们现在处理的是一个可能存在显示网页困难的 Web 服务器的特定问题。
正如我们之前所见,默认情况下,cURL 仅仅会输出所请求网页的内容。然而,通过使用一些额外的选项(或参数),你可以扩展它的功能,并请求更多的细节。
例如,如果我们使用-w选项(write-out),你可以通过以下语法获取任何网页的状态码:
$ curl -w "%{http_code}\n %{content_type}\n" http://www.example.com/path/to/page.html
在这里,\n用于将结果输出到新的一行(你还可以用\t输出制表符,或用\r输出回车符)。你现在应该知道该网页的 HTTP 状态码和 HTTP 内容类型。
例如,你可以尝试这样:
$ curl -w "%{http_code}\n %{content_type}\n" https://www.packtpub.com/virtualization-and-cloud/troubleshooting-centos
前述命令的结果稍显冗长,无法完整打印,但在输出的末尾,你应该能看到以下内容(其中目标数据按要求分行显示):
</body>
</html>
200
text/html; charset=utf-8
此外,你甚至可以像这样包含远程 IP 地址:
$ curl -w "%{remote_ip}\n %{http_code}\n %{content_type}\n" http://www.example.com/path/to/page.html
该命令的输出应该在末尾显示类似以下的内容:
</body>
</html>
23.205.169.129
200
text/html;charset=UTF-8
你可以使用以下命令获取网页的大小(以字节为单位):
$ curl -w "%{size_download}\n" http://www.example.com/path/to/page.html
该命令的结果将在输出的末尾显示63175字节:
</body>
</html>
63175
另一方面,如果你正在处理一个使用301和302重定向方法的 Web 服务器,我们可以像这样使用-L选项:
$ curl -Lw "%{remote_ip}\n %{http_code}\n %{content_type}\n" http://www.example.com/
最后,如果你想确保你对服务器网页的调查提供了 cURL 可能遇到的所有头信息的完整列表,你应该通过以下方式调用-v选项来增加输出详细程度:
$ curl -v http://www.example.com
例如,再次你可以像这样测试 Red Hat:
$ curl -v http://www.redhat.com
该命令的结果将提供以下输出:
* About to connect() to www.redhat.com port 80 (#0)
* Trying 104.66.92.228...
* Connected to www.redhat.com (104.66.92.228) port 80 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: www.redhat.com
> Accept: */*
>
< HTTP/1.1 301 Moved Permanently
< Content-Type: text/html; charset=iso-8859-1
< Location: http://www.redhat.com/en
< Server: Apache
< Content-Length: 296
< Expires: Mon, 04 May 2015 14:53:10 GMT
< Cache-Control: max-age=0, no-cache
< Pragma: no-cache
< Date: Mon, 04 May 2015 14:53:10 GMT
< Connection: keep-alive
< Set-Cookie: AWSELB=014101F31CE28463C273156EDFEB4013EF4DC7B4B58B2D0587192FCB8DB58F8B0E7B8A652EC4DCB07BB3CC9D65387BA7D24617BF645CEBCF6476050FABBDF5D9227C0A5A30;PATH=/;MAX-AGE=30
<
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>301 Moved Permanently</title>
</head><body>
<h1>Moved Permanently</h1>
<p>The document has moved <a href="http://www.redhat.com/en">here</a>.</p>
<hr>
<address>Apache Server at www.redhat.com Port 80</address>
</body></html>
* Connection #0 to host www.redhat.com left intact
对于那些希望仅将输出限制为响应头的用户,应该像这样使用-I选项,而不是使用前面的命令:
$ curl -I http://www.example.com
例如,如果你像这样重新尝试 Red Hat:
$ curl -I http://www.redhat.com
该命令的结果将提供以下输出:
HTTP/1.1 301 Moved Permanently
Content-Type: text/html; charset=iso-8859-1
Location: http://www.redhat.com/en
Server: Apache
Content-Length: 0
Expires: Mon, 04 May 2015 14:55:54 GMT
Cache-Control: max-age=0, no-cache
Pragma: no-cache
Date: Mon, 04 May 2015 14:55:54 GMT
Connection: keep-alive
Set-Cookie: AWSELB=014101F31CE28463C273156EDFEB4013EF4DC7B4B53E1B0B83C0D272B9D220605DDE604A12C4DCB07BB3CC9D65387BA7D24617BF642030376EDB73D2D8C226E62350AE4B75;PATH=/;MAX-AGE=30
在这一阶段,关于 cURL 的内容还有很多可以讨论。事实上,你可以写一本关于这个主题的书;然而,在我们偏离主要话题之前,你会很高兴知道你可以通过阅读手册来了解更多关于 cURL 的内容:
$ man curl
使用 cURL 调试 Akamai 头信息
CDN(内容分发网络)正变得越来越普遍,其中最流行的是 Akamai。然而,虽然 CDN 能够带来好处,但在你排查 Web 服务、应用程序,甚至一个简单的主页时,它们也可能成为一个绊脚石。换句话说,使用任何类型的 CDN 时,你通常在与缓存的对象进行交互,而你需要验证流量行为。因此,考虑到这一点,我们现在将讨论如何通过cURL来解决这一问题:
首先,我们必须发出一个正确格式的 Pragma 头,为此,你可以使用以下语法:
$ curl -IXGET http://www.example.com/path/to/home.html
然而,如果你希望包含调试信息,可以使用:
$ curl -IXGET -H "Pragma: akamai-x-cache-on, akamai-x-cache-remote-on, akamai-x-check-cacheable, akamai-x-get-cache-key, akamai-x-get-extracted-values, akamai-x-get-nonces, akamai-x-get-ssl-client-session-id, akamai-x-get-true-cache-key, akamai-x-serial-no" http://www.example.com/path/to/home.html
例如,由于 Red Hat 是 Akamai 的已知用户,如果你尝试:
$ curl -IXGET -H "Pragma: akamai-x-cache-on, akamai-x-cache-remote-on, akamai-x-check-cacheable, akamai-x-get-cache-key, akamai-x-get-extracted-values, akamai-x-get-nonces, akamai-x-get-ssl-client-session-id, akamai-x-get-true-cache-key, akamai-x-serial-no" http://www.redhat.com/en
然后,除非自本书出版以来发生了重大变化(而网页总是会随着时间改变),否则输出结果将类似于这样:
HTTP/1.1 200 OK
Content-Language: en
Content-Type: text/html; charset=utf-8
ETag: "1430747458-1"
Last-Modified: Mon, 04 May 2015 13:50:58 GMT
Link: <http://www.redhat.com/en>; rel="canonical"
Server: Apache
X-Drupal-Cache: HIT
X-Powered-By: PHP/5.3.3
X-RedHat-Debug: 1
X-Check-Cacheable: NO
Expires: Mon, 04 May 2015 13:51:17 GMT
Cache-Control: max-age=0, no-cache
Pragma: no-cache
Date: Mon, 04 May 2015 13:51:17 GMT
Transfer-Encoding: chunked
X-Cache: TCP_MISS from a2-20-133-122.deploy.akamaitechnologies.com (AkamaiGHost/7.2.0-15182023) (-)
X-Cache-Key: /L/1890/356403/3d/www.rollover.redhat.com.akadns.net/en cid=__
X-True-Cache-Key: /L/www.rollover.redhat.com.akadns.net/en cid=__
X-Akamai-Session-Info: name=CRS_VERSION; value=2.2.6
X-Akamai-Session-Info: name=DC_FORWARD_IP; value=54.187.212.127; full_location_id=X-DC-Origin-IP
X-Akamai-Session-Info: name=HEADER_NAMES; value=User-Agent%3aHost%3aAccept%3aPragma; full_location_id=
X-Akamai-Session-Info: name=INITORIGINIP; value=54.187.212.127
X-Akamai-Session-Info: name=NL_2580_BLACKLIST_NAME; value=Black List
X-Akamai-Session-Info: name=NL_6042_ORACLE_NAME; value=Oracle bot-block (per Keith Watkins by Sri Sankaran)
X-Akamai-Session-Info: name=NSCPCODE; value=298900
X-Akamai-Session-Info: name=OVERRIDE_HTTPS_IE_CACHE_BUST; value=all
X-Akamai-Session-Info: name=PARENT_SETTING; value=TD
X-Akamai-Session-Info: name=SITESHIELDMAP; value=s187.akamaiedge.net
X-Akamai-Session-Info: name=SQLI_SELECT_STATEMENT_COUNT; value=0
X-Akamai-Session-Info: name=SRTOPATH; value=/s/global.css
X-Akamai-Session-Info: name=SS4PMAP; value=www.redhat.com
X-Akamai-Session-Info: name=WAF_CREATE_ASSERTION_EXPIRE_TIME; value=1430747537
X-Akamai-Session-Info: name=WAF_CRS_ALLOWED_HTTP_VERSIONS; value=HTTP/0.9 HTTP/1.0 HTTP/1.1
X-Akamai-Session-Info: name=WAF_CRS_ALLOWED_METHODS; value=GET HEAD POST OPTIONS
X-Akamai-Session-Info: name=WAF_CRS_ARG_LENGTH; value=64000
X-Akamai-Session-Info: name=WAF_CRS_ARG_NAME_LENGTH; value=256
X-Akamai-Session-Info: name=WAF_CRS_CMD_INJECTION_ANOMALY_RULE_TUPLE; value=
X-Akamai-Session-Info: name=WAF_CRS_CMD_INJECTION_ANOMALY_SCORE; value=0
X-Akamai-Session-Info: name=WAF_CRS_CMD_INJECTION_ANOMALY_SCR; value=
X-Akamai-Session-Info: name=WAF_CRS_CRITICAL_ANOMALY_SCORE; value=5
X-Akamai-Session-Info: name=WAF_CRS_DEFAULT_ACTION; value=alert
X-Akamai-Session-Info: name=WAF_CRS_ERROR_ANOMALY_SCORE; value=4
X-Akamai-Session-Info: name=WAF_CRS_INBOUND_ANOMALY_RULE_SCR; value=
X-Akamai-Session-Info: name=WAF_CRS_INBOUND_ANOMALY_RULE_TUPLE; value=
X-Akamai-Session-Info: name=WAF_CRS_INBOUND_ANOMALY_SCORE; value=0
X-Akamai-Session-Info: name=WAF_CRS_INBOUND_MSG; value=
X-Akamai-Session-Info: name=WAF_CRS_INFO_ANOMALY_SCORE; value=1
X-Akamai-Session-Info: name=WAF_CRS_INVALID_HTTP_RULE_TUPLE; value=
X-Akamai-Session-Info: name=WAF_CRS_INVALID_HTTP_SCORE; value=0
X-Akamai-Session-Info: name=WAF_CRS_INVALID_HTTP_SCR; value=
X-Akamai-Session-Info: name=WAF_CRS_MAX_NUM_ARGS; value=255
X-Akamai-Session-Info: name=WAF_CRS_NOTICE_ANOMALY_SCORE; value=2
X-Akamai-Session-Info: name=WAF_CRS_OUTBOUND_ANOMALY_RULE_SCR; value=
X-Akamai-Session-Info: name=WAF_CRS_OUTBOUND_ANOMALY_RULE_TUPLE; value=
X-Akamai-Session-Info: name=WAF_CRS_OUTBOUND_ANOMALY_SCORE; value=0
X-Akamai-Session-Info: name=WAF_CRS_PHP_INJECTION_RULE_SCR; value=
X-Akamai-Session-Info: name=WAF_CRS_PHP_INJECTION_RULE_TUPLE; value=
X-Akamai-Session-Info: name=WAF_CRS_PHP_INJECTION_SCORE; value=0
X-Akamai-Session-Info: name=WAF_CRS_RESTRICTED_EXTENSIONS; value=asa asax ascx backup bak bat cdx cer cfg cmd com config conf cs csproj csr dat db dbf dll dos htr htw ida idc idq inc ini key licx lnk log mdb old pass pdb pol printer pwd resources resx sql sys vb vbs vbproj vsdisco webinfo xsd xsx
X-Akamai-Session-Info: name=WAF_CRS_RESTRICTED_HEADERS; value=Proxy-Connection Lock-Token Content-Range Translate Via If
X-Akamai-Session-Info: name=WAF_CRS_RFI_ANOMALY_RULE_SCR; value=
X-Akamai-Session-Info: name=WAF_CRS_RFI_ANOMALY_RULE_TUPLE; value=
X-Akamai-Session-Info: name=WAF_CRS_RFI_ANOMALY_SCORE; value=0
X-Akamai-Session-Info: name=WAF_CRS_RISK_GROUPS; value=
X-Akamai-Session-Info: name=WAF_CRS_RISK_SCRS; value=
X-Akamai-Session-Info: name=WAF_CRS_RISK_TUPLES; value=
X-Akamai-Session-Info: name=WAF_CRS_SQL_INJECTION_RULE_TUPLE; value=
X-Akamai-Session-Info: name=WAF_CRS_SQL_INJECTION_SCORE; value=
X-Akamai-Session-Info: name=WAF_CRS_SQL_INJECTION_SCR; value=
X-Akamai-Session-Info: name=WAF_CRS_TOTAL_ANOMALY_SCORE; value=0
X-Akamai-Session-Info: name=WAF_CRS_TOTAL_ARG_LENGTH; value=64000
X-Akamai-Session-Info: name=WAF_CRS_TROJAN_RULE_SCR; value=
X-Akamai-Session-Info: name=WAF_CRS_TROJAN_RULE_TUPLE; value=
X-Akamai-Session-Info: name=WAF_CRS_TROJAN_SCORE; value=0
X-Akamai-Session-Info: name=WAF_CRS_WARNING_ANOMALY_SCORE; value=3
X-Akamai-Session-Info: name=WAF_CRS_XSS_RULE_SCR; value=
X-Akamai-Session-Info: name=WAF_CRS_XSS_RULE_TUPLE; value=
X-Akamai-Session-Info: name=WAF_CRS_XSS_SCORE; value=0
X-Akamai-Session-Info: name=WAF_DATA_HEADER_SIGN_VAL; value=HnWuQRcXIUfMGG3LF/9PllRcUxUkocv8aFiFmuExQZE=
X-Akamai-Session-Info: name=WAF_DATA_HEADER_VAL; value=/en 1430747537
X-Akamai-Session-Info: name=WAF_HA_STATUS; value=checking
X-Akamai-Session-Info: name=WAF_MYSQLI_COUNT; value=0
X-Serial: 1890
Connection: keep-alive
Connection: Transfer-Encoding
Set-Cookie: WL_DCID=origin-www-c; expires=Mon, 04-May-2015 21:51:17 GMT; path=/
Set-Cookie: AWSELB=7DE7FB19045D425DE69229FBB7F229663FD24433135E354B67BC8404E265E1F485365E31B3F24C3F30EB76C3348446159423E486323BDC9105B0C92244E19C46091861E2C5;PATH=/;MAX-AGE=30
Set-Cookie: AWSELB=014101F31CE28463C273156EDFEB4013EF4DC7B4B52244855012161AA58C6EBAB965CAFA77C4DCB07BB3CC9D65387BA7D24617BF645CEBCF6476050FABBDF5D9227C0A5A30;PATH=/;MAX-AGE=30
X-Cache-Remote: TCP_MISS from a195-10-11-245.deploy.akamaitechnologies.com (AkamaiGHost/7.2.0-15182023) (-)
我同意这个例子相当长,但 Akamai 头部信息确实非常广泛。当然,这个过程不仅限于网页本身,也可以用来定位你选择的任何对象。
例如,如果你想定位特定的图像,可以使用:
$ curl -IXGET -H "Pragma: akamai-x-cache-on, akamai-x-cache-remote-on, akamai-x-check-cacheable, akamai-x-get-cache-key, akamai-x-get-extracted-values, akamai-x-get-nonces, akamai-x-get-ssl-client-session-id, akamai-x-get-true-cache-key, akamai-x-serial-no" http://www.example.com/path/to/image.jpg
或者,你可以像这样定位一个 CSS 文件:
$ curl -IXGET -H "Pragma: akamai-x-cache-on, akamai-x-cache-remote-on, akamai-x-check-cacheable, akamai-x-get-cache-key, akamai-x-get-extracted-values, akamai-x-get-nonces, akamai-x-get-ssl-client-session-id, akamai-x-get-true-cache-key, akamai-x-serial-no" http://www.example.com/path/to/style.css
在这一点上,我假设你已经了解了大多数 HTTP 响应代码(如果不了解,可以在本章末尾找到参考链接),但在我们结束这一主题之前,让我们简要看一下你可能遇到的一些不太显眼的头部:
-
X-Check-Cacheable:该值将告诉我们目标对象是否可以被 Akamai 缓存。 -
X-Cache-Key:忽略前两个值,从结果字符串的第三个值开始,你将看到 CP 代码和相关的 TTL,尽管当通过 Edge-Control 头部在应用程序级别设置时,TTL 可能会有所不同。 -
X-Cache:该值将告诉我们 Akamai Edge 服务器返回的输出内容。然而,该值还会指示以下几种情况:-
TCP_HIT:该值表示对象在缓存中是新鲜的,并且该对象是从磁盘缓存中获取的。 -
TCP_MISS:该值表示对象不在缓存中;服务器从源获取了该对象。 -
TCP_REFRESH_HIT:该值表示对象在缓存中是过期的,并且我们成功地在 If-Modified-Since 请求下刷新了源对象。 -
TCP_REFRESH_MISS:该值表示对象在缓存中是过期的,并且刷新操作从源获取了新对象,作为对我们的 If-Modified-Since 请求的响应。 -
TCP_REFRESH_FAIL_HIT:该值表示对象在缓存中是过期的,并且我们刷新失败(无法访问源对象),因此我们返回了过期的对象。 -
TCP_IMS_HIT:该值表示来自客户端的 If-Modified-Since 请求和对象在缓存中是新鲜的,并且已被提供。 -
TCP_NEGATIVE_HIT:该值表示该对象之前返回了一个“未找到”消息(或任何其他不可缓存的负面响应),并且缓存的响应对这个新请求是有效的。 -
TCP_MEM_HIT:该值表示对象位于磁盘并且已经在内存缓存中。服务器直接从内存中提供,而没有访问磁盘。 -
TCP_DENIED:该值表示由于某种原因,你被拒绝了访问客户端的权限。 -
TCP_COOKIE_DENY:该值表示你在进行 Cookie 认证时被拒绝访问(如果在配置中使用了集中式或分散式授权功能)。
-
所以,正如你所看到的,使用 cURL 调试 Akamai 头部信息非常简单。是的,也有浏览器插件可以完成相同的工作,但知道如何用 cURL 操作要有趣得多。
添加 Varnish 到 Apache
Varnish 是一个高性能的 HTTP 加速器,不仅有助于减少服务器的总体负载,还有助于提高网站响应时间。因此,它变得非常受欢迎;因此,我们将研究在 Apache Web 服务器与 Varnish 同时设置的过程。
在开始之前,我们假设已安装了 Apache。此外,您需要知道完成接下来的步骤需要访问 EPEL 仓库。请参考第四章,《故障排除包管理和系统升级》中有关如何在 CentOS 7 上下载和安装 EPEL 仓库的说明。
因此,当您准备好时,让我们开始安装 Varnish:
# yum install varnish
安装 Varnish 成功后,我们需要在启动时启用服务。可以通过输入以下命令来实现:
# systemctl enable varnish
然后,我们需要激活服务,如下所示:
# systemctl start varnish
因此,在完成基本安装后,您现在可以通过输入以下命令来检查 Varnish 的状态:
# systemctl status varnish
然后,通过输入以下命令来检查您正在运行的版本:
# varnishd -V
在这个阶段,我们需要完成此服务的基本配置,并使其能够与 Apache 配合工作。为此,我们将从打开主 Apache 配置文件开始,使用您喜爱的文本编辑器,如下所示:
# nano /etc/httpd/conf/httpd.conf
现在,向下滚动以找到以下行:
Listen 80
用以下行替换它:
Listen 127.0.0.1:8080
如果 Web 服务器正在运行一个或多个虚拟主机,则需要进行以下调整以反映 Apache 监听的新端口:
<VirtualHost *:8080>
现在保存文件并运行以下命令来检查语法:
# httpd -t
输出应为:
Syntax OK
现在,完成了这些步骤后,我们将对原始 Varnish 安装进行第一个配置更改:
# nano /etc/varnish/varnish.params
向下滚动并查找以下行:
VARNISH_LISTEN_PORT=6081
用以下内容替换它:
VARNISH_LISTEN_PORT=80
现在向下滚动并找到以下行:
VARNISH_STORAGE=
这就是 Varnish 变得有趣的地方,作为故障排除者,您可以确定最适合优化 Web 性能的方法。目前,您会注意到 Varnish 配置为使用服务器的硬盘来缓存文件,在这种情况下,您有两个选项。
在预期需要大量缓存、RAM 有限或打算构建专用 Varnish 存储以缓存文件的情况下,通过对默认设置进行简单调整来指定缓存大小。
例如,如果您希望创建 20 GB 的磁盘缓存,可以使用以下行:
VARNISH_STORAGE="file,/var/lib/varnish/varnish_storage.bin,20G"
但是,如果您希望体验使用 RAM 缓存方法的终极 Varnish 体验,则可以通过自定义以下行来实现,以反映系统的需求:
VARNISH_STORAGE="malloc,1G"
现在让我们进一步探讨这个问题。
例如,如果您希望 RAM 缓存高达 4 GB 的数据,可以使用以下方法:
VARNISH_STORAGE="malloc,4G"
或者,如果您想改善性能不太强大的基于 RAM 的环境,可以将此值更改为 512 MB,如下所示:
VARNISH_STORAGE="malloc,512m"
现在,你可以保存并关闭这个文件,然后打开以下文件:
# nano /etc/varnish/default.vcl
这个文件是 Varnish 的整体配置文件。我现在不会详细讲解具体内容,因为有很多基于 Varnish 的书籍已经详细覆盖了这个话题。然而,为了故障排除,你需要进行一些基本的修改,以确保系统正常运行。为此,只需确保以下部分符合相关系统的要求:
vcl 4.0;
# Default backend definition. Set this to point to your content server.
backend default {
.host = "127.0.0.1";
.port = "8080";
}
完成此操作后,你现在应该按如下方式重启 Apache:
# systemctl restart httpd.service
然后按如下方式重启 Varnish:
# systemctl restart varnish.service
干得好!Varnish 的安装已经完成;你可以像往常一样继续访问基于 Apache 的网站,但现在有了额外的优势,能够体验到更快的速度和性能。
使用 cURL 测试 Varnish
如果 Web 服务器依赖于 Varnish,那么确保网页被缓存并及时提供尤其重要。
要确认这一点,你可以使用以下语法开始:
# curl -I http://www.example.com/index.html
使用 -I 选项仅显示头部信息后,如果 Varnish 已安装,你应该看到类似这样的内容:
HTTP/1.1 200 OK
Date: Fri, 06 Mar 2015 00:59:24 GMT
Server: Apache/2.4.6 (CentOS) PHP/5.5.22
X-Powered-By: PHP/5.5.22
Content-Type: text/html; charset=UTF-8
X-Varnish: 5 3
Age: 16
Via: 1.1 varnish-v4
Content-Length: 97422
Connection: keep-alive
在前面的示例中,最重要的行是以下几行:
X-Varnish: 5 3
Age: 16
现在,让我们快速浏览一下这些值的解释:
-
X-Varnish: XXXXXXXX XXXXXXXX:X-Varnish头不仅包含当前请求的 ID,还维护了填充缓存的请求 ID。如果只有一个数字,你应该知道缓存是由当前请求填充的,可以认为是所谓的缓存未命中。 -
Age: XXXX:这个值表示内容在缓存中存储的时间。如果显示为零(0),则意味着该页面根本没有被缓存。
当然,显示的确切值可能不同,但通过这个例子,你现在不仅能够确认并验证服务器上 Varnish 的功能,还可以时刻关注给定的 Age 值(你将知道页面在缓存中存在的时间(秒))。
使用 cURL 访问 FTP 目录
通过实践,每个人都可以使用 FTP 客户端,但当你需要脚本化某些事件时,就需要调用 cURL 来完成所有的繁重工作。
因此,从最基础的层面开始,访问带有现有用户名和密码的 FTP 目录的最简单方法如下:
$ curl ftp://exampleftpsite.com -u <username>
当系统提示时,只需在提示符下输入你的密码:
$ curl ftp://exampleftpsite.com -u <username>
Enter host password for user '<username>':
现在,如果你想在 FTP 目录中搜索特定的文件列表,可以像这样使用 -s 静默选项和 grep 组合:
$ curl ftp://exampleftpsite.com -u <username> -s | grep <keyword>
你可以使用以下命令完成搜索并上传文件:
$ curl -T filename.zip ftp://exampleftpsite.com -u <username>
或者你可以使用以下语法直接下载:
$ curl ftp://exampleftpsite.com -u <username> -o filename.zip
同样,当提示时,你需要输入正确的密码,找到相关文件后,可以使用以下语法来发现你当前的位置:
$ pwd
最后,为了结束这一部分,你可以通过以下方式删除一个文件:
$ curl ftp://exampleftpsite.com -X 'DELE filename.zip' -u <username>
记住,在删除文件时需要格外小心,因为系统不会给出任何提示。使用 cURL 删除文件的操作是自动进行的。
启用 Apache 中的 mod_status
mod_status 是一个 Apache 模块,帮助监控 Web 服务器负载和当前的 httpd 连接。它配有一个 HTML 界面,并且可以通过任何浏览器访问。
要使用 mod_status,我们需要对 VirtualHosts 文件进行一些基本的配置更改,因此让我们从头开始,使用以下命令创建一个简单的虚拟主机:
# nano /etc/httpd/conf.d/vhost.conf
添加以下几行:
<VirtualHost *:80>
DocumentRoot /var/www/html
ServerName servername.domain.com
</VirtualHost>
记住:如果你使用的是 Varnish,请确保它使用正确的端口:
<VirtualHost *:8080>
DocumentRoot /var/www/html
ServerName servername.domain.com
</VirtualHost>
完成此操作后,你可以在适当的 <VirtualHost></VirtualHost> 指令之间添加以下几行,以启用 mod_status:
<Location /server-status>
SetHandler server-status
Order allow,deny
Allow from all
</Location>
最终的结果应该是这样的:
<VirtualHost *:8080>
DocumentRoot /var/www/html
ServerName servername.domain.com
<Location /server-status>
SetHandler server-status
Order allow,deny
Allow from all
</Location>
</VirtualHost>
你可以看到那行写着 Allow from all。对于前面的示例来说,这没问题,但出于安全考虑,你应该将连接访问限制为特定的 IP 地址。
因此,更好的选择是使用以下语法:
<Location /server-status>
SetHandler server-status
Order deny, allow
Deny from all
Allow from localhost
</Location>
当然,你应该根据系统的需求定制前面的示例代码;完成后,保存并关闭文件,然后重新启动 Apache:
# systemctl restart httpd
现在,打开浏览器,使用以下格式访问选定的虚拟主机:
http://XXX.XXX.XXX.XXX/server-status
这将使你能够完全访问静态的 server-status 页面。然而,如果你在 URL 后面加上 refresh 选项,如下所示,页面应该每 5 秒刷新一次:
http://XXX.XXX.XXX.XXX/server-status/?refresh=5
生成的页面将显示一系列信息,包括服务器运行时间、服务器负载、连接总数、CPU 使用率、进程 ID、请求总数以及当前正在处理的请求。所有这些都在你尝试诊断与特定网站相关的问题时非常有用。
总结
本章的目的是以一种非常不同的方式来看待 Web 服务故障排除。从使用 cURL 审核服务器到使用 Varnish 做性能优化,我们不仅考虑了系统管理员的需求,还探索了 CDN 和 Dev/Ops 的世界,目的是展示故障排除人员可以有多么灵活,以及你的技能将变得多么重要。
在下一章,我们将讨论一些故障排除 DNS 基于服务时使用的技巧。
参考文献
-
Curl 的 Wikipedia 主页:
en.wikipedia.org/wiki/CURL -
Curl 主页:
curl.haxx.se -
HTTP 状态码的 Wikipedia 主页:
en.wikipedia.org/wiki/List_of_HTTP_status_codes -
HTTPie,curl 的替代工具:
github.com/jakubroztocil/httpie -
Varnish 官网:
www.varnish-cache.org -
Varnish 管理员文档:
www.varnish-cache.org/docs/trunk/index.html
第十章 故障排除 DNS 服务
由于域名系统(DNS)可能是 IT 领域最具影响力的技术之一,在您的职业生涯中,您应该预期它会成为一个需要持续管理和解决的问题。DNS 服务器有多种形式,您的控制级别可能取决于您可以访问的基础设施类型,但无论如何,问题无疑会在整体或部分上保持一致。
在已经回顾了dig的优点和各种其他网络工具后,在本书的最后几页,我们将讨论故障排除 CentOS 7 的过程,特别是针对与 DNS 相关的监控问题,作为整体系统健康检查的一部分。
本章中,我们将:
-
学习如何使用
hostnamectl更改系统主机名,并通过/etc/hosts管理fqdn。 -
学习如何在按下恐慌按钮之前执行一些基本的系统和基于 BIND 的完整性检查
-
学习如何使用
iftop监控带宽 -
学习如何清空缓存
更改主机名并管理 FQDN
更改一个权威服务器或递归(缓存)服务器的主机名不一定是一个 DNS 问题(本质上),但是,作为经验法则,系统的主机名与 DNS 密切相关,作为整体系统的一部分;因此,我们现在将回顾更改主机系统主机名的过程。
要查看当前主机名,您可以使用以下语法:
# hostnamectl status
但是,您可以选择使用以下命令查看静态、临时或漂亮的名称:
# hostnamectl status --static
# hostnamectl status --transient
# hostnamectl status --pretty
基于此,要更改主机名,您应该使用以下命令:
# hostnamectl set-hostname <new-host-name>
或者,您可以选择使用以下命令更新静态主机名:
# hostnamectl --static set-hostname <new-host-name>
完成此操作后,主机名更改将自动应用于内核,无需重启。随后,任何对主机名的更改都必须反映在系统的网络配置中。
为此,您必须检查并确认/etc/hosts已更新,方法是输入:
# nano /etc/hosts
一个典型的安装后(或默认)文件如下所示:
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
要继续,请通过替换适合您系统配置的相关值,按如下方式修改文件:
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
192.168.1.183 <servername>.<domain-name>.<tld> <server-name>
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
例如,如果您的服务器名称是centos7(主机名),并且它位于centos.local域中,则您的文件应如下所示:
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
192.168.1.200 centos7.centos.local centos7
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
完成后,您可以通过输入以下命令来确认主机名:
# hostname
然后,您可以通过输入以下命令来确认并打印当前的完全限定域名(FQDN):
# hostname –f
但是,如果您发现新的主机名没有被接受或更新,您只需输入以下命令来解决任何未解决的问题:
# systemctl restart systemd-hostnamed
然后,您可以通过以以下方式运行ping来确认这些更改:
# ping –c 4 <hostname>
基于前面的示例,如果您运行:
# ping –c 4 centos
ping的输出现在应显示如下所示的 FQDN:
PING centos7.centos.local (192.168.1.200) 56(84) bytes of data.
64 bytes from centos7.centos.local (192.168.1.183): icmp_seq=1 ttl=64 time=0.048 ms
64 bytes from centos7.centos.local (192.168.1.183): icmp_seq=2 ttl=64 time=0.057 ms
64 bytes from centos7.centos.local (192.168.1.183): icmp_seq=3 ttl=64 time=0.038 ms
64 bytes from centos7.centos.local (192.168.1.183): icmp_seq=4 ttl=64 time=0.094 ms
使用 BIND 执行系统完整性检查
DNS 故障可能是由一些看似无害的问题引起的,这些问题通常源于基本的配置错误或系统近期的更改(和更新)。这种情况是可能发生的,因此,在遇到紧急情况之前,进行一系列常规检查总是有用的。
所以,从基本的工具开始,比如ping、nslookup或dig,你可以开始测试可能存在的问题区域。例如,你可以像这样使用telnet:
# telnet <remote-server-address> 53
telnet命令是一个既简单又实用的工具,如果连接被拒绝或连接时间过长,你可以通过简单地重命名反向 DNS 文件并重试来排除 RDNS 错误的可能性。
现在,如果你这样做,请确保正向 DNS 保持功能正常,并重新尝试 telnet 连接。如果成功,你就知道是 RDNS 出了问题,可以通过使用nslookup确认正向区域来再次检查:
# nslookup <remote-server-address>
然而,如果你仍然无法连接,那么你应该恢复 RDNS 文件,检查防火墙配置(如果使用SELinux,也需要检查),然后使用以下命令查看端口 53 的当前状态:
# netstat -tulpn | grep :53
如果你仍然遇到困难,那么你还应该检查日志文件,如下所示:
# tail -f /var/log/messages
现在确认 named 服务的状态:
# ps ax | grep named
然而,如果你使用以下代码,会获得更有用的信息:
# systemctl status named
该命令的输出可能会先显示以下提示信息,然后列出当前的解析错误:
named.service - Berkeley Internet Name Domain (DNS)
Loaded: loaded (/usr/lib/systemd/system/named.service; disabled)
Active: active (running) since Sun 2015-05-03 07:55:14 EDT; 16s ago
Process: 2853 ExecStart=/usr/sbin/named -u named $OPTIONS (code=exited, status=0/SUCCESS)
Process: 2851 ExecStartPre=/usr/sbin/named-checkconf -z /etc/named.conf (code=exited, status=0/SUCCESS)
Main PID: 2855 (named)
CGroup: /system.slice/named.service
└─2855 /usr/sbin/named -u named
May 03 07:55:15 centos7 named[2855]: error (network unreachable) resolving 'pdns196.ultradns.info/AAAA/IN': 2001:500:49::1#53
May 03 07:55:15 centos7 named[2855]: error (network unreachable) resolving 'pdns196.ultradns.info/A/IN': 2001:500:1b::1#53
May 03 07:55:15 centos7 named[2855]: error (network unreachable) resolving 'pdns196.ultradns.info/AAAA/IN': 2001:500:1b::1#53
May 03 07:55:15 centos7 named[2855]: error (network unreachable) resolving 'ns1.isc.ultradns.net/AAAA/IN': 2610:a1:1014::e8#53
May 03 08:55:15 centos7 named[2855]: error (network unreachable) resolving './DNSKEY/IN': 2001:7fd::1#53
May 03 08:55:15 centos7 named[2855]: error (network unreachable) resolving './NS/IN': 2001:7fd::1#53
May 03 08:55:15 centos7 named[2855]: error (network unreachable) resolving './DNSKEY/IN': 2001:dc3::35#53
May 03 08:55:15 centos7 named[2855]: error (network unreachable) resolving './NS/IN': 2001:dc3::35#53
如果一切正常,下一步将是检查你的区域文件是否有错误:
# named-checkconf /etc/named.conf
请记住,如果没有发现错误,则不会提供任何输出。然而,如果你遇到错误,根据系统的不同,输出可能如下所示:
/etc/named.conf:106: missing ';' before 'zone'
在此基础上,你还可以使用提供的工具named-checkzone来检查并确认区域文件的完整性和语法。它通过制造虚假的负载情况来工作,从而运行与文件加载到系统之前相同的验证规则。通过这种方式,它提供了一种非常可靠的方式来确认新区域文件在添加到生产服务器之前的完整性。
要使用named-checkzone,你需要输入:
# named-checkzone localhost /var/named/<filename>
或者,你可以使用以下命令检查特定主机名:
# named-checkzone <hostname> /var/named/<filename>
另一方面,如果你当前没有配置任何名字服务器,或者发现名字服务器无法访问,首先要检查系统的解析器配置,确保其配置正确,可以通过打开以下文件来确认:
# nano /etc/resolv.conf
打开该文件后,你会注意到,第一项应该指向主名字服务器,后面跟着次名字服务器。一般来说,你应该期望看到至少两个名字服务器,但三个也是常见的。根据系统的配置,/etc/resolv.conf文件的示例可能如下所示:
search local
nameserver XXX.XXX.XXX.XXX
nameserver XXX.XXX.XXX.XXX
例如,如果你使用的是 Google 的 DNS,那么主 DNS 服务器将是 8.8.8.8,辅助 DNS 服务器将是 8.8.4.4。因此,你的文件将如下所示:
search local
nameserver 8.8.8.8
nameserver 8.8.4.4
假如系统使用 127.0.0.1 或 localhost 作为主要或唯一的 DNS 服务器,那么你还应该预期在主 DNS 配置文件中使用转发器。具体的操作方式取决于你当前使用的 DNS 应用程序。然而,在 BIND 的情况下,这将在/etc/named.conf的options部分中找到,如下所示:
forwarders {
XXX.XXX.XXX.XXX;
XXX.XXX.XXX.XXX;
};
此外,在检查BIND配置文件时,你还应确保禁用递归查询,以减少递归查询,从而保护系统免受DDoS 放大攻击的风险,示例如下:
allow-transfer { 127.0.0.1; XXX.XXX.XXX.XXX; };
recursion no;
现在,确认 BIND 是否确实在端口 53 上监听:
listen-on port 53 { 127.0.0.1; XXX.XXX.XXX.XXX; };
请记住,在测试 DNS 时,你应确保 UDP 和 TCP 端口上的 53 端口是开放的。因为大于 512 字节的 UDP 查询可能会被截断,而 TCP 被用作故障转移解决方案。所以,记得检查防火墙配置,看看是否需要做出任何必要的更改;如果需要,记得重启防火墙。
完成此操作后,你可以通过输入以下命令检查BIND的当前状态:
# systemctl status named
然后,根据需要,使用以下一个或多个系统命令来启动或停止服务:
# systemctl start named
# systemctl restart named
# systemctl stop named
基于此,并假设区域文件不仅正确(包括正向和反向区域),而且维护了正确的权限,你还应该检查/etc/hosts,以确认系统是否具备适当的配置。
要做到这一点,请使用你喜欢的文本编辑器打开/etc/hosts,像这样:
# nano /etc/hosts
这个文件的示例如下:
127.0.0.1 localhost.localdomain localhost
XXX.XXX.XXX.XXX <servername>.<domainname>.<tld> <servername>
::1 localhost6.localdomain6 localhost6
如果你需要将任何特定或专用的 IP 地址添加到主机文件中,只需像这样将它们添加到前三行下面:
127.0.0.1 localhost.localdomain localhost
XXX.XXX.XXX.XXX <servername>.<domainname>.<tld> <servername>
::1 localhost6.localdomain6 localhost6
XXX.XXX.XXX.XXX live.intranet.local
XXX.XXX.XXX.XXX staging.intranet.local
XXX.XXX.XXX.XXX production.intranet.local
最后,你还应该检查并确认以太网设备的配置,可以通过在/etc/sysconfig/network-scripts中打开相关的以太网连接来访问。如你所见,这个配置文件通常会指明对特定的Gateway、DNS和Domain设置的偏好。在这方面,确保这些设置的准确性被视为良好的做法。
如此处所示,基于之前的示例,cat /etc/sysconfig/network-scripts/ifcfg-eth0的输出可能如下所示:
TYPE=Ethernet
BOOTPROTO=none
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
NAME=eth0
UUID=30420474-a7c9-4ea1-97b2-17f3b3a104cc
ONBOOT=yes
HWADDR=00:1C:42:1F:E6:BA
IPADDR0= XXX.XXX.XXX.XXX
PREFIX0= XXX.XXX.XXX.XXX
GATEWAY0= XXX.XXX.XXX.XXX
DNS1= XXX.XXX.XXX.XXX
DNS2= XXX.XXX.XXX.XXX
DOMAIN=local
IPV6_PEERDNS=yes
IPV6_PEERROUTES=yes
在此示例中,重要的是要记住,如果系统使用 CentOS 网络管理器,则必须添加 DNS 条目。此外,由于这里只显示了单一的以太网接口,如果系统具有多个网卡,则务必确保此检查清单中包括额外的以太网配置文件。
最后,如果你进行任何网络更改,请运行以下命令以确保新设置生效:
# systemctl restart network
现在,其中XXX.XXX.XXX.XXX是相关名称服务器的 IP 地址,在通过这些基本的健全性检查后,你应该能够通过运行一个成功的nslookup请求,像这样确认或重新确认你的系统配置:
# nslookup www.google.com XXX.XXX.XXX.XXX
或者,你可以通过以下方式使用dig:
# dig www.google.com XXX.XXX.XXX.XXX
因此,在检查系统的关键组件并确保防火墙没有阻止任何重要的 UDP 和 TCP 流量之后,你应该有信心,任何此时报告的非递归问题或警告(很可能)都会基于与 DNS 应用程序本身相关的特定配置问题。
使用 iftop 监控带宽
配置不当或有问题的 DNS 服务器可能导致多种问题,包括应用服务器故障和整体网络变慢。然而,在深入了解 DNS 的内部工作原理之前,重要的是要意识到网络变慢可能由多种原因引起;考虑到这一点,通常建议参考一个叫做iftop的包。
正如前面章节中讨论的那样,你会注意到iftop与top命令类似,但不同于top命令的是,你会发现它的目的是专门关注测量主机服务器与外部参考点(IP 地址)之间的网络连接带宽。
要安装此包,你需要 EPEL 仓库,并且在启用此仓库后,通过阅读前面章节的说明,iftop可以通过以下命令安装:
# yum install iftop
运行基本包无需任何参数。事实上,一个典型的iftop会话可以通过以下命令启动:
# iftop
否则,在拥有多个以太网接口的服务器上,其中X是分配给你的以太网接口的名称,你可以使用以下参数来显示特定设备的结果:
# iftop -i ethX
默认情况下,iftop将尝试将所有 IP 地址解析为主机名,但你可以使用-n选项避免这种情况,像这样:
# iftop -n -i ethX
此外,由于默认显示用于显示主机之间的总体带宽,一个有用的功能是切换此显示模式,改为显示每个主机用于通信的端口。为此,只需在iftop会话中按下P键,即可在显示所有端口和标准带宽读数之间切换。
注意
其他有用的键盘快捷键包括:
-
使用T键在显示类型之间切换
-
使用Shift + P键暂停当前显示
-
使用J和K键滚动显示
由于显示屏相对详细且不言自明,我将不会详细介绍该包本身。然而,在某些情况下,你应该意识到你可以使用iftop通过初始化适当的过滤器,像这样,来调查网络范围内的包流:
# iftop -F 192.168.1.0/255.255.255.0 -i eth0
你可以使用以下语法选择显示特定端口的结果:
# iftop -i eth0 -f 'port http'
或者,使用-B选项以以下方式,显示的带宽速率将以每秒字节(bytes per second)显示,而不是以比特每秒(bits per second)显示:
# iftop -B -F 192.168.1.0/255.255.255.0 -i eth0
请记住,故障排除的艺术在于尽可能快速地识别问题的根源。网络缓慢确实可能由配置错误或有问题的 DNS 引起,但同样也可以说,DNS 有时会被冤枉,问题可能源于带宽问题。因此,通过使用这个小巧但极其有用的工具包,你可能已经为自己节省了大量时间和精力,并永久解决了原本被认为是 DNS 问题的问题。
你可以通过输入以下命令了解更多关于iftop的信息:
# man iftop
刷新缓存
Time to Live(TTL)因子也可能影响当前问题。在某些情况下,简单的 dig 请求显示域名服务器与本地 DNS 显示的记录不同,那么(除了等待自动更新发生之外)一种不同的处理方法是刷新缓存。
对于 BIND,只需像这样重启服务:
# systemctl restart named
然而,如果不想采取那么极端的措施,你也可以使用以下语法:
# rndc flush
然后运行服务状态检查:
# systemctl status named
在这方面,你现在应该能看到以下通知:
received control channel command 'flush'
flushing caches in all views succeeded
或者,你可以使用以下语法针对特定域进行操作:
# rndc flushname google.com
运行了systemctl status named命令后,你将看到以下报告:
received control channel command 'flushname google.com'
flushing name 'google.com' in all cache views succeeded
现在,在将即时更改传播到本地桌面客户端时,你需要关闭所有正在运行的应用程序,然后遵循以下其中一个步骤。
对于 Windows 用户,只需打开命令提示符并使用:
# ipconfig /flushdns
对于 Mac OS-X 10.10,打开终端并使用以下命令:
# sudo discoveryutil udnsflushcaches
对于 Mac OS-X 10.5.2 到 10.6,使用以下命令:
# dscacheutil -flushcache
对于旧版本的 OS-X,使用此命令:
# lookupd -flushcache
总结
本章的目的并非一定要解决与 DNS 配置相关的问题,因为有许多书籍已经全面讨论了这一主题。然而,本章的内容旨在从 DNS 作为网络服务功能的角度来探讨这一主题。其结果是通过介绍一些基本技巧,帮助我们解决在权威或缓存域名服务器(DNS 服务器)出现故障时进行故障排除的艺术。
因此,从更改主机名到检查带宽,从刷新缓存到运行一些标准的系统检查,你应该意识到,故障排除并不仅仅是安装和配置软件包。在很多方面,真正的专业故障排除员很少会从头开始构建系统,但他们会被要求解决一个明显的问题,这个问题在本书的上下文中,通常是一些更紧迫的问题,甚至可能是网络环境本身固有的问题。
参考文献
-
红帽客户门户:
access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/ -
iftop 维基百科主页:
en.wikipedia.org/wiki/Iftop -
域名系统安全扩展维基百科主页:
en.wikipedia.org/wiki/Domain_Name_System_Security_Extensions -
BIND 项目主页:
www.isc.org/downloads/bind/ -
BIND 维基百科主页:
en.wikipedia.org/wiki/BIND -
RHEL 客户门户 – 第十九章:
access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/5/html/Deployment_Guide/ch-bind.html


浙公网安备 33010602011771号