如何将Linux服务配置为在崩溃或重启后自动启动-第1部分:实际示例

来自菜鸟教程
跳转至:导航、​搜索

作为 Write for DOnations 计划的一部分,作者选择了 Free and Open Source Fund 来接受捐赠。

介绍

在这个由两部分组成的教程中,您将学习如何使用 systemd 将 Linux 服务配置为在重启或崩溃后自动重启。

第一部分涵盖了一般的 Linux 服务管理概念,例如 init 守护进程和运行级别。 它以 systemd 中的服务管理演示结束。 在这里,您将检查 targetswantsrequiresunit 文件。

第二部分提供了完成实用且常见的 systemd 任务的分步教程。 具体来说,您将配置 MySQL 数据库服务器以在崩溃或重新启动后自动启动。

先决条件

要完成本教程,您需要:

介绍服务管理守护进程

Linux 服务可以通过更改服务管理守护进程(也称为 init 守护进程)处理它们的方式来实现自我修复。

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 守护进程,让我们从称为 runlevel 的东西开始。

运行级别

运行级别代表 Linux 系统的当前状态。 例如,运行级别可以是 Linux 服务器的关闭状态、单用户模式、重启模式等。 每种模式都将规定哪些服务可以在该状态下运行。

一些服务可以在一个或多个运行级别中运行,但不能在其他运行级别中运行。 运行级别由 0 到 6 之间的值表示。 以下列表显示了每个级别的含义:

  • Runlevel 0:系统关机
  • Runlevel 1:单用户,救援模式
  • Runlevels 2, 3, 4:多用户,文本模式,启用网络
  • Runlevel 5:多用户、网络启用、图形模式
  • Runlevel 6:系统重启

运行级别 2、3 和 4 因分布而异。 例如,一些 Linux 发行版没有实现运行级别 4,而另一些则实现了。 一些分布在这三个级别之间有明显的区别。 通常,运行级别 2、3 或 4 表示 Linux 以多用户、启用网络的文本模式启动的状态。

当您启用服务以自动启动时,Linux 实际上是将其添加到运行级别。 例如,在 System V 中,操作系统将以特定的运行级别启动; 并且,当它启动时,它将尝试启动与该运行级别关联的所有服务。 在 systemd 中,运行级别已成为目标,当服务自动启动时,它会被添加到目标中。 我们将在本文后面讨论目标。

介绍 System V init 守护进程

System V 使用 inittab 文件,为了向后兼容,后来的 init 方法保留了该文件。 让我们来看看 System V 的启动顺序:

  1. init 守护进程是从二进制文件 /sbin/init 创建的
  2. init 守护程序读取的第一个文件是 /etc/inittab
  3. 该文件中的一个条目决定了机器应该引导到的运行级别。 例如,如果将运行级别的值指定为 3,Linux 将以启用网络的多用户文本模式启动。 (此运行级别称为默认运行级别)
  4. 接下来,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 服务。

/etc/init/cron.conf

...

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.servicesshd.sockethome.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 3reboot.target 代替 runlevel 6。 当 Linux 服务器以 [X36X] 启动时,它实质上是将服务器带到 runlevel 2, 3, or 4,这是启用网络的多用户文本模式。

它如何将服务器带到那个阶段是不同之处所在。 与 System V 不同,systemd 不会按顺序启动服务。 一路上,它可以检查其他服务或资源的存在并决定它们的加载顺序。 这使得服务可以并行加载。

目标单元和运行级别之间的另一个区别是,在 System V 中,Linux 系统只能存在于一个运行级别中。 您可以更改运行级别,但系统将仅存在于该新运行级别中。 使用 systemd,目标单元可以是包容性的,这意味着当一个目标单元激活时,它可以确保其他目标单元作为它的一部分加载。

例如,使用图形用户界面启动的 Linux 系统将激活 graphics.target,这反过来将自动确保加载和激活 multi-user.target。 在 System V 术语中,这就像同时激活运行级别 3 和 5。

下表比较了运行级别和目标:

运行级别(System V 初始化) 目标单位(Systemd)
运行级别 0 poweroff.target
运行级别 1 恢复目标
运行级别 2、3、4 多用户.target
运行级别 5 图形目标
运行级别 6 重启.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 wantsrequires 控制 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.targetbasic.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

它看起来像这样:

/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 服务器。