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

作为Write for DOnations计划的一部分,作者选择了免费和开源基金来接受捐赠

介绍

在这个由两部分组成的教程中,您将学习如何使用systemd.

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

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

注意:您也可以考虑阅读我们非常流行的使用systemctl来控制 systemd 服务和单元的教程

先决条件

要完成本教程,您需要:

介绍服务管理守护进程

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

init是在机器启动并且内核加载到内存后在 Linux 系统中启动的第一个进程。其中,它决定用户进程或系统服务应如何加载、以何种顺序加载以及是否应自动启动。

随着 Linux 的发展,init守护进程的行为也在发展最初,Linux 从 System V 开始,与initUnix 中使用的相同。从那以后,Linux 实现了 Upstartinit守护进程(由 Ubuntu 创建),现在是 systemdinit守护进程(首先由 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
    • CentOS 6
  • systemd是最新的 Linux 服务管理器,用于

    • Debian 7 及以上
    • Ubuntu 15.04 及以上
    • CentOS 7 及以上

为了理解init守护进程,让我们从一个叫做runlevel 的东西开始

运行级别

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

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

  • 运行级别 0:系统关闭
  • 运行级别 1:单用户,救援模式
  • 运行级别 2、3、4:启用网络的多用户文本模式
  • 运行级别 5:多用户、支持网络、图形模式
  • 运行级别 6:系统重启

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

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

System Vinit守护进程简介

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脚本是什么在控制系统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

介绍新贵守护进程

随着 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 Vinit脚本。然后它将在/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守护进程

最新的 Linuxinit守护进程是 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.下同名文件的符号链接

systemdinit序列:目标单位

一种特殊类型的单元文件是目标单元

目标单元文件名以 .target 为后缀。目标单元与其他单元文件不同,因为它们不代表一种特定资源。相反,它们代表系统在任何时候的状态。目标单元通过分组和启动应该是该状态一部分的多个单元文件来做到这一点。因此,systemd 目标可以与 System V 运行级别进行粗略的比较,尽管它们并不相同。

每个目标都有一个名称而不是数字。例如,我们有multi-user.target代替runlevel 3reboot.target代替runlevel 6当 Linux 服务器以 , 启动时multi-user.target,它本质上是将服务器带到runlevel 2, 3, or 4,这是启用了网络的多用户文本模式。

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

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

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

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

运行级别(System V init) 目标单位(Systemd)
运行级别 0 关机目标
运行级别 1 救援目标
运行级别 2、3、4 多用户目标
运行级别 5 图形目标
运行级别 6 重启目标

systemd default.target

systemddefault.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

这将显示如下输出:

Output
lrwxrwxrwx. 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。

多用户.目标.想要

接下来,让我们运行以下命令来检查 multi-user.target 文件想要的所有服务:

  • sudo ls -l /etc/systemd/system/multi-user.target.wants/*.service

这应该显示一个符号链接文件列表,指向 /usr/lib/systemd/system/ 下的实际单元文件:

Output
lrwxrwxrwx. 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

输出显示:

Output
Requires=basic.target

基本目标

您可以运行以下命令来查看 basic.target 是否有任何必需的单位:

  • sudo systemctl show --property "Requires" basic.target | fmt -10

事实证明,basic.target 需要 sysinit.target:

Output
Requires=sysinit.target -.mount

它也需要一些目标:

  • sudo systemctl show --property "Wants" basic.target | fmt -10

该命令将返回以下内容:

Output
Wants=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

将出现这样的输出:

Output
Wants=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

您可以看到服务单元文件干净且易于理解。

第一个重要部分是部分中的 After 子句[Unit]这表示 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 服务器。

觉得文章有用?

点个广告表达一下你的爱意吧 !😁