原文:Pro linux system administration
协议:CC BY-NC-SA 4.0
五、用户和组
第四章介绍了 Linux 基础知识以及用户和用户组的概念。我们解释了用户和组如何拥有文件和对象。我们还演示了所有权如何与权限相结合来控制对这些文件和对象的访问。用户和组也用于启动和运行流程。
在本章中,我们将详细介绍用户和组是如何工作的,从您登录时会发生什么以及如何控制其中的一些过程开始。我们将演示如何创建用户和组,为您提供更多关于密码的信息,并解释 Linux 控制对您的主机的访问的过程。
我们将要谈论的话题包括su
和sudo
命令。这些命令允许您以其他用户的身份运行命令,特别是root
用户。因此,这些命令允许您避免作为root
用户登录来执行管理任务。su
和sudo
命令对于安全管理您的主机至关重要。
登录后会发生什么?
在第四章中,我们讨论了让用户登录到 Linux 主机,您看到了一些示例屏幕,显示了如何输入您的用户名和密码。在这一章中,我们将进一步解释当你登录时会发生什么,并且我们将开始探索在这个过程中你可以管理的一些选项和安全控制。
那么,在输入用户名和密码之后,在进入命令行提示符或图形用户界面(GUI)屏幕之前,实际上会发生什么呢?这个过程在不同的发行版之间略有不同,但通常会执行一个名为login
的应用程序,并执行以下操作:
- 检查用户和组是否存在,以及是否允许用户登录
- 检查是否允许用户从特定位置登录(例如,只有一些用户可以登录到控制台,或者连接到 Linux 主机的屏幕)
- 检查密码是否正确,如果密码不正确,允许指定次数(通常为三次)的重试
- 检查密码是否有效,如果密码过期,则提示用户输入新密码
- 设置环境变量,如用户的主目录和路径
- 启动 Shell 进程
- 向用户显示命令行提示符或 GUI 屏幕
在接下来的小节中,我们将带您完成这些过程,并解释如何配置和更改其中的一些步骤以适应您的环境。您将从学习如何创建、删除和管理用户和组开始。
Note
在本章中,我们将演示命令行用户管理,但是如果您喜欢以这种方式管理您的用户和组,我们向您展示的大多数内容也可以从 GUI 工具中获得。在应用程序搜索栏中,键入“用户”,你会找到用户应用程序(CentOS)或用户帐户(Ubuntu)——或者打开设置或系统设置菜单,你会在那里找到它们。
使用用户和组
管理对 Linux 主机的访问的核心是用户和组的概念。我们在第四章中介绍了用户和用户组,您会发现它们很像微软 Windows 平台上的用户和用户组。
您可以通过两种方式组织主机上的用户和组。一种方法是向域中的每个主机添加用户和组;另一种方法是将用户管理集中在一个或两个身份验证服务器上。在本章中,我们将解释前者,在第十六章中,我们将解释后者。
与在 Microsoft Windows 主机上一样,每个需要登录到您的主机的人都需要创建一个用户。许多应用程序,如 web 和邮件服务器,也需要创建用户。当它们启动时,这些应用程序将利用该用户的权利和特权来访问系统资源,如文件、网络或主机的其他方面。
Linux 主机上的每个用户还需要至少属于一个组,但是也可以属于任意数量的其他组。组是用户的集合,因为他们相似或需要访问特定资源而聚集在一起。例如,您组织的销售部门中的所有用户可能属于一个名为sales
的组。您可以配置您的主机,确保只有sales
组中的用户可以访问销售部门的应用程序和文件。
Note
安装应用程序时,他们通常会安装运行这些应用程序所需的其他用户和组。
使用两个命令很容易创建用户和组:useradd
(创建用户)和groupadd
(创建组)。此外,我们可以使用两个命令来修改现有的用户和组,它们是usermod
和groupmod
。最后,为了完成生命周期,可以使用userdel
和groupdel
命令删除用户和组。
Tip
在 CentOS 和 Ubuntu 上使用用户和组是一个非常相似的过程,使用许多相同的命令和选项。我们会告诉你发行版之间的任何微小变化。
介绍 sudo
在我们开始解释如何创建用户和组之前,我们想讨论一下sudo
命令,我们在第四章中已经讨论过一点。sudo
命令允许用户运行命令,就好像这个人是以root
用户的身份登录的,这是 Linux 的 Windows 管理员帐户。这种能力非常有用,原因有三:
- 它增加了安全性。
- 它允许更好地控制特权命令。
- 它为您提供了更好的审计跟踪,以了解谁在您的主机上做了什么。
Note
在 Ubuntu 上使用sudo
而不是root
用户的另一个好理由是 Ubuntu 默认不启用root
用户。您根本无法以root
用户的身份登录。
本章中我们将需要sudo
,因为几乎所有用于管理用户和组的命令都需要root
用户的特权才能运行。例如,只有root
用户可以创建另一个用户。
当您运行sudo
命令时,它会提示您输入密码(以确认您确实是您所说的那个人),然后您可以在 CentOS 上使用sudo
命令 5 分钟,在 Ubuntu 上使用 15 分钟。这段时间过后,系统会提示您再次输入密码。
Tip
第一次运行sudo
命令时,它可能会警告您小心使用sudo
命令的威力。
在 Ubuntu 上,sudo
命令是可用的,并且是为您在安装 Ubuntu 时创建的用户配置的。如果您以该用户身份登录,您已经可以使用sudo
命令了。您还可以通过将其他用户添加到admin
组来为他们启用sudo
访问。您可以使用usermod
命令(您将在本章后面看到更多)将用户添加到组中。
$ sudo usermod -G admin ataylor
这里我们使用了sudo
和usermod
命令来修改一个名为ataylor
的用户。我们通过指定-G
选项和用户要添加到的组的名称,将用户添加到了admin
组。(注意,我们已经使用了sudo
命令来进行用户修改。唯一允许这样做的用户是您在安装主机时创建的用户;因此,您必须以该用户身份登录才能进行更改。)
在 CentOS 上,如果您没有将用户(jsmith
)创建为管理员,默认情况下不会启用sudo
命令,您需要启用它。为此,您需要使用一个名为visudo
的命令来编辑sudo
命令的配置文件/etc/sudoers
。为此,您需要作为root
用户登录并运行visudo
命令。
# visudo
正如您在#
命令提示符下看到的,您以root
用户的身份登录,并且正在执行visudo
命令。这将打开一个看起来很像vi
或vim
编辑器的编辑应用程序。该文件中有下面一行:
# %wheel ALL=(ALL) ALL
如上所示,这一行中的#
表示您正在处理的行是一个注释。您需要取消对该行的注释。为此,将光标放在#
附近,并按下x
键两次。这将删除行中的散列(或井号,#)和一个空格字符。完成后,使用与使用vim
相同的命令编写并退出文件,方法是键入冒号、:
、w
和q
,然后输入 Enter 或:wq
。这使得名为wheel
的组中的任何成员都可以使用sudo
命令。然后,您可以将用户添加到wheel
组,如下所示:
# usermod –a wheel ataylor
同样,您使用-a
选项和您想要最后添加到组中的用户名来指定组wheel
。现在ataylor
用户可以使用sudo
命令了。您也可以使用–G <group1>,<group2>
为用户设置群组,这将替换分配给用户的任何现有群组。
创建用户
现在您已经知道如何启用和使用sudo
命令,我们可以开始查看用户和组了。让我们首先使用useradd
命令创建一个新用户,如清单 5-1 所示。
$ sudo useradd –m –c 'John Smith' jsmith
Listing 5-1.Creating a New User
Note
在清单 5-1 中,您可以看到我们在useradd
命令前面加上了sudo
命令,以避免作为root
用户登录。
命令有很多选项,我们在清单 5-1 中只使用了几个。第一个参数-m
告诉主机为用户创建一个主目录。主目录的名称和位置格式通常类似于/home/
username
。
Tip
例如,您可以用通用配置文件预填充新的主目录。为此,将文件添加到/etc/skel
(skeleton 的缩写)目录。创建新的主目录时(使用–m
选项),该目录中包含的所有文件都被复制到用户的新主目录中。
–c
选项添加了我们新用户的描述。该描述存储在/etc/passwd
文件中。所有用户在这个文件中都有一个条目,我们将在本章后面检查这个文件和用于存储组数据的/etc/group
文件。最后,我们指定了新用户的名字jsmith
。
默认情况下,新用户将被禁用,并且没有设置密码。您将需要使用passwd
命令更改用户的密码(我们将在本章后面更详细地介绍)。
表 5-1 列出了一些其他有用的useradd
命令行选项。
表 5-1。
Some useradd
Command-Line Options
–d
选项允许您指定用户的主目录。主目录是用户登录后所在的目录。这是用户拥有的用于用户文件的私有目录,适用于系统用户(如运行数据库的用户)或普通用户。–M
选项告诉 Red Hat 派生的发行版不要创建主目录。该选项强调了在 CentOS 和 Ubuntu 发行版上创建用户的主要区别。在 Red Hat 衍生的发行版中,主目录是自动创建的。
Ubuntu 要求使用–m
选项执行useradd
命令;否则,不会创建主目录。
Note
关于在 Ubuntu 上创建用户的另一种方法,请参见侧栏“Adduser:Ubuntu 上的另一种方法”。
最后,–s
选项允许您为用户指定不同于默认的 shell。
Tip
我们建议您阅读useradd
命令的man
页面,了解关于该命令的更多详细信息。
用户默认设置
您的新用户也将使用各种默认设置创建(例如,用户 shell 的设置)。那么,useradd
命令从哪里得到这些默认值呢?在 CentOS 和 Ubuntu 发行版中,默认值都包含在/etc/default/useradd
文件中,您可以使用以下命令显示当前默认值:
$ sudo /usr/sbin/useradd -D
清单 5-2 展示了这个文件的一个例子。
$ sudo cat /etc/default/useradd
# useradd defaults file
GROUP=100
HOME=/home
INACTIVE=-1
EXPIRE=
SHELL=/bin/bash
SKEL=/etc/skel
Listing 5-2.The /etc/default/useradd File
该文件通常在安装主机时默认填充,但您可以修改它以适应您的环境。
Note
当用户登录时,会为系统设置系统范围的默认值。这些可以在/etc/login.defs
文件中找到。它包含创建用户时使用的 uid 和 gid 范围等内容。
表 5-2 显示了可以包含在useradd
文件中的可能选项。
表 5-2。
The /etc/default/useradd
File
文件中的每个选项控制一个指定的默认值;例如,shell 选项为用户指定默认 SHELL。HOME 选项指定应该在其中创建所有新主目录的目录。SKEL 选项指定使用哪个目录来填充用户的主目录,正如我们前面讨论的,这默认为/etc/skel
。GROUP 选项指定要使用的默认组 ID (GID)。它被设置为 group 100,或者“users”组,通常您不需要更改它。在接下来的部分中,我们将更多地讨论组、成员和 GID。
最后,非活动和过期这两个选项控制两种不同类型的用户帐户过期。非活动值控制用户密码过期后用户可以重置其密码的天数。这允许您指定如果用户的密码过期,用户在被标记为非活动之前有有限的时间重置该密码。然后,用户需要一些交互来重新启用它进行访问。设置为-1 将禁用此设置,设置为 0 将在密码过期后立即禁用该帐户。
Note
我们将在本章后面更多地讨论密码过期。
EXPIRE
选项对于创建临时帐户很有用,因为它以YYYY-MM-DD
的格式指定了帐户过期和禁用的日期。默认的EXPIRE
允许你为所有账户指定一个日期。您也可以使用以下命令在命令行上创建个人帐户:
$ sudo useradd –e 2016-09-15 temp_account
此命令创建一个名为 temp_account 的帐户,该帐户将于 2016 年 9 月 15 日被禁用。
您可以通过执行带有-D
选项的useradd
命令来更改该文件中的许多默认设置。清单 5-3 向您展示了如何为您的新用户更改默认 shell,表 5-3 显示了可用于-D
选项的附加选项。
表 5-3。
The useradd -D
Defaults
$ sudo useradd -D -s /bin/bash
Listing 5-3.Changing useradd Defaults with the -D Option
Tip
您还可以使用 chsh 命令更改您的默认 shell。使用 CentOS 上的chsh -l
查看所有可用 Shell 的列表。在 Ubuntu 上,你可以在/etc/shells
文件中看到列表。
创建组
我们之前提到过,每个用户必须至少属于一个组。默认情况下,在大多数 Linux 发行版上,包括 CentOS 和 Ubuntu,当您创建一个新用户时,还会创建一个与该用户同名的新组。新用户始终是该组的唯一成员。
但是之前我们说过useradd
的默认组是 100?为什么不用那个?如果对 useradd 使用–N(无用户组)选项,或者如果 login.defs 文件中的用户组 _ENAB 设置为“否”,则将分配默认的 100(用户)组。默认情况下,useradd
命令将创建一个与用户同名的组。
Note
为每个用户创建一个唯一的组称为用户专用组(UPG)方案。这是一种灵活的管理组权限的模型。你可以在 https://wiki.debian.org/UserPrivateGroups
了解 UPG 的一些细节
在我们的例子中,我们的第一个用户jsmith
,将自动属于一个名为jsmith
的组。这个组被称为主要组。我们的用户也可以属于其他组,这些附加的组称为补充组。
那么,我们如何判断我们的新用户属于哪个组呢?要检查特定用户的详细信息,我们可以使用清单 5-4 中所示的 id 命令。
$ id jsmith
uid=1001(jsmith) gid=1001(jsmith) groups=1001(jsmith)
Listing 5-4.The id Command
在清单 5-4 中,我们使用id
命令查询我们的新用户jsmith
。但是这个命令返回了一些关于uid
和gid
的相当神秘的信息,我们用户的名字,以及一些数字。那么这些到底是什么?
每个用户和组在创建时都会被分配一个唯一的用户 ID (UID)和 GID。UID 的范围从 0 到 65535,根用户的 UID 始终为 0。GID 的范围也是从 0 到 65535,其中root
用户的 GID 也总是为 0。
如果您为 root 用户运行id
命令,您可以在下面一行看到结果:
$ id root
uid=0(root) gid=0(root) groups=0(root)
这显示了 UID 为 0、GID 为 0 的 root 用户。
Note
主机上的每个用户和组都必须有唯一的 UID 和 GID。不能在您的主机上创建与现有用户或组具有相同 UID 或 GID 的用户或组。您的操作系统将自动分配号码,并防止任何冲突。
大多数发行版为特定类型的用户和组保留了号码范围。在你的系统中有两种用户。一类是系统用户,如运行服务的用户和组,例如运行数据库或 web 服务器的用户。所以像“apache”和“www-data”这样的系统用户已经设置并知道了 UID。其他类型的用户是需要登录系统的“人”(例如,您和我)。
CentOS 发行版为分配的系统 UID 保留了从 1 到 200 的 UID 和 GID 范围(如 apache)。它们通过在创建用户时指定 UID 来实现这一点。从 201 到 999 的 UID 用于动态分配的系统 UID—这些是尚未定义 UID 的守护程序,将在安装时选择 UID。这是通过在创建用户时指定--system
选项来完成的。普通用户是用 1000 及以上的 uid 创建的。
Ubuntu 为指定的系统用户保留 UID 和 GID 范围 1 到 99。100 到 999,用于动态分配的系统用户(同样通过传递--system
选项)。在 Ubuntu 上,第一个新用户的 UID 和 GID 也是 1000。
Tip
您可以控制在/etc/login.defs
文件中提供给用户的 uid 和 GID 的范围。编辑 uid 的UID_MIN
和UID_MAX
范围以及 GID 的GID_MIN
和GID_MAX
范围。你不太可能想这么做,但是选择就在那里。您也可以设置SYS_UID_MIN
和SYS_UID_MAX
以及群组。
因此,在清单 5-4 中,我们为jsmith
用户执行了id
命令,并显示了用户的 UID 1001 和 GID 1001(UID 和 GID 后面的括号中是用户名和组名)。最后一个字段groups
,显示主要组和任何补充组。
有两种方法可以将用户添加到一个或多个组中。首先,您可以在创建时使用useradd
命令将用户添加到一个或多个组中。其次,您可以使用usermod
命令修改现有用户并添加组。
在下面一行,我们将创建第二个名为ataylor
的用户,并在创建她时将她添加到一些组中。
$ sudo useradd –m –c 'Anne Taylor' –G printing,finance ataylor
我们已经指定了–G
选项,这允许我们提供一个逗号分隔的组列表,我们希望新用户ataylor
加入这些组。-G
选项允许我们的用户加入除主组之外的其他组,主组是在创建用户并共享她的用户名时创建的唯一组。这里的用户ataylor
是一个名为ataylor
的独特的 UPG 计划主组的成员,我们试图将她添加到附加的补充组printing
和finance
。
但是,如果我们现在执行该命令,它将会失败,因为在我们可以向这些组添加用户之前,每个组都需要存在,否则我们将会得到一条错误消息,用户将无法创建。这是在 Ubuntu 上的这种情况下会产生的错误消息:
useradd: unknown group printing
useradd: unknown group finance
所以在这种情况下,我们需要首先创建我们的组,我们可以用groupadd
命令来完成,如清单 5-5 所示。
$ sudo groupadd printing
$ sudo groupadd finance
Listing 5-5.Creating New Groups
表 5-4 显示了一些可用于groupadd
命令的命令行选项。
表 5-4。
The groupadd Command-Line Options
| [计]选项 | 描述 | | --- | --- | | -我也想 | 设置组的 GID。这必须是一个唯一的数字。 | | -r | 创建系统组(GID 在系统 GID 范围内)。 |如果您希望用特定的数字覆盖自动生成的 GID,请使用-g
选项。仅在 CentOS 上提供的–r
选项允许您创建一个系统组,并确保为该组分配一个系统组范围内的 GID。
当我们尝试创建ataylor
用户时,我们成功了,因为先决条件组现在已经存在。
$ sudo useradd -m -c 'Anne Taylor' -G printing,finance ataylor
我们还可以使用usermod
命令将现有用户添加到组中。
$ sudo usermod -a -G accounts ataylor
usermod 命令用于修改现有用户。通过指定–a
(用于追加)选项、-G
选项和要加入的新组的名称(该组必须已经存在),我们将ataylor
用户添加到accounts
组。
Tip
您可以使用usermod
命令改变用户的许多方面,我们建议您阅读其man
页面以获取更多信息。如果用户当前已登录,则在用户注销并再次登录之前,更改不会生效。
还可以使用gpasswd
命令来管理组,该命令允许您委派管理组及其成员的责任。您可以为特定用户分配权限,以便在特定组中添加或删除用户。例如,您可以让销售团队中的某个人管理sales
组的成员资格。你可以在man
页面上更详细地了解gpasswd
。
删除用户和组
除了创建和修改用户和组之外,您还希望能够删除它们。您可以使用以下两个命令来完成此操作:userdel
和groupdel
。userdel
命令删除用户,groupdel
命令删除组。现在让我们删除我们之前使用userdel
命令创建的ataylor
用户,如清单 5-6 所示。
$ sudo userdel ataylor
Listing 5-6.Deleting a User
userdel
命令删除用户,但是默认情况下,它不会删除用户的主目录。您可以使用userdel
命令的–r
选项强制 Linux 删除用户的主目录。这将删除/home/
username
目录和其中的所有文件,但不会删除该目录之外可能也属于该用户的任何文件。userdel
命令也不会删除当前登录到主机的用户。
删除拥有文件的用户可能会有问题。如果您删除某个用户,那么该用户的所有对象将不再归该用户所有。您可以识别这些对象,因为用户名将在文件列表中被替换为以前的 UID(这同样适用于任何已删除的组)。因此,如果您创建另一个使用相同 UID 或 GID 的用户,该用户现在将拥有已删除用户的文件。在删除用户之前,确认用户拥有的文件和目录,并确定您将如何处理它们是一个非常好的主意。我们将在本章的后面向您展示如何分配文件和目录的所有权。鉴于此问题,有时禁用用户比删除用户更好。但是如果您决定删除一个用户,您可以运行命令find / -user UID –o –group GID
来查找与您刚刚删除的用户相关联的所有文件。
要删除一个组,使用groupdel
命令并指定要删除的组的名称。
$ sudo groupdel finance
此命令将从主机中删除该组。需要注意的是,groupdel
命令不会删除任何用户的主要组——例如,在删除ataylor
用户之前,不能删除ataylor
组。如果要删除用户的主要组,必须先删除该用户。与用户一样,删除组会使这些组拥有的文件成为孤立文件。
Adduser: An Alternative on Ubuntu
Ubuntu 附带了两个额外的用户管理工具,adduser
和addgroup
。这些为useradd
和groupadd
命令提供了易于使用和方便的替代方法。运行adduser
的正常方式是使用你想要创建的新用户的用户名。然后,该实用程序会要求您提供附加信息。例如,让我们为用户 Anne Taylor 添加一个帐户。
$ sudo adduser ataylor
Adding user `ataylor' ...
Adding new group `ataylor' (1001) ...
Adding new user `ataylor' (1001) with group `ataylor' ... Creating home directory `/home/ataylor' ...
Copying files from `/etc/skel' ... Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
Changing the user information for ataylor
Enter the new value, or press ENTER for the default
Full Name []: Anne Taylor
Room Number []:
Work Phone []:
Home Phone []:
Other []:
Is the information correct? [Y/n] y
adduser
命令要求提供它需要的所有变量,然后用正确的参数调用useradd
命令来创建帐户。这意味着即使你使用adduser
命令,你在/etc/default/useradd
中配置的默认useradd
选项仍然有效。
您还可以通过运行以下命令,使用adduser
脚本快速将用户添加到组中:
$ sudo adduser username groupname
用户和组都需要已经存在于主机上。
adduser 和 addgroup 脚本本身也可以通过/etc/adduser.conf
文件进行配置。默认情况下,他们将创建指定名称的用户,将他们放在同名的组中,创建主目录,并分配最低的可用用户和组 id。
通过 GUI 管理用户和组
CentOS 和 Ubuntu 都有管理用户的 GUI。在 CentOS 和 Ubuntu 上,通过选择应用程序➤系统工具➤设置(见图 5-1 )启动设置面板,即可访问管理用户帐户的 GUI 工具。
图 5-1。
Accessing users from the system settings
您可以使用此设置面板在中更改用户。但是首先您需要获得 root 权限(或者在 GUI 中也称为管理员权限)才能在这里更改设置。图 5-2 显示您需要点击解锁按钮,然后会提示您输入密码。
图 5-2。
Unlocking the Users settings interface
在图 5-2 中,当前用户的列表在左侧面板中。要添加用户,请单击列表底部的+按钮。您可以通过单击–按钮删除用户。在图 5-3 中,我们添加了一个名为ataylor
的新用户。
图 5-3。
Adding user ATaylor
在图 5-3 中,我们正在添加用户 ataylor。通过选择允许用户在下次登录时设置密码,ATaylor 将被允许在下次登录时创建自己的密码。我们可以添加两种类型的用户,标准用户或管理员。您还可以选择将用户的企业登录添加到 Active Directory 域或 IPA(身份策略审计)域。在第十六章中,我们将对此进行更深入的探讨。通过单击“Add”按钮,我们将在再次通过系统验证后添加用户 ataylor。
Caution
允许用户在下次登录时创建自己的密码确实会带来安全风险。任何以ataylor
身份登录的人都会被提示设置一个新密码,这样,他就可以访问ataylor
所做的一切。在这种情况下,最好确保让ataylor
尽快登录并确认访问。
最后,在图 5-4 中,我们展示了如何查看用户 JSmith 的登录历史。
图 5-4。
Login history for JSmith
在图 5-4 中,我们可以看到 JSmith 在 21:17 退出,并在 21:18 再次登录。使用标题栏中的箭头滚动浏览历史记录,查看更早的时间。
虽然您可以通过此应用程序添加和删除用户,但您不能管理组设置。为此,您必须使用命令行。
Note
请记住,Ubuntu Server 版本默认不附带 GUI,您应该使用提供的命令行工具。Ubuntu 桌面版确实附带了合适的 GUI 工具,因为它默认安装了一个 GUI。
密码
当您通过命令行创建帐户时,不会为该帐户设置密码。您现在可能想要设置或在某个时候更改用户的密码。为此,您可以使用passwd
命令。根据运行命令的人的不同,passwd
命令有两种工作方式。如果一个普通用户,比如ataylor
,已经设置了一个密码并且运行了这个命令,那么系统会提示她修改自己的密码。您可以在清单 5-7 中看到passwd
命令的运行。
$ passwd
Changing password for ataylor.
(current) UNIX password:
Enter new UNIX password:
Retype new UNIX password:
Listing 5-7.Changing Your Password
你输入当前密码,然后输入新密码。系统会提示您输入两次新密码,以确保其正确无误。你还必须提供一个合适的密码。默认情况下,在大多数发行版中,会执行一些基本的密码检查,以防止您提供一个脆弱的或容易猜到的密码。在大多数发行版中,这些检查通常如下:
- 最小密码长度为四个字符
- 不是回文(即最后一个密码的反码)
- 与之前的密码不同,只是大小写发生了变化(即,从密码到密码)
- 一些基本的相似性检查
- 基于密码长度和字符组合(全是字母、全是数字等)的一些简单测试。)
- 简单的旋转检查(即旋转密码中的字母,例如
ginger
被更改为ingerg
)
如果您提供的密码不够复杂,您会收到一条错误消息,指出您的密码有什么问题。然后会提示您提供一个更容易接受的密码。
或者,如果您以 root 用户身份运行 passwd 命令,您可以更改其他用户的密码,如清单 5-8 所示。
$ sudo passwd jsmith
Listing 5-8.Changing Someone Else’s Password
在清单 5-8 中,passwd
命令提示您为用户jsmith
提供一个新密码。
Tip
值得注意的是,作为root
用户,您可以忽略任何关于错误密码的警告,并将用户密码更改为弱密码或容易被猜到的密码。
密码老化
密码时效允许您指定密码有效的时间段。该时间段到期后,用户将被迫选择新密码。这有利于确保密码定期更改,并且被盗、被破解或被前雇员知道的密码将具有时间限制值。不幸的是,对于许多用户来说,定期更改密码的需要增加了他们写下密码的愿望。我们建议您对大多数密码使用 30 到 60 天的密码期限,这取决于主机的性质和鼓励密码管理员。更重要的是,主机应该具有更短的密码到期期限(例如 30 天),而不太重要的主机可以具有更长的期限。一些组织选择单个过期期限,以便该期限对所有主机上的所有用户保持一致。
有两种方法可以处理密码老化。第一种方法使用名为 chage 的命令行工具来单独设置或更改用户帐户的密码到期时间。清单 5-9 显示了这个命令。
$ sudo chage -M 30 ataylor
Listing 5-9.The chage Command
清单 5-9 使用-M
选项将用户ataylor
的密码有效期设置为 30 天。30 天后,用户密码将过期,系统会提示用户输入新密码。表 5-5 显示了其他几个你可以设置的变量。
表 5-5。
The chage Command Flags
| [计]选项 | 描述 | | --- | --- | | `-m days` | 设置密码更改的最小间隔天数。零允许用户随时更改密码。 | | `-M days` | 设置密码保持有效的最大天数。 | | `-E date` | 设置用户帐户过期并自动停用的日期。 | | `-W days` | 设置在密码过期前警告用户更改密码的天数。 | | `-d days` | 设置自 1970 年 1 月 1 日以来最后一次更改密码的天数。 | | `-I` `days` | 设置密码过期后帐户被锁定的天数。 |Tip
在 Unix/Linux 世界中,您会多次遇到日期 1970 年 1 月 1 日。这个日期也称为 Unix 纪元或 Unix 时间。它用于描述时间点,从 1970 年 1 月 1 日开始以秒为单位进行测量(例如 1229519557)。您可以使用命令date +%s
在您的主机上找到 Unix 时间。
第一个选项-m
,允许您指定密码更改之间的最短时间。设置为 0 允许用户随时更改密码。选项-W
指定用户密码到期前的天数,用户将收到密码即将到期的警告。-d
选项主要用于立即终止密码。通过将-d
选项设置为0
,用户的最后一次密码更改日期变为 1970 年 1 月 1 日,如果–M
选项大于0
,则用户必须在下次登录时更改密码。最后一个选项-I
提供了一个以天为单位的时间框架,在该时间框架之后,密码过期且未更改的用户帐户将被锁定,从而无法用于登录。
如果不带任何选项运行chage
,并且只指定用户,它将启动一系列交互式提示来设置所需的值,如清单 5-10 所示。方括号[ ]之间的值表示该用户密码时效设置的当前值。
$ sudo chage ataylor
Changing the aging information for ataylor
Enter the new value, or press return for the default
Minimum Password Age [0]:
Maximum Password Age [30]:
Last Password Change (YYYY-MM-DD) [2016-06-27]:
Password Expiration Warning [7]:
Password Inactive [-1]:
Account Expiration Date (YYYY-MM-DD) [2016-07-28]:
Listing 5-10.Running chage Without Options
用户还可以使用带有-l
选项的chage
命令来显示密码何时到期。
$ chage -l ataylor
另一种处理密码老化的方法是在/etc/login.defs
文件中为所有用户设置默认值。
清单 5-11 显示了/etc/login.defs
中可用于密码老化的控件。
PASS_MAX_DAYS 60
PASS_MIN_DAYS 0
PASS_WARN_AGE 7
Listing 5-11.The login.defs Password-Aging Controls
在清单 5-11 中,我们使用PASS_MAX_DAYS
选项将最长密码期限设置为 60 天,通过将PASS_MIN_DAYS
选项设置为 0,允许用户随时更改密码,并使用PASS_WARN_AGE
选项警告用户其密码将在密码到期日期前七天到期。
禁用用户
作为root
用户,您还可以使用passwd
命令来禁用和启用使用–l
或锁定选项的用户帐户。例如,考虑以下情况:
$ sudo passwd –l ataylor
前面的命令将锁定ataylor
用户,并阻止ataylor
使用她的密码登录主机。然后,您可以使用–u
或解锁选项解锁用户。
$ sudo passwd –u ataylor
但是,此命令不会完全禁止对主机的访问。用户可以通过其他身份验证机制访问主机,例如使用 SSH(安全 Shell)进行远程访问的公钥。
还有一种方法可以完全禁止用户使用带有--expiredate
选项的usermod
命令:
$ sudo usermod --expiredate 1 ataylor
这会将帐户到期日期设置为 1970 年 1 月 1 日,并立即禁用该帐户。用户现在无法在主机上执行任何操作。
最后,您可以将登录 shell 设置为/bin/false
或/usr/sbin/nologin
。这不会锁定用户,但会禁止用户访问 shell。
$ sudo usermod –s /bin/false ataylor
Note
您还可以将用户的 shell 设置为命令。例如,您可以将用户的 shell 设置为/bin/mail
命令,这是一个小的命令行邮件阅读器。当用户登录时,她只能访问该命令。
存储用户数据
首先,您的主机检查您的用户是否存在并被允许登录。Linux 发行版将用户、组和其他信息的详细信息存储在主机上的三个文件中:/etc/passwd
、/etc/shadow
和/etc/group
。您通常不需要编辑这些文件,因为有一些命令和工具允许您添加、删除和管理用户和组。然而,知道它们包含什么信息是有用的。
Tip
如果您使用其他形式的身份验证,如 NIS(网络信息服务)、LDAP(轻量级目录访问协议)或 Active Directory,我们将在第十六章中介绍,那么您的主机通常会查询这些身份验证存储之一,以确认您的用户存在并被允许登录。
第一个文件/etc/passwd
,包含所有用户及其详细信息的列表。清单 5-12 显示了一些passwd
条目的例子。
root:x:0:0:root:/root:/bin/bash
daemon:x:2:2:daemon:/sbin:/sbin/nologin
Listing 5-12.
/etc/passwd Entries
每个条目都可以分成几个组成部分,用冒号分隔。
username:password:UID:GID:GECOS:Home Directory:Shell
用户名最多可包含 32 个字符,区分大小写(尽管通常都是小写)。下一个字段中的 x 是密码的标记。实际的密码存储在/etc/shadow
文件中,我们将在侧栏“影子密码”中讨论它
接下来是 UID 和 GID。如前所述,在 Linux 主机上,每个用户帐户和组都被分配一个数字 ID;为用户分配一个 UID,为组分配一个 GID。根据发行版的不同,编号较低的 uid 和 GID 表示系统帐户和组,如 root 或 daemon。在 CentOS 和 Ubuntu 上,你通常会看到系统账户 uid 和 GID 低于 1000。
Note
如前所述,root
用户的 UID 和 GID 是0
。这应该是主机上 UID 和 GID 为 0 的唯一用户。
下一项是 GECOS 或注释字段。该字段通常包含诸如用户名、办公室位置和电话号码等数据。如果 GECOS 字段中有多个数据项,则用逗号分隔每个数据项。
接下来是用户的主目录。正如我们在第四章中描述的,它通常位于/home
目录中(例如/home/jsmith
)。
最后一项是用户的默认 shell。正如我们在第四章中讨论的,shell 是一个命令行环境,用户通过它与主机交互。每个 shell 都是通过运行二进制文件来初始化的。例如,要启动 Bash shell,需要执行/bin/bash
二进制文件。这个二进制文件在/etc/passwd
文件中指定。如果默认 shell 指向一个不存在的文件,那么用户将无法登录。
清单 5-12 中的第二行使用 shell /sbin/nologin
,这是一个伪 shell,它不仅阻止用户登录,还记录对syslog
守护进程的登录尝试。
Note
syslog
守护进程是 Linux 日志服务器。它从操作系统和应用程序接收日志条目,并将它们写入文件,通常在/var/log
目录中。我们将在第十八章中讨论更多关于登录的内容。
除非用户被设置为不登录,否则大多数用户都会有一个 shell 条目,引用启动其 shell 的二进制文件,例如,/bin/bash
。
Shadow Passwords
您可能已经注意到在/etc/passwd
中没有出现密码,而是出现了字母x
。这是因为现代发行版使用影子密码来处理密码管理。
以前,密码作为单向散列存储在/etc/passwd
中,这提供了有限的安全性,并将用户名和密码暴露给暴力破解方法。暴力破解是一种攻击密码的方法,其中尝试数千或数百万个不同的密码,直到找到匹配的密码。/etc/passwd
文件特别容易受到这种攻击,因为应用程序对它的使用要求它对所有用户都可读,或者对所有人都可读。当 passwd 文件的副本可能从主机上被窃取并在离线时被暴力破解时,这尤其危险。鉴于这种类型的密码存储在passwd
文件中的安全性较低,现代计算机可以在几分钟内破解简单的密码,或者在几天内破解更难的密码。
影子密码通过将用户和密码分开并将密码作为散列存储在/etc/shadow
文件中来帮助降低这种风险。默认情况下,使用 SHA512 哈希。这些 SHA512 哈希更难破解,为了进一步保护密码,/etc/shadow
文件由root
用户所有,root
是唯一可以访问该文件的用户。下一行显示了来自shadow
文件的一个典型行:
root:$6$RwETwzjv$ifht......7L/HiLCPR8Zc935fd0:13675:0:99999:7:::
您也可以将shadow
文件分解成组件,像passwd
文件一样,用冒号分隔每个组件。shadow
文件的组成如下:
- 用户名
- 密码
- 上次更改密码的日期
- 密码更改的最小间隔天数
- 密码过期时间(天)
- 密码过期警告期限(天)
- 密码过期后该帐户被禁用的天数
- 自帐户被禁用以来的日期
用户名与passwd
文件中的用户名相匹配。密码本身是加密的,两种类型的特殊字符可以告诉您可以作为密码字段前缀的用户帐户的状态。如果密码字段以!
或*
为前缀,则帐户被锁定,用户不允许登录。如果密码字段以!!
为前缀,则从未设置过密码,用户无法登录主机。其余条目涉及密码老化,我们将在“密码老化”一节中讨论这些内容
存储组数据
在 Linux 主机上,关于组的信息存储在/etc/groups
文件中。清单 5-13 展示了这个文件的一个例子。
root:x:0:root
ataylor:x:501:finance,printing
Listing 5-13.Sample of the /etc/groups File
/etc/group
文件的结构很像/etc/passwd
文件,数据用冒号分隔。该文件分为组名、密码、GID 和该组成员的逗号分隔列表。
groupname:password:GID:member,member
组文件中的密码允许用户使用newgrp
命令登录该组。如果启用了影子密码,那么像passwd
文件一样,组文件中的密码被替换为 x,真实密码存储在/etc/gshadow
文件中。
Login Messages
用户首先看到的是你的登录界面。在登录屏幕中放置一些重要的警告和信息是一个好主意。为此,您需要编辑/etc/issue
和/etc/issue.net
文件的内容。当您通过主机控制台上的命令行登录时,会显示问题文件,当您通过 SSH 会话登录到命令行时,会显示issue.net
文件。大多数发行版都使用这些文件,包括 CentOS 和 Ubuntu。这些文件可以包含纯文本和特殊转义字符的组合,例如,允许您输出颜色、换行和回车。
您还应该包括一条警告消息,说明未经授权访问主机是被禁止的,并且将被起诉。您可以在文件中使用一系列转义字符中的一个来用来自您的主机的数据填充登录屏幕。我们建议您使用如下所示的登录消息:
^[c
\d at \t
Access to this host is for authorized persons only.
Unauthorized use or access is regarded as a criminal act
and is subject to civil and criminal prosecution. User
activities on this host may be monitored without prior notice.
^[c 转义字符清除屏幕,\d 和\t 转义字符分别显示主机上的当前日期和时间。如果你查看问题、issue.net 和 getty man
页面,你还可以找到其他的转义字符。
除了/etc/issue
和/etc/issue.net
文件之外,/etc/motd
文件的内容会在命令行登录后直接显示,您可能希望调整它们以包含可接受的使用策略或类似信息。
如果您使用的是贵由,可以在登录屏幕上设置消息。你可以按照这些 CentOS 的指令来做: https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/Desktop_Migration_and_Administration_Guide/customizing-login-screen.html
对于 Ubuntu,您需要看到以下内容: http://askubuntu.com/questions/193357/how-do-i-create-a-popup-banner-before-login-with-lightdm
.
配置您的 Shell 和环境
在用户被认证和授权之后,他们的 shell 被启动。大多数 shell 都是高度可定制的,许多用户最终会调整 shell 环境的各个方面,以帮助他们更快、更有效地工作。
Bash shell 从/etc/profile
文件中读取它的初始配置。该文件通常包含对其他全局配置文件的引用,用于为主机上除 root 用户之外的所有用户配置 Bash。最后,处理用户主目录中的所有配置文件。.bash_profile
和.profile
文件是最常用的,每个用户的主目录中都有这些文件。
Note
您可以在bash man
页面的INVOCATION
部分查看其他配置文件的完整列表。
环境变量
定制 shell 的一个主要原因是设置环境变量。这些变量充当许多应用程序使用的默认选项。他们可以定义一些特性,比如你喜欢的文本编辑器,你喜欢的语言,以及用ls
列出文件和目录时使用的颜色。您还可以定义自己的变量,用于自己的脚本。
要获得所有环境变量的完整列表,使用env
命令。表 5-6 列出了最常见的定制变量。
表 5-6。
Environment Variables
| 名字 | 用于 | | --- | --- | | `HOME` | 用户的主目录 | | `LANG` | 定义应用程序应该使用的语言文件 | | `LS_COLORS` | 定义`ls`命令使用的颜色 | | `MAIL` | 用户邮箱的位置 | | `PATH` | 一个用冒号分隔的目录列表,shells 在其中查找可执行文件 | | `PS1` | 定义正常提示 | | `SHELL` | 当前 Shell | | `_` | 包含在此会话中执行的最后一个命令 |您可以通过echo
命令显示环境变量的内容。在想要显示的变量名称前加上$
。
$ echo $PS1
\u@\h:\w\$
前面是一串特殊的转义码,在提示符下显示用户名\u
,主机名\h
,当前工作目录\w
,以及最后一个字符\$
。\$
如果提示显示为 root 用户,则显示一个英镑(#
)符号,否则显示一个美元符号($
)。有关可用转义码的完整列表,请参见bash man
页的PROMPTING
部分。
您可以通过在任何 Bash 配置文件中定义环境变量或者从命令行设置它们来更改环境变量。如果我们想改变我们的提示,使其包含一个时间戳,并打破它,给我们更多的空间来键入命令,我们可以添加\T
和\n
代码:
$ PS1="[\T] \u@\h:\w\n\$ "
[12:50:59] jsmith@au-mel-ubuntu-1:∼
$
Tip
你可能已经注意到我们有时用 有时不用。这里的简单规则是,如果我们引用变量并在它前面加上 有时不用。这里的简单规则是,如果我们引用变量并在它前面加上 有时不用。这里的简单规则是,如果我们引用变量并在它前面加上前缀,那么我们感兴趣的是变量的值(即变量的内容)。没有$,我们说的就是变量本身。
另一个有用的例子是在路径中添加目录。您可以快速在路径中添加前缀或后缀目录。您可以在路径的开头添加一个目录,如下所示:
$ PATH=/home/ataylor/scripts:$PATH
这里,我们将目录/home/ataylor/scripts
添加到路径的前面,然后通过用冒号分隔并指定$PATH
值来包含现有路径。这允许您将二进制文件、脚本或其他应用程序放入路径中,每次运行命令或应用程序时都会搜索该路径。在这种情况下,当执行命令时,Linux 会先在/home/ataylor/scripts
目录中查找命令,然后再在主机上的其他地方查找。
您可以使用相同的基本结构将目录添加到路径的末尾:
$ PATH=$PATH:/home/ataylor/scripts
然后,当您运行一个命令时,Linux 将搜索您的路径中的所有目录,如果没有找到匹配的命令或应用程序,它将搜索您的后缀目录。
任何类型为KEY=value
的字符串都被 Bash 假定为环境变量赋值。将变量改为大写是一种惯例。
当然,在命令行上设置环境变量只会在会话期间改变它们。如果您注销,它们将恢复到以前的配置。要使这样的更改永久化,请将它们放在位于您的主目录中的.bash_profile
文件中,例如,
PATH=$PATH:/home/ataylor/scripts
export PATH
这里我们指定了新的路径,然后使用一个特殊的命令export
来传播更改。通常情况下,对环境变量的更改只会更改进行更改的当前会话或脚本。为了在其他会话或脚本中使用它们,您需要导出它们。为了对所有用户进行路径或其他环境更改,将更改添加到/etc/profile
文件中,或者通常将这些更改添加到/etc/profile.d/
目录中的文件中。该文件由所有用户使用(除了root
用户;使用/root
目录下的.bash_profile
文件修改root
用户变量)来设定值。
Tip
你可以在 http://tldp.org/HOWTO/
Bash-Prompt-HOWTO/
找到更多关于配置你的 Bash 提示符的信息。
命令别名
配置 shell 的第二个原因是创建命令别名。别名允许您为常用命令创建快捷方式或设置默认选项。一个主要的例子是我们在第四章中看到的ls
命令的别名。
当用ls
列出文件时,我们在第四章中看到,我们得到了一个目录中文件的简单列表。通过使用别名,您可以让 shell 在每次键入ll
时执行ls -lah
,这样您就可以一直拥有一个完整的目录列表。您可以通过alias
命令创建一个别名。
$ alias ll='ls -lah'
$ ll
total 40K
drwx------. 4 vagrant vagrant 4.0K Mar 9 06:07 .
drwxr-xr-x. 4 root root 4.0K Mar 3 05:37 ..
-rw-------. 1 vagrant vagrant 2.2K Mar 9 06:08 .bash_history
-rw-r--r--. 1 vagrant vagrant 18 Nov 20 00:02 .bash_logout
-rw-r--r--. 1 vagrant vagrant 225 Mar 9 06:04 .bash_profile
您可以通过将别名添加到主目录中的.bash_profile
配置文件来使其永久化。
要获得 shell 中定义的所有别名的列表,运行不带任何参数的alias
命令。
$ alias
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l.='ls -d .* --color=auto'
alias ll='ls -lah'
alias ls='ls --color=auto'
在这里,您可以看到我们定义的列表别名、其他列表别名,以及我们从/etc/profile.d/colorgrep.csh
文件中获得的几个别名。
除非设置默认选项,否则不应定义与现有命令同名的别名。通过指定可执行文件的完整路径,您仍然可以运行原始命令,但是这可能会在您没有预料到的时候产生令人讨厌的意外(例如,在自动化脚本中)。
要删除别名,使用unalias
命令。要删除我们的交互式删除,我们将使用:
$ unalias ll
要了解有关别名的更多信息,请参见bash man
页面的ALIASES
部分。
Bash shell 极其强大和灵活,它可以使日常管理任务变得非常容易。如果你想知道更多关于 Bash 的知识以及你可以用它做什么,请看 www.tldp.org/LDP/Bash-Beginners-Guide/html/
和 http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO.html
。
控制对主机的访问
您可以控制相当多的用户特征,包括用户何时以及如何登录,他们的密码是什么样的,以及他们更改和重置密码的频率。这些控件都是用户登录主机时检查的,一般由一系列模块管理。这些模块统称为可插拔身份验证模块(PAM)。几乎所有的 Linux 发行版,包括 CentOS 和 Ubuntu,都依赖 PAM 来控制用户如何以及何时与主机交互。
在本节中,我们将向您介绍 PAM 及其工作原理。您通常不需要对 PAM 配置进行太多的更改,但是理解它的工作原理是很重要的。
Note
我们将在第十六章中详细讨论 PAM 如何与其他认证机制一起使用(例如,与 Active Directory 和 LDAP 的集成)。
PAM 最初是由 Sun Microsystems 设计的,用于提供插件认证框架。它在 Linux 世界中得到了大量的使用和开发,并且存在大量的 PAM 模块来执行从检查密码到创建主目录的各种功能。PAM 模块最初用于为缺乏身份验证或特定身份验证功能的应用程序提供身份验证和其他服务。后来,随着更复杂的身份验证类型的出现,如智能卡和一次性密码(或令牌),PAM 成为集成和扩展身份验证机制的一种方式。不必为新的身份验证方法重写每个应用程序,只需添加 PAM 支持。然后,PAM 负责通过标准 API 进行身份验证的艰巨工作。
配置 PAM
本质上,PAM 是一个身份验证和授权检查的层次结构,当应用程序想要执行某个操作时,就会执行这些检查。这些支票叠在一起;例如,当登录时,我们检查用户是否存在,然后检查用户的密码是否有效,然后检查密码是否过期。这个堆栈通常由多个 PAM 模块组成,每个模块执行一些检查功能。此外,某些检查必须通过(例如,您的用户必须存在),而其他检查可能是可选的。理解 PAM 的最好方法是检查一些 PAM 配置文件。
在大多数 Linux 发行版中,您有两个可能的位置来查找 PAM 配置信息。遗留文件/etc/pam.conf
用于保存 Linux 发行版上的 PAM 配置信息,但是现在它已经被弃用,并被目录/etc/pam.d
所取代。大多数现代版本的 CentOS 和 Ubuntu 都使用这个目录来保存 PAM 感知服务的配置文件集合。该服务与其要验证的应用程序同名;例如,passwd
命令的 PAM 配置包含在一个名为/etc/pam.d/passwd
的文件中。这些文件称为服务配置文件。
有各种各样的服务配置文件——例如,当用户登录到主机时,我们使用一个名为login
的应用程序。当用户登录时,登录应用程序被触发,在pam.d
目录中,您会发现一个名为login
的文件,其中包含应用程序的认证配置。类似地,您会发现一个名为sshd
的文件,它为通过 SSH 连接登录的用户执行类似的工作。
默认 PAM 配置中的其他常见服务以及在/etc/pam.d
目录中找到的服务是passwd
命令和 cron 调度守护进程。在这些文件中,您会发现这些应用程序使用的身份验证配置。
Note
我们将在第六章讨论 crontab 以及如何调度作业和动作。
不过,我们不会查看每个特定的文件,因为大多数服务都依赖于一些通用的身份验证配置。CentOS 和 Ubuntu 都有单独的文件定义通用认证配置。许多服务文件都引用并包含这种通用配置。在 CentOS 上,这个文件是/etc/pam.d/system-auth
,它是在您安装主机时自动生成的,并使用一个名为authconfig
的特殊命令进行更新。在 Ubuntu 上,同样的角色由四个独立的文件执行:common-auth
、common-password
、common-session
和common-account
。让我们看看清单 5-14 中 CentOS system-auth
文件的内容。
#%PAM-1.0
# This file is auto-generated.
# User changes will be destroyed the next time authconfig is run.
auth required pam_env.so
auth sufficient pam_unix.so nullok try_first_pass
auth requisite pam_succeed_if.so uid >= 1000 quiet_success
auth required pam_deny.so
account required pam_unix.so
account sufficient pam_localuser.so
account sufficient pam_succeed_if.so uid < 1000 quiet
account required pam_permit.so
password requisite pam_pwquality.so try_first_pass
local_users_only retry=3 authtok_type=
password sufficient pam_unix.so md5 shadow nullok
try_first_pass use_authtok
password required pam_deny.so
session optional pam_keyinit.so revoke
session required pam_limits.so
-session optional pam_systemd.so
session [success=1 default=ignore] pam_succeed_if.so service
in crond quiet use_uid
session required pam_unix.so
Listing 5-14.The
login PAM File
system-
auth
和其他服务配置文件有四个可能的指令。让我们使用清单 5-14 中的一行来更详细地检查它们。
auth sufficient pam_unix.so nullok try_first_pass
我们行中的第一个指令是 auth,这是我们正在配置的管理组。PAM 中有四个主要的管理组,它们代表了可以配置的身份验证和授权过程的不同部分:
auth
:这些模块执行用户认证,例如检查密码。account
:该管理组处理帐户验证任务,例如,确认用户帐户是否解锁,或者是否只有根用户可以执行操作。- 这些模块设置密码,例如,检查以确保您的密码足够强。
- 这些模块检查、管理和配置用户会话。
Note
记得我们讨论过设置强而复杂的密码;密码管理组是您可以设置复杂性密码规则的地方之一。
通常为每个管理组分配一个或多个模块,通常按照指定的顺序检查这些模块,每个模块将返回成功或失败的结果。在 PAM 配置中,一个特定的模块也可能被多次指定。例如,在清单 5-14 中,您可以看到所有四个管理组都指定了pam_unix.so
模块。
auth sufficient pam_unix.so nullok try_first_pass
account required pam_unix.so
password sufficient pam_unix.so m5 shadow nullok try_first_pass use_authtok
session required pam_unix.so
这表明pam_unix.so
模块可以为每个管理组执行检查和功能,该模块负责大多数标准 Unix 身份验证功能,如输入传统密码。例如,它可以确认用户在 auth 组中的密码是正确的,还可以确认该用户存在于account
组中。
下一个指令sufficient
称为控制标志,它告诉 PAM 如何处理模块的结果。如前所述,有些检查比其他检查更重要。控制标志告诉 PAM 如何处理成功或失败的结果,以及该结果如何影响整个身份验证过程。表 5-7 列出了四个 PAM 控制标志。
表 5-7。
PAM Control Flags
| 旗 | 描述 | | --- | --- | | `required` | 要使身份验证成功,必需的模块必须成功。 | | `requisite` | 如果一个必要的模块失败,那么认证将立即失败。 | | `sufficient` | 如果模块成功,认证立即成功。 | | `optional` | 模块的成功或失败不影响认证。 |required
标志表示模块结果必须成功,认证过程才能成功。如果这个模块的结果是失败,那么整个认证也是失败的。如果多个模块堆叠在一起,堆栈中的其他模块也将被处理,但整体身份验证仍然会失败。
requisite
标志还指示模块结果必须成功,认证才能成功。此外,与required
标志不同,该模块的成功或失败将立即通知请求认证的服务,认证过程将完成。这意味着,如果任何模块堆叠在一起,并且一个带有requisite
控制标志的模块出现故障,那么剩余待处理的模块将不会被执行。相比之下,利用所需的控制标志,堆栈中的剩余模块继续被处理。
下一个控制标志是sufficient
。sufficient
标志意味着该模块的成功足以使认证过程成功,或者如果模块被堆叠,则足以使堆叠成功。这取决于在该模块出现故障之前没有处理其他所需的模块。然而,如果一个sufficient
模块出现故障,那么整个堆栈不会出现故障。
最后一个控制标志是optional
。一个optional
模块对于认证过程或模块堆栈的整体成败并不重要。它的成功或失败不会决定整个认证过程的成功或失败。
下一个指令pam_unix.so
指示将使用什么 PAM 模块及其位置。如果您指定一个没有路径的 PAM 模块,那么该模块被假定位于/lib/security
目录中。您还可以通过提供模块的路径,从这里的另一个位置指定模块,如下面一行所示:
auth required /usr/local/pamlib/pam_local.so id=-1 root=1
最后的指令是要传递给 PAM 模块的参数——在本例中,我们将参数try_first_pass
和nullok
传递给pam_unix.so
模块。try_first_pass
参数告诉模块查看模块是否已经收到密码,如果收到,则使用该密码进行身份验证。nullok
参数告诉模块可以使用空白密码。大多数模块将忽略传递给它们的无效或不正确的参数,模块将继续被处理,尽管有些模块确实会生成错误消息或失败。
Tip
您可以找到大多数 PAM 模块的man
页面(例如,man pam_unix
将返回pam_unix man
页面)。也可以在 www.linux-pam.org/Linux-PAM-html/Linux-PAM_SAG.html/
找到文档。
还有最后一个我们需要提到的 PAM 函数:include
。include
函数允许您将一个 PAM 文件包含在另一个中。这就是我们的通用配置被包含在特定服务配置文件中的方式。为了查看这个函数,让我们来看看清单 5-15 中 Ubuntu login
PAM 服务配置文件的一个片段。
@include common-auth
@include common-account
@include common-session
@include common-password
Listing 5-15.The Ubuntu login PAM
Service Configuration File
该文件中有更多的配置,但是我们可以看到,使用格式@include
,您可以在 PAM 服务配置文件中包含其他文件。所以@include common-account
会将文件common-account
的内容包含在login
文件中。当使用login
文件时,该文件中指定的每个模块将被处理。文件在被包含的地方被拉进来并被解析,被包含的文件中的任何模块都按顺序执行。
您也可以使用include
选项作为控制标志,如下所示:
auth include system-auth
这将包括来自文件system-auth
的所有auth
类型行。
更多关于须藤的信息
正如本章前面所讨论的,sudo
命令允许您以另一个用户的权限运行一些命令,在大多数情况下是root
用户。该命令的工作方式很像微软 Windows 中的RunAs
命令,允许一个用户以另一个用户的身份运行命令。
Note
另一个名为su
的命令,也称为替代用户或切换用户,允许您以特定用户的身份打开子 shell。通常用来改变root
用户来执行某个动作。你可以通过它的man
页面了解它。请注意,如果root
账户被锁定,那么su
将无法工作,因为它在 Ubuntu 上。您可以通过为root
用户设置密码来解锁帐户,但通常您只会使用sudo su
来临时打开根 subshell。使用sudo su <user>
,您不需要知道您试图访问的用户的密码,因为您通过sudo
使用权限。
要使用这个命令,您可以键入sudo
,然后键入您想要执行的命令。如果您被允许在那个命令上运行sudo
,您将被提示输入一个密码,通常是您自己的用户密码。那么指定的命令将以root
用户的身份执行,除非您使用–u <username>
选项为 sudo 指定一个不同的用户…这允许您执行root
用户可以执行的操作,比如创建用户,而不需要以root
用户的身份登录。您可以在清单 5-16 中看到sudo
在工作。
$ sudo userdel ataylor
We trust you have received the usual lecture from the local System Administrator.
It usually boils down to these three things:
#1) Respect the privacy of others.
#2) Think before you type.
#3) With great power comes great responsibility.
Password:
Listing 5-16.
Using sudo
这个相当吓人的消息通常在你第一次使用sudo
命令时出现;之后,您只会得到密码提示。
正确输入密码后,sudo
命令不会在每次使用时提示您输入密码。输入密码后,sudo
命令会给你一个宽限期,在此期间不会提示你输入密码。这个时间段在 CentOS 上是 5 分钟,在 Ubuntu 上是 15 分钟。过了这段时间后,当您下次运行sudo
命令时,系统会再次提示您输入密码。
在 Ubuntu 和 CentOS 上,默认安装sudo
命令。Ubuntu 其实连root
用户的密码都不设置;相反,我们鼓励您总是使用sudo
来运行特权命令。Ubuntu 上 admin 组的任何成员都可以运行sudo
命令。在 CentOS 上,我们之前对其进行了配置,如果您是wheel
组的成员,那么您可以使用sudo
命令运行命令。
sudo
命令也是高度可配置的。您可以使用sudo
命令精确地指定可以执行哪些命令,包括将命令分组为不同的命令类别。您可以配置sudo
命令,允许用户执行所有命令、部分命令,甚至执行命令时不提示输入密码(尽管不建议这样做)。
Tip
正如你在本章开始时学到的,你可以通过使用一个叫做visudo
的特殊命令编辑一个叫做/etc/sudoers
的文件来配置sudo
能做什么。我们强烈建议你只使用visudo
来编辑这个文件,因为糟糕的配置会使所有的sudo
命令失败。我们将在“配置 sudo”一节中详细讨论这一点
那么,如果不允许您执行sudo
命令,会发生什么呢?在清单 5-17 中,我们尝试以用户ataylor
的身份使用sudo
命令,他没有使用sudo
命令的正确权限。
$ sudo useradd –m –c 'Illegal User' iuser
ataylor is not in the sudoers file. This incident will be reported.
Listing 5-17.
Unauthorized sudo
使用sudo
命令的失败尝试将被你的主机的syslog
(或系统日志程序)服务记录,然后消息被发送到/var/log/
目录中的一个文件。在 CentOS 上,你可以在/var/log/secure
文件中看到sudo
命令失败,在 Ubuntu 上它们出现在/var/log/auth.log
文件中。将生成一条日志消息,显示日期、时间、试图执行sudo
命令的用户以及用户试图执行的未授权命令。
Sep 1 20:27:43 au-mel-centos-1 sudo: ataylor : user NOT in sudoers ; TTY=pts/1 ;
PWD=/home ; USER=root ; COMMAND=/usr/sbin/useradd –m –c 'Illegal User' iuser
这些消息允许您监控试图在您的主机上执行不适当操作的人,并且它们可用于检测企图的安全漏洞。
Note
在第十八章中,我们将更多地讨论日志记录,以及如何监控类似本节中详述的消息,并发送警报或采取某种措施。
配置 sudo
sudo
命令检查/etc/sudoers
文件以获得运行命令的授权。使用visudo
,您可以配置sudoers
文件来限制特定用户、特定命令和特定主机的访问。
我们来看一下/etc/sudoers
文件。首先,你需要使用命令visudo
来编辑/etc/sudoers
文件。visudo
命令是一个特殊的编辑器,设计用来和sudo
命令一起使用,它是编辑sudoers
文件最安全的方式。该命令锁定文件以防多次同时编辑,提供基本的健全性检查,并检查任何解析错误。如果当前正在编辑/etc/sudoers
文件,您将收到一条消息,提示您稍后再试。
我们将从如何允许用户ataylor
运行userdel
命令开始。我们已经将清单 5-18 的内容添加到sudoers
文件中。
ataylor ALL=/bin/userdel
Listing 5-18.Sample sudoers
我们可以把这条线分解成它的组成部分。
username host = command
清单 5-18 显示用户ataylor
被允许在所有主机上(使用变量ALL
)使用命令/bin/userdel
,就好像她是根用户一样。在命令选项中指定的任何命令都必须用其完整路径来定义。您还可以指定多个命令来授权使用,每个命令之间用逗号分隔,如下一行所示:
ataylor ALL=/bin/userdel,/bin/useradd
在前一行中,ataylor
现在被授权使用userdel
和useradd
命令,就像她是root
用户一样。在sudoers
文件中的所有配置行必须只在一行,你可以使用\来表示配置在下一行继续。
单个sudoers
文件设计用于配置多个主机。因此,它允许特定于主机的访问控制。您将在中央主机上维护您的sudoers
文件,并将更新后的文件分发给您的所有主机。
Note
在第十九章中,我们将讨论配置管理以及如何将这个文件分发给多个主机。
通过主机访问控制,您可以为不同的主机定义不同的授权,如清单 5-19 所示。
ataylor au-mel-centos-1=/bin/userdel,/bin/useradd
ataylor au-syd-ubuntu-1=ALL
Listing 5-19.Using sudo Authorization on Multiple Hosts
在清单 5-19 中,用户ataylor
仅被允许在主机 au-mel-centos-1 上使用userdel
和useradd
命令,但是在主机 au-syd-ubuntu-1 上,她被允许使用由ALL
选项表示的所有命令。
Caution
当使用ALL
变量来定义对主机上所有命令的访问时,您应该小心。ALL
变量不允许授权配置的粒度。
通过授予对特定目录中命令的访问权限,您可以更有选择性地进行授权:
ataylor au-mel-centos-1=/bin/*
这只适用于定义的目录,而不适用于它的任何子目录。例如,如果您授权访问/bin/*
目录,那么您将不能运行/bin/extra/
目录中的任何命令,除非您明确定义了对该目录的访问,如下一行中的配置所示:
ataylor au-mel-centos-1=/bin/*,/bin/extra/*
有时,您希望将特定命令的访问权限授予某个用户,但希望该命令以另一个用户的身份运行。例如,假设您需要作为特定用户启动和停止一些守护进程,比如 MySQL 或named
守护进程。您可以通过将用户名放在命令前面的括号中来指定希望命令启动的用户,如下所示:
ataylor au-mel-centos-1=(mysql) /usr/bin/mysqld,(named) /usr/sbin/named
可以想象,授权命令、用户和主机的列表会变得很长。sudo
命令还带有定义别名的选项。别名是相似用户、命令和主机的集合。通常在sudoers
文件的开头定义别名。我们来看一些别名。第一种别名是User_Alias
,它将用户分组。
User_Alias ADMIN = ataylor,jsmith
您以正在使用的别名类型的名称开始别名,在本例中为User_Alias
,后面是您正在定义的特定别名的名称,在这里为ADMIN
。接下来,指定属于该别名的用户列表。然后,您可以在配置行中引用此别名。
ADMIN=/bin/userdel,/bin/useradd, \
(named) /usr/sbin/named
在前一行中,我们已经指定别名ADMIN
中的用户能够使用命令userdel
、useradd
和named
。
您可以定义的下一种别名是命令别名Cmnd_Alias
,它对命令集合进行分组。
Cmnd_Alias USER_COMMANDS = /bin/userdel,/bin/useradd
您可以将此别名与刚刚创建的用户别名结合使用。
ADMIN ALL=/bin/groupadd,USER_COMMANDS
现在,别名ADMIN
中定义的所有用户都可以在ALL
主机上使用命令/bin/groupadd
以及命令别名USER_COMMANDS
中定义的所有命令。
您还可以指定对主机集合进行分组的别名。Host_Alias
别名可以指定主机名、IP 地址和网络的列表。
Host_Alias SERVERS = au-mel-centos-1, au-mel-centos-2, au-syd-centos-1
您可以将此别名与之前定义的别名结合使用。
ADMIN SERVERS=USER_COMMANDS
现在,ADMIN
别名中指定的所有用户都可以在SERVERS
别名组中定义的主机上运行USER_COMMANDS
中指定的命令。
您也可以通过放置感叹号(!idspnonenote)来否定别名。)在他们面前。让我们来看一个例子。首先,您用一些您不希望用户使用的命令定义一个命令别名,然后您可以将该别名与 sudo 配置行结合使用。
Cmnd_Alias DENIED_COMMANDS = /bin/su,/bin/mount,/bin/umount
ataylor au-mel-centos-1=/bin/*,!DENIED_COMMANDS
在这里,用户ataylor
可以使用 au-mel-centos-1 主机上/bin
目录中的所有命令,除了那些在DENIED_COMMANDS
命令别名中定义的命令。
让我们看看授权用户使用sudo
的另一种方式。在sudoers
文件中,您可以基于主机中的组信息定义另一种类型的别名,方法是在组名前面加上%。
%groupname ALL=(ALL) ALL
然后,您可以用主机上定义的组名替换groupname
。这意味着定义的组的所有成员都能够执行您授权给他们的任何命令,在本例中是在ALL
主机上的ALL
命令。
在 CentOS 主机上,已经有一个名为wheel
的组用于此目的,如果您在 CentOS 主机上取消注释/etc/sudoers
文件中的以下行,那么添加到wheel
组的任何用户都可以使用sudo
命令在您的主机上获得root
权限。在 Ubuntu 上这个组被称为admin
而不是wheel
。
%wheel ALL=(ALL) ALL
此外,sudoers
文件本身有许多选项和缺省值,您可以定义它们来改变sudo
命令的行为。例如,您可以配置sudo
在使用sudo
命令时发送电子邮件。要定义将电子邮件发送给谁,您可以使用以下行中选项:
mailto "admin@au-mel-centos-1.yourdomain.com"
然后,您可以使用更多选项修改sudo
发送电子邮件的时间。
mail_always on
为了让您对可用的默认和选项有个概念,表 5-8 定义了一个与电子邮件相关的选项列表。
表 5-8。
Sending E-mail When sudo
Runs
sudoers
手册页详细介绍了许多其他选项和缺省值。
sudo
命令本身也有一些你可以使用的命令行选项。表 5-9 显示了一些最有用的选项。
表 5-9。
sudo
Command-Line Options
-l
选项特别有用,它允许您确定当前主机上的当前用户被授权和禁止运行什么命令。
$ sudo -l
Password:
User ataylor may run the following commands on this host:
(root) ALL
为了提高可读性,将您的规则分解成逻辑分组的文件并将它们放在/etc/sudoers.d
目录中也是一个好主意。您将发出以下命令:
$ sudo visudo –f /etc/sudoers.d/01_operators
在上面的文件中,我们将放置特定于 operators 组的内容。Sudo 将浏览/etc/sudoers.d/
目录并加载它找到的任何文件,如果存在的话,按顺序,如上。
sudo
命令很复杂,如果执行不当,会使您的主机面临安全漏洞。我们建议您在实现任何sudo
配置之前仔细测试它,并彻底研究sudo
和sudoers
手册页的内容。
Auditing User Access
跟踪用户在做什么是用户管理的一个重要部分。在第十八章中,我们将讨论日志记录,事实上,记录用户行为的第一资源就是日志文件的内容。但是其他命令和资源对于跟踪用户及其活动也很有用。
who
命令显示当前登录到主机的所有用户,以及他们登录到的终端。如果用户远程连接,该命令会显示他们连接的 IP 地址或主机名。
$ sudo who
root tty1 Jul 3 12:32
ataylor pts/0 Jul 8 11:39 (host002.yourdomain.com)
您可以修改who
命令的输出,并且可以在 who man
页面中看到选项的完整列表。可能最有用的命令行选项是–a,它结合了各种命令行选项,提供了登录到您的主机的用户、登录过程以及主机重启和运行级别详细信息的详细概述。
同样有用的还有last
和lastb
命令,它们分别显示用户最后一次登录主机的记录和不良用户登录的记录。如果您在没有任何选项的情况下执行最后一个命令,它将打印上次登录主机的报告。
$ sudo last
root tty1 Sat Jul 3 12:32 still logged in
ataylor pts/0 192.168.0.23 Sat Jul 3 14:25 - 14:26 (00:01)
reboot system boot 2.4.20-28.8 Sat Jul 3 12:31 (4+05:40)
如您所见,last
命令告诉您root
已经登录,并且仍然处于登录状态。该列表还显示了用户ataylor
,他从 IP 地址 192.168.0.23 登录,并保持登录一秒钟。最后一个条目显示了一个reboot
条目。每次主机重新引导时,都会记录一个条目,给出重新引导的时间和主机引导到的内核的版本。
lastb
命令产生相同风格的报告,但是只列出那些“坏”的登录换句话说,它列出了那些输入了不正确的密码或者由于其他错误导致登录失败的登录。
与last
和lastb
命令相关的是lastlog
命令。lastlog
命令显示一份报告,其中显示了主机上所有用户的登录状态,包括那些从未登录过的用户。该命令显示所有用户及其上次登录日期和时间的列表,或者如果该用户从未登录过,则显示一条指示**Never Logged In**
的消息。使用命令行选项,您可以搜索特定用户的记录。阅读lastlog
命令的man
页了解更多详情。
摘要
在本章中,您学习了如何从命令行或通过 GUI 界面创建用户和组。您还了解了登录主机时会发生什么,以及 PAM 和如何控制对主机的访问。
本章还详细介绍了sudo
命令以及如何使用它来避免使用root
用户来管理您的主机。此外,我们研究了如何配置sudo
来控制谁可以访问特定的命令,以及如何报告sudo
的使用情况。最后,我们讨论了如何监控用户的登录。
在下一章,我们将看看当你的主机启动时会发生什么,以及如何启动、停止和管理服务。
六、启动和服务
在前几章中,您已经学习了如何安装 Linux 主机,探索了一些基本的 Linux 概念,并了解了用户和组的概念。这一章将更深入地探究你的 Linux 主机的工作方式,并检查它在“引擎盖下”的运行方式
在这一章中,我们将看看当你的主机启动时会发生什么。我们将逐步完成该过程,并向您展示如何在各种模式下启动您的主机,以及如何配置和修改启动过程。为了演示所有这些,我们将带您了解从您打开主机电源到登录提示符的整个启动过程。
我们还将带您超越引导过程,看看您的主机如何启动和停止应用程序、系统服务和其他进程。CentOS 和 Ubuntu 这两个发行版对这些服务的添加、删除、启动和停止的管理略有不同。我们将向您展示如何在每个发行版上管理这些服务,以及其中的细微差别。您将了解什么是服务,如何启动和停止服务,以及如何查看它们的状态。最后,我们将讨论如何让服务在您的主机启动或关闭时自动启动和停止。
当你的主机启动时会发生什么?
引导过程(boot 是 bootstrap 的缩写)通常涉及三个独立但相互联系的过程:BIOS(基本输入/输出系统)或 UEFI 统一可扩展固件接口)、引导加载程序和操作系统的加载。
- BIOS 或 UEFI 启动并检查您的硬件。
- 引导加载程序允许您选择要加载的操作系统。
- 最后,您的操作系统被加载和初始化。
这些步骤不是特定于 Linux 的;你会发现大多数操作系统执行相似的功能和步骤。
你会发现现代硬件将支持 UEFI。它是 BIOS 的替代品,旧系统将使用 BIOS。它们都执行类似的任务,我们将从 BIOS 开始向您解释它们。
打开电源
让我们更详细地看看当您引导您的主机时会发生什么。您可能已经注意到,当您打开主机时,通常会听到几声哔哔声和呼呼声,并看到前面板上和键盘上有一些闪烁的灯。这是主机启动的第一步,在运行 BIOS 的主机上,这个过程由主板上一个叫做 BIOS 的小芯片控制。
BIOS
BIOS 对连接到系统的不同硬件(如内存、硬盘、键盘和显卡)的可用性执行基本的系统检查或开机自检(POST)操作。根据您的 BIOS,您可以更改不同的设置,但我们会让您在闲暇时进行调查。
BIOS 还将轮询其他硬件,如硬盘控制器,并启动它们的板载芯片。根据您的硬件,您可能会看到 BIOS 屏幕,后面是控制器找到的设备的信息。您可以选择通过按下某个键序列(通常在硬件启动时显示在屏幕上)来配置控制器或其他硬件。此菜单使您能够操作主机的配置;例如,它允许您在硬盘控制器上设置 RAID(廉价磁盘冗余阵列)或解决现有硬件配置的问题。
Caution
更改某些配置可能会有危险;例如,错误地更改 RAID 配置可能会破坏您的数据,因此请谨慎使用这些菜单。
BIOS 还允许您更改主机的引导源。引导源是主机查找操作系统的介质(如硬盘)。启动顺序设置允许您从多个来源之一启动:硬盘驱动器、CD/DVD,甚至 USB 闪存盘。默认情况下,您的主机通常会尝试从连接的硬盘启动,如果配置了硬盘,还会寻找 CD/DVD 驱动器或 USB 闪存盘等替代设备。
每个主板制造商都有不同的方式进入启动源菜单,例如,按 Esc、Del 或功能键,如 F1、F2 或 F10。通常屏幕上会显示一条消息,指示要按的键。从这里通常会显示一个菜单,您可以选择您想要的引导顺序。
统一可扩展固件接口
更多最新的主板将支持 UEFI。当你用 UEFI 启动你的主机时,你会发现和 BIOS 相比差别很小;灯光会闪烁,东西会旋转。预计会比 BIOS 快一点。然而,幕后的事情却完全不同。
创建 UEFI 是为了克服 BIOS 的一些实际限制。BIOS 运行在 16 位处理器上;UEFI 可以在现代处理器上运行。BIOS 被限制在 RAM 中;UEFI 可以在任意多的 RAM 中运行。BIOS 从硬盘的一小部分(主引导记录,或 MBR)中读取数据来加载操作系统。UEFI 改为从安装时创建的特殊 FAT32 分区读取,并且不限于 512 字节。此外,UEFI 要求磁盘上的分区表是 GPT (GUID 分区表),这意味着我们可以启动超过 2tb 大小的磁盘。都说 UEFI 比老 BIOS 更像现代操作系统;在鼠标和键盘的支持下,它甚至可以运行更好的图形界面。
恶意软件可以加载到系统上的方式之一是通过引导加载程序。UEFI 提供了“安全引导”,旨在通过在加载之前使用公钥/私钥验证签名的引导加载程序和硬件来防止这种情况。大多数现代 64 位发行版应该支持安全引导,但这仍然是相对较新的,在安全引导下,您可能会遇到一些硬件问题。在这种情况下,您可以向发行版提交错误报告,并通过 UEFI 配置屏幕禁用安全引导。
最后,目前并不强制要求您使用 UEFI。BIOS 在大多数主板上仍然是“传统”的,并且已经过广泛的测试和支持。但是,在下列情况下,这是强制性的;您在已经运行 UEFI 的系统上运行双引导,并且想要访问大于 2TiB 的磁盘。BIOS 和 UEFI 的目的都是准备好您的硬件,并找到引导加载程序来加载您的操作系统。
More on Disks
在前面的章节中,我们已经讨论了磁盘分区,并且说磁盘就像一个蛋糕,你可以把它分成小块,但是这是怎么做到的呢?当你分割你的磁盘时,你在磁盘上创建了一个叫做分区表的表。分区表通常位于磁盘的开头,它告诉计算机磁盘是如何布局的。也就是说,有多少磁盘已经分配给了'/boot'
分区,预计有多少是逻辑卷管理(LVM)等等。
上面我们谈到了 MBR 和 GPT,这是两种类型的分区表。分区表保存有关块地址的信息(以 512 字节或 4KB 磁盘为单位)。MBR 只能容纳 2tb 的地址,而 GPT 可以容纳 8-9ZiB。
图 6-1。
Your hard disk
磁盘要么在开头有一个 MBR(前 512 个字节),要么有 GPT。如果它有 MBR,分区表会在磁盘的前 446 个字节之后写入。分区表的大小是 64 字节,后面是 MBR 引导签名(2 字节)。直到第一个分区的剩余空间通常称为 MBR 间隙,其大小会有所不同,因为大多数分区器会将分区的开头与第一个 1MB 对齐。
另一方面,GPT 的地址空间为 16,384 字节,最多可以容纳 128 个分区。GPT 会在磁盘末端制作一份自身副本,以备损坏时恢复。除了分区表之外,其余的磁盘可以按照您认为合适的方式进行划分。有关更多详细信息,请参见以下内容:
引导装载程序
带 BIOS 的引导加载程序
一旦您的主机加载了所有检查过的连接到主板的所有东西,并设置了低级系统设置,它就可以启动您的操作系统了。BIOS 和 UEFI 都不知道你正在引导的操作系统,但是它知道如何运行你的发行版提供的代码。这个代码被称为引导加载程序,它需要在您引导的磁盘上的正确位置。
Note
严格来说,UEFI“对你的操作系统一无所知”是不正确的。它实际上确实知道一些,但主要的一点是它不是你的操作系统,而是硬件的底层接口。
运行 BIOS 的主机使用引导源设置来指定在哪里寻找引导过程的下一阶段:引导加载程序。BIOS 使用硬盘上的特殊部分,即主引导记录。
当我们安装操作系统时,我们安装了一个名为 GRUB2 的引导加载程序。它代表 GRand Unified Bootloader (2 ),它的工作是启动自己,然后找到、加载并移交给你的操作系统。它分两个阶段完成,第一阶段的目的是加载第二阶段。我们之前讨论过 MBR,并且说过在分区表之前,磁盘的起始处有 446 个字节。这是您的操作系统的引导加载程序代码的第一阶段将被存储的地方,BIOS 将尝试执行它在那里找到的代码。对于 Linux,这是一个名为boot.img
的文件。
当 BIOS 执行boot.img
时,它会找到并运行一个名为core.img
的文件。该文件通常安装在 MBR 间隙中,即 MBR 和磁盘上第一个分区之间的空间。core.img
的工作是访问/boot/grub
并加载它在那里找到的模块。core.img
将加载菜单,并有能力加载目标操作系统。
使用 UEFI 的引导加载程序
如果您使用 UEFI 系统,引导过程会有所不同。UEFI 可以读取 GPT 分区表,并且可以在 EFI 系统分区的/EFI/
目录中找到并执行引导加载程序代码。与 BIOS 不同,UEFI 有自己的分区,引导加载程序和模块可以安装到其中。
在图 6-2 中,我们可以看到在安装之后,我们在驱动器/dev/sda
上创建了三个分区。第一个是我们的 EFI 系统分区,它是一个 FAT32 文件系统,大小为 537MB。它有 boot 和 esp 标志(都意味着它是一个引导分区)。另外要注意的是,分区表是 GPT。
图 6-2。
EFI partition on Ubuntu
因此,当 UEFI 准备运行引导加载程序时,它会读取这个分区,寻找引导加载程序。在这种情况下,我们的 Ubuntu 主机会找到/EFI/ubuntu/grubx64.efi
。引导加载程序的初始部分将找到包含 GRUB2 软件的'/boot'
分区,并从 GRUB2 中加载core.efi
并调出 grub 2 菜单。
有关 UEFI 和 UEFI Shell(可用于管理 UEFI 的交互式 Shell)的更多信息,请参见以下内容:
https://help.ubuntu.com/community/UEFI
https://fedoraproject.org/wiki/Unified_Extensible_Firmware_Interface
https://www.happyassassin.net/2014/01/25/uefi-boot-how-does-that-actually-work-then/
https://software.intel.com/en-us/articles/uefi-shell
在没有任何干预的情况下,GRUB2 将在短暂的倒计时后启动默认内核。按任意键将停止倒计时,向您显示更详细的可用选项菜单,并让您有机会编辑您的引导配置。在“使用 GRUB2 菜单”一节的后面,我们将解释这些选项以及如何操作它们。
在选择了您希望引导到的内核之后(或者在超时之后等待默认内核被加载),GRUB2 现在将找到内核二进制文件(vmlinuz-<release-number>
),然后将一个名为initrd.img
的特殊文件加载到内存中。这个文件包含您的内核需要加载的驱动程序,以利用您的主机的硬件。
启动操作系统
加载initrd.img
后,GRUB2 完成并将控制权移交给内核,内核通过初始化硬件(包括硬盘)继续引导过程。你的操作系统被启动,一个叫做systemd, upstart
或init
的特殊程序被调用,它启动你的服务并使你的主机活跃起来。我们将在本章的后面看一下all three of these system initializers
以及如何管理服务,但是首先,更多关于引导加载程序。
了解 GRUB2 引导加载程序
因此,现在让我们深入研究什么是引导加载程序,它做什么。我们还将了解一下如何配置它。我们不打算涵盖引导加载程序的每一个细节,因为你很少需要改变它,并且对它的大多数改变是自动发生的,例如,当你安装一个新的内核包时。但是您应该了解它的作用以及它在主机引导过程中的位置。
一些历史;在 Linux 世界中,有两种主要的引导加载程序:LILO 和 GRUB。几年前,GRUB 引导加载程序成为 Red Hat 和 Ubuntu 的默认设置。在这里,我们将专注于 GRUB 的最新版本 GRUB2。GRUB2 是一个强大的多重引导加载程序。多重引导加载程序可以使您的主机引导到许多不同的操作系统。与 Microsoft Windows 或 Mac OS X(以及它们的引导加载器工具—分别为 NTLDR 和 Boot Camp)不同,GRUB2 允许您在一个硬件上引导多个版本的 Linux、Microsoft Windows 和 Mac OS X。这并不意味着您可以像使用虚拟机技术一样同时运行它们,但是您可以在启动时通过从 GRUB2 菜单中选择它们来单独启动它们。
Note
LILO 是一个遗留的引导加载程序,在许多旧版本的 Linux 发行版中用作默认的引导加载程序。今天很少看到它,2015 年它的开发停止了。关于 LILO 引导加载程序的信息,请参见 http://tldp.org/
HOWTO/LILO.html
。
那么 GRUB2 是如何工作的呢?GRUB2 的核心使用四项来引导系统:内核文件、驱动器名、内核文件所在的分区号,以及可选的初始 RAM 磁盘。
GRUB2 能够以两种方式引导。一种是直接找到并加载所需的内核,这是大多数 Linux 发行版的引导方式。GRUB2 还支持一种引导的方法,叫做链式加载;使用这种方法,GRUB2 加载另一个引导加载程序,例如用于 Microsoft Windows 的加载程序,然后加载所需的操作系统内核。这允许 GRUB2 使用自己的引导加载程序来引导其他操作系统。
使用 GRUB2 菜单
当您的主机启动时,它将启动到默认内核(或操作系统),或者您可以覆盖它并显示 GRUB2 菜单。一旦菜单显示出来,您将看到一个引导选项列表,您可以使用键盘上的上下箭头来选择您希望引导的内核。您还可以编辑 GRUB 菜单,并在引导到您选择的内核之前更改参数、命令和自变量。
例如,我们可以选择引导到所谓的单用户模式或维护模式。这种特殊的模式在您的主机出现问题时使用,它将对主机的访问限制为根用户:通常在系统控制台。这种模式的功能与 Microsoft Windows 恢复控制台非常相似,允许您使用磁盘和文件等资源,而不必担心冲突或其他用户操纵主机。现在让我们来看看如何引导到单用户模式。
首先,这在 CentOS 和 Ubuntu 之间略有不同。两者都显示了类似的 GRUB2 引导菜单,允许你用箭头键选择你想运行的内核。CentOS 提供了我们之前讨论过的两个菜单项,一个是内核,另一个被描述为救援内核。在 Ubuntu 上,你会看到一个名为高级选项的子菜单项。您可以使用箭头键浏览以查看恢复模式内核。
在这个练习中,我们将使用 Ubuntu 主机的普通内核。按 e 键编辑突出显示的内核。您将看到该内核的配置,比如它的位置和参数,如图 6-3 所示。
图 6-3。
Booting to single-user mode , or maintenance mode , using the GRUB2 menu
您将在这里看到您在grub.cfg
菜单中看到的详细信息。在这个特定的例子中,我们感兴趣的线是linux /vmlinuz-4.4.0-15-generic.efi.signed…
线。使用箭头键导航到该行的末尾。要引导进入单用户模式,请在该行末尾添加单词’single’
(不带引号)。在图 6-3 中,你可以看到我们已经在线尾添加了single
字样。在图 6-3 的底部,你可以看到我们现在可以输入 Ctrl-x 或 F10 以此设置启动,或者输入 Ctrl-c 以获得命令行或 ESC 以放弃这些更改并返回主菜单。
我们可以选择 Ctrl-x,引导进入单用户模式。我们首先被要求输入密码来解密我们的硬盘。然后,根据您的发行版,您将得到一个要求 root 用户(仅 CentOS)的维护密码提示,或者您可以点击 enter 并得到一个 shell 提示(参见图 6-4 )。
图 6-4。
Maintenance mode
现在我们有了 shell 提示符,我们可以着手修复我们系统中可能存在的任何问题。不过,对内核行的这些更改不是永久的,下次主机启动时,它将正常启动。使用 GRUB2 菜单,您可以操作几乎所有可用的引导运行时配置设置。
需要注意的是,我们提供上面的内容作为示例,它显然有一些相关的安全问题——如果您在引导时可以访问控制台,这将为您的主机提供非常强大的访问权限。我们接下来会帮助解决这个问题。还有其他的恢复方法,我们将在第九章中进一步讨论。同时,以下是很好的信息来源:
https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/System_Administrators_Guide/sec-Terminal_Menu_Editing_During_Boot.html
https://wiki.ubuntu.com/RecoveryMode
配置 GRUB2
GRUB2 引导加载程序是高度可配置的,它的配置包含在grub.conf
配置文件中。GRUB2 使grub.cfg
比它更简单的前身更加模块化。您需要对 GRUB2 配置进行许多更改的机会很小,但却是可能的。
GRUB2 文件位于不同发行版的不同位置。在 CentOS 等基于 Red Hat 的主机上,可以在/boot/grub2/grub.cfg
找到它们(文件通常象征性地链接到/etc/grub.conf
)。在 Ubuntu 和 Debian 主机上,这些文件可以在/boot/grub/grub.cfg
找到。
GRUB2 中的grub.cfg
文件由一系列配置文件组成。在 Ubuntu 和 CentOS 主机上,您都可以在目录/etc/grub.d
中找到配置文件。在该目录中,您会看到一个按编号排序的文件列表。在清单 6-1 中,您可以看到 CentOS 7 主机上的文件。
total 72
-rwxr-xr-x. 1 root root 8702 Nov 25 02:49 00_header
-rwxr-xr-x. 1 root root 992 May 4 2015 00_tuned
-rwxr-xr-x. 1 root root 230 Nov 25 02:49 01_users
-rwxr-xr-x. 1 root root 10232 Nov 25 02:49 10_linux
-rwxr-xr-x. 1 root root 10275 Nov 25 02:49 20_linux_xen
-rwxr-xr-x. 1 root root 2559 Nov 25 02:49 20_ppc_terminfo
-rwxr-xr-x. 1 root root 11169 Nov 25 02:49 30_os-prober
-rwxr-xr-x. 1 root root 214 Nov 25 02:49 40_custom
-rwxr-xr-x. 1 root root 216 Nov 25 02:49 41_custom
-rw-r--r--. 1 root root 483 Nov 25 02:49 README
Listing 6-1.
ls –la /etc/grub.d
清单 6-1 显示了组成一个grub.cf
g 文件的文件。在这种情况下,这些文件通过grub2-mkconfig
命令从00_header
读入41_custom
。您通常不需要了解这些文件,因为您很少需要定期接触它们。您可能感兴趣的文件是01_users
和40_custom
文件。如果设置了引导加载程序密码,则01_users
文件会加载该密码。40_custom
文件是您可能希望添加定制 GRUB2 配置的地方。
Tip
在 Linux 配置文件中,以#符号为前缀的行通常表示注释,在处理配置文件时会跳过这些行。
GRUB2 配置文件通过grub2-mkconfig
命令生成。它有一个参数,即您希望在哪里创建文件的–o
或--output
选项。您现在可以创建自己的grub.cfg
文件了。它将探测您的系统,运行您的配置文件,并输出一个您可以查看的文件。当然,您不必用这个文件覆盖您当前的grub.cfg
,所以我们将把输出更改为本地目录中的一个文件。
$ sudo grub2-mkconfig --output mygrub.cfg
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-3.10.0-327.el7.x86_64
Found initrd image: /boot/initramfs-3.10.0-327.el7.x86_64.img
Found linux image: /boot/vmlinuz-0-rescue-65e567f18fe84907a6f1d8519e921c97
Found initrd image: /boot/initramfs-0-rescue-65e567f18fe84907a6f1d8519e921c97.img
done
Listing 6-2.Creating a grub.cfg
在清单 6-2 中,您可以看到我们使用了sudo
命令来提升我们执行grub2-mkconfig
命令的权限。该命令遍历/etc/grub.d
目录中的文件,并按编号顺序执行。控制台的命令输出显示,is 已经找到了两个内核(vmlinuz ),其中一个是“救援”内核。grub2-mkconfig
命令已经探测了我们的系统,并通过/etc/grub.d/30_os-prober
脚本找到了它们。
查看已经生成的mygrub.cfg
文件(使用$ less mygrub.cfg
),您将在/etc/grub.d
中看到所有这些文件的输出。我们将集中讨论启动操作系统的部分,从下面一行开始:
### BEGIN /etc/grub.d/10_linux ###
在开始行下面是配置我们菜单项的 menuentry。
menuentry 'CentOS Linux (3.10.0-327.el7.x86_64) 7 (Core)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-327.el7.x86_64-advanced-f60589f6-4d39-4c5b-8ac6-b1252f28f323' {
....
}
Listing 6-3.menuentry in the grub.cfg
这看起来已经很难消化了,我们已经把清单 6-3 减少到了第一行。以menuentry, this
开头,告诉 grub 我们有一个新的菜单项要列出来。CentOS Linux (...) 7 (Core)
给出了菜单列表中显示的名称。其他信息由--class
参数提供,用于显示某些主题(如闪屏等)。
--unrestricted
选项用于允许任何用户在引导时通过控制台菜单运行该条目。这可以通过--users
选项进行更改,在这里您可以列出能够运行该条目的用户(注意,任何被列为superuser
的用户仍然可以访问)。当然,这意味着任何移除了--unrestricted
的条目都不会自动引导,需要干预。GRUB2 文档指出,这并不是真正的最佳安全形式,因为它需要在重启时访问控制台,但在 kiosk 类型的安装中可以考虑。我们将在“保护您的引导加载程序”一节中详细讨论这个问题和超级用户
在清单 6-3 中,我们省略了花括号{ }之间的代码。现在让我们看看清单 6-4 中的代码。
menuentry ... {
load_video
set gfxpayload=keep
insmod gzio
insmod part_msdos
insmod xfs
set root='hd0,msdos1'
if [ x$feature_platform_search_hint = xy ]; then
search --no-floppy --fs-uuid --set=root --hint-bios=hd0,msdos1 --hint-efi=hd0,msdos1 --hint-baremetal=ahci0,msdos1 --hint='hd0,msdos1' 85932bb0-c5fe-431f-b129-93c567e4f76f
else
search --no-floppy --fs-uuid --set=root 85932bb0-c5fe-431f-b129-93c567e4f76f
fi
linux16 /vmlinuz-3.10.0-327.el7.x86_64 root=/dev/mapper/centos-root ro crashkernel=auto rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet
initrd16 /initramfs-3.10.0-327.el7.x86_64.img
}
Listing 6-4.Grub Boot Menu Code
在 menuentry 代码的花括号内,前几行代码安装了各种模块。例如,第一行,load_video
调用grub.cfg
脚本中的一个函数,为闪屏插入各种视频模块。CentOS 7 主机上的模块可以在/boot/grub/i386-pc/
中找到,并通过您在后续行中看到的insmod
命令加载。您在这里看到的三行 insmod 正在加载压缩和文件系统模块。
set root='hd0,msdos1'
是我们如何为 GRUB2 设置根设备。GRUB2 使用此设置来帮助查找 GRUB2 需要的文件。这意味着根设备在硬盘驱动器(hd)
上,并且是第一个硬盘驱动器(hd0)
。'msdos'
是根设备的文件系统,最后的“1”是hd0
上的分区号。如果你从一个 USB 驱动器启动,你可能希望它看起来像'usb0,msdos1'
。
Note
Linux 操作系统中的编号一般从 0 开始计数,而不是从 1 开始计数。然而,就 GRUB2 而言,磁盘上的第一个分区是分区 1。第一个磁盘/设备从 0 开始编号。
接下来在清单 6-4 中,我们看到一个 if…fi 条件语句,里面有一个搜索命令。根据‘$feature_platform_search_hint’
是否设置为 y,搜索命令会有所不同。此处发生的情况是,搜索命令通过 UUID(通用唯一标识符)查找设备。这用于再次设置 GRUB2 的根设备,以便它可以找到我们将要加载的 Linux 内核。
在清单 6-4 中,我们终于加载了我们的 Linux 内核。linux16 行的第一部分说我们将使用 16 位模式加载内核(16 位模式用于解决视频模式的某些问题)。下一部分是 Linux 内核本身,/vmlinuz-3.10.0-327.el7.x86_64
。您将在/boot
目录中找到这个文件。接下来,我们将选项传递给内核。我们通过root=/dev/mapper/centos-root
来提供到’/'分区的路径。最初,我们将内核加载为‘??’或只读。crashkernel=auto
选项是 kdump 内核的一个设置,表示为它保留的内存量。接下来的两个选项告诉内核它需要加载两个 LVM 逻辑卷:centos/root
和centos/swap
。最后,我们可以看到我们加载了 Red Hat Graphical Boot (rhgb),这是一个比文本更好的引导体验,并且我们设置了quiet
选项来抑制引导期间的噪声输出。
最后,清单 6-4 中我们关心的最后一行是加载内核 initrd。initrd 是一个临时根文件系统,引导过程使用它首先加载所需的可执行文件和驱动程序,然后挂载系统的“真正的”根(‘/’)文件系统。它仅在启动时使用,并且一旦装载了真正的文件系统,它就会被卸载。
我们只向您展示了一个 GRUB2 菜单,并且只来自 CentOS 主机。对于 Ubuntu 主机来说,菜单项会稍有不同。通常情况下,您会看到每个已安装的内核至少有两个菜单项,其中一个是用于系统恢复的“救援”内核。它是内核的一个副本,以防在 CentOS 上被破坏,没有特殊的内核选项。Ubuntu 是不同的,因为它通过了recovery
和nomodeset
内核选项。我们稍后会详细讨论这些。
Note
你可以在 http://www.gnu.org/software/grub/manual/grub.html
和 https://wiki.archlinux.org/index.php/kernel_parameters
找到更多关于定义内核和内核选项的信息。你也可以通过info grub
命令查找信息。
Managing Your Kernel
不是所有的内核都需要一个initrd
文件。例如,您自己编译的包含系统所需的所有模块的内核不应该需要一个initrd
文件。
例如,如果内核的后续版本支持您需要的一些新硬件或功能,您可能希望编译自己的内核。编译你自己的内核是一个很好的练习,只是为了看看选项是什么以及如何工作。
我们通常建议您坚持使用您的发行版提供的普通内核,并且只编译您自己的内核以获得乐趣,或者如果您确实需要某些特定的功能。管理“手工制作”的内核对于修补和更新来说可能是一个负担,有时会留给您一个无法更新的系统。
当你更新你的内核时,你需要重启以获得关键补丁。在 Linux 内核的版本 4 中,自 2015 年以来,一直在致力于一种修补内核的方法,使其不再需要重新启动,即使是关键的补丁。它是 SUSE 和 Red Hat 的工作成果,灵感来自 Oracle 的原创作品。在撰写本文时,它仍然是新的,支持代码仍然需要一些工作。
要获得最新内核的副本和其他信息,您可以到这里:
推荐的更新内核的方法是通过发行库。然而,这也是支持诸如 RHEL (Red Hat Enterprise Linux)、Oracle Linux、Canonical Enterprise Support 等发行版的巨大优势所在。如果你需要紧急的内核补丁,他们会经常为你报告的问题更新和发布内核补丁。等待非商业发行版发布您感兴趣的补丁可能会失败。
保护您的引导加载程序
拥有这样一个通用且可配置的引导加载程序有其缺点。我们提到的其中之一是安全。任何怀有恶意的人都可以在引导时修改不安全的引导加载程序。许多小型办公室会将服务器放在两张桌子上或下面,而不是锁在计算机房里,因此这些服务器很容易受到这种攻击。我们强烈建议您考虑在您的引导加载程序上设置一个密码,并将它与您的其他密码一起存储在一个非常安全的地方。
Caution
同样,你应该把你的密码放在一个安全的地方,比如一个保险箱或者其他安全的上锁的地方。有时,将它保存在异地的某个地方也是很好的(就像对异地备份一样),这样,如果您的站点发生问题,您不仅能够恢复您的数据,还可以随时使用正确的密码来访问您的主机。您还应该备份所有密码,并告诉您公司中信任的人在紧急情况下可以在哪里找到这些密码。
幸运的是,GRUB2 提供了为引导加载程序设置密码的能力,因此对预先配置的引导过程的任何更改都需要用户输入密码。CentOS 主机提供了一些工具来简化这一过程,我们将在本练习中探索这种分布。首先,我们发出以下命令:
$ sudo grub2-setpassword
这将要求您输入密码并进行确认,并且只会为 root 用户创建一个密码。这个命令实际上是创建一个文件/boot/grub2/user.cfg
。该文件的内容如下所示:
GRUB2_PASSWORD=grub.pbkdf2.sha512.10000.00E574C[...]DDF512CC090A9B[...]CCEA3B
既然文件已经创建,当您的主机重新启动时,现在将执行/boot/grub2/grub.cfg
文件中的代码:
### BEGIN /etc/grub.d/01_users ###
if [ -f ${prefix}/user.cfg ]; then
source ${prefix}/user.cfg
if [ -n ${GRUB2_PASSWORD} ]; then
set superusers="root"
export superusers
password_pbkdf2 root ${GRUB2_PASSWORD}
fi
fi
### END /etc/grub.d/01_users ###
Listing 6-5.Adding Root User to grub.cfg
清单 6-5 中代码的意思是,如果user.cfg
文件存在,那么我们将“获取”内容。如果声明了一个$GRUB2_PASSWORD
变量,那么我们将把root
添加到超级用户列表中,这将其他用户锁定在GRUB2
命令行之外。最后,password_pbkdf2
是一个 GRUB2 命令,它将用户与密码相关联。我们现在需要运行grub2-mkconfig –o /boot/grub2/grub.cfg
来设置超级用户 root 密码。
当您的主机下次启动时,您会注意到,如果您在 GRUB2 阶段中断启动过程,您将能够使用--unrestricted
menuentry 选项选择一个内核。但是,如果您想要编辑任何 GRUB2 配置详细信息,您需要按 e 键输入密码。然后,您将能够正常编辑 GRUB2 配置。
要删除密码,请删除user.cfg
文件。请记住,GRUB2 文档建议不要这样做,除非您的主机是公开的。我们建议你根据自己的情况做出最好的判断。
请记住,Ubuntu 并没有提供这些现成的工具,但是您可以遵循该发行版的类似过程。有关 Ubuntu 的具体指南,请参见 https://help.ubuntu.com/community/Grub2/Passwords
。
开机后会发生什么?
所以你的主机找到了你的内核并启动了它。您的操作系统现在开始加载,您的硬件初始化,磁盘准备就绪,IP(互联网协议)地址分配,以及各种其他任务的执行。为此,Linux 运行一个程序,其任务是启动操作系统及其服务。这个程序是第一个在您的系统上启动的程序,并且一直运行到系统关闭;不出所料,这个进程的进程 id (PID)将为 1。初始化程序,或称“init”,将通过找出需要启动的服务以及它们所依赖的东西,使系统达到一个已知的“状态”。它通过遍历文件系统上的一系列文件并读取它们的指令来实现这一点。
目前 Linux 正处于一个过渡阶段。直到最近,至少有三种不同的程序处理系统初始化。这些是旧的 SysV Init 程序,Ubuntu 的 Upstart 程序,或者更新的 systd。
Upstart 是 Ubuntu 试图替换旧的 SysV Init 初始化器。因为它与 SysV 兼容,所以它也被其他发行版用作初始值设定项;然而,没有多少完全实现暴发户。它只是被用作一个更好的“初始化”基于 Red Hat 的主机已经完全实现了 Systemd,基于 Debian 的系统,比如 Ubuntu,正在从 Upstart 和 SysV Init 过渡到 Systemd。
Systemd 是一种较新的系统初始化方法,可以在 CentOS 上默认使用(或者说是本地运行 systemd ),您可以在图 6-5 中看到 systemd 是 PID 1。另一方面,据说 Ubuntu“模仿”SysV Init。它通过使用 SysV initd 脚本来初始化许多使用 systd 包提供的兼容性脚本的服务来做到这一点。
图 6-6。
PID 1 onUbuntu
图 6-5。
PID 1 on CentOS
在 Ubuntu 上,/sbin/init
程序是 PID 1。PID 为 1 的 init 程序来自 systemd-sysv 包,实际上链接到 systemd 二进制文件或程序。Ubuntu 目前支持所有三种 init 类型,同时正在过渡到原生运行 Systemd。
这两个发行版都安装了 systd-sysv 包,其中包含用于运行 SysVInit 风格的 initd 脚本的兼容性实用程序。它旨在替代 SysVInit,但并不是 100%兼容。
让我们看看如何管理 Systemd 本机实现。我们还将简要讨论 Upstart 和较老的 SysV init。
Note
init 程序有很长的历史,解决如何启动系统的问题的流行和不受欢迎的尝试都有。为了更好地观察它们,请参见 http://blog.darknedgy.net/technology/2015/09/05/0/
。
理解系统
正如我们已经提到的,Systemd 是最新的系统初始化器,在许多现代发行版中都有使用。systd 是 SysV Init 和 Upstart 的替代品。有人批评它违背了 Unix 的哲学(做一件事,把它做好),但是它在以下几个方面(或多或少)比它的前辈提供了许多优势:
- 它是事件驱动的。这意味着它可以响应系统事件(例如插入新硬件、网络端口上开始的流量)
- 并发和并行引导处理
- 它可以重生过程
- 事件记录
- 通过内核的 CGroups 跟踪进程
对于那些已经熟悉 SysV 的人来说,systd 没有像 SysV 那样的运行级别,而是有“目标”。目标用于将服务依赖项组合在一起。systemd 中有一些常见的目标,如多用户、重启和救援。就像在运行级别中一样,我们可以有不同的目标,将我们带到特定的和离散的状态。例如,如果我们希望系统处于每个人都可以登录并使用服务的状态,我们将使用目标多用户。在这种情况下,我们希望 sshd、日志和网络可用。这些被认为是多用户目标的“需求”。
还记得图 6-3 中我们向您展示了如何从 GRUB2 菜单进入“维护”模式吗?我们在启动 Linux 内核的那一行的末尾键入单词“single”。嗯,使用 Systemd,我们也可以通过声明我们希望启动的目标来做同样的事情。
linux16 /vmlinuz-3.10.0-327.el7.x86_64 root=/dev/mapper/centos-root ro crashkernel=auto rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet systemd.unit=rescue.target
Listing 6-6.Using Systemd Targets to Boot to Rescue Mode
从清单 6-6 中,您可能会意识到我们是在 CentOS 服务器上;我们可以在 Ubuntu 服务器上做同样的事情。您可以看到,我们已经在该行末尾发出了systemd.unit=rescue.target
。我们告诉内核,当它运行 systemd 时,我们应该到达救援目标。
Systemd 使用一组“单元”文件来管理系统上的服务。当 systemd 启动时,它通过遍历以下加载路径来查找所需的单元文件:
表 6-1。
Systemd Load Path
| 小路 | 目的 | | --- | --- | | /etc/systemd/system | 本地化的配置文件 | | /run/systemd/system | 运行时单元文件 | | /usr/lib/systemd/system | 已安装软件包的单元文件 |因为我们使用了system.unit=rescue.target
参数,当系统进程启动时,它将按照优先顺序在这些目录中查找rescue.target
文件,然后是/etc/systemd/system, then the /run/systemd/system
目录,最后是/usr/lib/systemd/system
目录。/etc/systemd/system
和/run/systemd/system
目录被称为“插入”目录,systemd 将在那里搜索单元和*.conf
文件。目标文件将类似于下面的rescue.target
。
[Unit]
Description=Rescue Mode
Documentation=man:systemd.special(7)
Requires=sysinit.target rescue.service
After=sysinit.target rescue.service
AllowIsolate=yes
[Install]
Alias=kbrequest.target
Listing 6-7.The rescue.target File
在清单 6-7 中,我们删除了系统进程忽略的以“#”开头的注释。选项区分大小写。在分解这个文件时,您可以看到它有两个部分,用方括号([…])表示。Systemd 单元文件至少需要[Unit]和[Install]部分。您可以选择包含一个[服务]部分,我们将很快对此进行讨论。
[Unit]部分有一个描述和文档设置,它们是不言自明的。在清单 6-7 中,我们可以看到 rescue 目标需要 sysinit.target 和 rescue . service。Requires 不提供排序,但告诉 systemd 这些服务也应该执行。如果所需的目标或服务之一失败,该单元也将被停用。
通过添加像 After 这样的选项来提供对目标或服务的订购支持。rescue.unit
现在应该在sysinit.target
和rescue.service
之后开始。常见的模式是在所需选项中看到相同的服务和目标,在之后选项中也列出了这些服务和目标。
AllowIsolate 选项是一个由systemctl isolate
命令读取的布尔值。systemctl 命令的 isolate 参数本质上类似于 SysV 运行级别。您可以使用它将您的系统置于特定的“状态”,因此要启动您的图形环境,您可以选择运行systemctl isolate graphical.target
。因此,AllowIsolate 默认设置为“false/no ”,因为不是每个目标文件都提供稳定的系统状态。
当装置启用或禁用时,systemctl 工具使用[Install]部分。systemctl 工具是用于管理 systemd 的实用工具。这里的 Alias 选项指向kbrequest.target
,它是一个特殊的 systemd 单元,每当在控制台上按下 Alt+ArrowUp 时就会启动。看一下图 6-7 来看看它是如何工作的。
图 6-7。
Using systemctl to enable the Alt-ArrowUp alias
在图 6-7 中你可以看到,当我们发出$ sudo systemctl enable rescue.target
时,安装部分的别名选项意味着我们创建了一个从kbrequest.target
到rescue.target
的符号链接。现在,在控制台上,如果我们点击 Alt+向上箭头键,我们会得到如图 6-8 所示的结果。
图 6-8。
Entering rescue console from pressing the Alt+ArrowUp keys
让我们快速地看一下一个服务文件,它配置了我们如何管理 rsyslog 守护进程。Rsyslog 是 Linux 上的日志服务,我们将在第十八章中深入探讨它。在清单 6-8 中,我们显示了rsyslog.service
文件的内容。
[Unit]
Description=System Logging Service
;Requires=syslog.socket
[Service]
Type=notify
EnvironmentFile=-/etc/sysconfig/rsyslog
ExecStart=/usr/sbin/rsyslogd -n $SYSLOGD_OPTIONS
Restart=on-failure
UMask=0066
StandardOutput=null
[Install]
WantedBy=multi-user.target
;Alias=syslog.service
Listing 6-8.The rsyslog.service systemd File
在这个文件中,我们有[Unit]和[Install]部分,就像我们以前看到的一样。值得注意的是,在这些部分中,您可以看到 Requires 和 Alias 选项上的分号。如果行以#
或;
开头,那么它们被认为是注释并被忽略。在清单 6-8 中,我们看到有一个【服务】部分,我们用它来描述我们正在配置在我们系统上运行的服务。
所有[服务]部分都需要类型选项。它可以设置为“简单”、“分叉”、“一次性”、“dbus”、“通知”或“空闲”默认设置是“简单”对于 simple 类型,您期望由 ExecStart 选项运行的进程是主进程(即,它不派生子进程)。Notify 类似于 simple,但它会在完成启动后发送一条通知消息。一旦 Systemd 读取到此消息,它将启动其他单元。因为这是一个日志服务,所以在启动依赖于记录日志事件的其他单元之前,确保该服务启动并运行是有意义的。
环境文件是我们可以加载环境参数的地方。可以为 rsyslogd 设置许多可选参数,您可以将它们添加到/etc/sysconfig/rsyslog
文件中。可以将man rsyslogd
中的选项添加到文件中。
接下来我们有 ExecStart 选项。这是与任何参数一起执行的命令。这应该是守护进程的主进程,除非你要分叉这个进程(用 Type=fork)。
Restart 选项控制 systemd 如何监控服务并对任何问题做出反应。选项包括“否”、“成功时”、“失败时”、“异常时”、“监控时”、“中止时”或“总是”rsyslog 服务被设置为失败时重新启动,如果未设置,默认值为“否”。设置 on-failure 意味着当进程以非零退出代码退出、被信号终止、操作超时或触发监控超时时,systemd 将尝试重新启动服务。
UMask 设置由此进程创建的任何文件的权限。如果我们还记得在第四章中学到的内容,umask 是一个八位字节,用于设置文件和目录的权限。当应用它时,意味着我们给予由该进程创建的文件 0711 或 rwx-x-x 权限。这意味着该进程的所有者被给予对文件的读、写和执行权限,该组和其他每个人将只有执行权限。
[Service]部分的最后一个选项是 StandardOutput,它定义了文件描述符 1 或进程的标准输出应该连接到哪里。这些值是" inherit “、” null “、” tty “、” journal “、” syslog “、” kmsg “、” journal+console “、” syslog+console “、” kmsg+console “或” socket "。rsyslogd 服务被设置为 null,这是 Linux 上一个名为/dev/null
的特殊文件。如果你向/dev/null
写,你希望你的数据被黑掉或丢失。这意味着我们不关心这个服务在标准输出上的输出。
最后,如果您查看[Install]部分,您将看到 WantedBy=multi-user.target。该行指示 systemctl 命令在服务启用时在/etc/systemd/system/multi-user.target.wants
目录中创建一个到/lib/systemd/system/rsyslog.service
的符号链接,或者在服务禁用时删除该链接。稍后会有更多内容。
Systemd 单元文件很复杂,并且依赖于许多其他的依赖单元。systemd 单元还有数不清的选项和设置。如需进一步阅读,请参阅以下有用的链接:
https://access.redhat.com/videos/403833
www.freedesktop.org/wiki/Software/systemd/
www.freedesktop.org/software/systemd/man/systemd.html
https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/System_Administrators_Guide/chap-Managing_Services_with_systemd.html
一旦您的内核被转移到 systemd 进程,并使您的机器达到目标状态,您将需要知道如何与系统上运行的服务进行交互。我们将在查看 systemctl 命令时对此进行探讨。
新贵:Ubuntu 的 Init
Upstart 背后的想法是创建一个全面的init
进程,可以用来代表 Linux 主机上的服务启动、停止、监控和响应事件。这是对 SysV Init 范式的改造和扩展;设计师没有直接替换 SysV Init,而是创建了 Upstart 来模拟 SysV Init,直到所有人都转换过来。
Upstart 下的init
进程是一个基于事件的守护进程,它使用事件触发器来启动或停止进程。事件是可以通知init
的状态变化。事件可以是添加外围设备,如插入 USB 记忆棒。然后内核可以通过发送事件通知来通知 init 这个动作。根据init
控制下的作业定义,该事件反过来可以触发其他作业的启动或停止。
Upstart 在其命令作业下统一调用进程,您可以使用initctl
命令与这些作业进行交互。作业可以是服务或任务,也可以是抽象的。服务是持久的,就像邮件服务器,任务执行一个功能,然后退出到等待状态,就像备份程序。抽象作业永远运行,但没有子进程。作业的定义文件(或 Upstart 脚本)可以在/etc/init
目录下找到。
清单 6-9 展示了 rsyslogd 守护进程的系统作业定义。在这种情况下,rsyslogd 是一个需要写入到/var/log/syslog
文件的日志守护进程。作为日志守护进程,如果它由于某种原因停止了,最好让它尝试重新启动。让我们在这里过一遍要点。
# rsyslog - system logging daemon
#
# rsyslog is an enhanced multi-threaded replacement for the traditional
# syslog daemon, logging messages from applications
Description "system logging daemon"
start on filesystem
stop on runlevel [06]
expect fork
respawn
pre-start script
/lib/init/apparmor-profile-load usr.sbin.rsyslogd
end script
script
. /etc/default/rsyslog
exec rsyslogd $RSYSLOGD_OPTIONS
end script
Listing 6-9.
/etc/init/rsyslog.conf
Upstart 是“事件化的”,这意味着它可以对系统上的事件做出反应。在文件系统上启动意味着当文件系统“事件”发生时,我们也将自动启动 rsyslog。停止配置选项是一个事件定义信号 Upstart,用于在检测到运行级别 0 或 6 事件时停止 rsys logd
。如您所知,运行级别 0、1、6 是特殊的运行级别,它们可以关闭、重启或使您的主机进入维护模式。我们希望服务派生另一个进程,如果任务意外停止,那么respawn
选项会指示 Upstart 重新启动任务。我们可以编写在执行主脚本部分之前运行的预启动脚本。
虽然 Upstart 不同于 SysV,没有运行级别的自然概念,但它已经与 SysV Init 脚本向后兼容。这些通过执行/etc/init.d/rc
脚本来模拟旧式 SysV 脚本。这将依次运行旧的/etc/rcN.d
目录,并启动和停止特定运行级别的服务。
您可以使用initclt
命令管理 Upstart,它允许您启动、停止服务。
$ sudo initctl start rsyslog
$ sudo initctl stop rsyslog
Upstart 没有启用或禁用服务的工具,但是您可以使用 pre-start script section 在包含已启用变量集的文件中进行编译。暴发户 Ubuntu Cookbook 提出了这样一种被接受的方式:
pre-start script
# stop job from continuing if no config file found for daemon
[ ! -f /etc/default/myapp ] && { stop; exit 0; }
# source the config file
. /etc/default/myapp
# stop job from continuing if admin has not enabled service in
# config file.
[ -z "$ENABLED" ] && { stop; exit 0; }
end script
你可以在 http://upstart.ubuntu.com/cookbook/
阅读更多关于新贵的内容。
记忆系统
让我们回到过去。很长一段时间以来,Linux 系统都是由一个名为 systvinit、SysV Init、SysV 或简称为 Init 的程序初始化的。在大多数主流发行版中,包括 CentOS 和 Ubuntu,Init 已经被另一个名为 Systemd 的程序所取代。然而,这两个发行版仍然支持 SysVInit 启动脚本。我们将向您介绍 Init 的一些背景知识以及它是如何工作的。
SysVInit 有一个运行级别的概念。运行级别定义了主机在特定时刻应该处于什么状态。每个运行级别都包含一组应用程序和服务,以及一个指示每个应用程序和服务是应该启动还是应该停止的指示器。例如,在您的主机正常启动期间,每个运行级别的init
工具将启动该运行级别中所有需要的应用程序和服务集。另一个例子发生在您关闭主机时。当您告诉您的主机关闭时,init
工具将 runlevel 更改为 0。在此运行级别,所有应用程序和服务都将停止,系统也将暂停。
SysV 有 7 个运行级别,范围从 0 到 6,每个发行版使用不同的运行级别用于不同的目的。但是有些运行级别在所有发行版中都相当通用。常见的运行级别是 0、1 和 6。您已经看到了运行级别 0,它用于关闭主机。运行级别 1 是单用户模式,或维护模式,我们在本章前面已经描述过。当您的主机重新启动时,使用运行级别 6。
Ubuntu 和 CentOS 主机上的运行级别略有不同。在 Ubuntu 上,运行级别 2 到 5 都运行所谓的多用户模式。多用户模式是指多个用户可以登录的模式,而不仅仅是一个控制台用户。所有必需的服务通常都被设置为在这个运行级别启动。
相比之下,如果您安装了 GUI 控制台,CentOS 通常在运行级别 5 启动,或者只在命令行运行级别 3 启动。CentOS 具有以下运行级别:
- 运行级别 0:关闭主机并使系统停止运行
- 运行级别 1:在单用户(维护)模式下运行,命令控制台,无网络
- 运行级别 2:未分配
- 运行级别 3:在多用户模式下运行,使用网络,并启动级别 3 程序
- 运行级别 4:未分配
- 运行级别 5:在多用户模式下运行,使用网络,X Windows (KDE,GNOME),启动级别 5 的程序。
- 运行级别 6:重启主机
管理 SysV 初始化文件
传统上,在大多数发行版中,/sbin/init
工具是使用/etc/inittab
文件配置的。inittab
文件指定了系统应该使用的默认运行级别。它还详细说明了其他运行级别,以及在每个运行级别中哪里可以找到要启动或停止的应用程序列表。在运行 Systemd 的系统上,你可以忘记基本上忽略运行级别,因为它们在新的世界中并不严格适用,你也不会在你的系统上找到inittab
文件。
Note
如果您正在寻找比 inittab 手册页中更详细的信息,您可以在 www.cyberciti.biz/howto/question/man/inittab-man-page.php
中阅读信息。
传统的 init 程序会读取 inittab 来确定默认的运行级别,然后为该运行级别执行一系列脚本(文件在/etc/rcX.d
目录中,其中 X 是运行级别)。那些以 S 或 K '开头的目录中的文件将被执行,这取决于系统是正在启动(S)还是正在关闭(K)(或者在服务应该运行或停止的运行级别之间移动)。
对于安装了 systemd-sysv 包的主机,如果我们找不到 systemd 服务文件,系统将在/etc/init.d
目录中查找文件;比如/etc/init.d/postfix
。这个文件将被提取并生成到一个 systemd 服务文件中(稍后将详细介绍)。
在运行 systd 的现代发行版上,不再需要配置 SysV。
在运行级别之间移动
在旧系统上,您可以使用telinit
或init
命令在运行级别之间切换。在今天的系统上,您仍然可以使用这些命令,但是真正的运行级别概念不再适用。这些现在映射到不同的 systemd“目标”
但是,如果您碰巧在旧的 SysV 主机上,您可以使用如下的telinit
命令:
$ sudo telint 3
这将把你从当前的运行级别移动到运行级别 3。更多信息见man
页。
了解 SysV Init 中的 Initd 脚本
Initd 脚本是停止和启动进程的脚本,有时还提供进程的当前状态和可能的其他操作。今天的 initd 脚本据说是 LSB 兼容的,因为它们有特定的结构。让我们从看一个init
脚本开始:看一看位于我们 Ubuntu 服务器上/etc/init.d
的postfix
脚本。
LSB 是什么?Linux Standard Base 的缩写,它是各种 Linux 发行版同意的一组标准,使每个使用它的人,尤其是使用它进行开发的人的生活更加轻松。它寻求为 Linux 配置、文件位置、包名和其他约定制定通用标准。近年来,LSB 一直在努力保持相关性,根据它认证的发行版越来越少。你可以在 www.linuxfoundation.org/en/LSB
了解更多信息。
#!/bin/sh –e
### BEGIN INIT INFO
# Provides: postfix mail-transport-agent
# Required-Start: $local_fs $remote_fs $syslog $named $network $time
# Required-Stop: $local_fs $remote_fs $syslog $named $network
# Should-Start: postgresql mysql clamav-daemon postgrey spamassassin saslauthd dovecot
# Should-Stop: postgresql mysql clamav-daemon postgrey spamassassin saslauthd dovecot
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Postfix Mail Transport Agent
# Description: postfix is a Mail Transport agent
### END INIT INFO
Listing 6-10.Ubuntu Postfix Script Header
我们在这里省略了一些细节,但是我们讨论的重要信息在###BEGIN
和###END
注释之间。符合 LSB 的 init 脚本需要一个标准头。该标准要求你必须有以下关键字,后跟一个参数列表,有些用一个$
前缀表示。这些$
参数是保留的虚拟设备,在 LSB 规范中有描述。它们旨在为您的 init 脚本提供更多的顺序。例如,$local_fs
意味着“所有本地文件系统都被挂载了”因此,当您看到“Required-Start’,
”时,这意味着在执行该脚本之前必须启动列出的服务。清单 6-10 中的例子会阻止 Postfix 启动,除非所有的文件系统都已挂载,日志服务正在运行,指定的服务器正在运行,网络已经建立,并且时间已经同步。
列表 6-10 中的关键字的含义如下:
- 简要说明本服务提供的内容。此信息由其他服务使用。
Required-Start
:列出该脚本启动时必须可用的服务。Required-Stop
:表示在停止此处列出的服务之前,必须停止该服务。Should-Start
:定义在服务启动前可以启动的服务列表,尽管不是强制性的。Should-Stop
:表示此服务应该在此处列出的服务之前停止,尽管不是强制性的。Default-Start
:定义服务应该运行的默认运行级别。Default-Stop
:定义该服务不应该运行的默认运行级别。Description
:给出服务的描述。
有关 LSB init 脚本的更多信息,请访问
http://refspecs.linux-foundation.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html
https://wiki
.debian.org/LSBInitScripts
进一步剖析清单 6-10 示例,注意默认开始和默认停止关键字。这些映射到我们之前讨论过的运行级别。在这个脚本中,我们被告知后缀应该从运行级别 2、3、4 和 5 开始。我们不应该在运行级别 0、1 和 6 下运行。
Note
CentOS 5 等较老的操作系统使用前 LSB 标准来编写init.d
脚本。这些标准被 LSB 标准所取代。Ubuntu 已经在很多版本中使用了符合 LSB 的init.d
脚本。
postfix init
脚本的其余内容(我们在清单 6-10 中省略了)是用于启动、停止、有时查询由脚本管理的应用程序或服务的状态的指令。
How Systemd Emulates Sysv Init
systd 的实现支持与 SysV Init(以及 Upstart,正如它发生的那样)的向后兼容。它通过以下方式实现这一点:
- 检查 systemd 目录路径中的服务单元文件
- 如果找不到,它会在
/etc/init.d/
中查找没有.service
后缀的服务文件 - 如果找到一个,它使用
systemd-sysv-generator
将其转换成 systemd 单元文件 - 它使用 LSB 运行级别来决定它需要在哪个目标中执行。
当我们在/etc/init.d/
中有 SysV Init (LSB 兼容)文件,并使用 systemctl 命令启动服务时,systd 将找到这些文件,然后通过一个生成器(systd-SysV-generator)运行它们。其输出然后被转换成 Systemd 单位。
SysV 运行级别也映射到 systd 目标。Systemd 将把每个运行级映射到一个适当的目标,就像运行级 3 将链接到多用户目标一样通过使用符号链接。
$ ls -la /usr/lib/systemd/system/runlevel3.target
lrwxrwxrwx. 1 root root 17 Feb 3 22:55 /usr/lib/systemd/system/runlevel3.target -> multi-user.target
因此,当您发出 telinit 3 命令时,Systemd 将运行以下目标。
[Unit]
Description=Multi-User System
Documentation=man:systemd.special(7)
Requires=basic.target
Conflicts=rescue.service rescue.target
After=basic.target rescue.service rescue.target
AllowIsolate=yes
对于不是“Systemd 就绪”的应用程序和包,只要它们具有符合 LSB 的 init.d 脚本,就没有区别。
最初的 SysV Init 实际上已经很久没有在操作系统上使用了,Upstart 被用来管理基于 Red Hat 和 Debian 的系统中的 SysV。
管理服务
在第四章中,我们向您介绍了流程和服务的概念。您运行的每个应用程序和命令都会创建一个进程。某些过程在命令完成时结束,例如,列出目录的内容。其他进程的运行时间更长,除非您请求它们停止或者您重新启动主机,否则它们不会停止。这些长时间运行的进程中的一些运行应用程序和服务,如邮件和 web 服务器或打印或文件服务。这些类型的长时间运行的进程通常被称为守护进程。守护进程是在后台运行的进程;也就是说,它们不需要连接到控制台。正如我们在第四章中解释的,这些过程中的每一个都有一个名字;例如,sshd daemon 或 httpd,或者 apache web 服务器的 Apache。
Note
Linux 上的所有进程都源于一个父进程。派生一个进程包括一个父进程制作它自己的副本,称为子进程。对于 systemd,Systemd 进程将是父进程。这意味着进程可以持续存在,而不需要附加到控制台或用户会话。当父进程停止时,它的所有子进程也会停止。例如,如果您终止主机上的systemd
进程,您将停止主机上的所有进程。这不是一个很好的主意,可能会对宿主产生不良影响。如果您需要启动和停止所有服务,您应该使用我们在本章中介绍的命令。
用系统管理服务
正如我们之前所解释的,在 Systemd 中,目标用于对单元进行分组,以便当您将主机引导到特定目标时,您可以预期某些服务是可用的,而其他可能冲突的服务将被停止。如果您更改目标,您的服务也可以从运行状态更改为停止状态。您还可以随时手动停止和启动单个服务。
Systemd 有一个命令工具叫做 systemctl。Systemctl 用于管理本地、远程或虚拟容器上的 systemd 资源。通过发出--help
参数,我们可以看到参数列表、单元文件命令、机器命令、作业命令等等。首先,让我们看看如何管理单个服务,然后我们可以看看更广泛的系统。
Note
是的,您可以使用 systemctl 来管理远程或虚拟机。当用--host <hostname>
指定时,systemctl 使用 SSH 登录到远程系统并执行 systemctl 命令。当用--machine <machinename>
指定时,它将在指定的本地容器上执行命令。
系统服务—状态、停止和启动
首先,让我们看看如何获得一个名为 postfix 的服务的状态,它是一个用于发送电子邮件的 SMTP 服务器。
$ sudo systemctl status postfix.service
• postfix.service - Postfix Mail Transport Agent
Loaded: loaded (/usr/lib/systemd/system/postfix.service; enabled; vendor preset: disabled)
Active: active (running) since Wed 2016-04-27 20:35:10 AEST; 3h 0min ago
Process: 642 ExecStart=/usr/sbin/postfix start (code=exited, status=0/SUCCESS)
Process: 636 ExecStartPre=/usr/libexec/postfix/chroot-update (code=exited, status=0/SUCCESS)
Process: 621 ExecStartPre=/usr/libexec/postfix/aliasesdb (code=exited, status=0/SUCCESS)
Main PID: 993 (master)
CGroup: /system.slice/postfix.service
├─ 993 /usr/libexec/postfix/master -w
├─1003 qmgr -l -t unix -u
└─1926 pickup -l -t unix -u
Apr 27 20:35:09 au-mel-centos-1 systemd[1]: Starting Postfix Mail Transport Agent...
Apr 27 20:35:10 au-mel-centos-1 postfix/master[993]: daemon started -- version 2.10.1, configuration /etc/postfix
Apr 27 20:35:10 au-mel-centos-1 systemd[1]: Started Postfix Mail Transport Agent.
Listing 6-11.Getting the Status of the postfix
Service
我们在这里可以看到很多细节。我想引起你注意的主要事情是加载的和活动的。Loaded 向您显示启动此服务所使用的单元文件。Active 为您提供服务的当前状态,“active”,以及它已经运行了多长时间。从这个输出中,我们还可以看到这个服务是通过运行/usr/sbin/postfix start
启动的,并且那个进程(642)以退出代码 0 或成功结束。我们还执行了另外两个ExecStartPre
命令,都很成功。这些很好地映射到 CentOS 上的 systemd postfix.service
单元文件。
[Service]
Type=forking
PIDFile=/var/spool/postfix/pid/master.pid
EnvironmentFile=-/etc/sysconfig/network
ExecStartPre=-/usr/libexec/postfix/aliasesdb
ExecStartPre=-/usr/libexec/postfix/chroot-update
ExecStart=/usr/sbin/postfix start
清单 6-11 中需要注意的另一件事是 CGroup 信息。这表明postfix.service
在 CGroup system.slice
下。CGroups 在内核中实现,用于对系统资源进行分组,以达到隔离和提高性能的目的。
清单 6-11 中的输出非常详细,有助于系统管理员查看详细信息,但是如果我们以编程的方式来做,要查看我们服务的状态需要“搜索”大量数据。因此,systemctl 提供了一种压缩相同信息的方法,使程序很容易检测到状态。
$ sudo systemctl is-active postfix.service ; echo $?
active
0
上述命令提供了标准输出的状态(“活动”、“非活动”)和退出代码(0 表示活动,非零表示其他状态),这两种状态都可以在可能管理服务的脚本或程序中进行测试。在上面的代码行中,我们使用了 bash shell 中的特殊变量$?
,它保存了最后一次命令运行的退出代码。
现在我们知道了如何查看我们的服务的状态,我们可以看到它已经在运行,让我们停止服务。
$ sudo systemctl stop postfix.service
该命令没有明显的输出,因此如果我们查询状态,可以看到它已经停止。
● postfix.service - Postfix Mail Transport Agent
Loaded: loaded (/usr/lib/systemd/system/postfix.service; enabled; vendor preset: disabled)
Active: inactive (dead) since Thu 2016-04-28 11:28:04 AEST; 1s ago
Process: 5304 ExecStop=/usr/sbin/postfix stop (code=exited, status=0/SUCCESS)
.....
Main PID: 5267 (code=killed, signal=TERM)
很明显,我们可以看到服务是“不活动的”,主 PID 被 TERM 信号终止。
Note
进程可以接受来自 kill 命令的“信号”。一个 TERM 或 SIGTERM 信号告诉一个进程结束它正在做的事情并退出。你也可以发送更严厉的信号,比如 SIGKILL,它会立即退出进程,可能是在重要的事情进行中。SIGHUP 有时可以用来重新加载正在运行的进程的配置。更多信息见 http://linux.die.net/man/7/signal
。
现在 postfix 服务停止了,我们将再次启动它。
$ sudo systemctl start postfix.service
同样,控制台没有输出;我们运行状态以确认它正在运行。
● postfix.service - Postfix Mail Transport Agent
Loaded: loaded (/usr/lib/systemd/system/postfix.service; enabled; vendor preset: disabled)
Active: active (running) since Thu 2016-04-28 11:51:45 AEST; 2s ago
我们在本节中看到的是如何使用systemctl
命令启动、停止和查看服务的状态。但是这些服务最初是如何开始的呢?这些服务是如何在引导时启动的?让我们现在调查一下。
孤立的目标
我们已经说过,systemd 是管理我们主机上所有服务的进程,systemctl 是我们用来管理 systemd 进程的命令。我们已经讨论了 systemd 目标,它们使系统达到某一状态,在该状态下正确的进程正在运行。在 SysV 中,我们称之为运行级,它们由一系列从/etc/rcX.d
目录符号链接的文件控制。对于 systemd 来说,单一运行级别的概念并不十分准确,因为许多目标可以同时处于活动状态。但是,在 systemd 中,有些目标有特殊的用途。
在 systemd 中,像多用户这样的目标,如果在它们的单元文件中设置了布尔值 AllowIsolate=yes。这意味着这些目标将响应systemctl isolate
命令。这个命令允许我们启动离散的系统“状态”,其中我们启动一个单元(及其所有依赖项)并停止所有其他单元。
让我们发现我们当前的系统状态。我们将再次使用 systemctl 命令,这一次我们将列出系统上运行的当前目标。
$ sudo systemctl list-units --type target
UNIT LOAD ACTIVE SUB DESCRIPTION
basic.target loaded active active Basic System
cryptsetup.target loaded active active Encrypted Volumes
getty.target loaded active active Login Prompts
local-fs-pre.target loaded active active Local File Systems (Pre)
local-fs.target loaded active active Local File Systems
multi-user.target loaded active active Multi-User System
network.target loaded active active Network
paths.target loaded active active Paths
remote-fs.target loaded active active Remote File Systems
slices.target loaded active active Slices
sockets.target loaded active active Sockets
swap.target loaded active active Swap
sysinit.target loaded active active System Initialization
timers.target loaded active active Timers
下面是我们系统上运行的当前目标的列表。其中一些目标是“特殊”目标,如 swap.target,用于管理交换分区和交换文件及片。target,用于设置所有的 CGroup 片单元。多用户目标由所有这些其他目标组成。如果您查看 multiuser.target 的单元文件,您会看到它需要= basic . target。basic . target 具有 Requires = sysinit . target。sysinit . target 具有 Wants = local-fs . target swap . target。我在这里省略了一些其他细节,如冲突和 After 指令,但是您应该能够看到多用户目标由所有这些其他目标组成,这就是 systemd 如何知道要拉入哪个目标的原因。
我们已经说过,这些目标中的一些定义了机器的“状态”。这些状态类似于救援、多用户、图形化和关机。当您的系统启动后,您可以通过发出以下命令在这些目标之间移动:
$ sudo systemctl isolate graphical.target
这个命令将做什么查看 graphical.target 单元文件,确定它是否具有 AllowIsolate=yes,然后执行 Requires、Conflicts、After、Wants 和其他指令,使系统进入那个“状态”当您查看 graphical.target 单元文件(在/lib/systemd/system
目录中找到)时,您会注意到它需要多用户目标,并且在完成之前不应该启动。那么 systemd 如何知道如何在启动时启动我们的 postfix 服务呢?
禁用服务
让我们通过查看禁用后缀服务时会发生什么来探究这一点。如果我们不想让服务在系统重启时启动,我们需要禁用它。要禁用它,让我们执行以下命令:
$ sudo systemctl disable postfix.service
Removed symlink /etc/systemd/system/multi-user.target.wants/postfix.service.
这个命令的输出告诉我们它做了什么。它从/etc/systemd/system/multi-user.target.wants
目录中删除了一个符号链接(symlink)。如果我们在/lib/systemd/system
目录中查看我们的 postfix.service 文件,我们会看到[Install]部分有一个选项,WantedBy=multi-user.target。如果我们记得[Install]部分包含的指令告诉 systemctl 在我们启用或禁用服务时创建符号链接或删除符号链接,就是这个选项告诉 systemctl 在我们禁用服务时删除符号链接。
支持服务
现在我们已经完成了,我们希望启用该服务,以便它在系统启动时自动启动。让我们再次启用该服务,看看输出是什么:
$ sudo systemctl enable postfix.service
Created symlink from /etc/systemd/system/multi-user.target.wants/postfix.service to /usr/lib/systemd/system/postfix.service.
输出告诉我们,它已经在/etc/systemd/system/multi-user.target.wants
目录中创建了指向 postfix.service 文件的符号链接。现在,当 systemd 启动 multiuser.target 时,它将查看multi-user.target.wants
目录并启动这些服务。
现在让我们尝试获得 systemd 正在控制的所有当前正在运行的服务的列表(参见清单 6-12 )。
$ sudo systemctl --type=service --state=running
UNIT LOAD ACTIVE SUB DESCRIPTION
atd.service loaded active running Job spooling tools
crond.service loaded active running Command Scheduler
getty@tty1.service loaded active running Getty on tty1
NetworkManager.service loaded active running Network Manager
postfix.service loaded active running Postfix Mail Transport Agent
systemd-journald.service loaded active running Journal Service
systemd-logind.service loaded active running Login Service
systemd-udevd.service loaded active running udev Kernel Device Manager
wpa_supplicant.service loaded active running WPA Supplicant daemon
Listing 6-12.Listing the Running Services
在清单 6-12 中,我们可以看到使用- type=service 和- state=running 选项运行的systemctl
命令的(修剪后)输出。如果您运行不带任何选项或参数的 systemctl 命令,您将获得 systemd 已经加载的每个已加载单元定义(单元文件)的完整列表。我们通过添加我们感兴趣的单元的类型和该单元的状态来减少这个列表。您可以在列表中看到,我们的 postfix.service 已经加载、激活并正在运行。您也可以通过在命令中添加- all 来查看所有不活动的单元。
管理 SysV 样式文件
到目前为止,我们已经看到了如何处理控制服务的 systemd 单元文件。记住,我们也可以使用旧的 SysV init.d
文件。我们还说过,systemd 将首先在它自己的目录路径中寻找一个name.service
文件,或者在我们的例子中是postfix.service
。如果找不到,它将在/etc/init.d/
中寻找一个可执行的后缀文件(没有.service
后缀)。如果有一个并且它是 LSB 兼容的,它将运行systemd-generate-sysv
命令来创建一个 systemd 包装文件。
Ubuntu 服务器仍然使用一些 SysV init.d 系统文件(而 CentOS 原生使用 systd ),所以我们将看看该发行版如何管理 postfix 服务。当系统启动时或触发systemctl daemon-reload
后,如果 systemd 找到一个 postfix init.d
服务文件,它会将其传递给 systemd-generate-sysv,后者会创建一个 postfix.service 并将其放在/run/systemd/generator.late/postfix.service
中。它还将在/run/systemd/generator.late
目录中创建到multi-user.target.wants
目录的适当符号链接。
生成的机组文件具有与其他机组文件相同的选项([机组]和[服务])。启动、停止和重新加载选项引用如下init.d
文件:
[Service]
...
ExecStart=/etc/init.d/postfix start
ExecStop=/etc/init.d/postfix stop
ExecReload=/etc/init.d/postfix reload
我们可以使用同一个 system CTL start | stop postfix . service 来管理服务。同样,我们可以使用 systemctl enable|disable 来管理我们是否希望它在引导时启动。
$ sudo systemctl disable postfix
postfix.service is not a native service, redirecting to systemd-sysv-install
Executing /lib/systemd/systemd-sysv-install disable postfix
当处理 SysV init.d 脚本时,systd 做两件事。一种是将相同的符号链接应用于后缀服务的multi-user.target.wants
目录(在/run/systemd/generator.late/
目录中)。但是在这里您也可以看到,由于我们没有使用本地 systemd 服务,我们将把它重定向到另一个兼容性脚本,以处理 SysV land 中的启用和禁用。这个脚本在后台执行旧的 SysV init.d 管理器,在这里是在 Ubuntu,update-rc.d
上。在 CentOS 上,这将是chkconfig
命令。
让我们快速浏览一下这些命令,以便您也熟悉在这些情况下会发生什么。
update-RC . d—管理 Ubuntu SysV init.d
通过update-rc.d
命令管理 SysV init.d 服务 onUbuntu。如果得到指示,update-rc.d command
将创建进入/etc/rc?.d
目录的符号链接或者删除它们。update-rc.d
命令采用表 6-2 中列出的选项。
表 6-2。
update-rc.d
Options
update-rc.d
命令将简单地将init.d
脚本链接到/etc/rcN.d
目录(其中 N 是运行级别),通常默认运行级别为 2、3、4、5,启动优先级为 S20,运行级别为 0、1、6,停止优先级为K80
。
从命令行,您可以发出update-rc.d
来操作在特定运行级别运行的服务。例如,要使用 Ubuntu 默认值打开服务,您可以发出以下命令:
$ sudo update-rc.d postfix start defaults
如前所述,默认情况下,init.d
脚本象征性地链接到/etc/rcN.d
目录,并被赋予 20 和 80 的标准启动和停止优先级。
您可以使用以下命令指定希望服务启动的运行级别和优先级:
$ sudo update-rc.d postfix start 23 40
这里,我们将服务设置为在运行级别 2 和 3 启动,优先级为 40。
要在运行级别 2 中关闭该服务,请发出以下命令:
$ sudo update-rc.d postfix stop 2
前面的命令会将一个K80postfix
符号链接添加到/etc/rc2.d
目录中。
要从所有运行级别删除服务,可以发出以下命令:
$ sudo update-rc.d postfix remove
如果您试图删除的服务的init.d
脚本仍然存在于/etc/init.d
目录中,如果您没有卸载 Postfix,就会出现这种情况,除非您使用-f
选项,否则会出现错误。在这种情况下,您发出以下命令:
$ sudo update-rc.d -f postfix remove
这就是管理 Ubuntu SysV init.d 的方法。接下来让我们看看如何关闭系统。
关闭并重新启动您的 Linux 主机
有几种方法可以从 GUI 和命令行关闭和重启 Linux 主机。在命令行中,我们可以使用systemctl
命令来管理主机的电源状态。
要关闭系统,我们将发出以下命令:
$ sudo systemctl poweroff
这将立即关闭系统电源。您还可以发出重启、暂停、休眠、睡眠等命令。更多信息见systemctl --help
。
我们仍然可以发出旧的命令来关闭主机——您可以发出适当命名的shutdown
命令:
$ sudo shutdown –h now
systemctl poweroff
和shutdown
命令都链接到/lib/systemd/system/poweroff.target
的同一个 systemd 目标。
从 GUI 中,关闭主机很容易。找到电源符号,通常在屏幕的右上角,然后选择Shutdown
选项。
计划服务和命令
您可以使用 Linux 调度重复的作业,使其在指定的事件、指定的时间或指定的间隔运行。有两种方法可以做到这一点。一个是使用 systemd 计时器,另一个是使用名为 Cron 的工具。
系统计时器
Systemd 定时器是以后缀*.timer
结尾的单元文件。它们控制服务何时运行。预计这些将取代 Cron 来管理定期调度的作业管理。
它比 Cron 更有优势,因为它不仅可以根据挂钟(系统时间)触发事件,还可以根据上次事件运行后的时间、引导、启动或这些事情的组合触发事件。定时器单元文件也可以用来触发另一个没有定时器的服务单元。
该配置要求单元文件中有一个[Timer]部分。让我们以管理 apt 缓存日常检查的每日 apt 时间表为例(参见清单 6-13 )。
[Unit]
Description=Daily apt activities
[Timer]
OnCalendar=*-*-* 6,18:00
RandomizedDelaySec=12h
AccuracySec=1h
Persistent=true
[Install]
WantedBy=timers.target
Listing 6-13.Systemd timer /lib/systemd/system/apt-daily.timer
在这里,您可以看到我们有常用的[单元]和[安装]部分。OnCalendar 选项指定我们应该在什么时候运行服务,这可以通过星期几、年、月、日,然后 HH:MM:SS 或任何方式来指定!man 7 systemd.timer 中有一个完整的选项列表。星号(*
)表示任何值,这是每日(*-*-*
)的简写。触发时间为 06:00 或 18:00,随机窗口为 12 小时(RandomizedDelaySec),误差为 1 小时(AccuracySec)。Persistence=true 表示如果错过了最后一次启动就运行(比如系统被关闭)。
假设我们有一个 monitor.service 文件,它向一个网站发出一个 cURL POST 请求,告诉我们系统已经启动,并在此后每 20 分钟检入一次。
[Unit]
Description=Tell the monitoring service we are up
[Timer]
OnBootSec=2min
OnUnitActiveSec=20min
[Install]
WantedBy=timers.target
我们将把这个配置放到一个名为/etc/systemd/system/monitor.timer
的文件中,紧挨着我们的monitor.service
文件。在这里,我们可以看到一个定时器的单元文件需要这三个部分,[单元]、[定时器]和[安装]。
[定时器]部分是我们放置定时器选项的地方。我们在这里选择在引导事件(OnBootSec)后 2 分钟触发 cURL 作业,然后在最后一个事件(OnUnitActiveSec)后每 20 分钟触发一次。这里的时间可以表示为 1h (1 小时)、2w (2 周)或各种其他方式。这些被称为单调定时器,而不是我们在清单 6-13 中看到的实时定时器。
[Install]部分中的 WantedBy=timers.target 创建指向 timers 目标的符号链接,该目标启用 systemd 中的计时器。我们可以通过以下方式启用计时器:
$ sudo systemctl enable monitor.timer
Created symlink from /etc/systemd/system/timers.target.wants/monitor.timer to /etc/systemd/system/monitor.timer.
现在,我们可以列出如下计时器:
你可以在图 6-9 中看到我们的计时器。您可以看到它激活了我们的 monitor.service,并且在 18 分钟前成功完成。你也可以看到apt-daily.timer
。
图 6-9。
Listing timers
它不能简单地在失败时触发一封电子邮件。有些人依赖这个特性,这也是他们选择 Cron 的原因。
有关计时器的更多信息,请参见
https://wiki.archlinux.org/index.php/Systemd/Timers
www.freedesktop.org/software/systemd/man/systemd.time.html
www.freedesktop.org/software/systemd/man/systemd.timer.html
Cron 简介
我们需要向您展示最后一种类型的服务管理:调度。您可能已经熟悉了 Microsoft 任务计划程序,可以使用它来计划在给定的分钟、小时、天、周或月运行一次或定期重复的任务。Linux 中的对等物称为 crontab(计时表的缩写)。它的目的是根据主机的时钟在设定的时间提交任务。任务可以是您想要的任何脚本或应用程序。通常,您会在 crontabs 中找到维护类型的任务。这些可以被安排为每晚、每周或每月运行,并执行某种脚本,比如删除/var/ log/httpd
目录中超过两个月的所有文件。
Cron 作业(crontab 执行的任务)是在/etc/crontab
文件中定义的目录下的一系列脚本中定义的。这些被称为系统 cron 作业。/etc/crontab
文件中的目录列表如下所示:
$ less /etc/crontab
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/
# run-parts
01 * * * * root run-parts /etc/cron.hourly
02 4 * * * root run-parts /etc/cron.daily
22 4 * * 0 root run-parts /etc/cron.weekly
42 4 1 * * root run-parts /etc/cron.monthly
您不应该编辑这个文件,因为它是系统 crontab 文件,每次更新 crontab 时,它都可能被替换为新版本。这意味着任何更改都将丢失。此外,如果你犯了一个错误,你可能会导致其他问题。但是,它确实提供了一个很好的 crontab 文件语法示例。
Tip
当一台主机用于运行许多虚拟化服务器时,您应该更改 cron 作业在每台虚拟服务器上的启动时间,以确保它们不会同时启动。让多个虚拟服务器同时启动它们的日常 cron 任务会影响系统性能。
文件顶部列出的是 SHELL、PATH、MAILTO 和 HOME 环境变量,我们在第四章中已经描述过了。以#
开头的行是注释,可以忽略。在文件的下面,您可以看到五列,一列是数字或*
,一列是root
,一列是run-parts
,最后是一个目录列表。
前五列表示分钟、小时、月中的日、月和星期几。让我们看看最后一行:
42 4 1 * * root run-parts /etc/cron.monthly
这里,42 是一小时的第 42 分钟,小时是 4(小时基于 24 小时制),1 表示一个月的第一天。所以 crontab 会在每个月的第一天凌晨 04:42 运行最后一行。
Note
您还可以为月份、月份中的日期和星期几列指定标准的三个字母缩写,例如,sun
分别代表星期日和aug
代表八月。
任何带有星号(*)的列都意味着所有值都有效,并且不受运行时间的限制。让我们再看一下最后一行:
42 4 1 * 3 root run-parts /etc/cron.monthly
这里,我们将“星期几”列中的值更改为 3。我们的作业现在将在每月第一天以及每周三的凌晨 4:42 运行。
Note
一周中的每一天从星期日的 0 点开始,到星期六的 6 点结束。当在“一月中的第几天”列中指定值时,天数是累积的。因此,作业将在“一月中的某一天”列中列出的所有日期以及“一周中的某一天”列中列出的每个工作日执行。
您还可以指定自动重复的作业,如下所示:
*/2 4 1 * 3 root run-parts /etc/cron.monthly
这里,我们没有指定运行的确切时间,而是使用了符号*/2
。这种表示法告诉 cron 每当分钟数被 2 整除时运行作业。这允许你做一些强有力的事情。例如,您可以在 hour 列中使用*/4
,作业将每隔四小时运行一次,如下所示:
*/2 */4 1 * * root run-parts /etc/cron.monthly
使用逗号表示一系列值,例如
2 0,1,2,3,4 1 * * root run-parts /etc/cron.monthly
这将在凌晨 12:02、1:00、2:00、3:00 和 4:00 运行作业
您也可以指定数字范围,如下所示:
2 0-4,12-16 1 * * root run-parts /etc/cron.monthly
在这里,该命令将在凌晨 12 点和 4 点之间以及中午 12 点和下午 4 点之间的整点后 2 分钟运行
下一列root
代表运行该程序的用户。当您添加自己的 cron 作业(或脚本)时,可以将其设置为任何有效用户。
run-parts
选项是正在运行的命令。run-parts
是一个特殊的命令,它将运行指定目录下的任何可执行脚本。在这种情况下,run-parts
将切换到/etc/cron.hourly
目录、/etc/cron.daily
目录等等,并运行它在那里找到的可执行脚本。
让我们检查一个系统 cron 目录,例如,/etc/cron.daily
目录,并检查 Red Hat 主机上已经存在的一个脚本。除非另有定义,否则这些是每天运行一次的系统 crons。
Note
如果需要,您可以编辑这些 crontab 目录中的脚本;但是,当您的软件包更新时,任何更改都可能被覆盖。您还可以在这些目录中添加自己的脚本,每小时、每天、每周或每月运行一次。
$ ls -l /etc/cron.daily/
-rwxr-xr-x 1 root root 379 Dec 19 2016 0anacron
-rwxr-xr-x 1 root root 118 Oct 1 00:06 cups
-rwxr-xr-x 1 root root 180 Oct 22 2017 logrotate
-rwxr-xr-x 1 root root 114 Jan 16 2018 rpm
-rwxr-xr-x 1 root root 290 Nov 26 2016 tmpwatch
让我们查看其中一个文件/etc/cron.daily/rpm
,看看里面有什么。
$ less /etc/cron.daily/rpm
#!/bin/sh
/bin/rpm -qa --qf '%{name}-%{version}-%{release}.%{arch}.rpm\n' 2>&1 \
| /bin/sort > /var/log/rpmpkgs
这个每天执行的脚本用主机上所有 RPM 包的排序列表填充了/var/log/rpmpkgs
文件。
Note
我们将在第八章中进一步讨论 RPM 包。
个人用户也可以创建 crontab。您可以使用crontab –e
命令创建和编辑现有的 crontabs。如果用户的 crontab 不存在,这个命令会在/var/spool/cron/
username
中创建一个 crontab 文件。
用户的 cron 作业中使用的语法与您之前看到的系统 crontab 文件中的语法相同,只有一处不同。您只能在系统 crontab 文件中指定用户字段。让我们看一个由用户 jsmith 使用 crontab 的–l
或 list 选项创建的例子。
$ crontab -l
*/2 * * * * [ -e /tmp/log ] && rm -f /tmp/log
您将看到该用户安排的所有 cron 作业的列表。这是一系列简单的命令,首先检查名为/tmp/log
的文件是否存在,如果存在,就删除它。设置为每 2 分钟运行一次(*/2
)。
作为特权用户,您可以通过发出带有–u
username
选项的crontab
命令来查看另一个人的 cron。
$ sudo crontab –u ataylor –l
1 2 * * * /usr/local/bin/changeLog.sh
您还可以通过发出相同的 crontab 命令和–u
username
-e 选项来编辑另一个人的 cron。
$ sudo crontab –u ataylor –e
这允许您为用户编辑 crontab。
您还可以通过发出带有–r
选项的crontab
命令来删除您的 crontab 或另一个用户的 crontab。
$ sudo crontab –u ataylor –r
这将删除 ataylor 的 crontab 文件:/var/spool/cron/ataylor
。
您的主机有一个监控 cron 作业及其任何更改的服务。它还会在调度时执行单个作业。这个服务被称为 crond,可以通过我们前面谈到的 systemctl 命令来启动和停止。
$ sudo systemctl start|stop|reload cron(d if CentOS)
摘要
本章探讨了主机如何引导以及它背后的进程,如init
守护进程。您已经学习了如何管理您的服务,如何启动和停止它们,以及如何从不同的运行级别添加和删除它们。您还了解了 LSB 项目,并对新贵init
守护进程有了一个大致的了解。
现在,您应该能够执行以下操作:
- 描述 Linux 的引导过程。
- 使用、配置和保护 GRUB2。
- 描述 init 脚本,包括使用 LSB 标准的脚本。
- 描述 SysV、Upstart 和 Systemd
- 启动和停止 Red Hat 和 Ubuntu 上的服务。
- 了解目标和运行级别。
- 用 crontab 和 Systemd 定时器调度任务。
在下一章,我们将向您展示如何配置您的网络,讨论防火墙,并向您介绍 Linux 安全性。