如何将 Linux 服务配置为在崩溃或重启后自动启动——第 1 部分:实例
作者选择了 Write for DOnations 计划。
介绍
在这个分为两部分的教程中,您将学习如何使用 systemd
将 Linux 服务配置为在重启或崩溃后自动重启。
第一部分涵盖一般的 Linux 服务管理概念,如 init
守护进程和运行级别。它以 systemd
中的服务管理演示结束。在这里,您将检查 targets
、wants
、requires
和 unit
文件。
第二部分提供了完成实用且常见的 systemd
任务的分步教程。具体来说,您会将 MySQL 数据库服务器配置为在崩溃或重启后自动启动。
注意:您还可以考虑阅读我们非常受欢迎的教程,了解如何使用 systemctl
来控制 systemd 服务和单元。
先决条件
要完成本教程,您需要:
- 运行 CentOS 8 的服务器,包括具有 sudo 权限的非根用户。要设置所有这些,包括防火墙,您可以阅读《初始服务器设置指南》。
引入服务管理守护进程
通过改变服务管理守护进程(也称为 init
守护进程)处理它们的方式,Linux 服务可以在很大程度上实现自我修复。
init
是 Linux 系统在机器启动并且内核载入内存后启动的第一个进程。除其他外,它决定了用户进程或系统服务应该如何加载、以什么顺序加载,以及它是否应该自动启动。
随着 Linux 的发展,init
守护进程的行为也发生了变化。最初,Linux 从 System V init
开始,与 Unix 中使用的相同。从那时起,Linux 实现了 Upstart init
守护进程(由 Ubuntu 创建),现在是 systemd init
守护进程(首先由 Fedora 实现)。
大多数现代 Linux 发行版已逐渐从 System V 迁移出来,目前使用 systemd。保留旧样式 init
(如果使用)只是为了向后兼容。 FreeBSD 是 UNIX 的一个变体,使用不同的 System V 实现,称为 BSD init
。
我们将在本文中介绍 systemd,因为这是当今 Linux 发行版中使用的最新且最常用的服务管理器。但是,我们也会在必要时讨论 System V 和 Upstart,并了解 systemd 如何从那里发展而来。给你一个想法:
- System V是最古老的
init
系统,用于 - Debian 6 及更早版本
- Ubuntu 9.04 及更早版本
- CentOS 5 及更早版本
- Upstart 出现在 System V 之后,用于
- Ubuntu 9.10 到 Ubuntu 14.10,包括 Ubuntu 14.04
- 中央操作系统 6
- systemd 是最新的 Linux 服务管理器,用于
- Debian 7 及以上版本
- Ubuntu 15.04 及以上
- CentOS 7 及以上
要了解 init
守护进程,让我们从运行级别开始。
运行级别
运行级别表示 Linux 系统的当前状态。例如,运行级别可以是 Linux 服务器的关闭状态、单用户模式、重启模式等。每种模式都将规定在该状态下可以运行哪些服务。
某些服务可以在一个或多个运行级别中运行,但不能在其他运行级别中运行。运行级别由 0 到 6 之间的值表示。以下列表显示了每个级别的含义:
- 运行级别 0:系统关闭
- 运行级别 1:单用户,救援模式
- 运行级别 2、3、4:多用户、启用网络的文本模式
- 运行级别 5:多用户、启用网络、图形模式
- 运行级别 6:系统重启
运行级别 2、3 和 4 因发行版而异。例如,一些 Linux 发行版没有实现运行级别 4,而其他发行版则实现了。一些发行版在这三个级别之间有明显的区别。通常,运行级别 2、3 或 4 表示 Linux 以多用户、启用网络的文本模式启动的状态。
当您启用服务自动启动时,Linux 实际上是将其添加到运行级别。例如,在 System V 中,操作系统将以特定的运行级别启动;并且,当它启动时,它将尝试启动与该运行级别关联的所有服务。在 systemd 中,runlevel 变成了 target,当一个服务被设置为自动启动时,它被添加到一个 target 中。我们将在本文后面讨论目标。
介绍 System V init 守护进程
System V 使用 inittab
文件,后来的 init
方法为了向后兼容保留了该文件。让我们来看看 System V 的启动顺序:
init
守护进程是从二进制文件 /sbin/init 创建的init
守护进程读取的第一个文件是 /etc/inittab- 这个文件中的一个条目决定了机器应该引导到的运行级别。例如,如果运行级别的值指定为 3,Linux 将以多用户、文本模式启动并启用网络。 (此运行级别称为默认运行级别)
- 接下来,
init
守护进程进一步查看 /etc/inittab 文件并读取它需要为该运行级别运行的init
脚本
因此,当 init
守护进程找到它需要为给定运行级别运行的 init
脚本时,它实际上是在找出它需要启动的服务。您可以在这些 init
脚本中为各个服务配置启动行为。
init
脚本用于控制 System V 中的特定服务。服务的 init
脚本由应用程序供应商提供或随 Linux 发行版(用于本机服务)提供。您还可以为自定义创建的服务创建自己的 init
脚本。
当诸如 MySQL Server 之类的进程或服务在 System V 下启动时,其二进制程序文件必须加载到内存中。根据服务的配置方式,该程序可能会持续执行后台操作(并接受客户端连接)。启动、停止或重新加载此二进制应用程序的工作由服务的 init
脚本处理。它被称为 init
脚本,因为它初始化服务。
在 System V 中,init
脚本是一个 shell 脚本。它们也称为 rc
(运行命令)脚本。这些脚本位于 /etc/init.d
目录下。这些脚本符号链接到 /etc/rc
目录。在 /etc
目录中,有许多 rc
目录,每个目录的名称中都有一个数字。数字代表不同的运行级别。所以我们有/etc/rc0.d
、/etc/rc1.d
、/etc/rc2.d
等等。
要在崩溃或重启后重新启动服务,通常可以在 init
脚本中添加如下一行:
- ms:2345:respawn:/bin/sh /usr/bin/service_name
要使 System V 服务在系统启动时启动,请运行以下命令:
- sudo chkconfig service_name on
要禁用它,请运行以下命令:
- sudo chkconfig service_name off
要检查状态(正在运行或已停止),请运行此命令
- sudo service service_name status
介绍 Upstart 守护进程
随着 System V init
加载作业和服务的序列化方式变得更加耗时和复杂,引入了 Upstart 守护进程以加快操作系统的加载速度、优雅地清理崩溃的服务以及可预测的依赖性系统服务之间。
Upstart init
在几个方面优于 System V init
:
- 它不处理神秘的 shell 脚本来加载和管理服务。相反,它使用易于理解和修改的简单配置文件
- 服务不像 System V 那样连续加载,这减少了系统启动时间
- 它使用灵活的事件系统来自定义服务在各种状态下的处理方式
- Upstart 有更好的方法来处理崩溃的服务应该如何重新生成。
- 没有必要保留一些冗余的符号链接,都指向同一个脚本
为简单起见,Upstart 与 System V 向后兼容。/etc/init.d/rc
脚本仍然运行以管理本机 System V 服务。它的主要区别在于它允许多个事件与服务相关联的方式。这种基于事件的架构允许 Upstart 成为灵活的服务管理器。使用 Upstart,每个事件都可以触发处理该事件的 shell 脚本。这些事件包括:
- 开始
- 开始
- 停止
- 停止
在这些事件之间,服务可以处于多种状态,如等待、预启动、启动、运行、预停止、停止等。Upstart 也可以对这些状态中的每一个采取行动,创建一个非常灵活的建筑学。
在启动时,Upstart 将正常运行任何 System V init
脚本。然后它将在 /etc/init
目录下查找并执行每个服务配置文件中的 shell 命令。除其他事项外,这些文件控制着服务的启动行为。
这些文件的命名风格为 service_name.conf
,并且它们具有包含不同部分的纯文本内容,称为节。每个节都描述了服务的不同方面及其行为方式。要使服务在崩溃或重启后自动启动,您可以在其服务配置文件中添加 respawn
命令,如下所示的 cron 服务。
...
description "regular background program processing daemon"
start on runlevel [2345]
stop on runlevel [!2345]
expect fork
**respawn**
exec cron
介绍 systemd 守护进程
最新的 Linux init
守护进程是 systemd。事实上,它不仅仅是一个 init
守护进程:systemd 是一个包含现代 Linux 系统的许多组件的框架。
它的功能之一是充当 Linux 的系统和服务管理器。以这种能力,systemd 控制服务在崩溃或机器重启时的行为方式。您可以在此处阅读有关 systemd 的 systemctl 的信息。
systemd 向后兼容 System V 命令和初始化脚本。这意味着任何 System V 服务也将在 systemd 下运行。这是可能的,因为大多数 Upstart 和 System V 管理命令已被修改为在 systemd 下工作。
systemd 配置文件:单元文件
systemd 的核心是单元文件。每个单元文件代表一个特定的系统资源。有关资源的信息在单元文件中进行跟踪。服务单元文件是具有声明性语法的简单文本文件(如 Upstart .conf 文件)。这使得文件易于理解和修改。
systemd 与其他两个 init
方法的主要区别在于,systemd 负责服务守护进程和其他类型资源(如设备操作系统路径、挂载点、套接字等)的初始化。命名风格对于单元文件是 service_name.unit_type
。因此,您会看到像 dbus.service
、sshd.socket
或 home.mount
这样的文件。
目录结构
在 CentOS 等基于 Red Hat 的系统中,单元文件位于两个位置。主要位置是/lib/systemd/system/
。自定义创建的单元文件或系统管理员修改的现有单元文件将位于 /etc/systemd/system
下。
如果两个位置都存在同名的单元文件,systemd 将使用 /etc
下的那个。假设一个服务被启用以在引导时或任何其他目标/运行级别启动。在这种情况下,将在 /etc/systemd/system
中的适当目录下为该服务单元文件创建一个符号链接。 /etc/systemd/system
下的单元文件实际上是指向/lib/systemd/system
下同名文件的符号链接。
systemd init 序列:目标单位
一种特殊类型的单元文件是目标单元。
目标单元文件名以 .target 为后缀。目标单元不同于其他单元文件,因为它们不代表一种特定的资源。相反,它们代表系统在任何时候的状态。目标单元通过分组和启动应该属于该状态的多个单元文件来做到这一点。因此,systemd 目标可以粗略地与 System V 运行级别进行比较,尽管它们并不相同。
每个目标都有一个名称而不是编号。例如,我们有 multi-user.target
而不是 runlevel 3
或 reboot.target
而不是 runlevel 6
.当 Linux 服务器以 multi-user.target
启动时,它实际上是将服务器带到 runlevel 2、3 或 4
,这是多用户文本模式启用网络。
它如何将服务器带到那个阶段是不同之处。与 System V 不同,systemd 不会按顺序启动服务。在此过程中,它可以检查是否存在其他服务或资源并决定它们的加载顺序。这使得服务可以并行加载。
目标单元和运行级别之间的另一个区别是,在 System V 中,Linux 系统只能存在于一个运行级别中。您可以更改运行级别,但系统将仅存在于新的运行级别中。使用 systemd,目标单元可以是包容性的,这意味着当一个目标单元激活时,它可以确保其他目标单元作为它的一部分加载。
例如,使用图形用户界面启动的 Linux 系统将激活 graphical.target,这反过来将自动确保 multi-user.target 也被加载和激活。在 System V 术语中,这就像同时激活运行级别 3 和 5。
下表比较了运行级别和目标:
Runlevel (System V init) | Target Units (Systemd) |
---|---|
runlevel 0 | poweroff.target |
runlevel 1 | resuce.target |
runlevel 2, 3, 4 | multi-user.target |
runlevel 5 | graphical.target |
runlevel 6 | reboot.target |
systemd default.target
systemd default.target
相当于 System V 默认运行级别。
System V 在名为 inittab 的文件中定义了默认运行级别。在 systemd 中,该文件被 default.target 替换。默认目标单元文件位于 /etc/systemd/system 目录下。它是指向 /lib/systemd/system 下目标单元文件之一的符号链接。
当您更改默认目标时,您实际上是在重新创建该符号链接并更改系统的运行级别。
System V 中的 inittab 文件还指定了 Linux 将从哪个目录执行其 init
脚本:它可以是任何 rcn.d 目录。在 systemd 中,默认目标单元决定了哪些资源单元将在启动时加载。
当单元被激活时,它们会全部并行或全部依次激活。资源单元如何加载可能取决于它想要或需要的其他资源单元。
systemd 依赖关系:需要和需要
systemd 想要并要求控制 systemd 如何解决服务守护进程之间的依赖关系。
如前所述,Upstart 确保使用配置文件并行加载服务。在 System V 中,服务可以在特定的运行级别启动,但也可以让它等待直到另一个服务或资源可用。以类似的方式,可以使 systemd 服务加载一个或多个目标,或者等到另一服务或资源变为活动状态。
在 systemd 中,一个需要另一个单元的单元将不会启动,直到所需的单元被加载和激活。如果在第一个单元处于活动状态时所需单元由于某种原因发生故障,则第一个单元也将停止。
这保证了系统的稳定性。因此,可以使需要特定目录存在的服务等到该目录的安装点处于活动状态。另一方面,想要另一个单位的单位不会施加这样的限制。如果在呼叫者处于活动状态时所需的单元停止,它不会停止。这方面的一个例子是在图形目标模式下出现的非必要服务。
实例:了解 systemd 启动顺序
为了了解 systemd 下的服务启动行为,我们使用了 CentOS 8.3 Droplet。我们将尽可能地跟随 .target rabbit-trail。 systemd 的启动顺序遵循一长串依赖关系。
首先,让我们运行这个命令来列出默认的目标单元文件:
- sudo ls -l /etc/systemd/system/default.target
这显示如下输出:
Outputlrwxrwxrwx. 1 root root 37 Dec 4 17:42 /etc/systemd/system/default.target -> /lib/systemd/system/multi-user.target
如您所见,默认目标实际上是指向/lib/systemd/system/ 下的多用户目标文件的符号链接。因此,系统应该在 multi-user.target 下启动,这类似于 System V init 中的运行级别 3。
多用户.target.wants
接下来,让我们运行以下命令来检查 multi-user.target 文件需要的所有服务:
- sudo ls -l /etc/systemd/system/multi-user.target.wants/*.service
这应该显示符号链接文件列表,指向 /usr/lib/systemd/system/ 下的实际单元文件:
Outputlrwxrwxrwx. 1 root root 38 Dec 4 17:38 /etc/systemd/system/multi-user.target.wants/auditd.service -> /usr/lib/systemd/system/auditd.service
lrwxrwxrwx. 1 root root 39 Dec 4 17:39 /etc/systemd/system/multi-user.target.wants/chronyd.service -> /usr/lib/systemd/system/chronyd.service
lrwxrwxrwx. 1 root root 37 Dec 4 17:38 /etc/systemd/system/multi-user.target.wants/crond.service -> /usr/lib/systemd/system/crond.service
lrwxrwxrwx. 1 root root 42 Dec 4 17:39 /etc/systemd/system/multi-user.target.wants/irqbalance.service -> /usr/lib/systemd/system/irqbalance.service
lrwxrwxrwx. 1 root root 37 Dec 4 17:41 /etc/systemd/system/multi-user.target.wants/kdump.service -> /usr/lib/systemd/system/kdump.service
...
除了 multi-user.target
之外,还有不同类型的目标,例如 system-update.target
或 basic.target
。要查看多用户目标所依赖的目标,请运行以下命令:
- sudo systemctl show --property "Requires" multi-user.target | fmt -10
输出显示:
OutputRequires=basic.target
基本目标
您可以运行以下命令来查看 basic.target 是否有任何必需的单位:
- sudo systemctl show --property "Requires" basic.target | fmt -10
事实证明,basic.target 需要 sysinit.target:
OutputRequires=sysinit.target
-.mount
它也需要一些目标:
- sudo systemctl show --property "Wants" basic.target | fmt -10
该命令将返回以下内容:
OutputWants=slices.target
paths.target
timers.target
microcode.service
sockets.target
sysinit.target
递归地,您可以查看 sysinit.target 是否也需要运行任何其他目标:
- sudo systemctl show --property "Requires" sysinit.target | fmt -10
不会有的。但是,sysinit.target 还需要其他目标:
- systemctl show --property "Wants" sysinit.target | fmt -10
将出现这样的输出:
OutputWants=systemd-random-seed.service
dev-mqueue.mount
rngd.service
systemd-modules-load.service
proc-sys-fs-binfmt_misc.automount
local-fs.target
sys-fs-fuse-connections.mount
systemd-sysusers.service
systemd-update-done.service
systemd-update-utmp.service
systemd-journal-flush.service
dev-hugepages.mount
dracut-shutdown.service
swap.target
systemd-udevd.service
import-state.service
sys-kernel-debug.mount
nis-domainname.service
systemd-journald.service
selinux-autorelabel-mark.service
kmod-static-nodes.service
loadmodules.service
ldconfig.service
cryptsetup.target
systemd-sysctl.service
systemd-ask-password-console.path
systemd-journal-catalog-update.service
systemd-udev-trigger.service
systemd-tmpfiles-setup.service
systemd-hwdb-update.service
sys-kernel-config.mount
systemd-binfmt.service
systemd-tmpfiles-setup-dev.service
systemd-machine-id-commit.service
systemd-firstboot.service
检查 systemd 单元文件
现在更进一步,让我们看一下服务单元文件,即用于 sshd 的文件:
- sudo vi /etc/systemd/system/multi-user.target.wants/sshd.service
它看起来像这样:
[Unit]
Description=OpenSSH server daemon
Documentation=man:sshd(8) man:sshd_config(5)
After=network.target sshd-keygen.target
Wants=sshd-keygen.target
[Service]
Type=notify
EnvironmentFile=-/etc/crypto-policies/back-ends/opensshserver.config
EnvironmentFile=-/etc/sysconfig/sshd
ExecStart=/usr/sbin/sshd -D $OPTIONS $CRYPTO_POLICY
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartSec=42s
[Install]
WantedBy=multi-user.target
您可以看到服务单元文件干净且易于理解。
第一个重要部分是 [Unit]
部分中的 After 子句。这表示 sshd 服务需要在加载 network.target 和 sshd-keygen.target 之后加载。
[Install]
部分显示 multi-user.target 需要该服务。这意味着 multi-user.target 将加载 sshd 守护进程,但如果 sshd 在加载过程中失败,它不会关闭或崩溃。
由于 multi-user.target
是默认目标,sshd 守护进程应该在引导时启动。在 [Service]
部分,Restart
参数的值为 on-failure
。此设置允许 sshd 守护程序在崩溃或退出不干净时重新启动。
结论
在本文中,您了解了 System V、Upstart 和 systemd 服务管理守护进程。您探索了启动脚本和配置文件、重要参数、启动顺序以及控制服务启动行为的命令。
在本文的第二部分,我们将把这些技能应用到一个真实的例子中,并使用 systemd 配置 MySQL。完成后,您的 MySQL 实例将在重启或崩溃后自动重启。虽然您将使用 MySQL 作为示例应用程序,但您可以替代任意数量的服务,例如 Nginx 或 Apache Web 服务器。