原文:Pro linux system administration
协议:CC BY-NC-SA 4.0
八、包管理
在第二章中,你安装了你的第一台 Linux 主机。正如您在该章中了解到的,主机可以安装各种不同的应用程序,从最基本的安装到安装了所有应用程序和工具的安装。但是这并不是安装和管理应用程序的终点。一旦你安装了你的主机,你经常需要添加应用程序,升级和修补它们,有时还需要删除它们。本章解释了如何在 CentOS 和 Ubuntu 上执行这些任务。
在 Linux 发行版中,这种应用程序管理称为包管理。这是因为 Linux 主机上可用的大多数应用程序都是以包的形式提供的。软件包使在主机上添加和删除应用程序变得非常容易。软件包通常包含安装应用程序所需的所有二进制文件、配置文件和其他支持材料。该软件包还知道这些文件需要安装在哪里,通常还知道是否需要安装其他软件包来满足应用程序的任何先决条件。做个比较,Linux 包很像 Windows 安装 msi 或安装可执行文件。
软件包通常由称为软件包管理器的应用程序控制中心安装。大多数 Linux 发行版都有一个包管理器,它通常有一组用于管理包的命令行和图形工具,以及一个记录已安装内容的小型数据库。
在本章结束时,你将很好地理解什么是软件包,如何安装和删除它们,如何找到适合你需要的软件包,以及如何从源代码安装软件。我们将使用命令行工具以及 CentOS 和 Ubuntu 发行版可用的图形用户界面(GUI)来演示所有这些任务。
Note
在“软件包管理简介”一节之后,本章又分为几节,分别介绍在 CentOS、Ubuntu 上的安装以及从源代码安装。您只需要阅读与您选择的发行版相关的部分。我们还建议您阅读如何从源代码安装软件。您不会经常需要这样做(我们建议您坚持使用包来管理应用程序),但是知道这一点是很有用的。
包管理简介
不同的发行版有不同的软件打包方式。例如,Fedora、Red Hat Linux 和 CentOS 使用RPM
(Red Hat Package Management)包格式,而 Ubuntu 使用 deb(Debian 的缩写,Ubuntu 最初基于的发行版)格式。正如包格式不同一样,您可以用来管理它们的工具也不同。
这些包类型中的每一种都使用不同的工具来安装和管理包。在使用RPM
包的系统上,基本的包管理器被称为rpm
,而在使用 deb 包的系统上,它被称为dpkg
。两者都是非常强大的应用程序,允许您操作系统上的软件包。除了这些基本的包管理器,还有一些应用程序提供额外的功能,比如基于网络的升级、包搜索和 GUI。
Note
拥有不同的包格式和管理器可能看起来很奇怪——毕竟这些都是 Linux 发行版——但是原因主要是历史原因。当最初创建这些发行版时,开发人员没有就软件包系统应该如何工作达成一致,所以他们创建了自己的版本。多年来,对它们的开发一直在继续,现在我们有多种不同的成熟的包系统和格式。当然,如果您只使用一个发行版,那么您只需要学习一种类型的包管理。
尽管所有的 Linux 发行版都可以包含成千上万个包,但广义地说,这些包分为三个主要类别。
- 应用程序包
- 库包
- 开发包
顾名思义,大多数应用程序包都包含应用程序。这些应用程序的范围可以从简单的命令行编辑器到整个 LibreOffice 生产力套件。
Note
LibreOffice 是微软 Office 的开源等价物。它包含一个文字处理器,电子表格程序,演示软件,以及其他工具。它允许您编辑 Microsoft Office 文档,并提供与 Microsoft Office 类似的功能。
库包包含应用程序和操作系统用来提供附加功能的文件。例如,libssl
包提供了加密支持。就像你的社区图书图书馆一样,Linux 图书馆是应用程序可以找到他们需要的东西的地方,而不必自己拥有它。因为这样的库经常被多个应用程序使用,所以将它们分发到它们自己的包中是有意义的,而不是在每个应用程序中包含每个库的副本。如果更新了库包,所有使用该库的应用程序现在将自动使用更新的版本。这些包的名字往往以lib
开头。
开发包包含从源代码编译软件所需的源代码和头文件。这些包在 Ubuntu 上通常以-dev
结尾,在 Red Hat 上以-devel
结尾。大多数库包都有一个附带的开发包,允许使用这些库进行软件开发。通常,除非您正在开发应用程序,否则您不需要安装这些包。但是一些应用程序确实使用它们,如果您选择从源代码编译应用程序并以这种方式安装它们,您通常需要开发包来完成这项工作。
因为 CentOS 和 Ubuntu 使用的包管理工具完全不同,我们将在各自的章节中介绍它们。我们将首先介绍 CentOS 上的软件包管理,然后介绍 Ubuntu。
What’s a Package?
包旨在简化应用程序的管理。它们通常由应用程序的源代码构造而成,并且具有告诉您的发行版将应用程序的二进制文件、文件和配置放在哪里的逻辑。我们将使用两种类型的包,RPM
s 和 deb 文件。这两种包类型都是包含其他文件的归档。那么这些包裹里面是什么呢?包包含数据、元数据,有时还包含控制文件。数据是将要安装的文件。控制文件包含有关软件包的描述性信息、用户交互脚本以及管理自动化安装前或安装后任务的脚本。
CentOS 上的包管理
在最基本的层面上,在基于 Red Hat 的系统上管理应用程序的方式是通过 Red Hat 包管理工具,或rpm
。它用于 Red Hat Enterprise Linux、CentOS、Mandriva 和 Fedora 项目等发行版。rpm
工具本身是为在本地系统上安装、操作、查询和删除包而设计的。
Tip
您可以通过后缀.rpm
来识别 RPM 包。每个 RPM 包都是使用包含在一个spec
文件中的信息构建的。spec
文件包含关于每个包中的内容的元数据,并描述了应该如何在您的系统上安装这个包。在这一章的后面,我们将会稍微讨论一下spec
文件以及如何构建你自己的包。
rpm
工具提供了基本的包管理任务,如安装和删除包,但它不处理各种其他任务,如从在线存储库中检索依赖包(即,您需要在特定包安装的同时或之前安装的包)或包更新的定期自动化。
Note
长期使用 Linux 之后,我们可以证明,由于智能包管理,管理 Linux 系统现在变得更加容易了。在过去,安装一个软件包或更新一个应用程序可能需要几个小时来寻找依赖项,这些软件包应该在您安装和使用另一个软件包之前就在您的系统上了。在这些经理到来之前,您必须从源代码构建所有的应用程序,并处理所有出现的冲突。如今它简单多了。但是,当然,如果你真的想这么做,你总是可以从源代码开始构建——Linux 是如此强大,它给了你这样的选择。我们将在本章的最后一节讨论从源代码构建。
为了提供一些rpm
所缺乏的功能,大多数 Red Hat 衍生发行版都有一些额外的工具。这些工具中的大多数都是通过从存储库(存储包的地方;大多数发行版都有许多在线可用的存储库)并展示它们以供安装。这些工具包括 Red Hat 的 Red Hat Network (RHN,这是 Red Hat 的商业更新服务),杜克大学的 Yellowdog Updater Modified or yum
,Mandriva 的urpmi
,以及 Fedora 中名为dnf
的新包管理器。在这一节中,我们将重点介绍作为 CentOS 的一部分提供的工具,但其中包含的信息也将有助于其他基于 Red Hat 的发行版,如 Red Hat Enterprise Linux (RHEL)、Fedora 和 Mandriva。
在接下来的小节中,我们将带您通过 GUI 界面和命令行完成包的安装,以及如何使用rpm
工具本身来管理单个的包。
入门指南
在基于 Red Hat 的主机上,如 CentOS、Scientific Linux 和 Fedora,通过桌面管理软件包非常简单,不需要订阅。
然而,对于 RHEL 主机,您需要订阅才能获得软件更新和 Red Hat 的服务。RHEL 7 的订阅服务叫做红帽订阅管理。你可以在找到如何加入的详细信息
https://access.redhat.com/documentation/en-US/Red_Hat_Subscription_Management/1/html-single/RHSM/index.html
https://access.redhat.com/articles/11258
登录到你的桌面后,你会看到通常的 Gnome CentOS 桌面。我们将向您展示如何使用名为应用安装程序的工具。您可以使用应用程序安装程序来列出、搜索、安装和删除您的软件包。
您可以通过选择应用程序➤系统实用程序➤应用程序安装程序找到这两个软件包管理工具。或者,您可以将鼠标移动到屏幕的左上角,调出搜索窗口来搜索应用程序。这就是我们在图 8-1 中的做法。
图 8-1。
Finding Application Installer on CentOS
这个工具非常容易使用,我们将在下一节中演示。
应用程序安装程序
应用程序安装程序有一个简单的界面,可能类似于您可能见过的许多其他应用程序安装程序界面。在图 8-2 中,您可以看到顶部有以下视图,“全部”、“已安装”和“更新”
图 8-2。
Installation application
然后你就有了火狐浏览器和编辑推荐的常用软件包。下一部分是类别。在类别中,您可以找到您可能喜欢的相似应用程序组。我们将安装“虚拟机管理器”软件,该软件为 KVM、Xen 或 LXC 提供管理界面。
在图 8-3 中,我们选择系统类别。在这里,我们会发现 Virtual Machine Manager 是一个特色应用程序。如果它不再出现,您可以在系统页面的其他类别下找到它。
图 8-3。
Select System
在图 8-4 中你会注意到的一件事是盒子应用程序。您会注意到,我们的系统中已经“安装”了。我们将选择 Virtual Machine Manager 进行安装。
图 8-4。
Selecting Virtual Machine Manager
选择后,我们将看到关于该包的信息屏幕。有一个网站的链接,一些截图,甚至还有程序的评级。
如图 8-5 所示,我们所要做的就是点击安装按钮进行安装。如果软件包或您的系统有问题,安装程序将处于等待状态,如图 8-6 所示。
图 8-6。
Pending installation
图 8-5。
Virtual Machine Manager information screen
您的安装可能停滞在挂起状态的一些原因如下:
- 您的电脑在连接到互联网时可能会出现问题。这种情况的一个线索是信息屏幕没有显示屏幕截图。现在,您应该能够检查您的界面,使其正常工作;如果没有,返回第七章并再次查看
ip
命令。 - 软件包有问题,无法安装。CentOS 论坛通常可以帮助确认这一点。
- 安装软件包的存储库有问题。我们将很快讨论更多关于存储库的内容。
理想情况下,您将看到以下屏幕。
图 8-7。
Installing
安装完成后,您将会看到图 8-8 中的屏幕。
图 8-8。
Installation complete, Remove?
如果您希望删除应用程序,只需点击图 8-8 中的删除按钮。您将被要求输入密码。
这就是安装和删除软件包所需要做的全部工作。要查看所有已安装的软件包,我们返回初始屏幕并选择顶部的 installed 按钮(参见图 8-9 )。
图 8-9。
Installed packages
显然,您可以通过单击 remove 按钮从该屏幕中删除软件包。您也可以通过点击它们来查看已安装软件包的更多详细信息,并且您也可以从那里启动它们。当您打开此屏幕时,您会注意到您无法卸载系统软件包。如果你需要删除其中的任何一个,你必须通过YUM
包管理器来完成(稍后会有更多)。
通过转到“更新”选项卡,您可以看到您的系统当前需要的任何更新。在图 8-10 中,我们可以看到有三个更新在等着我们。我们可以通过单击左上角的刷新按钮来检查这是否是最新的列表。
图 8-10。
Refresh Updates
因为我们有一个操作系统更新,我们被要求重新启动和安装;通常我们可以不重启就安装更新。
图 8-11。
Restart & Install Updates message
单击重启和安装按钮后,在重启和安装前的 30 秒内,我们可以选择取消或继续。在主机安装了更新之后,我们会注意到我们安装了一个新的内核,如图 8-12 所示。
图 8-12。
New kernel has been installed
这些系统更新已经安装了一个新的内核,你的 grub 配置已经更新了一个新的菜单条目,我们在第六章已经讨论过了。您现在可以看到,我们可以选择最新的(新的系统默认值)或旧的内核版本。如果你在新内核上遇到问题,你可以重启并选择旧版本,看看问题是否仍然存在。
现在您的系统是最新的。在图 8-13 的底部,您将看到“上次检查:”时间。当你点击如图 8-10 所示的刷新按钮时,这个更新。您也可以选择从命令行更新您的系统。在下一节中,我们将看到如何在 CentOS 上实现这一点。
图 8-13。
System up to date
Yellowdog 更新程序已修改
对于基于 Red Hat 的发行版,用于安装、升级或更新系统的最常用工具之一是基于命令行的工具,称为 Yellowdog Updater Modified (YUM)。YUM
提供在远程存储库中搜索和查找系统可用软件的功能。如前所述,存储库是由发行版的供应商提供给你的发行版的软件包的集合,并由利益集团、大学和 ISP(互联网服务提供商)进行“镜像”。
Note
YUM
可用于 Red Hat Enterprise Linux 和 CentOS,以及其他 Red Hat 衍生的发行版。这通常是通过命令行更新和维护这些发行版上的包的默认方法。
YUM 还能够通过获取安装任何单个包所需的包来解决依赖性问题。它使用一个数据库来查询您的主机上安装了哪些软件包,然后将其与存储库提供的软件包列表进行比较。如果您需要一个或多个额外的包来满足任何依赖关系,那么这些包也会被下载和安装。
YUM 使用起来很简单。在命令行上,您只需输入yum
和一系列可能的操作之一,例如 install、remove 或 list,然后输入您希望对其执行操作的软件包的名称,例如:
$ sudo yum install nmap
Note
您需要 root 权限来运行yum
命令,要么作为 root 用户登录,要么使用sudo
命令。我们建议使用sudo
命令,正如我们在第五章中演示的那样。
表 8-1 列出了 YUM 提供的主要选项。
表 8-1。
Options Available with YUM
| [计]选项 | 描述 | | --- | --- | | 搜索 | 允许您搜索可供下载的软件包。 | | 目录 | 列出所有可供下载的软件包。 | | 安装 | 安装一个或多个软件包。 | | 检查-更新 | 列出可供更新的软件包。 | | 更新 | 更新指定的软件包或下载并安装任何可用的更新。 | | 移动 | 从主机中删除一个或多个包。 | | 信息 | 提供关于包的包信息。 | | 提供 | 告诉你一个特定的文件或特性属于哪个包。 | | 列表更新 | 列出所有只提供更新的软件包。 | | 可用列表 | 仅列出所有可用的软件包。 | | deplist | 列出包依赖项。 | | 全部清洗 | 清理不再需要的下载包文件。 | | 历史 | 显示了在此系统上执行的 YUM 命令的历史记录。 | | mssnapshot | 此子命令和相关子命令可以在发布 YUM 更新或安装之前管理 LVM 快照的创建和删除。 | | 重新喷水 | 查看在您的系统上配置的 YUM 存储库。您也可以通过`–v`或使用`repoinfo`命令来获取更多信息。 |接下来,我们将看看每个动作以及如何使用它。
用 YUM 安装软件包
让我们从YUM
开始,试着安装一个包。在正常情况下,我们会首先搜索包以确保它是可用的。我们选择安装nmap
包(如前所述,它是一个有用的网络映射和扫描工具)。我们将使用search
选项来查看该包是否可用,如清单 8-1 所示。
$ sudo yum search nmap
Listing 8-1.Searching with YUM
在清单 8-1 中,我们发出了带有search
选项的yum
命令,然后指定了我们希望搜索的包的名称。这将产生一个名称中有nmap
的可用包列表。yum
命令不够智能,无法准确知道您在寻找什么,所以它会为您提供名称或描述中带有nmap
的任何内容。
如果您不确定完整的名称,也可以搜索包名称的一部分。因此,举例来说,您可以输入yum
search map 并获得所有描述或名称中带有模式映射的包的列表。
Tip
您可以通过使用我们在第四章中展示的grep
命令来优化软件包列表。例如,您可以键入yum search python | grep boto
,这将通过搜索术语“boto”来细化与python
相关的包列表,然后显示结果包列表。
您还可以使用 yum list 查看存储库中所有可用的包,并且您可能会发现 yum groups list 对于查看包的分组很有用(yum help groups
将列出用于管理组的其他可能的子命令)。组是为方便起见而提供特定应用程序的单个包的集合。因此,例如,安装 KDE 等离子工作区组将提供运行您的 KDE 桌面的一切,而安装基本 Web 服务器组将提供 Apache web 服务器和相关的包。
有了这些信息,为了安装nmap
包,我们运行清单 8-2 中的命令。
$ sudo yum install nmap
Listing 8-2.Installing the nmap Package
将下载并安装一个名为nmap
的包。yum install 命令的输出中显示了一些信息。
Loaded plugins: fastestmirror, langpacks
Loading mirror speeds from cached hostfile
* base: centos.mirror.crucial.com.au
* extras: centos.mirror.crucial.com.au
* updates: centos.mirror.crucial.com.au
Resolving Dependencies
--> Running transaction check
---> Package nmap.x86_64 2:6.40-7.el7 will be installed
--> Finished Dependency Resolution
Dependencies Resolved
=============================================================
Package Arch Version Repository Size
=============================================================
Installing:
nmap x86_64 2:6.40-7.el7 base 4.0 M
Transaction Summary
=============================================================
Install 1 Package
Total download size: 4.0 M
Installed size: 16 M
Is this ok [y/d/N]:
第一行显示了 yum 加载的任何插件,以提供额外的特性或功能。然后我们可以看到这个安装命令使用的存储库* base:, * extra:
和* updates:
。接下来我们会看到依赖项和事务检查,然后是我们将要安装的软件包列表,在本例中是一个软件包。我们有更多关于我们正在安装的包的细节,包括所有正在安装的包的名称、架构(x86_64
)、版本(2:6.40-7.el7
)、我们正在下载这个包的 yum 存储库(base
)以及下载包的大小(4.0M
)。然后显示事务摘要,我们有机会继续安装(y
)、仅下载软件包(d
)或不安装软件包(N
)。如果您想在不提示确认的情况下安装软件包和依赖项,可以发出
$ sudo yum install –y nmap
这将对任何安装问题回答“是”(-y
),这在您通过脚本安装软件包时非常有用。
您也可以使用 groups install 命令,如下所示:
$ sudo yum groups install 'Basic Web Server'
这将在 group Basic Web 服务器中安装所有软件包。如果需要任何依赖项,它们也会被下载,并且会询问您是否要安装它们(除非您指定了groups install –y
)。如果您没有安装所有必需的依赖项,那么您将无法安装您需要的软件包。
更新您的存储库
YUM 存储库缓存由几个文件组成。这些是小型 db 文件,包含文件列表和包列表之类的内容。随着时间的推移,随着新的包被添加到存储库中并在存储库中进行更新,您的 YUM 存储库缓存数据将会过时。
要重建或刷新缓存,而不检查主机是否有任何可用的更新包,可以发出以下命令:
$ sudo yum makecache
这将从存储库中提取缓存文件。要检查您的主机是否有任何更新,您可以发出清单 8-3 中的命令。
$ sudo yum check-update
Listing 8-3.Checking for Updated Packages
check-update
子命令将下载最新的 YUM 存储库缓存数据(如果它已经过时),然后使用它来找出您的系统上哪些包有可用的更新。这将显示有可用更新的软件包列表。要安装这些更新,您可以发出
$ sudo yum update
您还可以更新一个或多个单独的包,如清单 8-4 所示。
$ sudo yum update nmap
$ sudo yum update nmap mutt
Listing 8-4.Updating Packages with YUM
Note
您不应该使用 yum 在操作系统的主要版本之间进行升级(例如,从 6.5 升级到 7.1)。从技术上讲,没有什么可以阻止您将 YUM 存储库指向最新版本并运行 yum update,但是这将产生非常不可预测的结果,并且很可能导致系统丢失。不过,您可以使用 yum 在次要版本之间进行升级(例如,从 7.1 升级到 7.2)。
使用 YUM 删除包
还可以用 YUM 删除包,如清单 8-5 所示。
$ sudo yum remove nmap
Listing 8-5.Removing Packages with YUM
清单 8-5 中使用的remove
选项将从你的系统中移除所有与该包相关的文件。您可以使用这个命令的别名erase
,它会做同样的事情。任何与原始包版本不同的配置文件都将被保存,扩展名为< filename>.conf
.rpmsave
。
执行其他 YUM 任务
您可以使用yum
命令做许多其他事情。让我们简单地看一下其他一些命令。
以下命令提供了有关您正在查询的包的信息,例如它的大小、版本和安装状态。包的描述;和其他有用的信息。
$ sudo yum info kernel
如果您想找到哪个包提供了一个特定的文件,您可以使用下面的。
$ sudo yum provides /bin/bash
bash-4.2.46-19.el7.x86_64 : The GNU Bourne Again shell
Repo : base
Matched from:
Filename : /bin/bash
前面的命令告诉您/bin/bash
二进制文件是由bash
包提供的,并描述了这个包的版本和细节。
要列出由文件路径提供的包,还可以使用以下命令:
$ sudo yum provides */sftp
这将列出所有提供sftp
文件的包。这将列出 openssh-client 包以及其他包。
查看主机可用更新列表的另一种方法是发出以下命令:
$ sudo yum list updates
如果您的主机是最新的,此命令应该不会产生任何结果。
接下来,通过发出以下命令,您可以列出可以安装在您的主机上的所有软件包:
$ sudo yum list available
前面的命令列出了尚未从存储库中为您的主机安装的所有可用软件包。
要获取主机的安全更新列表,请使用以下命令:
$ sudo yum --security check-update
这将提供等待安装到您的主机上的当前安全软件包的列表。要安装,只需安装那些安全补丁。
$ sudo yum --security update
您也可以使用以下命令从特定的 YUM 存储库中安装软件包
$ sudo yum install --enablerepo=myrepo my-package
在前面的命令中,我们告诉 YUM 从我们的myrepo
YUM 存储库中安装我们的my-package
。如果存储库被禁用,这意味着我们通常不从该存储库中获取包,我们可以在执行该命令时启用该存储库。除非指定,否则后续的 yum 命令不会从该存储库中提取。不久将有更多关于 YUM 存储库的内容。
最后,您可以清理您的缓存目录(YUM 临时存储您已经下载的包的地方)。如果需要回收一些磁盘空间临时磁盘空间,可以清除缓存。
$ sudo yum clean all
前面的命令删除了包含在/var/cache/yum cache
目录中的缓存包和头文件。
配置 YUM
YUM 应用程序可以通过多种方式进行配置。YUM 将其配置文件存储在/etc/yum.conf
和/etc/yum.repos.d/
下,并将状态文件存储在目录/var/lib/yum
和/var/cache/yum
下。
Note
状态文件告诉YUM
你的主机上已经安装了什么,还保存了下载包的缓存版本。注意不要删除这些目录,因为您很容易损坏您的软件包数据库。
您通常不需要更改默认的/etc/yum.conf
。例如,当您希望更改配置时,可以添加一个代理服务器,YUM 应该在下载包时使用它。默认设置通常适合大多数环境。YUM 可用配置设置的完整列表可通过yum.conf
手册页获得。
$ man yum.conf
虽然您很少改变 YUM 的配置方式,但是您可能希望向 YUM 添加额外的存储库,以便从中下载额外的包。定义 YUM 可用的存储库的文件包含在/etc/yum.repo.d
目录中。让我们看一个通用的存储库文件:
$ cat /etc/yum.repo.d/myrepo.repo
[myrepo]
name=myrepo
baseurl=http://myrepo.mydomain.com/pub/linux/releases/$releasever/$basearch/os/enabled=1
gpgcheck=1
gpgkey=http://myrepo.mydomain.com/linux/RPM-GPG-KEY-linux
表 8-2 中解释了这些选项。
表 8-2。
Basic Options for Adding a yum
Repository
在清单 8-6 中,我们为 CentOS 发行版定义了一个新的存储库,用于下载源 rpm 文件。如果我们希望重新构建我们自己的 rpm 包,将使用源 rpm 文件。这些源文件是 CentOS 维护人员用来生成我们在包中使用的普通二进制 rpm 的文件。
[source]
name=CentOS-releasever - Sources
baseurl=http://vault.centos.org/centos/$releasever/os/Source/
gpgcheck=1
enabled=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
Listing 8-6.Adding a CentOS Repository in a YUM Repo File
您可以看到,在 baseurl 选项中,我们指定了一个名为$releasever
的变量。在 Red Hat 和 CentOS 上,该变量默认为redhat-release
包的版本。
$ cat /etc/redhat-release
CentOS Linux release 7.2.1511 (Core)
在这种情况下,$releasever
将等于7.2.1511
。这个发布文件由centos-release-7-2.1511.el7.centos.2.10.x86_64
包放在系统中。
您还会看到我们用于源的 baseurl 指向了vault.centos.org
主机。在这里,您可以找到 CentOS 的早期历史版本以及用于构建您自己的 rpm 的源文件。在 baseurl 选项中可以列出多个 baseurl。
baseurl=http://myrepo1.org/centos/...
http://myrepo2.org/centos/...
URL 列表也可以通过mirrorlist=
选项而不是baseurl=
从网络服务器中检索。mirrorlist.txt
文件只包含以下内容:
mirrorlist=http://myrepo.org/mirrorlist.txt
http://myrepo1.org/centos/...
http://myrepo2.org/centos/...
加载了 yum 的fastestmirror
插件后,YUM 将从列表中找到响应最快的镜像,并在运行时使用它。
YUM 存储库配置中可能存在其他变量:
$arch
–您系统的架构(由 yum 检测)$basearch
–您系统的基础架构(例如,i686 变成 i386)$uuid
–为您的系统生成并存储在/var/lib/yum/uuid
中的唯一标识符$infra
–目前未使用,但您可以在您的镜像列表 URL (&repo=os&infra=$infra
)中看到它。
当变量如下使用时:
http://myrepo.org/centos/$releasever/$arch/myapp
这可以推断为
http://myrepo.org/centos/7-2.1511/x64_86/myapp
有关 YUM 使用的配置选项的完整列表,请参见man yum.conf
。当您创建一个新的 Yum 存储库时,您可以使用makecache
命令来刷新您的存储库缓存,并向其中添加新的存储库。
$ sudo yum makecache
在现代 Fedora 发行版(从版本 22 开始)和即将发布的 Red Hat 和 CentOS 发行版中,您将更新软件包管理器来处理称为 DNF 的 rpm。现在让我们来看看。
DNF——或者说奢华的美味
DNF 最初是百胜软件包管理器的一个分支,它是百胜的替代版本,而不仅仅是一个新版本。它被设计成保持(大致)与 YUM 当前版本的 CLI(命令行界面)兼容性。因此,您应该已经熟悉了 DNF 软件包管理器的主要命令。
虽然最终用户不应该注意到百胜和 DNF 之间有太多的区别,但实际上有很多区别。不同之处主要在于如何重写代码,以使开发人员更容易使用可预测和记录的 API(应用程序编程接口)进行维护和扩展。在 YUM 不兼容的地方,它也兼容 Python3。此外,包依赖算法已经完全重写。DNF 将会是一个受欢迎的,更快的,即使不被注意到的进步。
类似下面的命令执行与等效的 YUM 命令类似的功能。
$ dnf search nmap
$ dnf info nmap
$ dnf install nmap
$ dnf remove nmap
这些命令都具有与 YUM 相似的语法。有关可用命令的完整列表,请参见 DNF 文档,网址为
DNF 的存储库文件也将类似于当前的 YUM 存储库文件,并且来自同一个位置,/etc/yum.repos.d/*.repo
。
[fedora]
name=Fedora $releasever - $basearch
failovermethod=priority
#baseurl=http://download.fedoraproject.org/pub/fedora/linux/releases/$releasever/Everything/$basearch/os/
metalink=https://mirrors.fedoraproject.org/metalink?repo=fedora-$releasever&arch=$basearch
enabled=1
metadata_expire=28d
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$releasever-$basearch
skip_if_unavailable=False
正如您所看到的,在这里我们如何描述一个与 DNF 一起使用的存储库并没有真正的区别。有关 DNF 使用的配置选项的完整列表,请参见手册dnf.conf
。
红帽包管理
我们刚刚看了yum
和dnf
命令以及如何使用它们来管理包。YUM 或 DNF 的唯一目的是管理您系统上实际的 Red Hat Package Management (RPM)软件包。每个 RPM 包也可以通过rpm
命令检查、安装和移除。rpm
命令是操纵包含软件包的RPM
文件的基本工具。虽然您可能不经常需要直接使用rpm
命令,但了解它的工作原理是很重要的。
有许多选项可以传递给rpm
命令。要获得这些命令的完整列表,我们建议您阅读其man
页面。
$ man rpm
在rpm
手册页上,您可以看到rpm
工具可以执行三个基本功能。
- 查询包
- 安装、升级和删除软件包
- 杂项功能
让我们更详细地看看其中的一些选项。表 8-3 显示了你可以传递给rpm
的主要选项以及它们的作用。每个选项都有许多您添加的标志。
表 8-3。
The Major rpm
Options and Flags
查询包
首先,我们将使用-q 或- query 选项来查询安装在您的主机上的包。为了找出您的主机上安装了什么,rpm
工具查询存储在数据库中的数据。当软件包被安装和删除时,这个数据库被更新。
Note
RPM 数据库只知道您的主机的当前状态;它不知道昨天删除了什么,也不知道软件包的以前版本是什么。当您使用yum
或dnf
时会记录该信息,但当您使用rpm
时不会。
现在让我们使用rpm
来检查 Linux 操作系统的核心——内核。假设有人问你,“我们安装了什么内核?”要找到答案,您可以使用rpm
命令,如清单 8-7 所示。
Note
您也可以通过发出uname –r
命令找到您当前使用的内核。
# rpm --query kernel
kernel-3.10.0-327.el7.x86_64
kernel-3.10.0-327.18.2.el7.x86_64
Listing 8-7.Querying the Installed Kernel Version
这里我们运行了带有--query
标志的rpm
命令,并指定了我们想要查询的包的名称,在我们的例子中是内核。您可以看到,这产生了一个已安装内核的列表。
Note
您会在清单 8-7 中看到不止一个内核,因为您可以安装不止一个内核。这并不意味着你有多个内核同时运行;相反,你有多个潜在的内核可以运行。
安装的每个内核末尾的数字是不同的版本。一个是 3.10.0-327.el7.x86_64,一个是 3.10.0-327.18.2.el7.x86_64。两者都与 Red Hat Enterprise Linux 7 系统(. el7)兼容。
Tip
我们在第六章中讨论了如何选择想要启动的内核。
如果你不知道你要找的包的名字怎么办?或者,如果您想查看所有已安装的软件包,该怎么办?在这些情况下,您可以使用清单 8-8 中的命令。
# rpm --query --all
Listing 8-8.Querying All Packages
该命令使用- query
标志和- all flag
标志,表示您正在查询所有软件包,它列出了所有已安装的软件包。
正如您将看到的,这个列表可能会很长。假设您只想查找任何名称包含 vim 的包。然后,您可以通过grep
工具来处理输出,该工具会在输出中搜索字符串 vim,如清单 8-9 所示。
# rpm --query --all | grep vim
vim-minimal-7.4.160-1.el7.x86_64
vim-filesystem-7.4.160-1.el7.x86_64
vim-enhanced-7.4.160-1.el7.x86_64
vim-common-7.4.160-1.el7.x86_64
Listing 8-9.Querying All Using Piping and grep
Note
我们将在第四章中介绍grep
命令和管道。
清单 8-9 显示,通过管道将查询输出传递给grep
命令已经将列表从数千个包减少到四个名称中带有字符串vim
的包(空列表表示没有安装名称中带有该字符串的包)。
让我们了解更多关于内核包的信息。在清单 8-10 中,我们结合使用查询选项和--info
选项来查找关于我们安装的一个内核的更多信息。
# sudo rpm --query --info kernel-3.10.0-327.18.2.el7.x86_64
Name : kernel
Version : 3.10.0
Release : 327.18.2.el7
Architecture: x86_64
Install Date: Thu 26 May 2016 17:43:40 EDT
Group : System Environment/Kernel
Size : 142681799
License : GPLv2
Signature : RSA/SHA256, Thu 12 May 2016 19:41:18 EDT, Key ID 24c6a8a7f4a80eb5
Source RPM : kernel-3.10.0-327.18.2.el7.src.rpm
Build Date : Thu 12 May 2016 07:51:03 EDT
Build Host : kbuilder.dev.centos.org
Relocations : (not relocatable)
URL : http://www.kernel.org/
Summary : The Linux kernel
Description :
The kernel package
contains the Linux kernel (vmlinuz), the core of any
Linux operating system. The kernel handles the basic functions
of the operating system: memory allocation, process allocation, device
input and output, etc.
Listing 8-10.Getting Information About Packages
清单 8-10 产生了大量的信息。其中一些可能最初对你来说意义不大,但让我们来看看一些数据。您可以看到版本和发布号,以及它的构建和安装日期。您还可以看到该软件包属于哪个组,因为主机上的每个软件包都属于一组相似的软件包。当你在第二章安装你的主机并选择你想要的软件包作为这个过程的一部分时,你就看到了这一点。
此外,您可以看到发布软件包的许可证(在本例中是 GPLv2 许可证)、软件包的大小,最重要的是,软件包的描述和摘要以及一些关于软件包的更多信息的链接。
有时你会想知道哪个软件包安装了一个特定的文件或命令。您也可以使用rpm
工具来查询这些信息。例如,我们在主机上安装了/bin/bash
命令,我们可以通过使用清单 8-11 中所示的rpm
来找出是什么安装了这个命令。
# rpm --query --whatprovides /bin/bash
bash-4.2.46-19.el7.x86_64
Listing 8-11.Using query and whatprovides
清单 8-11 告诉我们包bash
负责文件/bin/bash
,它也通知我们安装的bash
包的版本号(你也可以用更短的格式$ rpm -qf /bin/bash
)。
所以现在我们知道bash
提供了那个文件,但是我们系统上还有哪些文件属于bash
包呢?有了来自--whatprovides
的信息,我们可以通过使用清单 8-12 所示的--query --list
选项来查看还有哪些文件属于bash
包。
# rpm --query --list bash
/etc/skel/.bash_logout
/etc/skel/.bash_profile
/etc/skel/.bashrc
/usr/bin/alias
<snip> ...
Listing 8-12.Using query and list
清单 8-12 显示了出现在bash
包中的所有文件的删减列表。我们还可以列出关于软件包的其他有用信息。例如,rpm –qc <package>
命令会显示与包相关的配置文件,rpm –qd
会列出文档文件。
软件包通常会在安装或卸载之前或之后运行安装前和安装后以及卸载脚本。这些可能会创建用户,配置和启动服务,或清理自己。您可以使用以下内容查看此类脚本:
# rpm –q --scripts bash
postinstall scriptlet (using <lua>):
nl = '\n'
sh = '/bin/sh'..nl
bash = '/bin/bash'..nl
f = io.open('/etc/shells', 'a+')
if f then
local shells = nl..f:read('*all')..nl
if not shells:find(nl..sh) then f:write(sh) end
if not shells:find(nl..bash) then f:write(bash) end
f:close()
end
在上面的 Lua 脚本(Lua 是一种编程语言)中,我们可以看到在安装 bash 程序后执行的脚本。在安装 bash 包之后,该脚本执行对/etc/shells
文件的必要添加。
正如你现在可能看到的,我们可以用yum
或dnf
完成类似的任务。让我们继续用rpm
安装软件包。
使用 RPM 安装软件包和删除软件包
rpm
工具也可以用来安装或升级软件包;但是,不建议这样做。这与百胜的工作方式相冲突。通过 RPM 安装通常也很烦人。要安装软件包,您需要下载所需的RPM
文件和任何依赖项,然后使用rpm
工具将其安装到您的主机上。
移除包会出现同样的问题,也应该避免。
从源代码构建 RPM 包
为什么需要从源代码构建一个包?嗯,有时你需要一个源代码的补丁,或者你想构建一个更新版本的包。如果是这种情况,您可以采取几种方法。
许多包都有所谓的上游RPM
包,上游RPM
包包含的应用程序版本比发行版附带的版本更新。它们通常是由应用程序的开发人员或应用程序开发社区的其他成员构建的。它们会有你可能需要的更新的代码补丁或更新的特性,但是它们会更尖锐,可能包含错误和问题。这些上游 ?? 通常可以在应用程序的网站上找到。
Caution
上游RPM
s 文件任何人都可以建。它们可能不稳定、不安全或没有定期维护。你应该小心使用它们。
第二种方法是下载需要更新的应用程序的源代码,并构建自己的 rpm。网上有一些优秀的参考资料可以帮助你创建自己的RPM
文件:
Maximum
RPM
:
www.rpm.org/max-rpm-snapshot/
How to create a RPM:
https://fedoraproject.org/wiki/How_to_create_an_RPM_package
Packaging Software with``RPM``, Part 1``:
www.ibm.com/developerworks/library/l-rpm1/
Creating``RPM``s``:
http://pmc.ucsc.edu/~dmk/notes/RPMs/Creating_RPMs.html
我们将快速演示构建 RPM 包的过程。这个包将简单地在我们的系统上放置一个脚本。为此,我们需要安装 rpm-build 和 rpmdevtools 包。如果你打算编译一个程序,你也需要合适的开发包。
$ sudo yum install rpm-build rpmdevtools
接下来,我们需要创建一些rpm build
命令所需的基本目录。为此,我们使用 rpmdevtools 包中的一个命令。
$ rpmdev-setuptree
$ ls -l rpmbuild/
total 20
drwxrwxr-x. 2 vagrant vagrant 4096 Jul 24 09:46 BUILD
drwxrwxr-x. 2 vagrant vagrant 4096 Jul 24 09:46 RPMS
drwxrwxr-x. 2 vagrant vagrant 4096 Jul 24 09:46 SOURCES
drwxrwxr-x. 2 vagrant vagrant 4096 Jul 24 09:46 SPECS
drwxrwxr-x. 2 vagrant vagrant 4096 Jul 24 09:46 SRPMS
当构建 RPM 包时,我们至少需要上面目录中的规范和源代码。构建是我们构建包的地方。构建完成后,我们的包将放在 RPMS。SOURCES 是我们放置用于构建的源文件的地方。SPECS 是放置我们的 spec 文件的地方。SRPMS 是我们的 RPM 源文件所在的地方。我们将进入我们的rpmbuild
目录。
我们在名为simple_echo.tar.gz
的 SOURCES 目录中放置了一个压缩的 tarball(一个压缩的归档文件)。它包含一个名为simple_echo.sh
的文件,我们打算将它安装到/usr/local/bin directory
中。
在我们继续之前,我们需要创建我们的simple_echo.spec
文件,并把它放在 SPECS 目录中。在我们的 rpmdevtools 包中,我们使用如下的rpmdev-newspec
命令:
$ rpmdev-newspec simple_echo && mv simple_echo.spec SPECS/
simple_echo.spec created; type minimal, rpm version >= 4.11.
这已经创建了我们的规范文件,并将其移动到我们的规范目录中。我们现在可以使用我们的 vi 编辑器来编辑文件。spec 文件包含关于我们的包的细节——版本号、许可证等等。它还有几个宏,rpmbuild 用它们来帮助创建包。它们以%<macro>
开始。
我们的规范文件将如下所示:
Name: simple_echo
Version: 1.0
Release: 1%{?dist}
Summary: Echoes your input
License: GPLv3+
URL: http://www.example.com/simple_echo
Source0: %{name}-%{version}.tar.gz
BuildRequires: bash
Requires: bash
%description
This program echoes the first parameter entered.
%prep
%setup -q
%install
rm -rf $RPM_BUILD_ROOT
mkdir -p $RPM_BUILD_ROOT/usr/local/bin
install simple_echo.sh -m0755 $RPM_BUILD_ROOT/usr/local/bin/simple_echo.sh
%files
%doc
%attr(0755,root,root)/usr/local/bin/simple_echo.sh
%changelog
* Sun Jul 24 2016 JSmith <jsmith@example.com>
- First simple_echo package
在我们的规范文件中,我们给出了包名和版本。在发布中你可以看到第一个宏,%{?dist}
。这会将分发详细信息添加到包中。摘要、许可证、来源和 URL 是必需的信息。如果需要,您可以有多个源文件,我们再次使用宏来描述它——它可以是一个 URL 或者必须存在于 SOURCES 目录中。
BuildRequires 和 Requires 用于处理包依赖关系。如果指定,必须在构建或安装之前安装所需的软件包。我们选择 bash 作为我们需要的包。
Tip
您也可以为 RPM 构建创建自己的宏。有关宏的更多信息,请参见 www.rpm.org/wiki/PackagerDocs/Macros
。
我们已经删除了一些用于编译软件的标准宏,因为我们在这里不编译任何东西。prep 和 setup 宏通过清理旧文件并将源文件解包到构建目录中来准备构建空间。接下来是%install 部分,在这里我们删除任何旧的构建数据并创建 BUILDROOT 目录结构。然后,我们使用 install 命令(将文件复制到所需的位置,并为它们提供所需的模式)。
下一节将列出我们正在安装的文件。它们可以是 doc 文件、conf 文件和目录。在本例中,我们列出了一个模式为 0755、所有者和组根的文件。
最后,我们有一个变更日志部分。这应在特定日期格式(DayofWeek Month Day Year name <email>
)中定义。这需要跟一个以‘-‘
开头的 changelog 消息。
一旦这个文件被保存,我们现在可以运行构建。构建 RPM 有几种主要的方法。首先是只构建二进制文件。第二步是编译源代码和二进制代码。还有其他选项,您可以使用 man rpmbuild
命令找到这些选项。
$ rpmbuild –bb SPEC/simple_echo.spec
Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.7kXFJS
+ umask 022
+ cd /home/vagrant/rpmbuild/BUILD
+ cd /home/vagrant/rpmbuild/BUILD
+ rm -rf simple_echo-1.0
+ /usr/bin/gzip -dc /home/vagrant/rpmbuild/SOURCES/simple_echo-1.0.tar.gz
+ /usr/bin/tar -xf -
+ STATUS=0
+ '[' 0 -ne 0 ']'
+ cd simple_echo-1.0
+ /usr/bin/chmod -Rf a+rX,u+w,g-w,o-w .
+ exit 0
Executing(%install): /bin/sh -e /var/tmp/rpm-tmp.EJ4LAv
+ umask 022
+ cd /home/vagrant/rpmbuild/BUILD
+ '[' /home/vagrant/rpmbuild/BUILDROOT/simple_echo-1.0-1.el7.centos.x86_64 '!=' / ']'
+ rm -rf /home/vagrant/rpmbuild/BUILDROOT/simple_echo-1.0-1.el7.centos.x86_64
++ dirname /home/vagrant/rpmbuild/BUILDROOT/simple_echo-1.0-1.el7.centos.x86_64
+ mkdir -p /home/vagrant/rpmbuild/BUILDROOT
+ mkdir /home/vagrant/rpmbuild/BUILDROOT/simple_echo-1.0-1.el7.centos.x86_64
+ cd simple_echo-1.0
+ rm -rf /home/vagrant/rpmbuild/BUILDROOT/simple_echo-1.0-1.el7.centos.x86_64
+ mkdir -p /home/vagrant/rpmbuild/BUILDROOT/simple_echo-1.0-1.el7.centos.x86_64/usr/local/bin
+ install simple_echo.sh -m0755 /home/vagrant/rpmbuild/BUILDROOT/simple_echo-1.0-1.el7.centos.x86_64/usr/local/bin/simple_echo.sh
+ '[' '%{buildarch}' = noarch ']'
+ QA_CHECK_RPATHS=1
+ case "${QA_CHECK_RPATHS:-}" in
...
<snip>
...
Processing files: simple_echo-1.0-1.el7.centos.x86_64
Provides: simple_echo = 1.0-1.el7.centos simple_echo(x86-64) = 1.0-1.el7.centos
Requires(rpmlib): rpmlib(CompressedFileNames) <= 3.0.4-1 rpmlib(FileDigests) <= 4.6.0-1 rpmlib(PayloadFilesHavePrefix) <= 4.0-1
Requires: /bin/bash
Checking for unpackaged file(s): /usr/lib/rpm/check-files /home/vagrant/rpmbuild/BUILDROOT/simple_echo-1.0-1.el7.centos.x86_64
Wrote: /home/vagrant/rpmbuild/RPMS/x86_64/simple_echo-1.0-1.el7.centos.x86_64.rpm
Executing(%clean): /bin/sh -e /var/tmp/rpm-tmp.LPOTLL
+ umask 022
+ cd /home/vagrant/rpmbuild/BUILD
+ cd simple_echo-1.0
+ /usr/bin/rm -rf /home/vagrant/rpmbuild/BUILDROOT/simple_echo-1.0-1.el7.centos.x86_64
+ exit 0
我们有构建过程的输出。你可以看到我们有线Wrote ... simple_echo-1.0-1.el7.centos.x86_64.rpm
。我们现在将使用 rpm–IVH 安装该 rpm。
$ sudo rpm –i RPMS/x86_64/simple_echo-1.0-1.el7.centos.x86_64.rpm
现在,我们可以测试脚本是否已安装并正常工作:
$ simple_echo.sh hello
hello
应该指出的是,从源代码创建您自己的包可能需要一些时间,这取决于您要构建的包的复杂性以及它所依赖的包的数量。你还必须支持它,这有时会比你想象更麻烦。因为您可能会选择不常见的选项,所以您可能会发现自己独自面临其他人没有经历过的生产问题。
在您构建自己的包之前,您还可以查看 EPEL 包,它们是基于 Fedora 的上游包,但为 RHEL、CentOS 和 Scientific Linux 进行了重建。这些可能比管理你自己的一套 rpm 更好,但仍然带有相同的警告。
这并不是说要阻止你去尝试,而是要提醒你,构建你自己的包有时会变得漫长而危险。在“从源代码编译”一节中,我们将向您展示如何从源代码编译您自己的包,并为您提供一种制作 rpm 和 deb 包的方法。
Ubuntu 上的包管理
在 Ubuntu 服务器上管理软件包通常是使用命令行工具来完成的,因为 Ubuntu Server Edition 在默认情况下不安装 GUI。在这一节中,我们将首先介绍管理包的命令行工具。之后,我们将看看 Unity 桌面上的图形化软件包管理器。
在 Ubuntu 主机上添加软件最常见的方式是通过命令行工具从在线软件仓库安装软件包。该发行版提供了包含 22,000 多个现成安装包的在线软件库。这些年来,已经开发了一些工具来帮助你从远程仓库向你的 Ubuntu 主机添加应用程序。这些工具为基于 Red Hat 的发行版提供了相当于rpm and yum
的 Ubuntu。我们将看看两个命令行工具:
aptitude
dpkg
这些工具都默认安装在 Ubuntu 主机上。aptitude
工具允许您安装、删除、更新和搜索在线存储库中的包。这是管理包的首选方式,所以我们将最详细地介绍这个工具。另一个具有类似用途的流行工具是Apt
( https://wiki.debian.org/Apt
)。
dpkg
工具是用于安装和移除软件包的基本命令行工具。Aptitude 在内部使用dpkg
来管理包。我们将只简要地看一下dpkg
,因为你不太需要经常使用它。
才能
你可以用两种方式使用aptitude
工具:通过菜单和对话框交互,或者通过命令行向它传递指令。对于初级用户,最简单的方法是使用aptitude
的基于菜单的用户界面。让我们启动它看看。
$ aptitude
处理完包列表后,aptitude
显示其主窗口,如图 8-14 所示。
图 8-14。
The main aptitude
screen
主屏幕由菜单栏、命令列表、窗口列表、状态信息、软件包列表窗口和信息窗口组成。您的光标将首先出现在软件包列表窗口中。您可以使用箭头键在列表中上下移动,并通过按 Enter 键展开突出显示的项目。
按 Enter 键展开已安装的软件包列表,然后展开主列表。您将在main
部分看到按字母顺序排列的当前已安装软件包列表。突出显示某个包时,该包的描述会显示在信息窗口中。通过按 Tab 键切换到此窗口,然后使用箭头键上下滚动信息。再次按 Tab 键切换回列表窗口。在图 8-15 中,您可以看到我们突出显示了adduser
包。
图 8-15。
Displaying the package description
要显示更详细的包信息,请滚动以突出显示包名称并按 Enter 键,如图 8-16 所示。您现在可以看到诸如依赖项、维护者等信息。
图 8-16。
Displaying detailed package information
按 q 关闭信息窗口并返回软件包列表。
因为滚动这个列表并不快,所以能够搜索它是有用的。按下正斜杠(/)并输入所需的搜索词,调出搜索对话框。我们找找 Ubuntu 内核包,叫linux-image
。当您键入时,aptitude
将在列表中向下跳转,显示第一个匹配的包。你可以在图 8-17 中看到这样的例子。
图 8-17。
Searching packages by name
按 Enter 键关闭搜索对话框。要跳转到下一个匹配的包名,请按 n。如果您继续按 n,您最终会发现自己在未安装包的列表中,其中包含更多的内核。要在屏幕上显示更多的软件包名称,您可以通过按 d 键切换信息窗口。
现在让我们安装一个包。一个小但有用的网络实用程序是nmap
,所以我们将选择它。使用find
命令在列表中找到这个包,然后突出显示它。要标记此软件包以便安装,请按加号(+)。你会看到一个警告对话框,告诉你aptitude
不能安装包,除非你成为 root 用户,如图 8-18 所示。
图 8-18。
root user warning dialog
您可以禁止此警告在将来出现。您会注意到有一个“不再显示此消息”复选框。首先按 Tab 跳转到复选框,按空格键选中它,然后再次按 Tab 选择 OK 按钮并回车接受。要确认此警告,请按 Enter 键。
Tip
如果我们通过sudo
启动aptitude
,警告对话框就不会出现。然而,作为一个non-root
用户进行选择增加了一层防止错误的保护。因为不作为根用户是不可能意外删除包的,所以作为non-root
用户运行aptitude
并成为根用户来应用挂起的更改是一个好主意。
您将看到软件包状态已经从 p 变为 pi,而不是立即安装软件包。现在它被标记为安装。这允许您在将更改应用到系统之前,选择任意数量的软件包进行安装或删除。
现在您将只安装nmap
应用程序,但是首先您必须成为 root 用户。为此,按 Ctrl+T 激活动作菜单(参见图 8-19 )。
图 8-19。
Selecting Become root
使用箭头键选择成为 root(避免玩扫雷游戏的诱惑),按回车键,aptitude
现在会为你运行sudo
。输入密码后,它会以根用户权限重新启动。虽然软件包列表会恢复到最初的折叠状态,但是安装软件包的命令会添加到内部待办事项列表中。
为了处理你的待安装,按 g. aptitude
发现nmap
包需要其他几个包存在于系统中,因此它被自动选择安装(用 piA 标记),如图 8-20 所示。
图 8-20。
Added package dependencies
再次按 g 确认您想要安装这个依赖项,然后aptitude
现在将下载所需的包文件并安装它们。在这个过程中,你会被告知正在发生的事情(见图 8-21 )。
图 8-21。
Processing installation tasks
安装完成后,按回车键,返回到Aptitude
菜单。您现在将学习如何通过移除刚刚安装的nmap
包来移除包(参见图 8-22 )。再次使用/
键进行搜索。您会看到它旁边有一个(I)表示已安装。按连字符(-
)键标记要移除的包。您将看到所需的包状态字符从 I 变为 id。如果您已经定制了配置文件,并希望确保在此阶段也删除这些文件,您可以按下下划线(_
)键来标记要清除的包;如果这样做,您将看到所需的状态变为 p。在图 8-22 中,您可以看到nmap
现在被设置为 id,因为它被标记为删除。要应用排队的更改,请按 g。
图 8-22。
Package removal via aptitude
安装 nmap 时作为依赖项添加的软件包,由于没有被任何其他软件包使用,因此也被设置为删除。再次按 g 确认并处理更改(参见图 8-23 )。
图 8-23。
Process pending removals
有关Aptitude
中可用命令的更多信息,请按问号(?
)键。图 8-24 显示了可用命令的列表。
图 8-24。
The aptitude
command list
您可以按 q 退出帮助列表。然后您可以再次按 q 退出aptitude
。
非交互模式
所有这些导航和窗口切换可能是用户友好的,但它很难快速。为此,aptitude
还有一个命令行模式,不使用交互菜单,而是以动作命令和包名作为参数。为了证明以这种方式使用aptitude
和使用 GUI 一样方便,我们将再次安装nmap
包。当以非交互方式使用aptitude
时,您需要以 root 用户身份运行它来执行安装和卸载任务。看看如何在清单 8-13 中再次安装nmap
。
$ sudo aptitude install nmap
The following NEW packages will be installed:
libblas-common{a} libblas3{a} liblinear3{a} liblua5.2-0{a} libxslt1.1{a} lua-lpeg{a} ndiff{a} nmap python-bs4{a} python-chardet{a} python-html5lib{a} python-lxml{a} python-pkg-resources{a}
python-six{a}
0 packages upgraded, 14 newly installed, 0 to remove and 4 not to upgrade.
Need to get 0 B/6,311 kB of archives. After unpacking 28.1 MB will be used.
Do you want to continue? [Y/n/?] y
Selecting previously unselected package libblas-common.
(Reading database ... 99366 files and directories currently installed.)
Preparing to unpack .../libblas-common_3.6.0-2ubuntu2_amd64.deb ...
Unpacking libblas-common (3.6.0-2ubuntu2) ...
...<snip>...
update-alternatives: using /usr/lib/libblas/libblas.so.3 to provide /usr/lib/libblas.so.3 (libblas.so.3) in auto mode
Setting up nmap (7.01-2ubuntu2) ...
Processing triggers for libc-bin (2.23-0ubuntu3) ...
Listing 8-13.Installing nmap with aptitude in Noninteractive Mode
首先,aptitude
检查软件包数据库以确保系统能够安装软件包;如果有部分配置或挂起的软件包,它会告诉您并中止安装。
接下来,aptitude
通知我们nmap
有几个依赖项也将被安装,并通知我们这些包将使用多少磁盘空间(28.1 MB)。请注意,它告诉我们需要获得 6,311KB 归档文件中的 0 个。因为我们之前已经安装了nmap
,原始的包文件仍然缓存在机器上,否则一旦你输入 y 开始安装,你就会看到 aptitude 下载这些包。
它在内部使用dpkg
命令来处理这一部分。完成后,它处理可能由刚刚添加的包定义的触发器,并重新检查包状态数据库以确保一切成功。
现在我们可以通过从命令行执行以下命令来检查是否安装了nmap
。
$ nmap –v
Starting Nmap 7.01 ( https://nmap.org ) at 2016-05-31 23:37 AEST
The Apt Cache
当您从互联网安装软件包时,它们首先被下载到您的计算机并存储在位于/var/cache/apt/archives
的缓存中。如果您删除一个包,然后重新添加它,它不需要重新下载。有一些实用程序可以让您在多台计算机之间共享这样的缓存,如果您的互联网连接速度很慢或很贵,这很有用。这类实用程序的例子有apt-cacher
、apt-cacher-ng
和apt-proxy
,它们都可以作为软件包获得。
使用 Aptitude 移除包
清单 8-14 展示了如何使用aptitude
移除一个包。同样,像使用dpkg
一样,您可以删除或清除一个包。当然,删除会从主机上删除除配置文件之外的所有内容,而清除会删除整个软件包,包括所有配置文件。
$ sudo aptitude remove nmap
The following packages will be REMOVED:
libblas-common{u} libblas3{u} liblinear3{u} liblua5.2-0{u} libxslt1.1{u} lua-lpeg{u} ndiff{u} nmap python-bs4{u} python-chardet{u} python-html5lib{u} python-lxml{u} python-pkg-resources{u}
python-six{u}
0 packages upgraded, 0 newly installed, 14 to remove and 4 not to upgrade.
Need to get 0 B of archives. After unpacking 28.1 MB will be freed.
Do you want to continue? [Y/n/?] y
(Reading database ... 100407 files and directories currently installed.)
Removing nmap (7.01-2ubuntu2) ...
Removing libblas3 (3.6.0-2ubuntu2) ...
...<snip>...
Processing triggers for man-db (2.7.5-1) ...
Processing triggers for libc-bin (2.23-0ubuntu3) ...
Listing 8-14.Removing Packages with aptitude
如果您还想删除任何配置文件,您可以将purge
选项传递给aptitude
。
$ sudo aptitude purge nmap
Repositories
高级打包工具(APT)和Aptitude
都从在线存储库中获取包。如前所述,存储库是由包维护者为您的特定发行版维护的包的集合。我们要看的两个工具都使用特殊的配置文件,称为 APT 源文件,来定义它们将去哪里找到这些库,以及它们想要什么类型的包可用。
APT 和Aptitude
使用这些源文件来查找数万个包的信息。默认存储库的配置信息通常存储在/etc/apt/sources.list
文件中,该文件是在主机安装过程中创建的。在/etc/apt/sources.list.d/
目录中还可以定义更多的库。
一般来说,不同的发行版有不同的存储库,在这些发行版中,发行版的每个版本都有不同的存储库。对于不同类型的软件,还存在一组存储库。听起来很复杂?当你分解它的时候就不是了。再来看 Ubuntu 16.04 版本(代号 Xenial Xerus)。如果您安装了这个版本,您应该会在/etc/apt/sources.list
文件中看到如下一行:
deb http://archive.ubuntu.com/ubuntu/ xenial main restricted
存储库定义从存储库类型和 URL 开始。URL 可能会被本地化到离您最近的存储库,如“ http://au.archive.ubuntu.com
”。类型指示存储库是包含二进制包还是源代码。存储库类型deb
包含二进制包,存储库类型deb-src
包含包含应用程序源代码的包。你通常不需要使用deb-src
库,除非你正在创建反向端口(见侧栏“Ubuntu 反向端口”)。URL 指向托管存储库的服务器。下一个字段是版本,对于 Ubuntu 16.04 是“xenial”,你可以在 https://en.wikipedia.org/wiki/List_of_Ubuntu_releases
找到 Ubuntu 的其他版本。最后,我们有一个由一个或多个部分组成的列表,这些部分定义了您希望哪些包集可用。
这些软件包按照许可证类型和支持级别分为以下几个部分。Ubuntu 有四个部分。首先是“main
”,它包含了 Ubuntu 的开发者 Canonical 支持的所有自由软件。“restricted
”包由规范但不完全免费的许可证支持,如 Nvidia 驱动程序包。还有其他类型的。Canonical 不直接支持“universe
”包,但是它受到更广泛的 Linux 社区的支持。最后,可能受到专利或法律问题阻碍的软件——如 MP3 播放器或 DVD 播放器软件——可从“multiverse
获得你可以在 https://help.ubuntu.com/community/Repositories/Ubuntu
了解更多。
通过不指定这些部分中的一个或多个,您可以限制在您的主机上安装什么类型的软件包。例如,您可能希望只安装 Canonical 提供的受支持的免费软件包,在这种情况下,您的源代码行可能如下所示:
deb http://archive.ubuntu.com/ubuntu xenial main
作为一个练习,为什么不把你的浏览器指向 http://archive.ubuntu.com/ubuntu
,看看一个存储库是如何布局的呢?
您可以在 https://help.ubuntu.com/community/Repositories/Ubuntu
找到更多关于存储库和分区以及如何设置它们的信息。
使用 Aptitude 更新包
升级的另一个标准任务是,首先更新可用软件包的列表(检查您是否拥有存储库中可用的最新更新软件包记录),然后在您的主机上执行需要升级的软件包的升级。
清单 8-15 展示了如何更新可用包的列表。这里发生的事情是,aptitude
程序使用在/etc/apt/sources.list
文件中找到的库列表(以及包含在/etc/apt/sources.list.d/
中的任何附加库)并为您的主机编译一个可用包列表。
$ sudo aptitude update
Listing 8-15.
aptitude Update
现在当你升级时,你有两个选择:safe-upgrade
和full-upgrade
。safe-upgrade
不会删除已安装的软件包来升级正在升级的软件包,这有时是必需的。有时,为了升级第二个软件包,您可能需要删除第三方软件包。有了safe-upgrade
,这个包就不会升级到新版本。在这种情况下,您必须使用full-upgrade
,它将通过移除和安装完成工作所需的任何包来升级所有已安装的包。
清单 8-16 显示了这些命令的语法。
$ sudo aptitude safe-upgrade
$ sudo aptitude full-upgrade
Listing 8-16.Automatically Install Pending Package Upgrades
Advanced Packaging Tool
在aptitude
之前,APT 工具套件在基于 deb 的发行版上提供了大部分在线包管理功能。这些工具仍然存在,但是它们提供的一些功能在aptitude
中不存在或者不容易使用,所以熟悉它们是值得的。组成 APT 的命令有apt-get
、apt-cache
、apt-file
。apt-get
命令下载、安装和删除软件包和源文件。apt-cache
命令搜索包列表并显示包信息。apt-file
命令搜索包提供文件的文件内容列表。
aptitude
工具是作为apt-get
的替代工具编写的,所以在所有非交互式运行aptitude
的情况下,都可以用apt-get
来替代它。然而,aptitude
有更高级的算法来解决包依赖和冲突,所以我们建议您尽可能使用aptitude
。例如,如果您想安装带有apt-get
的nmap
包,您可以使用以下命令:
$ sudo apt-get install nmap
要使用apt-cache
命令找出关于特定包的信息,可以按如下方式使用:
$ sudo apt-cache showpkg nmap
要使用apt-file
命令找出哪个包提供了系统上尚未安装的特定文件,您可以使用apt-file
来搜索由存储库提供的包内容文件:
$ apt-file search /usr/sbin/foo
这需要您的系统上有最新的内容列表。如果您认为这些内容可能已经过时,您可以通过以下方式更新到最新版本:
$ sudo apt-file update
或者,您可以通过 http://packages.ubuntu.com
在线搜索套餐列表。
使用 Ubuntu 软件应用程序进行软件包管理
如果你已经在 Ubuntu 上安装了 Unity desktop,你还有另外一种管理软件安装的方式。在 Unity desktop 中有一个应用商店 Ubuntu Software,它与我们在 CentOS desktop 中看到的非常相似。
如果您的服务器上没有安装 Unity desktop,您可以跳过此部分。大多数服务器安装在机架中,没有屏幕或键盘,因此安装大型复杂的桌面环境毫无意义。如果你想添加一个完整的 GUI,你应该能够安装unity8-desktop-session-mir
包。
安装完成后,通过sudo service lightdm start
启动显示管理器,并使用您的用户名和密码登录。
访问 Ubuntu 软件商店非常容易,你可以通过图 8-25 所示的图标访问它。
图 8-25。
Starting the Ubuntu Software app store
打开后如图 8-26 所示。
图 8-26。
The Ubuntu Software app store
这个界面非常容易导航。在顶部,我们看到了与 CentOS、All、Installed 和 Updates 相同的视图。我们已经看到有四个更新等待安装。下面是搜索栏,底部是热门应用和推荐应用的快速链接。
让我们搜索一个叫做“终结者”的程序,这是一个很棒的小高级终端。在搜索栏中输入,会返回一个可能匹配的列表。由于这是唯一的“终结符”,我们返回了一个包(见图 8-27 )。
图 8-27。
Finding the terminal package
我们可以点击安装按钮开始安装,或者点击列表上的任意位置获取更多信息(参见图 8-28 )。
图 8-28。
More information for terminal
现在我们要安装这个包(见图 8-29 )。
图 8-29。
Entering our password to get root privileges to install packages
我们被要求输入密码,然后才能安装软件。
一旦安装完毕(见图 8-30 ),我们可以从这里启动应用程序,也可以将其移除(见图 8-31 )。
图 8-31。
Our installation is finished
图 8-30。
Installing the package
现在让我们移除包(参见图 8-32 )。就像点击删除按钮一样简单。
图 8-32。
Are we sure we want to remove?
一旦我们确认要移除软件包,可能会要求您再次确认您的密码,然后我们开始移除应用程序(参见图 8-33 )。
图 8-33。
Removing the terminator application
如果我们单击 Installed 视图,我们将获得所有已安装软件包的列表(参见图 8-34 )。
图 8-34。
Listing our installed packages
在已安装的页面中,我们可以单击任何列出的软件包,并获得更多相关信息,如果您愿意,也可以删除某个软件包。
转到更新页面,我们看到以下内容(参见图 8-35 ):
图 8-35。
Updates view
我们再次看到,我们可以刷新列表,确保我们有最新的列表,方法是单击左上角的 reload 图标。我们可以通过单击安装按钮来安装个别更新,也可以通过右上角的安装按钮来安装所有更新。
如果我们想看看将安装什么,我们可以点击更新。
在图 8-36 中,我们看到了将随操作系统更新一起安装的软件包列表。
图 8-36。
Listing the packages in the OS Updates update
现在我们将安装所有更新(见图 8-37 )。
图 8-37。
Installing updates
最后,当所有更新都已安装后,您应该会看到以下屏幕(图 8-38 ):
图 8-38。
All up to date
这就是使用桌面应用安装程序的全部内容,现在让我们来看看 Ubuntu 上最基本的打包工具。
使用dpkg
Ubuntu 上最基本的包管理工具是dpkg
(读作“dee-package”)。apt
和aptitude
工具都是dpkg
的包装器,就像yum
是rpm
命令的包装器一样。
Tip
我们建议您使用aptitude
而不是dpkg
来管理您的软件包。命令aptitude
处理依赖关系并管理包之间的关系;dpkg
命令不会。
dpkg
命令允许你列出已经安装的软件包,安装你之前下载的软件包文件,并找出系统上的软件包文件属于哪个。通过发出 man dpkg
命令,您可以找到对dpkg
可用的所有选项(有很多),如清单 8-17 所示。
$ man dpkg
Listing 8-17.The dpkg man page
表 8-4 列出了dpkg
命令的一些主要选项和标志。
表 8-4。
Options and Flags for dpkg
首先,我们将获得已经安装在我们新的 Ubuntu 系统上的软件包列表,如清单 8-18 所示。
$ dpkg -l
Listing 8-18.Listing Installed Packages
这将生成我们主机上所有包的完整列表。这通常是一个很长的列表,但是我们可以将来自dpkg
的输出通过管道传输到 more 命令,并逐页显示输出(参见清单 8-19 )。然后我们可以在闲暇时浏览它。
$ dpkg -l | more
Listing 8-19.Piping the dpkg -l Output to More
注意在图 8-39 中dpkg
列出了四列输出:状态、名称、版本和描述。我们通过head
命令传输这个输出,默认情况下,它只给出前十行输出。
图 8-39。
Viewing results of dpkg -l
Note
虽然从清单 8-20 的输出中没有自动清除,但前三行实际上是状态栏。
让我们看一下这些列。“状态”列实际上由包可能处于的三种状态组成。
- 期望的状态
- 当前状态
- 错误
通常情况下,状态会是ii
,这意味着软件包当前已经安装,如果有更新的版本,将会升级。表 8-5 列出了最常见的状态代码及其含义。
表 8-5。
The dpkg
Status Codes
其他专栏不言自明。它们包含软件包名称、版本(如果当前安装了软件包)和简短描述。
您通常不希望列出所有内容,所以让我们通过传递一个字符串让dpkg
来匹配,从而将输出限制在提供 Linux 内核的包中。Ubuntu 中的 Linux 内核被命名为linux-image
,这与 RHEL 不同,在那里它只是被称为内核。l 通过在我们的目标字符串前后使用*符号,使用一个 glob 字符串列出安装在我们主机上的所有linux-image
(意味着我们捕获所有包含字符串linux-image
的结果)。
Tip
Glob strings 是处理字符串的非常有用的方法,尤其是像文件名这样的字符串。你可以在 www.faqs.org/docs/abs/HTML/globbingref.html
阅读关于使用 glob strings 的内容。
在这种情况下,我们使用的是*linux-image*
(您应该阅读一些关于 globbing 的知识,并测试当您使用linux-image
*和linux-image
作为搜索字符串时返回的结果)。
在图 8-40 中,你可以看到有几个linux-image
包,它们的名字都基于它们包含的内核版本。这就是为什么不同的内核包没有相同的名字,从而允许你安装多个内核。此外,您会发现linux-image
包,这是一个所谓的虚拟包。这个包实际上不包含任何文件,但是它包含一个到最新可用内核的链接,所以正常的升级总是包含任何可用的新 Linux 内核包。
图 8-40。
Listing the Linux Kernel Tip
因为缺省的 Linux 终端只有 80 个字符宽,而dpkg
想要在一行中显示每个包的信息,所以如果包名超过 14 个字符,它就不能显示完整的包名。对于许多包来说,这不是问题,但是内核包有很长的名字,所以不能完全显示。要解决这个问题,您可以使用环境变量覆盖dpkg
的终端大小,这样它将显示更多信息。要做到这一点,给命令加上前缀如下:$ COLUMNS=200 dpkg -l
’ *linux-image*
'。这告诉你的主机你的屏幕有 200 个字符宽,所以它显示了更多的列。
检查包详细信息
我们先来看看 Ubuntu 上的一个常用包 adduser 用dpkg
的一些信息。清单 8-20 显示了dpkg –p
命令查询我们的adduser
包的信息的输出。
$ dpkg -p adduser
Package: adduser
Priority: required
Section: admin
Installed-Size: 648
Origin: Ubuntu
Maintainer: Ubuntu Core Developers <ubuntu-devel-discuss@lists.ubuntu.com>
Bugs: https://bugs.launchpad.net/ubuntu/+filebug
Architecture: all
Multi-Arch: foreign
Version: adduser-3.113+nmu3ubuntu4
Replaces: manpages-it (<< 0.3.4-2), manpages-pl (<= 20051117-1)
Depends: perl-base (>= 5.6.0), passwd (>= 1:4.1.5.1-1.1ubuntu6), debconf | debconf-2.0
Suggests: liblocale-gettext-perl, perl-modules, ecryptfs-utils (>= 67-1)
Filename: pool/main/a/adduser/adduser_3.113+nmu3ubuntu4_all.deb
Size: 161698
MD5sum: 36f79d952ced9bde3359b63cf9cf44fb
Description: add and remove users and groups
Original-Maintainer: Debian Adduser Developers <adduser-devel@lists.alioth.debian.org>
SHA1: 6a5b8f58e33d5c9a25f79c6da80a64bf104e6268
SHA256: ca6c86cb229082cc22874ed320eac8d128cc91f086fe5687946e7d05758516a3
Homepage: http://alioth.debian.org/projects/adduser/
Description-md5: 7965b5cd83972a254552a570bcd32c93
Supported: 5y
Task: minimal
Listing 8-20.Output of the dpkg -p Command
adduser 包包含用于系统用户管理的命令。您可以在清单 8-20 中看到,除了描述和版本之外,每个包还包含一个支持联系人的电子邮件以及安装时使用的磁盘空间信息。Depends 部分还详细说明了在安装软件包本身之前需要安装的软件包,这称为依赖性。
检查包裹内容
除了关于软件包的描述信息之外,您还可以查询它安装了哪些文件以及将它们安装到了哪些目录。您可以使用dpkg -L
命令找出包内容,如下所示:
$ dpkg –L adduser
这将返回由adduser
包安装的文件的完整列表。
Tip
找出软件包提供了哪些命令的一个简单方法是列出它安装到包含可执行应用程序的目录中的文件。让dpkg
列出包的内容,并通过管道将输出传递给grep
,以将输出限制在包含字符串 bin 的文件和目录中,例如:dpkg -L
| grep bin
。
执行文件搜索
对于主机上已经存在的文件,您可以使用dpkg
来确定它们属于哪个包:
$ dpkg -S /usr/sbin/userdel
这个命令告诉你哪个包提供了userdel
命令。
安装软件包
所有的 Ubuntu 包文件都由三部分组成:包名、包版本和目标架构。例如,用于 32 位 Intel 机器的 foobar 包的 2.17 版应该是“foobar-2.17_i386.deb”。如果你能在任何架构上安装这个包,它将是“foobar-2.17_all.deb”
Note
目标体系结构是您的主机的处理器技术(例如,i386 或 x64)。
在您获得了适用于您的 Ubuntu 版本和架构的包文件之后,您可以使用dpkg
来安装它。因为软件包包含需要安装到特权系统位置的文件(比如/bin, /usr/sbin
等)。),安装需要以root
用户的身份进行。在 Ubuntu 上,你可以使用第五章讨论的sudo
命令,以root
用户的身份执行安装命令:
$ sudo dpkg -i wget_1.17.1-1ubuntu1_amd64.deb
在安装过程中,dpkg
命令会让您了解进度。根据软件包的不同,它可能还会询问您一些关于如何配置软件包的问题。不要担心,你可以在以后更改这些问题的答案。
安装手动下载的软件包时要小心。如果该软件包不是为您的 Ubuntu 版本创建的,它所依赖的其他软件包可能在正确的版本中不可用。无论如何安装都可能会导致“无法解析的依赖关系”,这可能会使您的软件包系统处于不一致的状态,在这种状态下,软件包被部分安装,并阻止进一步的软件包管理,直到问题得到解决。会警告你,不强迫你就不让你这么做。一个最佳实践是,在从第三方来源下载软件包之前,总是检查该软件包在发行版中是否可用。
移除包
你有两种不同的方法来移除一个 Ubuntu 包:一种是移除这个包,另一种是从系统中清除这个包。当您使用--remove
选项时,您将从主机上删除除该包的已修改配置文件之外的所有内容。当您使用--purge
选项时,您是在告诉dpkg
删除该软件包安装到您主机上的所有东西,包括您自己修改的配置文件。
为什么有这两种方法?因为有时您希望完全删除所有内容,有时您希望删除某些内容,以便在以后的某个阶段重新安装。
清单 8-21 展示了用dpkg
命令从主机删除包的两种方法。
$ sudo dpkg --remove wget
Listing 8-21.Package Removal
或者
$ sudo dpkg --purge wget
从源代码编译
尽管打包软件的列表很广泛,但并不是所有东西都可以作为方便的 deb 或RPM
包获得。如果一个软件没有打包格式,甚至没有用于反向移植的源代码包(见侧栏“Ubuntu 反向移植”),你可能需要从源代码构建它。
Ubuntu Backports
有时,如果您需要的特定包版本不可用,您可能会被告知创建一个 backport。如果您使用的是发行版的旧版本,或者您的发行版中还没有打包应用程序的新版本,就可能会出现这种情况。创建一个 backport 需要从一个较新(或较旧)的 Ubuntu 版本中获取源码包,并在你自己的机器上编译它。反向端口超出了本书的范围,但是网上有一些很好的参考资料,你可以从中学习如何使用和创建它们。一个好的起点是 https://help.ubuntu.com/community/UbuntuBackports
。
在这一节中,我们将向您展示如何从源代码编译软件,并给出一些关于如何保持这种源代码安装可管理性的提示。
从源代码构建应用程序通常有三个阶段:
- 配置应用程序。
- 编译或制作应用程序。
- 安装应用程序。
我们将带您经历这三个阶段,并以nginx
web 服务器为例。这一次,我们将在撰写本文时构建最新的源代码(版本 1.10.1),而不是从包中安装我们的应用程序。首先,让我们使用wget
工具从 http://nginx.org/
中抓取 tarball。
$ wget –c http://nginx.org/download/nginx-1.10.1.tar.gz
Note
tarball 是包含一组文件和/或目录的文件(通常是压缩的)。用来创建这些 tarballs 的应用程序被称为tar
(磁带存档),这样命名是因为它最初被用来将存档写入磁带。Tarballs 的文件扩展名通常表示归档文件是如何压缩的。例子包括tar.gz
或者。tgz
为gzip
和tar.bz2
或。tbz
为bzip2
压缩。你可以在它的man
页面上看到更多关于 tar 的信息。
c 标志告诉wget
恢复部分下载。这意味着如果下载由于某种原因被中断,它不会重新开始下载。使用-c 选项,如果下载失败,您可以重新运行该命令,下载将从它停止的地方恢复。
wget
命令将文件下载到当前目录,所以我们现在有了一个可以解压的 tarball。扩展告诉我们它是用gzip
压缩的,所以我们需要-z
标志让tar
使用gzip
解压缩。我们传递–x 来告诉 tar 提取归档文件。–f 用于提供要处理的文件。
$ tar -xvzf nginx-1.10.1.tar.gz
Tip
如果您不知道 tarball 使用什么压缩方式,您可以使用file
命令来查找。运行file <tarball>
和file
将检查 tarball 的魔术字节,这表明了文件类型。数千种文件类型的神奇字节列表存储在/usr/share/file/magic
中。一旦你知道 tarball 是如何被压缩的,你就可以打开它了。
-v
参数告诉tar
要详细并打印它从存档中提取的每个文件的路径。如果您知道归档中包含哪些文件,您可能希望删除此参数,这样您的终端就不会滚动显示冗余信息。额外的好处是,不打印文件名意味着提取操作完成得更快。
tarball 现在已经被提取出来了,所以我们应该转到源文件目录并查看一下,看看那里有哪些文件。
$ cd nginx-1.10.1
∼/ nginx-1.10.1$ ls
在许多情况下,编译和安装应用程序的说明将包含在一个名为 README 或 INSTALL 的文件中。对于nginx
,似乎没有安装文件,但有一个自述文件。通过阅读这个文件,我们应该能够找到安装应用程序的说明。
$ less README
我们从这个文件中了解到,安装文档是在线的,不包含在 tarball 中。详细信息可参考 http://nginx.org/
的nginx
具体在线文档。我们将在这里使用这些指令( http://nginx.org/en/docs/configure.html
)来编译和安装应用程序。
但是在编译我们的应用程序之前,我们需要安装一个编译器及其相关的库和实用程序。这些通常是打包的,所以我们将简单地通过包系统安装它们。表 8-6 显示了 Red Hat 和 Ubuntu 所需的包。
表 8-6。
Installing a Compiler and Essential Build Tools
| 分配 | 命令 | | --- | --- | | CentOS | `yum install gcc make` | | 人的本质 | `aptitude install build-essential` |安装ˌ使成形
安装了编译器之后,我们现在可以配置编译的源代码了。大多数软件都是高度可配置的,不仅在可用特性方面,而且在安装位置方面。为了在构建应用程序之前配置它,我们使用了configure
命令。在清单 8-22 中,我们运行带有--help
选项的配置命令来显示所有可用于配置我们的应用程序的选项。
∼/nginx-1.10.1$ ./configure --help
--help print this message
--prefix=PATH set installation prefix
--sbin-path=PATH set nginx binary pathname
--modules-path=PATH set modules path
--conf-path=PATH set nginx.conf pathname
--error-log-path=PATH set error log pathname
--pid-path=PATH set nginx.pid pathname
--lock-path=PATH set nginx.lock pathname
--user=USER set non-privileged user for
worker processes
--group=GROUP set non-privileged group for
worker processes
Listing 8-22.Shortened List of Configuration Help
Note
注意,在清单 7-28 中,我们在configure
命令前面指定了./
。这告诉 Linux 运行它在当前目录中找到的configure
脚本。
输出还在继续,但是我们将在最重要的选项--prefix
处停止。这个选项决定了软件的安装位置,重要的是这个位置不能被打包的软件使用。否则,您可能会遇到从源文件安装的文件覆盖打包文件的情况。这将使包系统混乱,当您删除有问题的包时,您编译的文件也将被删除。
通常,当您从源代码安装应用程序时,它们被部署在/usr/
本地目录结构中。这通常是--prefix
的默认选项。我们将把nginx
安装在另一个安装你自己软件包的公共目录下,/opt
。
其他需要注意的选项是那些决定软件中可用特性的选项。它们决定了在配置期间是否应该检查第三方库,如果存在,是否应该使用第三方库。这些选项通常以--with
-和--without
-为前缀。我们将编译最基本的默认nginx
服务器。有关可用选项的更多信息,请参考上面的文档链接。
有了这些新的知识,我们现在可以用默认选项配置我们的nginx
源,如清单 8-23 所示。
∼/nginx-1.10.1$ ./configure --prefix=/opt/nginx
checking for OS
+ Linux 4.4.0-22-generic x86_64
checking for C compiler ... found
+ using GNU C compiler
+ gcc version: 5.3.1 20160413 (Ubuntu 5.3.1-14ubuntu2.1)
checking for gcc -pipe switch ... found
checking for -Wl,-E switch ... found
checking for gcc builtin atomic operations ... found
checking for C99 variadic macros ... found
checking for gcc variadic macros ... found
...<snip>...
checking for sha1 in system md library ... not found
checking for sha1 in system OpenSSL crypto library ... not found
checking for zlib library ... not found
./configure: error: the HTTP gzip module requires the zlib library.
You can either disable the module by using --without-http_gzip_module
option, or install the zlib library into the system, or build the zlib library
statically from the source with nginx by using --with-zlib=<path> option.
Listing 8-23.Configuring Our Source Tree
脚本检查我们的系统是否存在编译器、所需的头文件以及这些头文件中的函数和数据结构的定义。我们在本章开始时讨论了头文件和库,并提到通常只有在从源代码编译软件时才需要它们。在清单 7-29 中,注意脚本无法找到 zlib 头。我们可以选择给出 zlib 文件的安装路径(--with-zlib=<path>
),或者在没有 zlib 的情况下编译(--without-http_gzip_module
)。对于我们的 Ubuntu 主机,我们将安装 zlib1g-dev 和 libpcre3-dev,它们提供了必要的压缩和 perl 头文件。根据您在构建时包含的选项,您可能需要其他包。
$ sudo aptitude install -y zlib1g-dev libpcre3-dev
如果您指定--without-<option>
,该选项将被禁用。我们现在再次运行编译命令。
∼/nginx-1.10.1$ ./configure --prefix=/opt/nginx
checking for OS
+ Linux 4.4.0-22-generic x86_64
checking for C compiler ... found
+ using GNU C compiler
+ gcc version: 5.3.1 20160413 (Ubuntu 5.3.1-14ubuntu2.1)
checking for gcc -pipe switch ... found
checking for -Wl,-E switch ... found
checking for gcc builtin atomic operations ... found
checking for C99 variadic macros ... found
checking for gcc variadic macros ... found
...<snip>...
creating objs/Makefile
Configuration summary
+ using system PCRE library
+ OpenSSL library is not used
+ using builtin md5 code
+ sha1 library is not found
+ using system zlib library
nginx path prefix: "/opt/nginx"
nginx binary file: "/opt/nginx/sbin/nginx"
nginx modules path: "/opt/nginx/modules"
...<snip>...
nginx http proxy temporary files: "proxy_temp"
nginx http fastcgi temporary files: "fastcgi_temp"
nginx http uwsgi temporary files: "uwsgi_temp"
nginx http scgi temporary files: "scgi_temp
输出显示了 nginx 的成功配置,并提供了一个摘要。
编译和制作
完成后,configure
命令会写入一个配置头文件和一个名为Makefile
的特殊文件。前者包含向编译器指示可用函数和库的代码,后者包含通过make
命令构建软件所需的命令。make
命令读取Makefile
并执行其中包含的命令和有序步骤(参见 http://www.tutorialspoint.com/makefile/why_makefile.htm
了解更多关于 make 的信息)。我们发出make
命令开始构建清单 8-24 中的nginx
。
∼/nginx-1.10.1$ make
make -f objs/Makefile
make[1]: Entering directory '/home/jsmith/nginx-1.10.1'
cc -c -pipe -O -W -Wall -Wpointer-arith -Wno-unused-parameter -Werror -g -I src/core -I src/event \
-I src/event/modules -I src/os/unix -I objs \
-o objs/src/core/nginx.o \
src/core/nginx.c
cc -c -pipe -O -W -Wall -Wpointer-arith -Wno-unused-parameter -Werror -g -I src/core -I src/event \
-I src/event/modules -I src/os/unix -I objs \
-o objs/src/core/ngx_log.o \
src/core/ngx_log.c
sed -e "s|%%PREFIX%%|/opt/nginx|" \
-e "s|%%PID_PATH%%|/opt/nginx/logs/nginx.pid|" \
-e "s|%%CONF_PATH%%|/opt/nginx/conf/nginx.conf|" \
-e "s|%%ERROR_LOG_PATH%%|/opt/nginx/logs/error.log|" \
< man/nginx.8 > objs/nginx.8
make[1]: Leaving directory '/home/jsmith/nginx-1.10.1'
Listing 8-24.Compiling nginx
如果make
过程成功完成,应用程序就构建好了。如果失败,您通常会收到一条错误消息,指出原因,并希望得到一些关于如何修复它的指导。构建应用程序失败的原因有很多——太多了,无法在此详述——但一般来说,您可能会遇到别人以前发现过的问题。您遇到的问题可能在应用程序的网站上有详细说明,例如,在安装文档或常见问题部分。通过谷歌搜索特定的错误信息也可能指出可能的解决方案。此外,联系支持列表,通常会有人非常乐意提供帮助。
安装
现在我们的nginx
应用程序已经编译好了,我们需要让它对系统上的所有用户都可用,方法是将它安装到我们之前配置时选择的前缀位置。Makefile 也包含这样的命令,您可以在清单 8-25 中看到安装过程。
∼/nginx-1.10.1$ sudo make install
[sudo] password for jsmith:
make -f objs/Makefile install
make[1]: Entering directory '/home/jsmith/nginx-1.10.1'
test -d '/opt/nginx' || mkdir -p '/opt/nginx'
test -d '/opt/nginx/sbin' \
|| mkdir -p '/opt/nginx/sbin'
test ! -f '/opt/nginx/sbin/nginx' \
|| mv '/opt/nginx/sbin/nginx' \
'/opt/nginx/sbin/nginx.old'
<snip>
test -d '/opt/nginx/logs' \
|| mkdir -p '/opt/nginx/logs'
make[1]: Leaving directory '/home/jsmith/nginx-1.10.1'
Listing 8-25.Installing nginx
我们需要使用sudo
,因为作为普通用户,我们不允许在/opt/nginx
下创建新文件。同样,make
处理Makefile
中的规则,并执行命令在系统上安装nginx
及其相关文件。我们现在可以运行新安装的应用程序来确保一切正常,如清单 8-26 所示。
∼/nginx-1.10.1$ sudo /opt/nginx/sbin/nginx -v
nginx version: nginx/1.10.1
Listing 8-26.Running nginx
从计算机上卸载
当您想从系统中删除它们时,管理源代码安装的棘手部分就来了。一些(但不是全部)包含卸载规则。对于nginx
,没有一个,但是我们将调用下面的:
∼/<some-package-source>$ sudo make uninstall
这意味着我们需要在我们的系统中保存配置好的资源。这并不理想,因为我们不仅需要跟踪我们从源代码安装了哪些软件,还需要跟踪我们将这些源代码保存在哪里。这也是我们建议您避免从源代码安装应用程序,而是依靠软件包来提供应用程序的原因之一。因为我们在/opt/nginx
中安装了我们的应用程序,这意味着我们可以通过发出rm -rf /opt/nginx
有效地“卸载”,这将删除整个nginx
目录。
使用 FPM 创建包
FPM 是一个应用程序,它从各种不同的源类型构建 deb 或 rpm 包(以及其他包类型),包括 deb 源包和 RPM 源包。我们将构建一个 nginx 安装包作为 deb,但是这个过程对于 RPM 包也是一样的。
从安装 FPM 开始,它就像一个 Ruby 宝石,一个封装和分发软件的另一种方式的宝石,特别是对于 Ruby 应用程序。
首先,在 Ubuntu 上,我们将发布以下内容:
$ sudo aptitude install –y install ruby ruby-dev
如果您正在运行 CentOS:
$ sudo yum install -y ruby ruby-devel
下面的步骤对于 CentOS 和 Ubuntu 是一样的。我们将在我们的 Ubuntu 主机上构建并执行它(但是如果你已经安装了所需的包,你可以在任一发行版上构建 rpm 和 deb)。然后 FPM 通过宝石命令:
$ sudo gem install fpm
我们现在创建一个临时安装目录来保存我们的 nginx 安装。
$ sudo mkdir /tmp/installdir
然后我们转到 nginx 源目录,在那里我们编译了 nginx 源,如清单 8-25 所示,现在发出下面的命令将 nginx 安装到我们的临时安装目录中。
$ sudo make install DESTDIR=/tmp/installdir
如果你查看/tmp/installdir
目录,你会看到我们已经在那个目录中安装了 nginx。我们现在指示 FPM 进入那个目录,为我们创建一个 deb 包。我们让 FPM 施展它的魔法,发布了以下内容:
$ sudo fpm -s dir -t deb -n nginx -v 1-10.1 -C /tmp/installdir/
这里我们为 dir 的源类型指定了–s,这意味着目录。目标(-t)是一个 debian 包。如果我们正在构建一个 RPM 包,这将是-t rpm
。我们将其命名为(-n
) nginx
,并给出版本(-v
)或1-10.1
。最后,我们告诉 FPM 转到(-C /tmp/installdir
)并将目录中的内容打包。
这将在本地目录中创建一个nginx_1-10.1_amd64.deb
包。您现在可以用dpkg
命令安装它。
$ sudo dpkg -i nginx_1-10.1_amd64.deb
Selecting previously unselected package nginx.
(Reading database ... 213564 files and directories currently installed.)
Preparing to unpack nginx_1-10.1_amd64.deb ...
Unpacking nginx (1-10.1) ...
Setting up nginx (1-10.1) ...
我们可以通过发出以下命令来测试它是否工作:
$ /opt/nginx/sbin/nginx -v
nginx version: nginx/1.10.1
这就是我们,一个由我们编译的源代码制作的 debian 包。你可以在这里看到更多关于 FPM 的信息:
https://github.com/jordansissel/fpm
www.digitalocean.com/community/tutorials/how-to-use-fpm-to-easily-create-packages-in-multiple-formats
摘要
在这一章中,我们已经看到了很多。现在,您应该能够在您的 Linux 服务器上安装、删除、更新和维护这些包了。我们展示了以下内容:
- CentOS 应用程序安装程序
- 百胜包管理和 DNF
- RPM 包管理
- Ubuntu 软件应用程序
- 智能包管理
- Dpkg 包管理
- 从源代码编译
- 创建一个 debian 或 RPM 包
在下一章中,我们将看看如何设置您的存储以获得最大的可靠性,您将学习如何避免硬盘问题并从中恢复。
九、存储管理和灾难恢复
当您安装第一台 Linux 主机时,您接受了设置磁盘和分区的所有默认设置。现在,您已经掌握了一些基本的系统管理知识,让我们重新回顾一下存储配置,看看如何更改它以满足您的需求。我们将了解各种类型的存储硬件,以及如何利用存储管理软件为您带来优势。任何业务的关键部分都是数据,因此您需要确保数据既安全又可访问,并保持这种状态。
在本章中,我们将解释如何创建和管理磁盘分区和 RAID,如何使应用程序可以访问您的存储,以及如何从崩溃中恢复。
Note
在第十四章中,我们将介绍如何备份和恢复您的数据。
存储基础知识
我们将从 Linux 如何处理存储开始。为此,我们将添加各种新磁盘,对这些磁盘进行分区,然后格式化和管理这些存储。
格式化后,Windows 下的驱动器显示为驱动器号,但 Linux 的工作方式不同。它没有驱动器号的概念,格式也不完全相同。相反,驱动器和存储显示为可以分区的设备。这些分区又可以被格式化或聚集到逻辑卷中,然后被格式化。
让我们从设备开始,设备是 Linux 存储的基本构建块。然后,我们将继续讨论分区和文件系统。
设备
我们在第四章中简单提到了设备文件。这些文件是 Linux 使硬盘驱动器、USB 和 DVD 驱动器等硬件设备可以从操作系统内部访问的方式。主机中的大多数(但不是全部)设备由/dev
目录中的文件表示。
/dev
目录是一个特殊的目录,由名为udev
的服务填充。当主机启动时,内核检测到一个设备,它告诉udev
,然后在/dev
目录中创建该设备的一个表示。这些设备文件是内核为应用程序和服务提供访问设备的方式。
设备文件有很多种,但是在这一章中,我们将只讨论那些处理存储的文件,它们都属于块设备的范畴。此类别包括硬盘、USB 驱动器、磁带驱动器以及 CD 和 DVD 驱动器。所有类型的硬盘(例如 ATA、串行 ATA、SCSI、SAS 和 SSD)都由名称以sd
开头的设备文件表示,它代表 SCSI 磁盘,因为所有这些不同类型的驱动器都像 SCSI 驱动器一样被访问。
Note
SCSI 是代表小型计算机系统接口的首字母缩略词,它是计算机如何连接和访问存储设备的规范。您可以在 http://en.wikipedia.org/wiki/SCSI
.
了解更多关于此规范的信息
您可以通过使用ls
命令列出主机上可用的磁盘设备,如清单 9-1 所示。
$ $ ll /dev/sda*
brw-rw---- 1 root disk 8, 0 Jun 7 22:45 /dev/sda
brw-rw---- 1 root disk 8, 1 Jun 7 22:45 /dev/sda1
brw-rw---- 1 root disk 8, 2 Jun 7 22:45 /dev/sda2
brw-rw---- 1 root disk 8, 5 Jun 7 22:45 /dev/sda5
Listing 9-1.Listing Device Nodes
清单 9-1 显示了四个块设备,或设备节点。它们对root
用户和disk
组是可读和可写的。接下来,通常显示文件大小的地方是由逗号分隔的两个数字。这些是设备主要编号和次要编号。主号告诉内核使用哪个设备驱动程序来访问设备,次号给出内核关于设备的特定信息,在本例中是分区号。最后,显示上次修改设备文件的日期和时间。
实际的设备文件名由前缀sd
和一个表示它属于哪个磁盘的字母组成。第一个检测到的磁盘是sda
,第二个是sdb
,第三个是sdc
,依此类推。最后,磁盘上的每个分区也有自己的设备节点,分区号是名称的最后一部分。这意味着sda1
是磁盘sda
上的第一个分区,sdb2
是磁盘sdb
上的第二个分区,依此类推。我们将很快讨论分区。
您可能会看到的其他设备有:
| 设备名称 | 你会在哪里找到它 | | --- | --- | | 巨人十六号 | Xen 虚拟机 | | /dev/vda | KVM 虚拟机 | | /dev/hda | KVM 虚拟机,较旧的 ATA 主机 | | /dev/md | Linux 软件 raid | | /dev/sda | 配备 SAS、SSD 等设备的物理服务器。 |Note
旧系统不能支持很多驱动器,因为设备次编号范围从 1 到 255,每个磁盘只能有 16 个编号,所以 Linux 可以容纳 16 个硬盘,每个硬盘有 16 个分区,在耗尽设备节点之前从/dev/sda1
到/dev/sdp16
。现在你的系统理论上可以支持 10000 个驱动器( https://access.redhat.com/articles/rhel-limits
)。这是关于 Linux 内核中块和字符设备的权威文档: www.kernel.org/doc/Documentation/devices.txt
。
如果您有硬件 RAID 控制器,它可能会以不同的方式命名您的阵列和任何分区。RAID 控制器将多个磁盘组合成廉价磁盘冗余阵列(RAID)。我们将在本章的后面详细讨论 RAID。要找出 RAID 阵列的设备节点,您可以使用以下命令列出/dev/
目录中的所有块设备:
$ ls -l /dev | grep ^b
该命令将只列出以b
开头的行。然而,检查内核内部日志缓冲区的内容会更准确。每当内核事件发生时,它都会被添加到内核内部日志缓冲区中。然后,日志守护程序将这个缓冲区写入日志文件,您可以使用dmesg
命令直接查询它。
$ dmesg |less
大多数 RAID 控制器也至少使用部分内核 SCSI 子系统,您可以通过less
中的内置搜索功能来搜索检测到的 SCSI 设备。在less
窗口中输入/scsi
并按回车键搜索包含字符串scsi
的任何行。你可以按 n 键跳到下一场比赛。
划分
将磁盘添加到主机后,需要执行一些步骤来使其可用。首先,您可以在该磁盘上创建一个或多个分区。如果创建一个分区,系统需要能够找到关于分区几何的信息。它将这些信息存储在磁盘的开始处(有时会在磁盘的其他地方存储一份副本——稍后会详细介绍)。
我们之前已经描述过分区是将一块蛋糕分割成更小的块,这就是我们可以对物理磁盘做的事情。我们把磁盘分成小块。例如,这样您可以将日志和用户数据与操作系统分开,这样日志或用户就不会填满您的系统磁盘并导致问题。
在第六章中,我们向您介绍了两种不同的分区管理器,主引导记录(MBR)和 GPT (GUID 分区表)。您可能还记得,存储在磁盘前 446 个字节中的 MBR 描述了分区信息,它存储在引导记录之后的 64 个字节中。你不能在 64 字节中存储大量数据,所以一个磁盘可以容纳的分区数量最初是相当有限的。另一方面,GPT 最多可以容纳 128 个分区。
Disks and Partitions
我们之前已经解释了 MBR 和 GPT 分区之间的区别。如果您记得 MBR 保存在磁盘的前 512 个字节中,并且只能保存小于 2 Tb 的磁盘大小的足够信息。GPT 没有这种限制,可以在任何大小的磁盘上使用。这导致了分割磁盘方式的不同。
使用 MBR,分区有三种风格:物理的、扩展的和逻辑的。这是因为只有有限数量的分区信息可以存储在可供此类数据使用的 64 个字节中。一个分区需要 16 个字节的数据来描述,所以有了四个分区的信息,就满了!
作为一种变通方法,人们发明了扩展分区的概念。四个可用的物理分区中的一个被标记为扩展分区,然后作为无限数量的逻辑分区的容器。
这 16 个字节描述了每个分区,包括关于分区类型的信息,在磁盘上的什么地方可以找到它,以及它是否是可引导的,尽管 Linux 不关心后者。
您将使用 fdisk 实用程序来管理 MBR 磁盘。
对于 GPT,我们之前说过我们可以对高达 2ZiB 的磁盘进行分区。GPT 的默认限制是 128 个分区。GPT 使用 64 位逻辑块地址。它增加了校验和的可靠性。分区被赋予 UUIDs 和名称以避免冲突。
您可以使用parted
或gdisk
工具来管理 GPT。
您可以在 https://wiki.manjaro.org/index.php?title=Some_basics_of_MBR_v/s_GPT_and_BIOS_v/s_UEFI
找到关于这些分区管理器的更多详细信息。
您可以使用fdisk
实用程序创建和删除分区,或者如果您使用的是 GPT,gdisk
或parted
实用程序。让我们通过列出 Ubuntu 主机上第一个磁盘上的分区来看看已经有哪些分区(参见清单 9-2 )。因为只允许 root 用户读写原始磁盘设备,所以需要使用sudo
。
- 引导分区的物理分区
- 容纳其他分区的扩展分区
- 与 LVM 一起使用的分区
$ sudo fdisk -l /dev/sda
Disk /dev/sda: 8 GiB, 8589934592 bytes, 16777216 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x105922fd
Device Boot Start End Sectors Size Id Type
/dev/sda1 * 2048 999423 997376 487M 83 Linux
/dev/sda2 1001470 16775167 15773698 7.5G 5 Extended
/dev/sda5 1001472 16775167 15773696 7.5G 83 Linux
As you can see in the output of Listing 9-2), the installer created three partitions:
Listing 9-2.Listing Partitions with fdisk
你不想修改你的系统盘,但是假设你买了一个新硬盘,需要分区,你就可以开始用它存储数据了。首先,您需要检查磁盘是否被操作系统检测到,以及它的设备名称是什么。内核在启动时会打印它检测到的所有设备的信息,一旦登录,您就可以通过dmesg
命令访问这些信息。
$ dmesg | grep sd
[ 1.838874] sd 2:0:0:0: [sda] 16777216 512-byte logical blocks: (8.59 GB/8.00 GiB)
[ 1.839510] sd 2:0:0:0: [sda] Write Protect is off
[ 1.839824] sd 2:0:0:0: [sda] Mode Sense: 00 3a 00 00
[ 1.839834] sd 2:0:0:0: Attached scsi generic sg1 type 0
[ 1.840183] sd 2:0:0:0: [sda] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[ 1.842304] sda: sda1 sda2 < sda5 >
[ 1.842784] sd 2:0:0:0: [sda] Attached SCSI disk
[ 2.178862] sd 3:0:0:0: [sdb] 16777216 512-byte logical blocks: (8.59 GB/8.00 GiB)
[ 2.179508] sd 3:0:0:0: [sdb] Write Protect is off
[ 2.179863] sd 3:0:0:0: [sdb] Mode Sense: 00 3a 00 00
[ 2.179874] sd 3:0:0:0: Attached scsi generic sg2 type 0
[ 2.180268] sd 3:0:0:0: [sdb] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[ 2.181498] sd 3:0:0:0: [sdb] Attached SCSI disk
[ 25.702112] EXT4-fs (sda1): mounting ext2 filesystem using the ext4 subsystem
[ 25.711836] EXT4-fs (sda1): mounted filesystem without journal. Opts: (null)
通过使用grep
只显示包含sd
的行,您可以将输出限制为关于 SCSI 磁盘子系统的信息。
Dmesg and the Kernel Ring Buffer
内核将关于它正在做什么的消息写入内核环形缓冲区。这个缓冲区保存一定量的消息,当它满了时,新的消息进来,旧的消息被丢弃。内核并不认为会有一个日志守护进程将这些消息写到一个文件中,例如在系统启动时。因此,内核将其所有消息写入环形缓冲区,您可以通过dmesg
访问这些消息。
内核的环形缓冲区包含诸如内核是如何被调用的,内核找到的硬件,以及一旦找到它它做了什么。您可以使用dmesg
找到您的网络设备以及您的磁盘是如何配置的。它还可以显示内核某个组件出现严重故障或问题的时间。
一些对dmesg
有用的选项有:
- -C 清除内核环形缓冲区
- -H 人类可读
- -T 人类可读时间戳
- -w 关注或等待新消息
- -l 仅显示特定级别的消息,如信息、紧急、错误、紧急
在dmesg
的输出中,我们可以看到系统已经检测到两个磁盘,sda
和sdb
。当它检测到sda
时,它也发现了分区sda1
、sda2
和sda5
。分区sda5 (<sda5>)
周围的尖括号表示这是一个逻辑分区。另一个磁盘是新的,没有分区表(sdb
),所以让我们使用gdisk
命令创建一个。
$ sudo gdisk /dev/sdb
sudo gdisk /dev/sdb
GPT fdisk (gdisk) version 1.0.1
Partition table scan:
MBR: not present
BSD: not present
APM: not present
GPT: not present
Creating new GPT entries.
Command (? for help): ?
B back up GPT data to a file
c change a partition's name
d delete a partition
i show detailed information on a partition
l list known partition types
n add a new partition
o create a new empty GUID partition table (GPT)
p print the partition table
q quit without saving changes
r recovery and transformation options (experts only)
s sort partitions
t change a partition's type code
v verify disk
w write table to disk and exit
x extra functionality (experts only)
? print this menu
如果您打算使用 MBR 分区表,那么gdisk
实用程序反映了您可以在fdisk
中使用的许多选项。如果我们使用gdisk
实用程序中的?
选项,就会得到帮助输出。让我们快速浏览一下这些选项。
您可以使用l
选项列出设备上的分区。d
选项允许你删除一个(小心,删除分区是危险的)。要删除当前的分区表并创建一个新的空分区表,使用o
选项,这比较危险,但有时需要删除分区表。此选项将破坏您磁盘上的所有分区。
要创建一个分区,使用n
选项,这将启动一个向导来引导您完成创建过程,您马上就会看到。
要列出当前分区表,请按 p。这将按分区表在内存中的位置列出,而不是按它在磁盘上的位置列出。
如果您做出了不想保存的更改,请按 q。这将退出gdisk
,而不会将修改后的分区表写入磁盘。
分区还包含关于它们所包含的文件系统类型的信息。我们从l
选项获得的十六进制标识符可以使用t
选项进行设置。
当您对新的分区图满意时,您可以按 w 键将它保存到磁盘。最后,x 允许您访问高级的gdisk
选项,例如恢复和转换选项、更改 GUID、更改磁盘几何和移动分区中包含的数据。我们不包括这些很少使用的专家选项的使用。
现在按 p 键打印当前磁盘上的分区列表。你会发现它是空的。通常,我们建议在一个数据存储磁盘上只创建一个分区,但是让我们来玩玩这个磁盘,创建几个分区。我们将创建一个 4 GiB 分区和两个 2 GiB 分区。
首先创建一个 2gb 大小的分区,按 n。
Command (? for help): n
Partition number (1-128, default 1):
First sector (34-16777182, default = 2048) or {+-}size{KMGTP}:
Last sector (2048-16777182, default = 16777182) or {+-}size{KMGTP}: 2G
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300):
Changed type of partition to 'Linux filesystem'
首先要求您输入分区号,一个介于 1 和 128 之间的数字。我们将采用默认值 1。接下来要求我们选择磁盘扇区,每个扇区为 512 字节。现代系统在扇区边界对齐,这里我们选择从扇区 2048 或 1024 千比字节开始。接下来,输入2G
表示您想要创建一个 2 GiB 大小的分区。最后,我们选择一个分区 ID,用十六进制代码表示,缺省值是 8300,即 Linux 文件系统。
重复该过程以创建另一个分区。
Partition number (2-128, default 2):
First sector (34-16777182, default = 4196352) or {+-}size{KMGTP}:
Last sector (4196352-16777182, default = 16777182) or {+-}size{KMGTP}: +2G
对于分区 2,我们再次采用分区号和第一个扇区的默认值。对于最后一个扇区,我们必须添加一个+2G,这样该实用程序将额外添加 2 GiB。
为了创建最后一个 4gb 分区,我们再次选择分区号、第一个扇区和最后一个扇区的默认值。
Partition number (3-128, default 3):
First sector (34-16777182, default = 8390656) or {+-}size{KMGTP}:
Last sector (8390656-16777182, default = 16777182) or {+-}size{KMGTP}:
这将创建一个分区所有剩余的磁盘空间。现在我们可以通过选择 p 选项来打印我们一直在做的事情。
Command (? for help): p
Disk /dev/sdb: 16777216 sectors, 8.0 GiB
Logical sector size: 512 bytes
Disk identifier (GUID): 1C42CAB1-754B-4B21-A7A9-D7CE87C8965B
Partition table holds up to 128 entries
First usable sector is 34, last usable sector is 16777182
Partitions will be aligned on 2048-sector boundaries
Total free space is 4061 sectors (2.0 MiB)
Number Start (sector) End (sector) Size Code Name
1 2048 4194304 2.0 GiB 8300 Linux filesystem
2 4196352 8390655 2.0 GiB 8300 Linux filesystem
3 8390656 16777182 4.0 GiB 8300 Linux filesystem
我们还没有把这个分区表写到实际的磁盘上;如果这看起来不对,我们可以使用q
选项放心退出。如果我们满意,我们选择w
选项来编写我们的 GPT 表。
Command (? for help): w
Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
PARTITIONS!!
Do you want to proceed? (Y/N): y
OK; writing new GUID partition table (GPT) to /dev/sdb.
The operation has completed successfully.
前面我们提到了分区类型和 id。Linux 本身通常不关心分区类型,但是为了使管理更容易,我们建议您更改分区类型以匹配预期用途。正如我们已经说过的,分区 id 是一个十六进制代码。您可以通过发出一个l
来获得所有可能选项的列表。在表 9-1 中,我们给你一个与 Linux 相关的列表。
表 9-1。
Linux Partition IDs and Types
| 十六进制代码/分区 id | 分区类型 | | --- | --- | | Eight thousand two hundred | `Linux swap` | | Eight thousand three hundred | `Linux filesystem` | | Eight thousand three hundred and one | `Linux reserved` | | Eight thousand three hundred and two | `Linux /home` | | Eight thousand three hundred and three | `Linux x86 root (/)` | | Eight thousand three hundred and four | `Linux x86-64 root (/)` | | Eight thousand three hundred and five | `Linux ARM64 root (/)` | | Eight thousand three hundred and six | `Linux /srv` | | Eight thousand three hundred and seven | `Linux ARM32 root (/)` | | 8e00 | 使用 |如果您想改变您的分区类型,您可以通过发出以下命令来实现。我们将在刚刚分区的/dev/sdb
驱动器上再次查看 gdisk。在这里,我们将把第一个 2 GiB 分区从 Linux 文件系统类型改为 Linux 交换。
$ sudo gdisk /dev/sdb
Command (? for help): t
Partition number (1-3): 1
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): 8200
Changed type of partition to 'Linux swap'
这里,我们使用 gdisk 来管理分区表,并发出了t
选项来更改分区的类型代码。我们选择分区 1,它显示我们当前的类型,“Linux 文件系统”。接下来,我们输入代码 8200,它现在已经将类型更改为 Linux swap。当我们打印结果时,我们会看到以下内容:
Command (? for help): p
Disk /dev/sdb: 16777216 sectors, 8.0 GiB
Logical sector size: 512 bytes
Disk identifier (GUID): 1C42CAB1-754B-4B21-A7A9-D7CE87C8965B
Partition table holds up to 128 entries
First usable sector is 34, last usable sector is 16777182
Partitions will be aligned on 2048-sector boundaries
Total free space is 4061 sectors (2.0 MiB)
Number Start (sector) End (sector) Size Code Name
1 2048 4194304 2.0 GiB 8200 Linux swap
2 4196352 8390655 2.0 GiB 8300 Linux filesystem
3 8390656 16777182 4.0 GiB 8300 Linux filesystem
我们必须选择w
将此更改写入表格,选择q
退出。内核现在重新加载分区图,并为您的分区创建新的设备节点。您将在dmesg
的输出中看到磁盘检测例程已经运行并找到了您的新分区。您还可以检查它们的设备节点现在是否存在于磁盘上。
$ ls -l /dev/sdb*
brw-rw---- 1 root disk 8, 16 Jun 16 23:56 /dev/sdb
brw-rw---- 1 root disk 8, 17 Jun 16 23:56 /dev/sdb1
brw-rw---- 1 root disk 8, 18 Jun 16 23:56 /dev/sdb2
brw-rw---- 1 root disk 8, 19 Jun 16 23:56 /dev/sdb3
有时内核无法重新读取分区表,这意味着在重新启动主机之前,您无法访问新的分区设备文件。如果您正在编辑的磁盘上的其中一个分区仍处于装载状态,则会发生这种情况。若要避免重新启动,请确定您正在分区的磁盘上没有装载任何分区。我们将在这一章的后面讨论安装。
Note
您还可以通过运行partprobe
命令让内核重新检测分区——无需重启。
另一个创建和删除分区的工具是 parted。与gdisk
和fdisk
不同,该实用程序允许您编辑分区的大小和顺序。我们建议你不要走用parted
调整分区大小的道路,因为这些操作可能是灾难性的,而是使用 LVM。我们将在本章后面详细介绍 LVM。更多关于parted
的信息,请访问 www.gnu.org/software/parted/index.shtml
。
Caution
调整分区大小会导致不可恢复的数据丢失。务必首先备份您的数据!
Gibibytes VS. Gigabytes
当硬盘制造商为其产品做广告时,它希望可用的存储空间看起来尽可能大,因此它将每千兆字节计算为 1,000 兆字节,依次是 1,000,000 千字节,即 1,000,000,000 字节。
但是因为计算机上的所有计算都是通过二进制算术来完成的,所以实际的乘法值是 1024(gibi 的意思是 2 30 )。但是,如果一家存储制造商使用了这一因素,那么与竞争对手相比,它的设备似乎会更小,所以它不会。
为了避免这些计算大小的方法之间的混淆,使用 1,024 因子的值创造了新的术语:kibibyte、mebibyte、gibibyte 等等。它们用 KiB、MiB、GiB 等表示。Linux 文件系统工具使用 1,024 因子,因此如果您购买一个 500 GB 的磁盘,当通过 Linux 查看时,它的大小将总是小于 500 GiB。
更多信息,请参见 http://en.wikipedia.org/wiki/Gigabyte
.
文件系统
您现在已经创建了分区,但是还没有准备好使用它们。接下来您需要做的是创建一个文件系统。你可能知道这就是格式化。
文件系统有点像库。它存储大量数据,并有一个目录,以确保您可以找到您正在寻找的东西。过道和货架的布局以及目录的设计决定了查找和检索任何特定信息所需的时间。创建文件系统就像初始化目录并将书架移到一个空的库中。
正如没有适合所有图书馆的最佳过道和书架布局一样,也没有适合所有用途的“最佳”文件系统。我们不会涉及太多细节,但是让我们看看一些最常用的 Linux 文件系统。表 9-2 列出了它们的主要特征。
表 9-2。
Linux Filesystems and Their Main Features
| 文件系统 | 特征 | | --- | --- | | Ext2 | 稳定,通用,可收缩或膨胀 | | Ext3 | 稳定,通用,快速恢复,可收缩或膨胀 | | Ext4 | 稳定、通用、快速恢复,比 ext3 有所改进 | | XFS | 稳定,通用,恢复快,可在线扩展 | | btr 护堤 | 不稳定、容错、写时拷贝(COW)、池化和多设备跨转 |ext2 和 ext3 文件系统是较老的文件系统。这些文件系统的一般用途是在其上存储许多小文件。对于电子邮件存储、网站存储或 office 文件存储来说,它们是文件系统的良好选择,因为这些文件通常由许多大小高达数百千字节的文件组成。在较新的系统上,你很少看到 ext3,但是在 Ubuntu 16.04 上,默认情况下,你会看到 ext2 作为/boot
分区的文件系统。
ext2 和 ext3 的主要区别之一是日志支持。对于 ext2,如果发生崩溃,在可以再次挂载磁盘之前,fsck 会等待很长时间。为了解决这个问题,创建了日志文件系统。Ext3、ext4 和 XFS 就是这样的日志文件系统,因此没有 ext2 那样长的恢复等待时间。有关更多信息,请参见侧栏“日志文件系统”。
有了 ext3 的经验教训,ext4 得到了进一步的发展。它提供了一些 ext3 中没有的特性,比如在线碎片整理、更好的日志可靠性和更快的文件系统检查。Ext4 旨在成为一个性能卓越的全方位文件系统。它可以支持高达 1 兆字节的卷和 16 兆字节的最大文件大小。这是 Ubuntu 16.04 发行版的默认选择。
存储视频、大型图像或数据库文件的另一个选择是 XFS 文件系统。它提供了一些与 ext4 相同的优点;但是,您不能收缩 XFS 分区(在线)。它的性能不亚于 ext4。它最多可以支持 8ex bibyte 和 8ex bibyte 的文件大小。这是 CentOS 7 的默认选择。
最后,Btrfs 是一个更新的文件系统,具有与 XFS 和 ext4 不同的特性。首先,它可以支持大得离谱的卷(16 兆字节)和相同的最大文件(16 兆字节)。在如此大的规模下,ext4 和 XFS 上的日志记录变得非常慢而且不可能。它旨在自然地支持快照和池化等操作和组织。它还具有自动碎片整理和清理等功能,使用校验和来自动检测和纠正错误。根据工作负载的不同,Btrfs 可能是一个不错的选择,而且在一定规模下,它是唯一的选择。由于 Raid5/6 配置中最近出现的一些写入漏洞问题,我们在表 9-2 中将它列为不稳定。查看此页面以了解文件系统的最新状态: https://btrfs.wiki.kernel.org/index.php/Status
。
Note
Btrfs 不是唯一的大规模文件系统,但它是 Linux 默认安装中可用的文件系统。像 ZFS 这样的其他软件也很受欢迎,性能也很好,但是 ZFS 由于其许可证的原因不能再发行(它不能成为 Linux 发行版的一部分)。尽管如此,您仍然可以在 Linux 上使用它;不过需要自己下载安装: http://zfsonlinux.org/
。
您可以在 http://en.wikipedia.org/wiki/List_of_file_systems
和 http://en.wikipedia.org/wiki/Comparison_of_file_systems
找到文件系统的详尽列表及其特性对比。
Journaled Filesystems
想象一下,在一个图书馆里,一本书被归还后,图书管理员会走开,在书架上找一个空的地方放书,然后更新目录,然后回到前台处理下一本书——在此期间,任何人都不可能借到书。还书的顾客也可能会想,仅仅因为他们站在图书馆里,图书馆目录就知道他们已经还书了。这不是一个有效的系统,顾客可能会排队等着还书,或者更糟糕的是,把书放在地上就走了。
有了退书滑槽,这个问题就可以解决了。一旦书被放入返回槽,顾客就可以回去工作了,因为他们知道书已经被图书馆安全地接受了。当图书馆不忙于人们借阅新书时,图书管理员可以处理还书。即使图书馆关门前没有处理好斜道里的书,它们也不会丢失。他们第二天还会在滑槽里。
日志文件系统利用了循环缓冲区,它的工作方式有点像一个带有书籍滑道的图书馆。这是文件系统上的一个区域或日志,保存尚未提交到文件系统存储主要部分的更改。任何需要写入磁盘的信息都放在日志中,然后当操作系统有空闲时间时,再放在磁盘的最终位置。同样,如果计算机崩溃,日志中的数据也不会丢失。如果系统崩溃,可以在重新装载磁盘后重新应用日志。这有助于防止应用部分更改,并在系统出现故障时避免损坏。
不过,我们的比喻在这里失效了。在我们的文件系统库中,人们也可以从还书槽借书,如果还书槽太满,图书管理员可以忽略想借书的人。
大多数现代文件系统使用日志,尽管有些文件系统仅将日志用于文件元数据。像 Btrfs 这样的文件系统可以用不同的方式处理元数据。您可以选择不同于文件数据的元数据布局(例如,元数据为 raid1,数据为 raid10)。对于频繁更新的文件数据,Btrfs 使用日志树,这是一个按子卷记录更改的日志,有助于在崩溃或重新启动时保持一致性。
创建交换文件系统
我们将使用您之前创建的第一个分区/dev/sdb1
作为交换分区。为这个文件系统选择文件系统很容易,因为只有一种交换文件系统格式。让我们首先使用mkswap
命令来设置它,如清单 9-3 所示。
$ sudo mkswap /dev/sdb1
Setting up swapspace version 1, size = 2 GiB (2146430976 bytes)
no label, UUID=6d0ce2f6-f9f6-4ac2-91f6-3099a40d5624
Listing 9-3.Setting Up Swap Space
您正在使用mkswap
实用程序将/dev/sdb1
标记为交换空间。您可以使用生成的 UUID 在/etc/fstab
文件中添加一个条目,该文件列出了将在主机上使用的所有文件系统(参见侧栏“UUID”了解什么是 UUID)。我们将在本章的后面回到/etc/fstab
文件。从技术上讲,您没有格式化分区;相反,您正在编写少量的信息向内核表明它可以用作交换空间。
您可以通过swapon
命令立即激活新的交换分区。这个命令告诉内核它可以使用指定的分区作为交换空间。
$ sudo swapon /dev/sdb1
该命令将完成,但不打印任何内容,但是您可以检查dmesg
以了解发生了什么。将输出输入tail
,将显示的行数限制在指定的数量。
$ sudo dmesg | tail -n 1
[13066.031700] Adding 2096124k swap on /dev/sdb1\. Priority:-2 extents:1 across:2096124k FS
检查交换的另一种方法是查看free
命令是否报告了交换空间。指定-h
选项,以人类可读的形式显示尺寸。
$ sudo free -h
total used free shared buff/cache available
Mem: 992M 520M 62M 12M 409M 321M
Swap: 3.0G 0B 3.0G
或者,您可以使用swapon
命令:
$ swapon –s
Filename Type Size Used Priority
/dev/dm-1 partition 3145728000 0 -1
该命令报告了总共 3.0 G 的交换空间,这是我们已经拥有的原始 1 G 加上我们刚刚添加的 2 G。当我们讨论绩效管理时,我们将在第十七章中回到free
命令。
UUID
在安装软件时或在某些网站的 URIs 中,您可能会看到长而随机的十六进制字符串,如“6 d0ce 2 f 6-f9f 6-4 ac2-91 F6-3099 a40d 5624”。这些字符串是通用唯一标识符(UUIDs)。
UUIDs 提供了一种方便且计算成本低廉的识别信息的方法,而不需要检查生成的 ID 是否已经在使用。因为 UUIDs 是随机或半随机生成的,所以它们很难猜测,因此也能提供一点安全性。
在 Linux 上,UUIDs 越来越多地被用来区分 RAID、逻辑卷和文件系统的组件。它使我们能够管理设备,并使它们在重启后保持不变。虽然标记设备也可以达到这个目的,但是 UUIDs 不太可能发生命名冲突。
你可以在 http://en.wikipedia.org/wiki/Universally_Unique_Identifier
了解更多。
创建 Ext4 分区
对于您的数据分区,从另一个新的 2 GiB /dev/sdb2 partition
开始。您将使用mkfs.ext4
实用程序将其格式化为 ext4,如清单 9-4 所示。如果你想创建一个 ext2 文件系统,有时用于创建一个引导分区,只需运行mkfs.ext2
即可。
$ sudo mkfs.ext4 –L mail /dev/sdb2
mke2fs 1.42.9 (28-Dec-2013)
Filesystem label=mail
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
131072 inodes, 524288 blocks
26214 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=536870912
16 block groups
32768 blocks per group, 32768 fragments per group
8192 inodes per group
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912
Allocating group tables: done
Writing inode tables: done
Creating journal (16384 blocks): done
Writing superblocks and filesystem accounting information: done
Listing 9-4.Creating an Ext4 Filesystem
在清单 9-4 中,我们创建了一个 ext4 文件系统,并使用-L
参数指定了一个标签。这个标签将允许您通过标签名来引用分区,而不是设备名或 UUID。在没有太多格式化分区的系统上(命名冲突的可能性更小),使用标签有助于提高可读性。在这种情况下,我们为将要使用的内容选择了一个标签。
使用 Ext 文件系统,您可以看到一系列关于文件系统大小和存储空间如何分配的统计数据。在输出中,您可以看到“Block size”、“Maximum filesystem blocks”和“Inodes”的设置,这些设置描述了您的文件系统是如何设置的。请看侧栏“块和索引节点”中对这些的简短解释。值得注意的是为超级用户和超级数据块备份保留的数据块。
26214 blocks (5.00%) reserved for the super user
...<snip>...
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912
超级块是文件系统元数据的一部分。它包含关于文件系统的信息,例如文件系统的大小、文件系统中的可用空间量以及文件系统中可以找到数据的位置。如果发生崩溃,这个超级块被损坏,您将无法确定文件系统的哪些部分包含您的数据。为了在出现这种问题时帮助您,超级块的几个备份副本被保存在众所周知的块号中。我们将在本章的后面重新讨论恢复。
超级用户百分比的保留块的存在使得普通用户不能将文件系统填充到超级用户(root
)不能再登录的程度,或者作为root
用户运行的服务不能将数据写入磁盘。
5%的限制是历史的,适合于根文件系统'/'
,它通常不会大于几千兆字节。但是,当您使用 1 TiB 文件系统时,这一限制相当于 50 GiB 的空间,您不能用它来存储用户数据,因此在数据存储卷上更改或删除它是有意义的。
您可以在创建文件系统时为mkfs.
ext4
指定-m 0
选项,以将保留块的百分比设置为0
,或者您可以稍后更改该值(稍后将详细介绍)。
Blocks and Inodes
当您创建文件系统时,可用磁盘空间被划分为特定大小的单元。这些单元称为块,默认情况下,它们的大小为 4 KB。
一个数据块只能容纳一个文件或一个文件的一部分,因此一个 1 KB 的文件仍然会用完整个数据块,也就是 4 KB 的磁盘空间,浪费 3 KB 的存储空间。较大的文件分布在多个块中。如果您主要存储小于 4 KB 的文件,您可以选择为您的文件系统使用不同的、更小的块大小。同样,如果您的文件预计比 4 KB 大得多,您可以选择更大的块大小。
为特定任务设置服务器时,试验和测试不同块大小的性能非常重要。数据库、共享文件系统和邮件系统都有不同的块大小最佳点来获得最佳性能。如果您可以模拟预期的工作负载,那么您应该对文件系统的最佳调优有更好的想法。
Inodes 是符合 posix 标准的文件系统存储元数据的地方,比如文件或目录的创建和修改日期、权限和所有权,以及指向哪些块包含实际文件数据的指针。这意味着文件系统只能包含与它拥有的 inodes 一样多的文件和目录。因此,在 Ext 文件系统的情况下,块很小而文件很多,您可以在用完磁盘空间之前用完索引节点。要了解关于 inodes 的更多信息,请参见 http://en.wikipedia.org/wiki/Inode
。
调整 ext2、ext3 和 ext4 文件系统选项
要在创建后更改 ext2、ext3 和 ext4 文件系统参数,可以使用 tune2fs 实用程序。要获得可用选项的概述,首先运行不带任何参数的实用程序。也可以通过man
tune2fs
调出整本手册。
$ tune2fs
tune2fs 1.42.13 (17-May-2015)
Usage: tune2fs [-c max_mounts_count] [-e errors_behavior] [-g group]
[-i interval[d|m|w]] [-j] [-J journal_options] [-l]
[-m reserved_blocks_percent] [-o [^]mount_options[,...]] [-p mmp_update_interval]
[-r reserved_blocks_count] [-u user] [-C mount_count] [-L volume_label]
[-M last_mounted_dir] [-O [^]feature[,...]]
[-Q quota_options]
[-E extended-option[,...]] [-T last_check_time] [-U UUID]
[ -I new_inode_size ] device
虽然没有明确说明,但是-l
参数列出了当前的文件系统选项。让我们在您的新 ext4 分区上运行它(参见清单 9-5 )。
$ sudo tune2fs -l /dev/sdb2
tune2fs 1.42.13 (17-May-2015)
Filesystem volume name: mail
Last mounted on: <not available>
Filesystem UUID: 71bd5774-33cb-491b-8ffe-49cb33935001
...<snip>...
Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize
Filesystem flags: signed_directory_hash
Default mount options: user_xattr acl
Filesystem state: clean
Errors behavior: Continue
Filesystem OS type: Linux
Inode count: 131072
Block count: 524288
Reserved block count: 26214
Free blocks: 498900
Free inodes: 131061
First block: 0
Block size: 4096
Fragment size: 4096
...<snip>...
Last mount time: n/a
Last write time: Sun Jun 19 10:42:04 2016
Mount count: 0
Maximum mount count: -1
Last checked: Sun Jun 19 10:42:04 2016
Check interval: 0 (<none>)
...<snip>...
Journal backup: inode blocks
Listing 9-5.Displaying Ext2, Ext3, or Ext4 Filesystem Options
显示了很多信息,但我们最感兴趣的是文件系统 UUID 和状态,它们告诉我们如何引用文件系统及其健康状况。“错误行为”表明如果有文件系统错误会发生什么。在这种情况下,如果我们检测到错误,我们会“继续”,但其他选项是“remount-ro”(以只读方式重新挂载文件系统)或“panic”,这会导致内核崩溃,从而暂停系统。对诊断容量问题有用的其他信息是“空闲信息节点”和“空闲块”“上次写入时间”、“上次装载时间”和“上次装载时间”也很有用。
Note
当我们讨论容量规划和性能时,我们将在第十七章中更仔细地研究一些文件系统特性。
我们现在将使用 tune2fs 将保留块百分比设置为 0,因为我们不需要该分区上的保留空间。
$ sudo tune2fs -m 0 /dev/sdb2
tune2fs 1.42.9 (28-Dec-2013)
Setting reserved blocks percentage to 0% (0 blocks)
表 9-3 列出了你最有可能使用的tune2fs
选项。
表 9-3。
Commonly Used tune2fs
Options
Note
当我们讨论性能和容量规划时,我们将在第十七章中回到-O
选项和高级文件系统特性。
XFS 文件系统
XFS 文件系统最初是专有的和封闭源代码的。XFS 是由硅图形公司为其 IRIX 操作系统开发的。
几年前,XFS 的文件系统驱动程序是开源的,IRIX 帮助将其集成到 Linux 内核中,因为当时 Linux 缺少日志文件系统。社区热情地接受了这些新的开源文件系统,因为它们都提供了新的特性和出色的性能。现在它们在 Linux 平台上被广泛接受和支持,包括作为 CentOS 7 的默认设置。
XFS
您已经创建了一个 ext4 分区来存储一些小文件。让我们使用 XFS 文件系统格式化另一个分区。为此,我们将使用mkfs.xfs
工具。根据发行版的不同,您可能没有管理 XFS 文件系统所必需的实用程序。这些实用程序是由xfsprogs
包提供的,在您开始之前,您应该已经安装了它。在 Ubuntu 上,您可以按如下方式安装它们:
$ sudo aptitude install xfsprogs
在 CentOS 上,您可以使用命令(尽管它是作为默认文件系统安装的)
$ sudo yum install xfsprogs
安装包之后,您可以使用默认选项创建您的文件系统,如清单 9-6 所示。
$ sudo mkfs.xfs /dev/sdb3
meta-data=/dev/sdb3 isize=512 agcount=4, agsize=262079 blks
= ectsz=512 attr=2, projid32bit=1
= crc=1 finobt=1, sparse=0
data = bsize=4096 locks=1048315, imaxpct=25
= sunit=0 swidth=0 blks
naming = version 2 bsize=4096 ascii-ci=0 ftype=1
log = internal log bsize=4096 blocks=2560, version=2
= sectsz=512 sunit=0 blks, lazy-count=1
realtime = none extsz=4096 blocks=0, rtextents=0
Listing 9-6.Creating an XFS Filesystem
创建文件系统时,会显示一些关于其配置的信息。我们将在第十七章中进一步利用这些信息来研究性能和容量规划。
所有这些选项,例如控制块大小和日志大小,都可以在创建文件系统时设置,但是mkfs.xfs
工具会根据需要格式化的分区的大小选择合理的默认值。
Note
XFS 不会为 root 用户保留 5%的可用空间,也不会在特定时间过后自动强制进行文件系统检查。
XFS 文件系统可以通过几个命令来管理。这些命令以 xfs_ 开头,您可以通过键入 xfs_ 并按 tab 键两次来查看可用的选项。表 9-4 显示了您感兴趣的主要产品。
表 9-4。
Common xfs_ Commands
| 命令 | 目的 | | --- | --- | | xfs_repair | 帮助修复受损或损坏的文件系统 | | xfs_growfs | 扩展 XFS 文件系统。 | | xfs_freeze | 创建快照时很有用。 |Btrfs 文件系统
我们已经解释了 Btrfs 文件系统的许多好处,现在我们将向您展示如何创建和管理它。如果您还没有安装实用程序,您可以通过安装 btrfs-progs 包来完成,类似于我们安装 XFS 包的方式。
我们说过 Btrfs 使用 COW(或写时复制)。但那是什么?当数据被修改时,数据被复制、修改,然后写入新的空闲位置,而不是在先前的数据位置上写入修改的数据。然后,元数据(文件的位置)以同样的方式更新,以反映数据的新位置。
我们将快速演示如何创建 Btrfs 分区并挂载它。我们有一个连接到主机的新磁盘。我们通过 dmesg 发现这个新磁盘被赋予了设备/dev/sdc
。我们将把整个磁盘用于该分区。创建 Btrfs
$ sudo mkfs.btrfs /dev/sdc
btrfs-progs v4.4
See http://btrfs.wiki.kernel.org for more information.
Label: (null)
UUID: e1c6cbb0-4fbf-4a61-a912-0a9cda611128
Node size: 16384
Sector size: 4096
Filesystem size: 8.00GiB
Block group profiles:
Data: single 8.00MiB
Metadata: DUP 417.56MiB
System: DUP 12.00MiB
SSD detected: no
Incompat features: extref, skinny-metadata
Number of devices: 1
Devices:
ID SIZE PATH
1 8.00GiB /dev/sdc
我们现在可以简单地挂载这个分区了。我们已经创建了一个名为/data1
的目录,并将它挂载在那里。
$ mount /dev/sdc /data1
我们可以看到文件系统已经挂载。
$ df -h /data1
Filesystem Size Used Avail Use% Mounted on
/dev/sdc 8.0G 60M 7.2G 1% /data1
Btrfs 附带了一个管理 Btrfs 文件系统的实用程序。我们将向您展示该实用程序的一些特性:首先是如何调整文件系统的大小。我们将把我们的文件系统减少 2 GiB,然后再把它加回来。
$ sudo btrfs filesystem resize -2G /data1
Resize '/data1' of '-2G'
Btrfs 实用程序的一个子命令是filesystem
。这里我们传递了选项resize -2G /data1
,它告诉实用程序将文件系统减少 2 GiB。使用filesystem show
子命令,我们可以看到结果。
$ sudo btrfs filesystem show /data1
Label: none uuid: e1c6cbb0-4fbf-4a61-a912-0a9cda611128
Total devices 1 FS bytes used 42.03MiB
devid 1 size 6.00GiB used 1.64GiB path /dev/sdc
我们现在要添加 2 个 GiB。所以我们简单地使用下面的:
$ sudo btrfs filesystem resize +2G /data1
Resize '/data1' of '+2G'
在下一个示例中,我们有四个连接到主机的备用磁盘。我们将把这些磁盘用作一个组合磁盘。dmesg 的输出显示它们已被分配给以下设备:
[ 47.815498] sdb: unknown partition table
[ 47.833520] sdc: unknown partition table
[ 47.848420] sdd: unknown partition table
[ 47.868448] sde: unknown partition table
有了 Btrfs,我们可以用 RAID 对设备进行分组。它使用多设备文件系统来做到这一点,我们将在“RAID”一节中详细讨论我们可以使用的一种可能的 RAID 类型是 RAID 10。这种 RAID 类型为我们提供了镜像和条带化,这意味着设备是成对镜像的,然后进行条带化。这将给我们带来冗余和速度。
为了创建 Btrfs RAID 分区,我们发出以下命令:
$ sudo mkfs.btrfs -d raid10 -m raid10 /dev/sdb /dev/sdc /dev/sdd /dev/sde
btrfs-progs v3.19.1
See http://btrfs.wiki.kernel.org for more information.
Turning ON incompat feature 'extref': increased hardlink limit per file to 65536
Turning ON incompat feature 'skinny-metadata': reduced-size metadata extent refs
adding device /dev/sdc id 2
adding device /dev/sdd id 3
adding device /dev/sde id 4
fs created label (null) on /dev/sdb
nodesize 16384 leafsize 16384 sectorsize 4096 size 32.00GiB
这里我们发出了mkfs.btrfs
命令。我们已经指定了为数据块组设置配置文件的–d
选项。–m
选项设置元数据块组的配置文件。然后,我们指定了正在使用的四个磁盘。
最后,它说我们已经在/dev/sdb
上创建了一个 fs 标签。让我们获取该设备的 UUID,以便将其放入 fstab 中。
$ sudo blkid /dev/sdb
[sudo] password for jsmith:
/dev/sdb: UUID="0cd0e135-feb8-4f99-a973-5751549d2e4f" UUID_SUB="4d327afb-1330-43e5-b392-0e676ebab1b5" TYPE="btrfs"
我们将我们的行添加到 fstab 中,如下所示:
UUID=0cd0e135-feb8-4f99-a973-5751549d2e4f /data btrfs defaults 0 0
让我们知道使用 mount 命令挂载我们的磁盘:
$ sudo mount /data2
最后,让我们用df –h
命令来看看我们在/data2
分区上有多少空间:
$ df –h /data2
Filesystem Size Used Avail Use% Mounted on
/dev/sdb 16G 18M 14G 1% /data2
我们有四个 8 GiB 的磁盘组合在一起,形成一个 14 GiB 的可用分区。我们现在将向您简要展示创建子卷和快照的能力。
子卷是一个“POSIX 命名空间”或容器。它不是像/dev/sda
或 LVM(逻辑卷管理)逻辑卷那样的块设备。也就是说,您不能单独挂载它或者在它上面创建一个不同的文件系统,但是您可以将它挂载为一个子卷,Linux 内核可以读写它。
您可以像使用普通目录一样使用子卷。它们具有以下优点:
- 您可以重命名和删除子卷
- 您可以轻松快速地拍摄子卷的快照
- 您可以装载快照
- 您可以嵌套子体积
- 您可以对子卷应用配额
我们将创建一个名为 mail 的子卷,并挂载它。
$ sudo btrfs subvolume create /data2/mail
Create subvolume '/data2/mail'
我们现在已经创建了一个名为/srv/mail
的目录,我们将在那里挂载我们的邮件子卷:
$ sudo mount -t btrfs -o subvol=mail /dev/sdc /srv/mail
我们现在可以看到该文件系统已经挂载。
$ df -h /srv/mail
Filesystem Size Used Avail Use% Mounted on
/dev/sdb 16G 18M 14G 1% /srv/mail
BtrFS 子体积的最大特点是快照的速度。我们可以创建两种类型的快照:只读子卷快照或可写子卷快照。因为这是一个 CoW 文件系统,所以在我们对数据进行修改之前,我们不会改变磁盘空间。现在,让我们创建子卷的快照,我们可以将它挂载到其他地方,例如在/mnt/snap_mail
中。
$ sudo btrfs subvolume snapshot /data/mail /data2/snap_mail
现在将它安装在/mnt/snap_mail
上。
$ sudo mount -t btrfs -o subvol=snap_mail /dev/sdc /mnt/snap_mail
$ df -h /mnt/snap_mail
Filesystem Size Used Avail Use% Mounted on
/dev/sdb 16G 18M 14G 1% /mnt/snap_mail
快照是子卷的时间点副本。您可以使用它来复制繁忙的文件系统上的数据,或者制作子卷的时间点备份。要制作只读快照,您需要发出btrfs subvolume snapshot –r (vol_target) (vol_dest)
。
数据共享的文件系统
到目前为止,我们已经讨论了只能由 Linux 访问的文件系统。如果您需要在不同的操作系统之间传输数据——例如,当您的笔记本电脑和客户的机器之间没有网络时——您可能希望使用 Windows 和 Mac OS X 以及 Linux 都可以访问的文件系统。
用于此目的的事实上的标准是 FAT 文件系统,它是由微软为 MS-DOS 开发的。脂肪有几种口味。最新版本是 FAT32,它支持超过 32 GiB 的磁盘大小和高达 4 GiB 的文件大小。
要创建 FAT32 文件系统,可以使用mkfs.vfat
实用程序。这个工具在 Ubuntu 和 CentOS 上都由dosfstools
包提供,所以你需要确保安装了dosfstools
。
插入想要格式化的 USB 驱动器后,通过内核日志检查它的设备节点名,如清单 9-7 所示。
$ dmesg
[ 52.464662] usb 1-1: new high speed USB device using ehci_hcd and address 2
[ 52.887506] usb 1-1: configuration #1 chosen from 1 choice
[ 52.967324] usbcore: registered new interface driver libusual
[ 52.981452] Initializing USB Mass Storage driver...
[ 52.986046] scsi3 : SCSI emulation for USB Mass Storage devices
[ 52.987804] usbcore: registered new interface driver usb-storage
[ 52.987831] USB Mass Storage support registered.
[ 52.988661] usb-storage: device found at 2
[ 52.988687] usb-storage: waiting for device to settle before scanning
[ 58.982976] usb-storage: device scan complete
[ 59.350262] usb 1-1: reset high speed USB device using ehci_hcd and address 2
[ 59.772402] scsi 3:0:0:0: Direct-Access SanDisk Cruzer
8.01 PQ: 0 ANSI: 0 CCS
[ 59.789834] sd 3:0:0:0: [sdg] 15682559 512-byte hardware sectors (8029 MB)
[ 59.792747] sd 3:0:0:0: [sdg] Write Protect is off
[ 59.792754] sd 3:0:0:0: [sdg] Mode Sense: 45 00 00 08
[ 59.792766] sd 3:0:0:0: [sdg] Assuming drive cache: write through
[ 59.805772] sd 3:0:0:0: [sdg] 15682559 512-byte hardware sectors (8029 MB)
[ 59.815884] sd 3:0:0:0: [sdg] Write Protect is off
[ 59.815891] sd 3:0:0:0: [sdg] Mode Sense: 45 00 00 08
[ 59.815894] sd 3:0:0:0: [sdg] Assuming drive cache: write through
[ 59.816480] sdg: sdg1
[ 59.831448] sd 3:0:0:0: [sdg] Attached SCSI removable disk
[ 59.831942] sd 3:0:0:0: Attached scsi generic sg7 type 0
Listing 9-7.Determining the Device Node for a USB Key
在清单 9-7 中,SanDisk Cruzer USB 驱动器被检测为/dev/sdg
。一旦您知道 USB 驱动器是哪个设备节点,您就可以创建一个类型为c - W95 FAT32 (LBA)
的主分区,然后您可以使用mkfs.vfat
格式化这个分区。使用-n
选项标记分区,并通过-F 32
选项指定您想要一个 FAT32 文件系统。
$ sudo mkfs.vfat -n "USB Key" -F 32 /dev/sdg1
mkfs.vfat 2.11 (12 Mar 2005)
其他文件系统
Linux 有太多不同的文件系统,所以你可能会问为什么我们只讨论了其中的三种。尽管存在许多其他文件系统,但我们认为它们中的大多数不适合或不适合在生产环境中使用。文件系统需要具备的最重要的特性是稳定性,我们讨论的文件系统提供了这一点,以及出色的性能。如果您根据存储的数据类型选择 ext4、XFS 或 Btrfs,您应该会看到出色的可靠性和速度。为您的服务器选择一个更快但不太稳定的文件系统不会有任何帮助,如果您因此需要花费时间每月一次从备份中恢复数据的话。
对于 Linux 内核支持的其他文件系统的简要概述,您可以阅读filesystems
手册页。
Note
Linux 可以通过ntfsprogs
包中的mkntfs
工具创建 NTFS 文件系统。但是,我们建议您不要在 Linux 下使用 NTFS 文件系统来存储数据。
使用您的文件系统
现在,您已经在新磁盘/dev/sdb
上创建了分区,并且已经用您选择的文件系统格式化了这些分区。然而,在使用文件系统存储数据之前,您需要挂载它。
正如我们在第四章和本章开始时简要解释的,Linux 上的文件系统不会被分配一个驱动器号。相反,它们被挂载为一个目录,位于根文件系统或子目录下。在第四章中,我们提到过/mnt
目录通常被用作临时挂载文件系统的地方。接下来,您将创建一个名为/mnt/data
的目录,并将其用于新的 ext4 分区。
$ sudo mkdir /mnt/data
挂载分区是通过mount
命令完成的。使用-t
选项指定文件系统类型,然后是设备文件,最后是希望文件系统可用的目录。
$ sudo mount -t ext4 /dev/sdb2 /mnt/data/
如果一切顺利,mount
命令将不会打印任何信息,而只是退出。要验证分区现在是否已经挂载,请使用df
命令。
$ df -h
Filesystem Size Used Avail Use% Mounted on
udev 478M 0 478M 0% /dev
tmpfs 100M 3.3M 96M 4% /run
/dev/mapper/au--mel--ubuntu--1--vg-root 6.3G 2.6G 3.4G 44% /
tmpfs 497M 0 497M 0% /dev/shm
tmpfs 5.0M 0 5.0M 0% /run/lock
tmpfs 497M 0 497M 0% /sys/fs/cgroup
/dev/sda1 472M 147M 301M 33% /boot
tmpfs 100M 0 100M 0% /run/user/1000
/dev/sdb2 2.0G 3.0M 1.8G 1% /mnt/data
我们的分区列在输出的底部,所以mount
命令成功了。我们将在本章的后面重新讨论df
,并更详细地解释这个输出意味着什么。
您还可以通过使用dmesg
命令检查内核日志来查看一些更详细的信息。
$ dmesg
[37881.206060] EXT4-fs (sdb2): mounted filesystem with ordered data mode. Opts: (null)
内核检测到一个 ext4 文件系统,并使用默认选项“有序数据模式”挂载它(这意味着我们首先将数据写入主文件系统,然后将元数据提交给日志)。它还启动了一个内核线程,每五秒钟将日志中的数据刷新到文件系统中——我们的图书管理员正在清空图书槽。
看看新挂载的分区内部,我们可以使用 ls 来查看它是否包含任何内容:
$ cd /mnt/data && ls -l
total 16
drwx------ 2 root root 16384 Jun 19 10:42 lost+found
您全新的文件系统包含一个名为lost+found
的目录,这个目录不是您创建的!这是一个特殊的目录,存在于所有 ext2、ext3 和 ext4 文件系统中。这个目录由 Linux 的文件系统修复工具使用,我们将在后面的“从故障中恢复”一节中研究它
当您不再需要文件系统时,可以使用umount
命令将其从主机上卸载。
$ sudo umount /mnt/data
umount: /mnt/data: target is busy
(In some cases useful info about processes that
use the device is found by lsof(8) or fuser(1).)
$ pwd
/mnt/data
这里发生了什么事?命令 umount 拒绝卸载目录,因为它包含正在使用的文件或目录。在这种情况下,这是因为我们当前的工作目录是/mnt/data
,当我们在目录中时,我们的主机不能卸载设备——也就是说,我们位于我们试图卸载的目录中!设备繁忙的原因有很多,而且并不总是清楚哪个用户或应用程序打开了哪个文件或目录。为了帮助您找到答案,lsof
命令列出了打开的文件和目录:
$ sudo lsof /mnt/data
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
bash 2750 jsmith cwd DIR 8,18 4096 2 /mnt/data
sudo 3999 root cwd DIR 8,18 4096 2 /mnt/data
lsof 4000 root cwd DIR 8,18 4096 2 /mnt/data
lsof 4001 root cwd DIR 8,18 4096 2 /mnt/data
除了lsof
本身,还有一个用户jsmith
拥有的bash
流程。您可以通过返回到您的主目录来停止使用该目录。键入 cd 和主目录的快捷方式,然后使用lsof
再次检查/mnt/data
。
$ cd ∼
$ lsof /mnt/data
这一次,lsof
命令没有返回任何打开的文件和目录,由于目录不再被列为使用中,您现在可以安全地卸载它了:
$ sudo umount /mnt/data
Note
正确卸载文件系统会将您在tune2fs
输出中看到的Filesystem state
标志设置为clean
,因为它会要求内核处理整个日志文件,并确保所有数据都写入磁盘。这可以防止下次主机启动时自动检查文件系统。
当您作为非root
用户运行lsof
时,它将只列出该用户拥有的进程。其他人可能仍在使用您试图卸载的文件系统上的文件或目录。使用sudo
运行lsof
进行检查总是一个好主意。
Note
如果某个系统服务正在使用一个已挂载的文件系统,您必须先停止该服务,然后才能卸载该文件系统。
自动化安装
您可能已经注意到,您的其他分区不需要手动挂载。当您启动主机时,它们已经被装载。这是启动过程的一部分。您希望在启动时自动挂载的每个分区都需要在/etc/fstab
文件中列出。清单 9-8 显示了来自我们 Ubuntu 主机的一个。
# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# <file system> <mount point> <type> <options> <dump> <pass>
/dev/mapper/au--mel--ubuntu--1--vg-root / ext4 errors=remount-ro 0 1
# /boot was on /dev/sda1 during installation
UUID=d036bc4a-6f9b-4989-a377-7778a29bf16c /boot ext2 defaults 0 2
/dev/mapper/au--mel--ubuntu--1--vg-swap_1 none swap sw 0 0
Listing 9-8.An fstab File
文件中的每一行由六个字段组成,由空格或制表符分隔。这些字段指定了每个文件系统的挂载方式和位置,以及在执行检查时应该做什么。所有以散列符号(#)
开始的行都是注释。
文件系统字段包含要挂载的文件系统的设备节点名称。您还可以通过指定LABEL=label
或文件系统 UUID 来替换文件系统标签,如示例所示。我们将使用 UUID 引用,因为即使以不同的顺序检测到磁盘,它们也不会改变,因此可能会以不同的方式命名。Ubuntu 将原始设备节点名放在正上方一行的注释中。接下来是挂载点,它只是文件系统上任意位置的一个目录。挂载点可以位于也是单独挂载的分区上。
Tip
请记住,/etc/fstab
文件中的条目是按照从上到下的顺序处理的。
文件系统类型告诉系统预期的类型。如果不匹配,装载将会失败。您可以指定要尝试的逗号分隔的类型列表,例如 DVD-ROM 驱动器/dev/scd0
。这将首先尝试udf
DVD 文件系统,然后尝试 CD-r om 使用的iso9660
。
挂载选项也以逗号分隔的列表形式传递。在我们的示例fstab
中,您可以看到 ext4 文件系统使用了两种不同的选项。选项errors=remount-ro,
控制文件系统出错时会发生什么。在这种情况下,文件系统将立即以只读模式挂载。这可以防止额外的数据损坏,同时保持文件对服务和用户可读。
错误行为的另外两个可能值是continue
,这将导致系统写入一个日志条目,但忽略问题,以及panic
,这将导致系统不正常地崩溃。默认的错误行为也可以通过tune2fs -e
命令在文件系统中指定。在清单 9-5 中,我们向您展示了如何使用tune2fs
来列出选项,对根挂载“/”这样做表明使用了以下默认挂载选项:
Default mount options: user_xattr acl
user_xattr
是允许支持“用户”扩展属性(可用于提高文件系统的安全性,有关更多详细信息,请参见 man attr)。acl 选项允许使用 posix acl,这同样可以用于细粒度的目录访问(有关详细信息,请参见 man acl)。
还有许多挂载选项,用于定义对文件系统上的文件和目录的访问,这可能会调整性能,还有一些选项用于不支持 Unix 风格的文件权限的文件系统,如 FAT32 和 NTFS。每个支持的文件系统的选项可以在mount
手册页中找到。
dump 字段包含一个数字(0 或 1),它告诉系统在执行文件系统检查时是否转储某些文件系统元信息。文件系统修复工具可以使用这些转储信息。0
意味着文件系统不需要被转储。我们将在后面的“从失败中恢复”一节中更详细地介绍这一点
最后,pass 字段用于确定检查文件系统的顺序。在我们的fstab
文件中,根文件系统被列为 1,所以首先检查它。之后,将检查/boot
文件系统。最后检查该列中带有0
的文件系统。您可以在fstab
手册页上找到这些字段的详细描述。
将分区添加到/etc/fstab
为了将您的新分区添加到我们的/etc/fstab
中,我们将把我们的设备 id(设备路径、标签或 UUID)映射到我们的挂载点。我们将使用 UUID,因此我们需要知道它的 UUID。
您可以在 Ext 文件系统的tune2fs -l
清单中找到它,XFS 文件系统的xfs_admin -u
清单,BtrFS 的btrfs filesystem show
清单,或者您可以使用blkid
实用程序。如果您不带任何参数运行后者,它将打印所有检测到的块设备的 UUID,如清单 9-9 所示。
$ sudo blkid
/dev/mapper/sda5_crypt: UUID="MdUlYF-y6Ol-XcB5-mS9L-mxPN-jNLF-ATAImA" TYPE="LVM2_member"
/dev/mapper/au--mel--ubuntu--1--vg-root: UUID="0b9eec02-06a4-46e4-b9ac-1e1ea871ff89" TYPE="ext4"
/dev/sda1: UUID="d036bc4a-6f9b-4989-a377-7778a29bf16c" TYPE="ext2" PARTUUID="105922fd-01"
/dev/sda5: UUID="33dcd288-27f0-4f09-ab74-617db851a552" TYPE="crypto_LUKS" PARTUUID="105922fd-05"
/dev/mapper/au--mel--ubuntu--1--vg-swap_1: UUID="e45b953f-284f-45f5-b16d-8f5be5d5a970" TYPE="swap"
/dev/sdb2: LABEL="mail" UUID="71bd5774-33cb-491b-8ffe-49cb33935001" TYPE="ext4" PARTLABEL="Linux filesystem" PARTUUID="b704ec19-833d-4727-a572-189f214f2ecf"
/dev/sdb1: UUID="6d0ce2f6-f9f6-4ac2-91f6-3099a40d5624" TYPE="swap" PARTLABEL="Linux swap" PARTUUID="db962e77-53f3-4cfe-847c-f53133f063f7"
/dev/sdb3: UUID="ccd60fc3-bbaf-40e5-a93e-43743f9176d9" TYPE="xfs" PARTLABEL="Linux filesystem" PARTUUID="f9d90e5f-0186-4cd5-a2be-9b89e7286abb"
Listing 9-9.Displaying All UUIDs
要让它只打印单个设备的 UUID,请将设备节点名作为参数传递,比如
$ sudo blkid /dev/sdb2
要使用默认挂载选项挂载 ext4 分区(uuid
命令也会打印文件系统类型),请在/etc/fstab
文件中添加下面一行:
UUID="71bd5774-33cb-491b-8ffe-49cb33935001" /mnt/data ext4 defaults 0 0
在挂载 ext4 文件系统时,“defaults”选项为我们提供了以下挂载选项。它们是rw
,读/写;relatime
,这意味着系统相对于修改或更改时间更新信息节点访问时间(一种性能改进);以及data=ordered
,这意味着系统将首先将数据写入主文件系统,然后将元数据提交给日志。
如果您想使用设备节点,可以执行以下操作。但是,我们更希望您使用标签或 UUID,因为设备路径可能会改变。
/dev/sdb2 /mnt/data ext4 defaults 0 0
现在,您可以测试这个条目,而不需要重新启动。如果您使用mount
命令,并且只将挂载点作为参数传递,它将检查/etc/fstab
文件中的匹配条目,并使用文件中指定的选项挂载它。
$ sudo mount /mnt/data
如果mount
命令退出而没有显示任何错误,那么fstab
条目是正确的,并且您的文件系统将在您每次引导主机时自动挂载。如果您传递文件系统类型,比如用一个mount -t ext4
,它将挂载所有的 ext4 文件系统。你可以用一个mount –a
挂载fstab
文件中的所有挂载点。您可以通过运行清单 9-10 中的mount
来仔细检查文件系统是否已经挂载。
$ sudo mount –t ext4
/dev/mapper/au--mel--ubuntu--1--vg-root on / type ext4 (rw,relatime,errors=remount-ro,data=ordered)
/dev/sdb2 on /mnt/data type ext4 (rw,relatime,data=ordered)
Listing 9-10.All Mounted Filesystems
我们使用参数–t ext 4 在输出中只指定 ext4 fs-types,您可以看到我们的/dev/sdb2
挂载在/mnt/data
上。或者,要添加 XFS 分区,创建挂载点目录并将正确的 UUID 或设备节点名称和文件系统类型添加到/etc/fstab
:
UUID="ccd60fc3-bbaf-40e5-a93e-43743f9176d9" /mnt/data2 xfs defaults 0 0
Caution
文件fstab
中的错误可能会导致系统无法启动。如果是这样,您可能需要遵循“从故障中恢复”一节中讨论的一些步骤,或者使用第六章中描述的单用户模式来引导并修复错误。
内核可能没有注册文件系统上的 UUID 已经改变。如果发生这种情况,尝试使用 UUID 引用来装载文件系统将导致如下错误:
$ sudo mount /mnt/datax
mount: special device /dev/disk/by-uuid/ccd60fc3-bbaf-40e5-a93e-43743f9176d9
does not exist
您可以通过重新加载udev
服务来重新检测 UUID,并在/dev/disk/by-uuid
中创建正确的符号链接。我们可以通过以下方式做到这一点:
$ sudo udevadm control --reload
检查文件系统使用情况
当您开始使用文件系统进行数据存储时,您会希望能够留意可用空间的数量。当文件系统填满时,使用它的服务可能会拒绝启动、停止工作或崩溃。
您可以通过df
命令列出整个文件系统的空间使用情况,该命令通常与-h
选项一起使用。该选项产生人类可读的输出,用 KiB、MiB、GiB 或 TiB 的数字代替块,如清单 9-11 所示。
$ df -h
Filesystem Size Used Avail Use% Mounted on
udev 478M 0 478M 0% /dev
tmpfs 100M 4.6M 95M 5% /run
/dev/mapper/au--mel--ubuntu--1--vg-root 6.3G 2.6G 3.4G 44% /
tmpfs 497M 0 497M 0% /dev/shm
tmpfs 5.0M 0 5.0M 0% /run/lock
tmpfs 497M 0 497M 0% /sys/fs/cgroup
/dev/sda1 472M 147M 301M 33% /boot
tmpfs 100M 0 100M 0% /run/user/1000
/dev/sdb2 2.0G 3.0M 1.8G 1% /mnt/data
/dev/sdb3 4.0G 33M 4.0G 1% /mnt/data2
Listing 9-11.Filesystem Usage
输出显示了总大小、已用空间量和可用空间量,以及这相当于每个已挂载文件系统的百分比。这个命令很快,因为它只是查询文件系统元数据。如您所见,您还可以传递装载路径,以便只返回该装载的信息。
$ df -h /data
Filesystem Size Used Avail Use% Mounted on
/dev/sdb 16G 22M 14G 1% /data
Note
要检查索引节点的数量,请使用df -i
命令。当应用程序报告磁盘已满时,请使用此命令,即使显然还有大量剩余空间。
您可以使用du
命令检查目录及其包含的所有文件的累积大小。这个命令需要递归扫描运行它的目录下的文件,所以可能需要很长时间才能完成。我们将再次使用-h
选项来给出人类可读的输出。默认情况下,它还会打印每个子目录的大小。为了避免这种情况,我们传递了-s
选项,所以它只显示最终的总数。
$ du -sh *
2.5M Documents
44G src
这里我们列出并计算了主目录中的文件和目录。我们有两个目录,Documents 和 src,我们可以看到这些目录中每个文件的总大小。当我们尝试一个像/etc
目录这样的系统目录时会发生什么?
$ du -sh /etc
du: cannot read directory '/etc/ssl/private': Permission denied
du: cannot read directory '/etc/lvm/archive': Permission denied
du: cannot read directory '/etc/lvm/backup': Permission denied
du: cannot read directory '/etc/polkit-1/localauthority': Permission denied
7.0M /etc
因为它扫描/etc
中的子目录,所以该命令可能会遇到您无权访问的目录。它无法计算这些目录的大小,因此在这种情况下,它报告的总数是不正确的。为了总是得到正确的总数,您可以以root
用户的身份运行du
:
$ sudo du -sh /etc
7.0M /etc
虽然我们的结果中显示了相同的数量(7.0 M),但这是由于四舍五入的原因。如果我们使用–k
(代表 KiB)而不是–h
,我们会看到值分别为 7,084 和 7,116。如果文件系统已满,这对于确定将哪些目录移动到自己的分区很有帮助。另一种解决方案是调整文件系统的大小,我们很快就会谈到这一点。
Tip
在第 17 和 18 章中,当我们讨论监控和日志记录时,我们将讨论如何自动化文件系统监控。
袭击
将数据存储在硬盘上有助于保持数据在服务器上的可访问性,但是当硬盘出现故障时,您会丢失数据。有几种方法可以解决这个问题。一种是使用 LVM,它可以将多个磁盘分组并作为一个设备呈现,或者您可以使用 BtrFS,它可以做类似的事情。在本节中,我们将向您展示另一种替代方案,RAID。
RAID 允许您使用多个磁盘,就像它们是一个更大的磁盘一样,并具有可选的内置冗余。RAID 实施的三大类型如下:
- 硬件 RAID
- 假突袭
- 软件 RAID
硬件 RAID 使用专门的硬件控制器,通常称为 RAID 控制器,它从操作系统透明地管理 RAID。企业级服务器通常带有这些专用的硬件控制器。在这样的系统上,你通常会通过 BIOS(基本输入/输出系统)或 UEFI(统一可扩展固件接口)来配置 RAID(我们在第六章中简要讨论过)。Linux 将会看到一个 RAID 阵列,您可以像使用普通硬盘一样使用它。
伪 RAID 是一种较小形式的硬件 RAID,用于较小的系统或台式机。在这里,制造商可能已经通过芯片为主板添加了 RAID 功能。我们建议您不要使用假 RAID,因为使用此实现创建的任何 RAID 阵列都只能在共享相同控制器的主机上工作。它的性能还取决于制造商提供的专有代码。这些控制器通常可以配置为作为简单的串行 ATA 控制器运行,而不是 RAID。在 https://raid.wiki.kernel.org/index.php/DDF_Fake_RAID
可以找到最常见的假冒 RAID 控制器的简短列表。
Note
如果你用 Windows 设置了伪 RAID,并且想要双引导,你仍然可以通过 dmraid 系统在 Linux 下使用大多数伪 RAID 阵列。禁用假 RAID 会导致 Windows 停止工作,您可能会丢失数据。
第三种 RAID 实现类型是通过 Linux 内核中包含的软件。这个系统被称为 md 或多磁盘。md 系统的性能通常比假 RAID 好得多,并且 md RAID 阵列可以在主机之间转移。在本节中,我们将重点介绍 md RAID 的使用。
RAID 的类型
RAID 有几种类型或级别。你使用的级别取决于什么对你最重要。不同的级别提供了可用磁盘空间、可靠性和速度之间的平衡。表 9-5 列出了最常用的 RAID 级别。
表 9-5。
Commonly Used RAID Levels
| Raid 级别 | 功能 | 存储容量 | | --- | --- | --- | | RAID 0 | 速度 | N *尺寸 | | RAID 1 | 裁员 | N *尺寸/ 2 | | RAID 5 | 冗余,速度 | n-1 *大小 | | RAID 6 | 冗余、可靠性、速度 | n-1 *大小 | | RAID 10 | 冗余、可靠性、速度 | N / 2 *尺寸 | | RAID 50 | 冗余,速度 | n–1 *尺寸 |存储容量的计算方法是 raid 阵列中的 N(磁盘总数)(减去所有奇偶校验磁盘)乘以磁盘大小。你可以在 http://en.wikipedia.org/wiki/Redundant_array_of_independent_disks
找到 RAID 等级的详尽列表和描述。
使用一个硬盘作为备用也是很常见的。如果阵列中的一个磁盘出现故障,备用磁盘可以立即取代它的位置。
Note
没有任何备用设备也可以运行 RAID,但是您需要立即更换故障设备,以避免数据丢失。
条带化和镜像
使用 RAID 的最基本方式是使用两个磁盘,这使您可以选择使用 RAID 级别 0 或 RAID 级别 1。
RAID 0,也称为条带化,使 Linux 将两个磁盘视为两倍大小的组合磁盘。当向这样的 RAID 阵列写入数据时,部分数据将最终出现在每个磁盘上。因为这是 Linux 可以在两个磁盘上同时执行的操作,所以写入 RAID 0 比写入单个磁盘更快。但是,缺点是当其中一个磁盘出现故障时,分布在两个磁盘上的文件的任意部分都会消失。所以你丢失了所有的数据。
Caution
避免在服务器或任何保存持久数据的机器上使用 RAID 0。
RAID 1,也称为镜像,允许您在阵列上仅存储单个磁盘所能容纳的数据。它在两个磁盘上存储所有文件的相同副本,因此,如果一个磁盘出现故障,您仍可以从另一个磁盘检索数据。因为所有数据都需要写入每个磁盘,所以 RAID 1 没有提供任何改进的写入性能。
图 9-1 显示了使用 RAID 0 或 RAID 1 时文件是如何存储在磁盘上的。在 RAID 1 上,每个磁盘包含每个文件的完整副本。在 RAID 0 上,每个磁盘只包含每个文件的部分副本。
图 9-1。
RAID 0 and RAID 1 file storage
当您有更多的磁盘可以使用时,您将有更多的选项来选择 RAID 级别,从而提高性能并增加冗余。最简单的扩展是 RAID 1+0 (RAID 10),它使用多个 RAID 1 镜像作为 RAID 0 条带的元素。这样,所有条带化数据都保存到至少两个磁盘上,这为您提供了 RAID 0 速度和 RAID 1 冗余的优势。但是,您只能存储组合磁盘大小一半的数据。当磁盘既大又便宜,并且服务器中有足够的插槽来容纳至少四个磁盘时,这可能是一个不错的选择。
处理器拯救世界
为了获得最好的结果——冗余、存储容量和速度——你可以借助一些处理能力。RAID 级别 5 最少使用三个磁盘,可让您更有效地利用可用存储空间,并提高读写速度。它通过在多个磁盘上对数据进行分条并将每个分条的校验和写入不同的磁盘来实现这一点(也称为块奇偶校验-有关如何计算的详细信息,请参见 http://searchstorage.techtarget.com/definition/parity
)。如果磁盘出现故障,校验和可用于重建丢失条带中的数据。
权衡的结果是,这种方法使用处理能力来计算校验和。当数据写入阵列时,需要计算校验和并将其存储在其中一个磁盘上。如果一个磁盘出现故障,校验和可以与其余磁盘上的数据结合使用,以重新计算丢失的数据部分。你的 CPU 越快,这个过程就越快。
图 9-2 显示了一个简单的图表,说明了数据和校验和是如何在磁盘之间分割的。B1、B2 和 B3 是文件 b 的一部分。Bp 是校验和,即奇偶校验。如果磁盘 1 出现故障,可以从 B1、B3 和 Bp 计算 B2,因此当添加替换磁盘时,可以恢复其内容。
图 9-2。
RAID 5 stripe layout across multiple disks
请记住,使用 RAID 不能替代创建常规备份,这一点很重要。它将保护您免受硬件故障,但不会被故意删除。如果您不小心从 RAID 阵列中删除了一个文件,该文件将从阵列中的所有设备中删除。我们将在第十四章中讨论数据备份和恢复。
创建数组
您希望保护主机上的数据免受磁盘故障的影响,因此您希望在主机上使用 RAID。为了更好地概述常见的 RAID 级别,我们将向您展示 RAID 1 和 RAID 5。您使用哪一种取决于您可用的硬盘数量。首先,您需要确保至少有三个磁盘,并在所有磁盘上创建大小相同的分区。
Note
如果没有足够的磁盘来使用 RAID,您可以在单个磁盘上创建多个大小相同的分区,并将它们用作 RAID 阵列中的组件。这将允许您测试 RAID 安装和管理。请注意,这种配置的性能会非常慢,因为数据需要多次写入同一个磁盘的不同部分。它也不能提供更多的磁盘故障恢复能力。如果单个磁盘出现故障,那么您的 RAID 阵列也会出现故障。
在我们的示例主机上,我们将再次使用三个新磁盘,sdc、sdd 和 sde,它们的大小都相同。磁盘大小必须相同,RAID 才能工作,如果大小不同,您需要在相同大小的磁盘上创建分区。这里我们创建一个 2 G 分区,并将分区类型设置为 fd00–Linux RAID,如清单 9-12 所示。
$ sudo gdisk /dev/sdc
GPT fdisk (gdisk) version 0.8.6
Partition table scan:
MBR: not present
BSD: not present
APM: not present
GPT: not present
Creating new GPT entries.
Command (? for help): n
Partition number (1-128, default 1):
First sector (34-16777182, default = 2048) or {+-}size{KMGTP}:
Last sector (2048-16777182, default = 16777182) or {+-}size{KMGTP}: 2G
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): fd00
Changed type of partition to 'Linux RAID'
Command (? for help): w
Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
PARTITIONS!!
Do you want to proceed? (Y/N): y
OK; writing new GUID partition table (GPT) to /dev/sdc.
The operation has completed successfully.
Listing 9-12.Clearing the Partition Table and Creating a RAID Partition
您需要对/dev/sdd
和/dev/sde
重复这个过程。但是,如果您的磁盘都是相同大小的(因此最好是来自同一制造商的相同驱动器),则根本不需要对驱动器进行分区。因为我们的驱动器大小相同,所以我们不会先对它们进行分区。
现在,您已经准备好了三个磁盘,可以创建 RAID 阵列了。为此,您将需要 RAID 管理实用程序,它由mdadm
包提供。
管理 RAID 配置所有方面的命令也称为mdadm
,您可以通过模式选项指定它应该对您的阵列做什么。要创建一个阵列,您需要指定create
模式,您想要使用哪个 RAID 级别,以及哪些分区需要成为阵列的一部分。清单 9-13 展示了如何创建一个 RAID 1 阵列。
$ sudo mdadm --create /dev/md0 --level=raid1 --raid-devices=2 /dev/sdc /dev/sdd
--spare-devices=1 /dev/sde
mdadm: Note: this array has metadata at the start and
may not be suitable as a boot device. If you plan to
store '/boot' on this device please ensure that
your boot-loader understands md/v1.x metadata, or use
--metadata=0.90
Continue creating array? y
mdadm: Defaulting to version 1.2 metadata
mdadm: array /dev/md0 started.
Listing 9-13.Creating a RAID 1 Array with a Hot Spare
在这里,我们创建了一个名为/dev/md0
的可挂载设备,这是一个由两个分区/dev/sdc
和/dev/sdd
组成的RAID 1
设备,其中/dev/sde
作为热备盘。如果我们要从这个设备启动(例如,可能创建一个 MBR 分区并在其上安装 grub ),我们需要改变我们希望使用的元数据格式。我们可以通过指定- metadata=0.90 来实现(这是原始的超级块格式,更多细节请参见man mdadm
页)。
创建或启动 RAID 阵列将导致加载 md 内核模块并显示一些状态信息。您可以通过dmesg
查看内核日志,如清单 9-14 所示。
$ sudo dmesg
[ 9508.794689] md: bind<sdc>
[ 9508.795609] md: bind<sdd>
[ 9508.795996] md: bind<sde>
[ 9508.806492] md: raid1 personality registered for level 1
[ 9508.807304] md/raid1:md0: not clean -- starting background reconstruction
[ 9508.807306] md/raid1:md0: active with 2 out of 2 mirrors
[ 9508.807318] md0: detected capacity change from 0 to 8584626176
[ 9508.809302] RAID1 conf printout:
[ 9508.809305] --- wd:2 rd:2
[ 9508.809306] disk 0, wo:0, o:1, dev:sdc
[ 9508.809307] disk 1, wo:0, o:1, dev:sdd
[ 9508.812318] md: resync of RAID array md0
[ 9508.812320] md: minimum _guaranteed_ speed: 1000 KB/sec/disk.
[ 9508.812321] md: using maximum available idle IO bandwidth (but not more than 200000 KB/sec) for resync.
[ 9508.812323] md: using 128k window, over a total of 8383424k.
[ 9508.821845] md0: unknown partition table
[ 9550.509411] md: md0: resync done.
[ 9550.516479] RAID1 conf printout:
[ 9550.516481] --- wd:2 rd:2
[ 9550.516483] disk 0, wo:0, o:1, dev:sdc
[ 9550.516484] disk 1, wo:0, o:1, dev:sdd
[ 9550.517712] RAID1 conf printout:
[ 9550.517715] --- wd:2 rd:2
[ 9550.517716] disk 0, wo:0, o:1, dev:sdc
[ 9550.517717] disk 1, wo:0, o:1, dev:sdd
Listing 9-14.Kernel RAID Information
因为您的新阵列从未同步过,所以内核将首先确保两个磁盘上的数据是相同的。它会通知您它将尽可能快地执行同步,但不会慢于每个磁盘每秒 1,000 KB,并且总速度不会超过每秒 200,000 KB。
Tip
我们将在第十七章告诉你如何改变同步速度。
要检查我们的 RAID 设备的状态,您可以在查询模式下使用带有--detail
选项的mdadm
实用程序。这将显示关于指定 RAID 设备的大量信息,如清单 9-15 所示。
$ $ sudo mdadm --query --detail /dev/md0
/dev/md0:
Version : 1.2
Creation Time : Mon Jun 20 09:41:18 2016
Raid Level : raid1
Array Size : 8383424 (8.00 GiB 8.58 GB)
Used Dev Size : 8383424 (8.00 GiB 8.58 GB)
Raid Devices : 2
Total Devices : 3
Persistence : Superblock is persistent
Update Time : Mon Jun 20 09:42:00 2016
State : clean
Active Devices : 2
Working Devices : 3
Failed Devices : 0
Spare Devices : 1
Name : au-mel-centos-1.example.com:0 (local to host gateway.example.com)
UUID : ca66c4e2:49e8c87e:94d311de:01ca4f55
Events : 17
Number Major Minor RaidDevice State
0 8 33 0 active sync /dev/sdc
1 8 49 1 active sync /dev/sdd
2 8 65 - spare /dev/sde
Listing 9-15.Querying RAID Device Status
清单 9-15 显示了关于阵列的元信息,以及每个组件的详细状态。在我们的 RAID 1 阵列中,您可以看到/dev/sdc
和/dev/sdd
都处于活动状态并且同步。这意味着写入 RAID 设备的任何数据都会立即写入/dev/sdc
和/dev/sdd
。如果这些设备中的任何一个出现故障,我们的备用(/dev/sde)
将自动启动并同步。
您还可以通过查询/proc 文件系统来快速查看您的 RAID 设备:
$ cat /proc/mdstat
Personalities : [raid1]
md0 : active raid1 sde2 sdd[1] sdc[0]
8383424 blocks super 1.2 [2/2] [UU]
unused devices: <none>
我们可以看到[UU]
,这告诉我们两个设备[2/2]
都已启动。如果一个被降级或关闭,它可能会出现这样的[U_]
。设备指示其正被用作备用设备后的(S)
。
在引导时,您的 Linux 主机将调用mdadm
实用程序。根据其配置,该实用程序将扫描所有分区或已定义磁盘的 RAID 超级块。如果它发现任何,它将分析它们,并尝试组装和启动所有 RAID 阵列。您还可以在mdadm
配置文件中显式定义 RAID 阵列,以确保它们的设备节点名称不会改变。定义阵列的配置文件在 CentOS 上是/etc/mdadm.conf
,在 Ubuntu 上是/etc/mdadm/madadm.conf
。我们在清单 9-16 中包含了一个来自 Ubuntu 的默认mdadm.conf
文件。
# mdadm.conf
#
# Please refer to mdadm.conf(5) for information about this file.
#
# by default (built-in), scan all partitions (/proc/partitions) and all
# containers for MD superblocks. alternatively, specify devices to scan, using
# wildcards if desired.
#DEVICE partitions containers
# auto-create devices with Debian standard permissions
CREATE owner=root group=disk mode=0660 auto=yes
# automatically tag new arrays as belonging to the local system
HOMEHOST <system>
# instruct the monitoring daemon where to send mail alerts
MAILADDR root
# definitions of existing MD arrays
# This file was auto-generated on Tue, 10 May 2016 21:55:12 +1000
# by mkconf $Id$
Listing 9-16.Default mdadm.conf
这个配置文件将使主机在启动时扫描阵列,并创建属于root
用户和磁盘组的设备节点,就像普通硬盘驱动器一样。它指定当mdadm
在监控模式下运行时,任何关于设备故障的电子邮件都会发送给root
用户。
Note
我们将在第十二章中向您展示如何将root
用户的所有电子邮件重定向到不同的地址。
最后,还有一个空间可以添加 RAID 阵列的配置。您将在这里为您的 RAID 1 阵列添加一个定义。根据mdadm.conf
手册页,您需要以下内容:
ARRAY /dev/md0 level=raid1 num-devices=2 spares=1
UUID=ca66c4e2:49e8c87e:94d311de:01ca4f55 devices=/dev/sdc,/dev/sdd,/dev/sde
注意,添加这个数组定义并不是绝对必要的。mdadm
将自动检测和组装阵列,即使您在配置文件中没有这个阵列定义。
我们已经提到,如果事件发生,mdadm
将向root
用户发送电子邮件。稍后,当我们开始让阵列中的设备出现故障时,我们将向您展示一个示例。
The /Proc Filesystem
你可能已经注意到本章中提到了一个名为/proc
的目录。这是一个特殊的目录,包含内存文件系统中的虚拟或伪目录,提供了一种与内核交互的方式。例如,您可以通过cat /proc/cpuinfo
获得关于主机处理器的信息,或者您可以通过发出echo 1 > /proc/sys/net/ipv4/ip_forward
来改变内核网络栈以转发 IPv4 包。
内部内核变量可以通过/proc/sys
目录下的文件访问。我们将在第十七章回到这些。
/proc
文件系统实际上并不存在于磁盘上,所以它不使用任何空间,即使它看起来包含一些非常大的文件。
你可以在 http://en.wikipedia.org/wiki/Procfs
阅读更多关于/proc
文件系统的内容。
如果您至少有四个硬盘,您可以创建一个 RAID 5 阵列。这样做可以让您更有效地使用可用的存储空间,在某些情况下,还可以提高性能。要创建新的 RAID 5 阵列,您需要首先拆卸 RAID 1 阵列。通过停止它,您可以释放它使用的所有设备:
$ sudo mdadm --manage /dev/md0 --stop
mdadm: stopped /dev/md0
现在,您可以将这些设备用于新的 RAID 5 阵列。注意删除添加到mdadm.conf
文件中的条目。您将添加一个磁盘/dev/sdf
,并在其上创建一个类型为“Linux RAID”的主分区。
完成后,您可以创建一个 RAID 5 阵列,其中有三个活动设备和一个备用设备,如清单 9-17 所示。
$ sudo mdadm --create /dev/md0 --level=raid5 --raid-devices=3 --spare-devices=1 /dev/sdc /dev/sdd /dev/sde /dev/sdf
mdadm: /dev/sdc appears to be part of a raid array:
level=raid1 devices=2 ctime=Mon Jun 20 09:41:18 2016
mdadm: /dev/sdd appears to be part of a raid array:
level=raid1 devices=2 ctime=Mon Jun 20 09:41:18 2016
mdadm: /dev/sde appears to be part of a raid array:
level=raid1 devices=2 ctime=Mon Jun 20 09:41:18 2016
Continue creating array? y
mdadm: Defaulting to version 1.2 metadata
mdadm: array /dev/md0 started.
Listing 9-17.Creating a RAID 5 Array
其中一些设备是以前的 RAID 1 阵列的一部分,它们仍然包含带有阵列信息的旧 RAID 超级块。您想要创建一个新的阵列,覆盖旧的数据,所以回答 y。因为旧的 RAID 1 阵列是同步的,所以所有设备现在都包含一个文件系统,即使您最初只在/dev/sdc 上创建了一个文件系统。您可以通过/proc/mdstat
再次检查阵列状态。
$ cat /proc/mdstat
Personalities : [raid1] [raid6] [raid5] [raid4]
md0 : active raid5 sde[4] sdf3 sdd[1] sdc[0]
16765952 blocks super 1.2 level 5, 512k chunk, algorithm 2 [3/2] [UU_]
[===>.................] recovery = 15.2% (1280840/8382976) finish=0.7min speed=160105K/sec
在这里,您可以看到我们有[3/2][UU_],这意味着其中两个驱动器运行正常,另一个驱动器已降级但正在恢复,这意味着它正在获取将数据放入 RAID 阵列所需的数据拷贝。在此系统上,阵列启动不需要很长时间。
$ cat /proc/mdstat
Personalities : [raid1] [raid6] [raid5] [raid4]
md0 : active raid5 sde[4] sdf3 sdd[1] sdc[0]
16765952 blocks super 1.2 level 5, 512k chunk, algorithm 2 [3/3] [UUU]
现在,您有了一个 RAID 5 阵列,其中有三个活动设备和一个备用设备。如果您有足够的硬盘,您也可以增加 RAID 5 阵列的大小。这将导致数据被转移,校验和被重新计算,因此需要一些时间来完成。您将向您的主机添加第六个磁盘/dev/sdg
,这样您就可以扩展阵列,并且仍然有一个备用设备可用。然后,您可以将新设备添加到您的阵列中,并通过--add
选项在管理模式下使用 mdadm 扩展阵列,如清单 9-18 所示。
$ sudo mdadm --manage /dev/md0 --add /dev/sdg
mdadm: added /dev/sdf
Listing 9-18.Expanding a RAID 5 Array
要在一个命令中添加多个设备,只需在--add
选项后列出所有设备。快速检查/proc/mdstat
现在显示 sde1 和 sdf1 都被列为备件。
$ cat /proc/mdstat
Personalities : [raid1] [raid6] [raid5] [raid4]
md0 : active raid5 sdg5 sde[4] sdf3 sdd[1] sdc[0]
16765952 blocks super 1.2 level 5, 512k chunk, algorithm 2 [3/3] [UUU]
unused devices: <none>
现在,您可以在增长模式下使用 mdadm 将阵列从三个活动磁盘扩展到四个。其中一个备件将自动用于此目的。此过程的一部分是破坏性的,因此如果在扩展阵列时发生电源故障,您可能会丢失数据。为了防止这种情况,指定--backup-file
选项。确保不要将该备份文件存储在/tmp
目录中,该目录在启动时会被清空!
$ sudo mdadm --grow /dev/md0 --raid-disks=4 --backup-file=/root/raid-backup-file
mdadm: Need to backup 384K of critical section..
mdadm: ... critical section passed.
您可以再次通过/proc/mdstat
文件关注进度。
$ cat /proc/mdstat
Personalities : [linear] [multipath] [raid0] [raid1] [raid6] [raid5] [raid4]
[raid10]
md0 : active raid5 sdg15 sde1[4] sdf1[3] sdd1[1] sdc1[0]
16771584 blocks super 0.91 level 5, 64k chunk, algorithm 2 [4/4] [UUUU]
[=======>.............] reshape = 35.8% (3008512/8385792) finish=22.2min
speed=4022K/sec
unused devices: <none>
现在,您有四个活动设备和一个备用设备。在整形完成之前,无法访问数组的完整新大小。如您所见,整形运行的速度比 RAID 1 重新同步慢得多。
Tip
不用手动重新运行cat /proc/mdstat
命令,您可以通过watch
命令以指定的时间间隔自动运行它。登录第二个控制台,运行watch –n 5 cat /proc/ mdstat
,每五秒钟自动运行一次命令。按 Ctrl+C 退出watch
我们将在“从故障中恢复”一节中再次讨论 RAID,并向您展示如何处理磁盘故障关于 Linux 上 md RAID 的更多信息,可以访问 http://linux-raid.osdl.org/index.php/Linux_Raid
。
接下来,我们将向您展示如何利用这些 RAID 设备,而无需对它们进行分区。
逻辑卷管理
我们已经看到了如何对磁盘进行分区,并在磁盘上创建不同的文件系统。问题是,一旦对磁盘进行分区,就很难调整分区大小或添加额外的分区。即使您添加了磁盘和分区,您的数据也可能分布在不同的位置和目录中。这使得整合、备份和管理您的数据变得更加困难,并且有可能使您的用户更难找到他们的数据。为了解决这个问题,创建了逻辑卷管理(LVM)。
LVM 将一个或多个分区或设备合并成一个逻辑卷组,而不是将磁盘分割成固定数量的分区,存储在磁盘的固定区域。然后,您可以动态地创建、调整和删除卷组中的卷,从而无需卸载卷或重新启动系统来更新分区图。
LVM 系统有三层。底层由物理卷组成:磁盘、分区或 RAID 阵列。物理卷用于创建卷组。卷组可以由一个或多个物理卷组成。最后,卷组可以包含任意数量的逻辑卷,这些逻辑卷是分区的 LVM 等价物。
Ubuntu 和 CentOS 都有一个图形用户界面(GUI),可以用来管理磁盘,但它们不支持 LVM(有一个应用程序叫做“disks”)。我们将带您通过命令行进行管理,从 LVM 卷和组开始。
创建组和卷
如果想使用 LVM 分区,需要使用 gdisk 将其类型设置为8e00 - Linux LVM
。您也可以使用整个磁盘或 RAID 阵列作为 LVM 的存储。这很方便,因为您通常不会在软件 RAID 阵列上创建分区。
对于我们的示例,我们将在前面创建的 RAID 5 阵列上设置 LVM。在 RAID 1、单个分区或整个磁盘上设置 LVM 时,步骤是相同的。
LVM 使用的每个存储设备都称为一个物理卷(PV)。您可以通过pvcreate
命令对设备进行标记。
$ sudo pvcreate /dev/md0
Physical volume "/dev/md0" successfully created
这个命令在设备的开头写一个小水印,标识它用于 LVM。您可以通过pvs
命令列出系统中的所有此类设备。
$ sudo pvs
PV VG Fmt Attr PSize PFree
/dev/md0 lvm2 --- 15.99g 15.99g
/dev/sda2 centos lvm2 a-- 7.51g 40.00m
Note
如果使用pvdisplay
命令,您将获得关于物理卷的更多详细信息。
回想一下,当我们第一次安装 CentOS 系统时,我们选择了使用 LVM。您现在可以看到,它使用了/dev/sda2
分区作为物理卷。第二列标记为 VG,表示卷组,这是 LVM 系统中的下一层。
您可以通过vgs
命令列出系统上的所有卷组。
$ sudo vgs
VG #PV #LV #SN Attr VSize VFree
centos 1 2 0 wz--n- 7.51g 40.00m
Note
如果使用vgdisplay
命令,您将获得更多关于卷组的详细信息。
有一个名为centos
的卷组,是由安装程序创建的。它跨越一个物理卷,包含两个逻辑卷。您可以通过lvs
命令列出这些。目前有两卷,root
和swap_1
。
$ sudo lvs
LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert
root centos -wi-ao--- 6.67g
swap centos -wi-ao--- 820.00m
Note
如果使用lvdisplay
命令,您将获得更多关于逻辑卷的详细信息。
现在,您可以通过vgextend
命令将您的物理卷添加到现有组中:
$ sudo vgextend centos /dev/md0
Volume group "centos" successfully extended
为了进行检查,您可以使用pvs
和vgs
来显示物理卷。
$ sudo pvs
PV VG Fmt Attr PSize PFree
/dev/md0 centos lvm2 a-- 15.99g 15.99g
/dev/sda2 centos lvm2 a-- 7.51g 40.00m
$ sudo vgs
VG #PV #LV #SN Attr VSize VFree
centos 2 2 0 wz--n- 23.50g 16.03g
新的物理卷现在是centos
卷组的一部分。将新的物理卷添加到组中意味着它现在有 23.50 GiB 的未分配空间。
另一种方法是创建一个新的卷组,并使用您的物理卷。您仍然可以通过vgreduce
命令从centos
组中移除/dev/md0
来完成:
$ sudo vgreduce centos /dev/md0
Removed "/dev/md0" from volume group "centos"
它现在可用于不同的卷组,该卷组是使用vgcreate
命令创建的。您将把/dev/md0
设备分配给新的raid-volume
卷组。完成后,您可以使用vgs
命令检查新卷组是否存在。
$ sudo vgcreate raid-volume /dev/md0
Volume group "raid-volume" successfully created
$ sudo vgs
VG #PV #LV #SN Attr VSize VFree
centos 1 2 0 wz--n- 7.51g 40.00m
raid-volume 1 0 0 wz--n- 15.99g 15.99g
现在您有了一个新的卷组,可以用来创建逻辑卷。为了准备后面的章节,我们为什么不为网站创建一个存储区呢?有了 LVM,我们可以很容易地在磁盘上给每个函数分配一个专用的区域。
首先,您需要创建一个逻辑卷,这可以通过lvcreate
命令来完成。您需要指定名称、大小和要在其中创建卷的卷组。然后您可以通过lvs
将其列出。
$ sudo lvcreate --name www --size 2G raid-volume
Logical volume "www" created
$ sudo lvs
LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert
root centos -wi-ao---- 6.67g
swap centos -wi-ao---- 820.00m
www raid-volume -wi-a----- 2.00g
现在剩下要做的就是在逻辑卷上创建一个文件系统,并将其挂载到某个地方。为此,您需要逻辑卷的设备节点名。这由名为 device-mapper 的驱动程序管理,它为您创建的任何卷创建一个设备节点条目。
逻辑卷可通过/dev/mapper/<vgname>-<lvname>
访问,从/dev/<vgname>/<lvname>
开始进行符号链接。所以对于新“www”的吕,可以使用/dev/raid-volume/www
。我们将使用以下内容为这个逻辑卷创建一个 XFS 文件系统:
$ sudo mkfs.xfs /dev/raid-volume/www
您可以像使用普通分区一样使用该卷,并将其添加到/etc/fstab
文件中,这样当您的主机启动时,它会自动挂载到/var/www
上。为此,您可以使用设备节点名或刚刚创建的文件系统的 UUID。blkid 会为你提供这两者。/etc/fstab
条目如下所示:
# /dev/mapper/raid--volume-www
UUID=0814d564-b61c-407a-8483-9b176c684816 /var/www xfs defaults 0 0
创建了/var/www
目录后,可以使用以下命令挂载它:
$ sudo mount /var/www
扩展逻辑卷
到目前为止,使用 LVM 似乎只是一种更复杂的磁盘使用方式,但是如果您的网站超过 2gb 会怎样呢?如果没有 LVM,您将需要在一个未使用的磁盘上创建一个分区,然后复制所有数据并确保/etc/fstab
得到更新。然而,使用 LVM,您可以简单地扩展逻辑卷,然后在其上调整文件系统的大小。如果卷组中没有剩余空间,您可以先向组中添加一个物理卷。
您需要完成两个步骤来安全地调整逻辑卷中包含的文件系统的大小。首先,您需要调整逻辑卷本身的大小,其次,您需要调整文件系统的大小。LVM 可以为你做这些,我们很快会告诉你怎么做。
可以使用lvextend
命令扩展卷。您需要指定新的总大小或所需的大小增量,以及卷的名称。通过在 size 参数前加+前缀,可以表明您希望将指定的大小添加到现有大小中。
$ sudo lvextend --size +2G --resizefs /dev/raid-volume/www
Size of logical volume raid-volume/wwwl changed from 2.00 GiB (512 extents) to 4.00 GiB (1024 extents).
Logical volume spool successfully resized.
meta-data=/dev/mapper/raid--volume-www isize = 256 agcount=4, agsize=131072 blks
= ectsz=512 attr=2, projid32bit=1
= crc=0 finobt=0
data = bsize=4096 blocks=524288, imaxpct=25
= sunit=0 swidth=0 blks
naming = version 2 bsize=4096 ascii-ci=0 ftype=0
log = internal bsize=4096 blocks=2560, version=2
= sectsz=512 sunit=0 blks, lazy-count=1
realtime = none extsz=4096 blocks=0, rtextents=0
data blocks changed from 524288 to 1048576
如您所见,我们已经指定要向/dev/raid-volume/www
逻辑卷添加 2 G ( +2G
)。我们也希望它能为我们调整大小(--resizefs
。这告诉 LVM 只需在调整逻辑卷大小后执行xfs_growfs
。
Note
在调整文件系统大小时,您会受到文件系统功能的限制——lvextend 和 lvreduce 使用底层的文件系统工具来调整文件系统的大小,不需要添加任何特殊的东西。因此,您将能够使用 LVM 扩展和缩减 Ext 系列的文件系统,但只能扩展 XFS,因为您不能缩减 XFS 文件系统。
要指定新的总大小,您也可以使用以下命令,而不是将 2G 添加到卷中:
$ sudo lvextend -s 4G /dev/raid-volume/www
Size of logical volume raid-volume/www changed from 2.00 GiB (512 extents) to 4.00 GiB (1024 extents).
Logical volume www successfully resized.
在这种情况下,两种方法产生相同的结果:逻辑卷 4 GiB。但是,在这种情况下,我们没有告诉 lvmextend 调整文件系统的大小,因此文件系统的大小仍然是 2gb。虽然我们可以让 lvextend 使用–r
(或--resize
)选项来调整文件系统的大小,但是我们将自己手动完成。
我们现在将告诉文件系统它所包含的设备的新大小,为此您可以使用xfs_growfs
实用程序。如果我们有一个 Ext4 文件系统,我们将使用resize2fs
实用程序。您将从一个 2 GiB 的文件系统开始,如清单 9-19 所示。
$ df -h /var/www
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/raid--volume-www 2.0G 135M 1.9G 7% /var/www
$ sudo xfs_growfs /dev/raid-volume/www
meta-data=/dev/mapper/raid--volume-www isize=256 agcount=8, agsize=65408 blks
= sectsz=512 attr=2, projid32bit=1
= crc=0 finobt=0
data = bsize=4096 blocks=523264, imaxpct=25
= sunit=128 swidth=256 blks
naming =version 2 bsize=4096 ascii-ci=0 ftype=0
log =internal bsize=4096 blocks=2560, version=2
= sectsz=512 sunit=8 blks, lazy-count=1
realtime =none extsz=4096 blocks=0, rtextents=0
data blocks changed from 523264 to 1048576
$ df -h /var/www
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/raid--volume-www 4.0G 136M 4.0G 3% /var/www
Listing 9-19.Resizing an Ext3 Filesystem
现在您有了一个 4 GiB 的文件系统。
缩小逻辑卷
除了扩展文件系统之外,您还可以收缩一些文件系统。要收缩文件系统和逻辑卷,可以反向执行前面的步骤,并使用lvreduce
命令。只需确保不要将逻辑卷缩小到比它包含的文件系统更小。
我们创建了一个新的 4g LVM 组和 LVM 卷。我们将其格式化为 Ext4 文件系统,并准备将其大小调整为 2 G。与增加文件系统不同,如果您正在减少的卷已装入,以下命令将卸载并重新装入它。
$ sudo lvreduce --size -2G -r /dev/vg-mail/spool
Do you want to unmount "/tmp/block"? [Y|n] y
fsck from util-linux 2.23.2
/dev/mapper/vg--mail-spool: 11/262144 files (0.0% non-contiguous), 53326/1048576 blocks
resize2fs 1.42.9 (28-Dec-2013)
Resizing the filesystem on /dev/mapper/vg--mail-spool to 524288 (4k) blocks.
The filesystem on /dev/mapper/vg--mail-spool is now 524288 blocks long.
Size of logical volume vg-mail/spool changed from 4.00 GiB (1024 extents) to 2.00 GiB (512 extents).
Logical volume spool successfully resized.
现在我们的文件系统已经减少了。
$ df -h /tmp/block
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/vg--mail-spool 1.9G 12M 1.8G 1% /var/spool
LVM 命令
虽然这比简单的分区要多做一点工作,但是 LVM 允许你以更灵活的方式使用你的存储空间。表 9-6 列出了你最常用的 LVM 命令。
表 9-6。
Basic LVM Commands
| 命令 | 用于 | | --- | --- | | `pvcreate` | 与 LVM 一起使用的标签装置 | | `pvremove` | 从物理卷中删除 LVM 标签 | | `pvdisplay / pvs` | 显示系统上指定设备或所有物理卷的信息 | | `vgcreate` | 创建新的卷组 | | `vgremove` | 移除(删除)卷组 | | `vgextend` | 向卷组添加物理卷 | | `vgreduce` | 从卷组中删除物理卷 | | `vgdisplay / vgs` | 显示系统上指定组或所有卷组的信息 | | `lvcreate` | 创建新的逻辑卷 | | `lvremove` | 移除(删除)逻辑卷 | | `lvextend` | 增加逻辑卷的大小 | | `lvreduce` | 减小逻辑卷的大小 | | `lvdisplay / lvs` | 显示系统上或指定卷组中的所有逻辑卷 |从失败中恢复
如果您的主机发生崩溃,导致文件系统处于不一致的状态,系统将在引导时自动尝试修复问题。图 9-3 显示了我们主机上的根文件系统是如何被自动检查的,以及/dev/mapper/au--mel--ubuntu--1--vg--root
上的日志是如何在崩溃后被重放的。
图 9-3。
Automatic filesystem recovery
虽然我们不建议这样做,但是您可以通过在引导时将fsck.mode=force
添加到内核来强制您的系统在引导时运行fsck
,或者通过编辑 grub 永久地运行,或者通过中断引导并通过 grub 控制台添加来一次性关闭。根据文件系统的大小,fsck
可能会花费大量的时间——长达几个小时!这些自动恢复通常是有效的,但是有时修复工具会发现他们不能自动修复的问题。
如果存储修复实用程序的根文件系统出现这种情况,您可以尝试使用 systemd 紧急目标(systemctl emergency
)或者需要从安装 DVD 或 USB 引导。你可能还记得第二章中,从 DVD 或 USB 引导包括一个选择,以救援或恢复模式引导。这种模式从安装盘引导至最小系统,并让您进入根 shell。从这个 shell 中,您可以执行恢复文件系统所需的任何步骤。我们稍后将更详细地解释引导至救援模式。
最简单的步骤是运行适当的文件系统检查器。表 9-7 详细说明了您最可能使用的文件系统的系统检查和修复工具。
表 9-7。
Filesystem Check and Repair Tools
| 文件系统 | 修理工具 | | --- | --- | | Ext2、ext3 和 ext4 | `e2fsck or its aliases fsck.ext2, fsck.ext3 or fsck.ext4` | | XFS | `xfs_repair` | | btr 护堤 | `btrfs check --repair ` |要运行这些修复工具,您需要确保您正在检查的文件系统不是为了写入而挂载的。修复以读/写模式挂载的文件系统肯定会破坏数据,因为修复工具会直接修改文件系统,而内核对此一无所知。
要检查文件系统,需要将适当的设备节点名作为参数传递给修复工具。
Note
当通过从根文件系统本身运行工具来修复根文件系统时,确保首先以只读方式挂载文件系统。
让我们带您了解一下我们的一个磁盘的问题。如果文件系统出现问题,系统将通知您文件系统无法挂载并进入维护模式,如图 9-4 所示。
图 9-4。
A filesystem problem prevents an automatic mount
您可以按 enter 键进入维护模式,在这种模式下,我们将查看日志日志(journalctl,它是 systemd 日志记录实用程序)。通过输入我们访问的journalctl –xb
,我们向消息(-x)添加了更多的细节,并指定了 boot (-b)。在图 9-5 中,我们看到了我们停止系统的原因。
图 9-5。
Error message on disk mount
我们可以看到,我们未能在/data 目录中挂载/dev/sdg1
。它说它找不到文件系统。我们将退出日志,并将手动运行fsck
检查(参见图 9-6 )。
图 9-6。
Manually running fsck
这里fsck
调用了 e2fsck 并试图修复文件系统。我们告诉它对所有问题都“假设是”(-y),因此它会自动尝试修复您的文件系统。我们现在可以重启我们的系统,或者用 ctrl-d 继续启动。
有时,ext2、ext3 或 ext4 文件系统的超级块出现问题,这意味着文件系统检查工具无法找到修复文件系统所需的文件系统元数据。因此,这些文件系统也保留备份超级块。您可以使用dumpe2fs
工具显示它们在磁盘上的位置,然后使用-b
选项为e2fsck
指定这个位置(使用另一个超级块),如清单 9-20 所示。
$ sudo dumpe2fs /dev/sdg1 | grep Backup
dumpe2fs 1.42.13 (17-May-2015)
Journal backup: inode blocks
Backup superblock at 32768, Group descriptors at 32769-32769
Backup superblock at 98304, Group descriptors at 98305-98305
Backup superblock at 163840, Group descriptors at 163841-163841
Backup superblock at 229376, Group descriptors at 229377-229377
Backup superblock at 294912, Group descriptors at 294913-294913
Backup superblock at 819200, Group descriptors at 819201-819201
Backup superblock at 884736, Group descriptors at 884737-884737
Backup superblock at 1605632, Group descriptors at 1605633-1605633
Listing 9-20.Finding Backup Superblocks
一旦您知道备份超级块的位置,您可以尝试运行e2fsck
并使用-b
选项指定备份超级块的位置。
$ sudo e2fsck -b 98304 -y /dev/sdg1
e2fsck 1.42.13 (17-May-2015)
/dev/sdg1 was not cleanly unmounted, check forced.
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/sdg1: ***** FILE SYSTEM WAS MODIFIED *****
/dev/sdg1: 11/524288 files (0.0% non-contiguous), 70287/2096891 blocks
e2fsck
命令现在可以运行并修复文件系统了。
如果出现问题,并且在索引节点中发现了e2fsck
无法放置的文件数据,这些数据将存储在您正在检查的文件系统上的lost+found
目录中的文件中。文件名是与数据相关联的索引节点号。虽然这并不能告诉您哪些文件已经不在它们应该在的位置,但是您可以手动检查这些编号的文件,并了解哪些数据可能丢失了。如果发生了大量损坏,并且在lost+found
目录中有数百个文件,那么从备份中恢复您的数据可能会更好。
引导加载程序问题
如果硬盘出现问题,系统可能会因为引导扇区损坏而完全无法引导。在这种情况下,引导加载程序无法启动,您会在屏幕上看到奇怪的错误,正如我们在第六章中向您展示的那样。
使用安装介质上的 Rescue 模式修复引导加载程序相当简单。如果由于某些问题需要重新安装引导加载程序,您可以使用安装介质(DVD、USB)并进入救援部分(参见图 9-7 )。
图 9-7。
Enter Rescue Mode
接下来,我们将经历一个类似的安装过程,就像我们第一次安装系统时执行的一样,注意,这是一个 Ubuntu 系统。进入救援模式的 CentOS 程序在概念上非常相似。
救援过程最终会扫描您的磁盘,并向您提供一个可能的根分区列表,您可以选择安装。在这个 Ubuntu 系统上,我们的根分区类似于图 9-8 所示:
图 9-8。
Selecting the root partition to mount
我们的根分区是 LVM 卷 au-mel-ubuntu-1-vg/root。我们选择该选项,然后进入救援菜单,如图 9-9 所示。
图 9-9。
The rescue menu
我们选择了重新安装 GRUB 引导加载程序,进入后,我们将看到下一个屏幕,选择我们希望安装 GRUB 的磁盘(参见图 9-10 )。
图 9-10。
Re-installing the GRUB boot loader
我们将把引导加载程序重新安装到我们的/dev/sda
设备上。如果我们使用 UEFI,我们将有一个不同的分区来安装引导加载程序。
您还可以挂载根分区并执行 shell 来修复您可能遇到的其他问题,比如执行其他类型的磁盘修复和维护。
从图 9-11 所示的救援菜单中选择以下选项:
图 9-11。
Opening a shell on the root partition
这向我们提出了几个问题,并告诉我们它在做什么(见图 9-12 )。
图 9-12。
Mount /boot ?
就像它说的那样,您的单独的引导分区可能已损坏,您可能不想在此时挂载它。相反,您可能希望保持未安装状态,然后对其运行e2fsck
以进行任何修复。在这种情况下,我们将挂载/boot 分区。
图 9-13 是信息性的,表示如果您将分区挂载到文件系统的其他区域,可能还需要挂载其他分区。您可以在这里继续,并采取任何必要的措施来挂载任何分区。
图 9-13。
Information about other mounts
现在我们有了救援 Shell(见图 9-14 )。这是您的系统通过 chroot 特别安装的。chroot 是一种特殊的坐骑,我们很快会解释。
图 9-14。
The rescue shell Rescue and Chroot
chroot 命令允许您运行“带有特殊根目录的命令或交互式 shell”当我们在救援模式下运行时,我们首先挂载我们的磁盘,然后使用 chroot 切换到我们挂载的设备上的根目录。这允许我们访问我们系统上的所有数据和命令,就像我们已经引导进入它一样。
当使用救援模式时,您可以改为进入“安装程序环境”并自己设置 chroot 环境。在运行chroot
之前,我们需要确保我们可以通过动态/dev
和/proc
文件系统访问设备文件和内核接口。我们可以将现有的挂载到根文件系统上,我们将通过绑定挂载在根文件系统上运行chroot
。绑定挂载是一种无需使用符号链接就可以在系统的多个位置使用目录的方式。在这种情况下,我们不能使用符号链接,因为它们会指向chroot
外部的目标,而从chroot
内部是无法访问的。
# mount –o bind /dev /mnt/dev
# mount –o bind /proc /mnt/proc
当绑定挂载完成后,我们可以chroot
到挂载的根文件系统,并在那里运行 Bash shell。这个提示看起来有点奇怪,因为 Bash 启动脚本不会运行。
# chroot /mnt && /bin/bash
bash-2 #
现在我们有了一个 shell,我们可以运行命令在第一个磁盘上重新安装引导加载程序。
bash-2 # /usr/bin/grub-install /dev/sda
完成后,我们从chroot
注销,并以相反的顺序卸载文件系统。如果我们不卸载它们,我们的固定根文件系统就不能被卸载,并且在我们下次启动时会再次强制检查。
bash-2 # exit
# umount /mnt/proc
# umount /mnt/dev
# umount /mnt
我们现在可以使用 Ctrl+Alt+Delete、reboot
命令或shutdown -r now
命令重新启动主机。移除安装介质,以便主机从硬盘启动。
有关 chroot 的更多信息,请参见 www.cyberciti.biz/faq/unix-linux-chroot-command-examples-usage-syntax/
。
磁盘故障
迟早你的一个硬盘会出故障。当您使用 RAID 时,这不再是一个问题,但是您将需要采取措施来确保阵列在下一个磁盘出现故障之前再次完全工作。正如您在本章前面所看到的,您可以将一个磁盘标记为备用磁盘,这将自动完成该过程的一部分。
为了模拟磁盘故障,我们将使用mdadm
告诉内核/dev/sdb1
已经发生故障,如清单 9-21 所示。
$ sudo mdadm --manage /dev/md127 --fail /dev/sdd1
mdadm: set /dev/sdd1 faulty in /dev/md127
Listing 9-21.Testing Our RAID Array
RAID 子系统现在知道设备出现了故障。这与 RAID 驱动程序检测到阵列中的某个设备出现错误时的情况相同。让我们再看一下/proc/mdstat
文件。
$ cat /proc/mdstat
Personalities : [raid6] [raid5] [raid4] [linear] [multipath] [raid0] [raid1] [raid10]
md127 : active raid5 sdc1[1] sde1[3] sdb1[0] sdf1[5] sdd14
25148928 blocks super 1.2 level 5, 512k chunk, algorithm 2 [4/3] [UU_U]
[======>..............] recovery = 34.0% (2852268/8382976) finish=2.3min speed=39764K/sec
unused devices: <none>
sdd1
磁盘现在用(F)
标记为故障,而我们的备用磁盘sdf1
正在更新。我们可以检查系统日志,以确保 RAID 监控器已经注意到这些变化并采取了适当的行动。我们可以使用journalctl –xb
命令来查看任何消息。
Jun 23 01:06:01 au-mel-ubuntu-1 kernel: md/raid:md127: Disk failure on sdd1, disabling device.
md/raid:md127: Operation continuing on 3 devices.
Jun 23 01:06:01 au-mel-ubuntu-1 kernel: RAID conf printout:
Jun 23 01:06:01 au-mel-ubuntu-1 kernel: --- level:5 rd:4 wd:3
Jun 23 01:06:01 au-mel-ubuntu-1 kernel: disk 0, o:1, dev:sdb1
Jun 23 01:06:01 au-mel-ubuntu-1 kernel: disk 1, o:1, dev:sdc1
Jun 23 01:06:01 au-mel-ubuntu-1 kernel: disk 2, o:0, dev:sdd1
Jun 23 01:06:01 au-mel-ubuntu-1 kernel: disk 3, o:1, dev:sdf1
Jun 23 01:06:01 au-mel-ubuntu-1 kernel: RAID conf printout:
Jun 23 01:06:01 au-mel-ubuntu-1 kernel: --- level:5 rd:4 wd:3
Jun 23 01:06:01 au-mel-ubuntu-1 kernel: disk 0, o:1, dev:sdb1
Jun 23 01:06:01 au-mel-ubuntu-1 kernel: disk 1, o:1, dev:sdc1
Jun 23 01:06:01 au-mel-ubuntu-1 kernel: disk 3, o:1, dev:sdf1
Jun 23 01:06:01 au-mel-ubuntu-1 kernel: RAID conf printout:
Jun 23 01:06:01 au-mel-ubuntu-1 kernel: --- level:5 rd:4 wd:3
Jun 23 01:06:01 au-mel-ubuntu-1 kernel: disk 0, o:1, dev:sdb1
Jun 23 01:06:01 au-mel-ubuntu-1 kernel: disk 1, o:1, dev:sdc1
Jun 23 01:06:01 au-mel-ubuntu-1 kernel: disk 2, o:1, dev:sde1
Jun 23 01:06:01 au-mel-ubuntu-1 kernel: disk 3, o:1, dev:sdf1
Jun 23 01:06:01 au-mel-ubuntu-1 kernel: md: recovery of RAID array md127
Jun 23 01:06:01 au-mel-ubuntu-1 kernel: md: minimum _guaranteed_ speed: 1000 KB/sec/disk.
Jun 23 01:06:01 au-mel-ubuntu-1 kernel: md: using maximum available idle IO bandwidth (but not more than 200000 KB/sec) for recovery.
Jun 23 01:06:01 au-mel-ubuntu-1 kernel: md: using 128k window, over a total of 8382976k.
重建完成后,我们应该会看到类似这样的内容:
Jun 23 01:09:21 au-mel-ubuntu-1 kernel: md: md127: recovery done.
Jun 23 01:09:21 au-mel-ubuntu-1 kernel: RAID conf printout:
Jun 23 01:09:21 au-mel-ubuntu-1 kernel: --- level:5 rd:4 wd:4
Jun 23 01:09:21 au-mel-ubuntu-1 kernel: disk 0, o:1, dev:sdb1
Jun 23 01:09:21 au-mel-ubuntu-1 kernel: disk 1, o:1, dev:sdc1
Jun 23 01:09:21 au-mel-ubuntu-1 kernel: disk 2, o:1, dev:sde1
Jun 23 01:09:21 au-mel-ubuntu-1 kernel: disk 3, o:1, dev:sdf1
Jun 23 01:09:21 au-mel-ubuntu-1 mdadm[1341]: RebuildFinished event detected on md device /dev/md127
Jun 23 01:09:21 au-mel-ubuntu-1 mdadm[1341]: SpareActive event detected on md device /dev/md127, component device /dev/sde1
太好了。监控器发现了故障,激活了备用设备,开始重建,并完成了阵列的重建。RAID 系统保护了我们的数据,阵列仍然完好无损。我们剩下要做的就是从阵列中移除故障磁盘,然后更换它。
首先,我们将调用mdadm
从 RAID 阵列中移除故障磁盘。
$ sudo mdadm --manage /dev/md127 --remove /dev/sdd1
mdadm: hot removed /dev/sdd1
下一步取决于你的硬盘控制器。如果它支持热插拔驱动器,您可以拔下损坏的磁盘并用新磁盘替换它。否则,您将不得不关闭主机,以物理方式更换驱动器。
安装新驱动器并启动主机后,您需要对新磁盘进行分区,因为阵列中有其他磁盘。新磁盘可能与它替换的磁盘具有相同的设备节点名称。分区完成后,您可以通过mdadm
将新分区添加到数组中,如清单 9-22 所示。
$ sudo mdadm --manage /dev/md127 --add /dev/sdd1
mdadm: added /dev/sdd1
$ cat /proc/mdstat
Personalities : [raid6] [raid5] [raid4] [linear] [multipath] [raid0] [raid1] [raid10]
md127 : active raid5 sdd14 sde1[6] sdc1[1] sdb1[0] sdf1[5]
25148928 blocks super 1.2 level 5, 512k chunk, algorithm 2 [4/4] [UUUU]
unused devices: <none>
Listing 9-22.Adding a New Device to a RAID Array
新磁盘作为备用磁盘添加,准备在另一个磁盘出现故障时接管。
有可能是某个问题阻止了 RAID 阵列自动启动。如果您从 DVD 或 USB 以救援模式启动,阵列可能也不会被检测到和启动。如果发生这种情况,您可以手动组装阵列。要从现有组件重新创建 RAID 阵列,请在汇编模式下使用mdadm
。这将尝试从您指定的组件组装阵列。有关更多信息,请查看mdadm
手册页。
摘要
在本章中,您学习了如何在 Linux 上管理存储,以及如何利用 RAID 和 LVM 最安全、最灵活地存储数据。
- 我们探索了 Ubuntu 和 CentOS 附带的不同文件系统
- 我们看了 XFS 的 ext4
- 我们看到了如何创建 Btrfs RAID 卷和子卷
- 我们看了安装和自动安装分区
- 我们学习了如何设置软件 RAID
- 我们查看了 LVM,并调整了卷和文件系统的大小。
- 在磁盘出现故障的情况下,您现在已经知道如何从 RAID 阵列中移除组件以及向其中添加组件
- 现在您可以修复基本的文件系统错误了。
在第十章中,我们将向您展示如何设置 SSH 服务器等基础设施服务,讨论如何使用 NTP(网络时间协议)管理主机上的时间,并介绍 DNS(域名系统)和 DHCP(动态主机配置协议)。