新贵事件系统:它是什么以及如何使用它
介绍
初始化 是一个至关重要的过程,它位于任何基于 Unix 的操作系统的核心,用于控制每个脚本和服务的操作。 这在服务器环境中是必不可少的,在该环境中,问题可能发生在启动和关闭的关键点,并且确保最佳性能是优先事项。
本质上,初始化遵循这样的过程:
- 服务器启动
- init 进程运行(通常为
PID 1
) - 一组预定义的启动任务按顺序激活
初始化负责确保云服务器可以干净地启动和关闭。
一些具有 Unix 基础的发行版使用标准的 init 进程进行初始化。 在本文中,我们将介绍 Upstart - 一种实用且功能强大的替代品,可以增强服务器的操作。
经典的init有什么问题?
传统的初始化遵循线性过程:在系统启动时,各个任务以预定义的顺序加载。 这没什么用,尤其是在快速变化的情况下。 要了解原因,请想象一下,例如,您通过添加额外的存储设备来修改服务器的环境。
初始化过程无法考虑环境的突然变化,这意味着您的云服务器必须重新初始化才能识别额外的存储空间。 动态检测是需要的,尽管它不是经典初始化过程的能力。
以线性顺序启动也需要时间,这在快速部署至关重要的基于云的环境中尤其不利。
您可能还关心系统加载后任务的状态。 不幸的是,init 仅在您启动或关闭电源时关注序列。
不再需要同步引导序列。 一个僵化的系统可以支持昨天的系统,但今天是动态的。
这就是 Upstart 的用武之地——通过高级功能解决这些问题。
基于 实时 事件而不是按顺序预设的任务列表,这个替换的 init 守护进程处理任务 的启动和停止,并且 在系统运行时监视这些进程 – “全覆盖”是最好的描述方式。
这种新的异步处理消除了对严格的启动顺序的需要。 实时处理可能难以概念化,但 Upstart 可以支持最复杂的系统并通过使用 jobs 的结构来检查所有内容。
新贵概述
Upstart 事件系统从一开始就具有灵活性,它利用了与传统初始化系统不同的各种概念。 该解决方案默认安装在 Red Hat Enterprise Linux (RHEL) 6 以及 Google 的 Chrome OS 和 Ubuntu 上,尽管最近的争论引发了关于这种情况是否会继续的争论。
工作
在 Upstart 的世界中,作业是工作流程,分为任务作业(有目的)和服务作业(可以在后台运行)。 还有一些抽象作业——永远运行的进程,直到被具有管理权限的用户停止。
活动
然而,Events 是用于触发作业或其他事件的特定操作的信号或“调用”。 事件的常见形式是指对进程的监控:starting
、started
、stopping
和stopped
。
发射事件
广播事件的过程称为“发射”。 这通常是由进程或作业状态引起的,尽管管理员也可以通过发出 initctl emit <event>
命令手动发出事件。 您会注意到 init control
命令在导航与 Upstart 相关的大量操作时变得非常有用。
编写您的第一个作业配置
众所周知,Upstart 在 Ubuntu 上表现良好,因此在开始之前启动 Ubuntu 14.04 Droplet。
现在您已经准备好了,重要的是要了解作业配置文件必须遵守三个基本原则才能有效。
- 它不能为空(没有内容的文件)
- 它不能包含任何语法错误
- 它必须包含至少一个命令块,称为 节
让我们暂时保持基本状态。 稍后我们将在 /etc/init
目录中创建一个名为 testjob.conf
的文件。 在这种情况下,“init”只是用作“initialization”的缩写版本。
注意 .conf
文件关联 - 表明您将编写 作业配置文件 。
就本教程而言,建议使用命令行文本编辑器 nano。 其中一些命令可能需要 sudo
的管理权限,因此请查看 这篇文章 以创建合适的用户。
要为我们的测试作业创建一个新的配置文件,运行:
sudo nano /etc/init/testjob.conf
现在让我们概述目标。 我们希望此作业 将消息和当前时间戳写入日志文件 。
有两个基本节可以帮助您定义作业脚本的目的和创建者:description
和 author
。 将这些写为文件中的第一行。
description "A test job file for experimenting with Upstart" author "Your Name"
现在,我们希望这项工作在系统服务和进程已经加载后进行(以防止任何冲突),因此您的下一行将包含以下事件:
start on runlevel [2345]
您可能想知道什么是运行级别。 本质上,它是代表当前系统配置的单个值。 [2345]
指的是具有一般 Linux 访问和网络的所有配置状态,非常适合用于基本测试示例。
然后我们将添加执行代码。 此行以 exec
开头,表示应通过 Bash shell 运行以下命令:
exec echo Test Job ran at `date` >> /var/log/testjob.log
请注意,此 echo
命令使用反引号将 date
作为命令运行,然后将整个消息写入日志文件。 如果您写的单词 date
没有反引号,则将打印单词本身而不是命令的输出。
保存并关闭此文件。
您可以通过手动启动作业来验证这是否有效,但让我们先检查配置文件语法:
init-checkconf /etc/init/testjob.conf
如果检测到任何问题,此命令将指示特定的行号和问题。 但是,通过测试作业,您应该会看到如下输出:
File /etc/init/testjob.conf: syntax ok
此命令可用于控制 Upstart 作业和其他后台服务,例如 Web 服务器。
基本的命令语法是:
sudo service <servicename> <control>
此语法适用于以下基本控件:
- 重启:这将停止,然后启动服务
- start:这将启动一个服务,如果它没有运行
- 停止:这将停止服务,如果它正在运行
- status:这将显示服务的状态
我们想手动启动我们的测试作业,所以命令应该是这样的:
sudo service testjob start
现在,通过运行以下命令检查 testjob.log
文件:
cat /var/log/testjob.log
该命令会将文件读入shell; 您应该会看到与以下类似的一行:
Test Job ran at Fri Aug 1 08:43:05 BST 2014
这表明您的测试作业已设置好并准备就绪。
重新启动您的 Droplet,然后再次登录并读取日志文件:
cat /var/log/testjob.log
您应该会在日志中看到第二行显示稍后的时间戳,以确认它作为 Upstart 作业运行。
Test Job ran at Fri Aug 1 08:44:23 BST 2014
这只是触及了你可以用 Upstart 做的事情的表面。 稍后我们将介绍一个详细的示例,但现在,让我们继续解释作业状态和事件。
作业状态和事件
系统作业驻留在 /etc/init/
目录中,用户作业驻留在用户自己的 init 目录 ~/.init/
中。
用户作业在用户自己的会话中运行,因此它们也称为会话作业。 这些不在系统范围内运行,也不在 PID 1
名称中。 出于我们测试工作的目的,我们使用了 /etc/init
,以便它可以在系统启动时加载。
无论其类型如何,作业都是 always 在配置文件 (.conf) 中定义的,其文件名应代表所涉及的服务或任务。
这些工作中的每一个都有一个目标——start
或 stop
。 这两个目标之间是一组任务状态,它们定义了与目标相关的工作的当前操作。 重要状态如下:
- 等待:处理的初始状态
- 开始:工作即将开始的地方
- 预启动:加载预启动部分的位置
- spawned:脚本部分即将运行的地方
- post-start:启动后操作发生的地方
- running:作业完全可操作的地方
- pre-stop: pre-stop 操作发生的地方
- 停止:作业停止的位置
- 杀死:工作停止的地方
- 停车后:进行停车后操作的地方 - 清理
在启动后状态之后,作业被定义为正在运行。 它会一直运行,直到触发了 pre-stop,此时作业准备停止,然后作业被终止,并且如果定义了 post-stop cleanup 过程,则会发生。
您可以通过使用以下命令将 Upstart 系统日志(位于 /var/log/upstart/
目录中)的优先级设置为 debug
来查看作业如何在状态之间转换:
sudo initctl log-priority debug
请记住, 状态不是事件,事件也不是状态。 四个事件(开始、开始、停止和停止)由 Upstart 发出,但任务状态定义了作业生命周期阶段之间的转换。
我们现在准备继续进行一个更集中的示例,该示例通过编写服务作业来合并您的第一个配置中的元素。 这将演示如何从运行基本测试配置过渡到生产就绪脚本。
深入示例:服务作业
在简介中简要介绍,服务作业涉及脚本配置文件,允许进程在后台运行。 我们将从头开始设置 基本 Node.js 服务器。
如果您不熟悉 Node,本质上它是一个“用于服务器端和网络应用程序的跨平台环境”(维基百科)。
Node.js 是一个非常轻量级的包,虽然它没有默认安装在 Ubuntu 14.04 上。 要开始使用,请继续将其安装在您的云服务器上。
sudo apt-get install nodejs
现在,让我们开始服务工作。 在 /etc/init
中创建一个名为 nodetest.conf
的新作业配置文件。 参考文件的用途命名文件是必不可少的,因此您将能够识别此服务作业用于 Node.js 测试。
sudo nano /etc/init/nodetest.conf
我们将在示例后面介绍 Node 应用程序本身,因为事先了解 Upstart 配置很重要。
第一件事。 首先输入职位描述和作者行来定义配置。
description "Service for a test node.js server" author "Your Name"
我们希望这个节点驱动的服务器应用程序在服务器启动并运行时启动,并在它正常关闭时停止。 因此,请确保指定两个条件:
start on filesystem or runlevel [2345] stop on shutdown
还记得之前的运行级别标准吗? 结合 filesystem
事件,这将确保在服务器正常运行时加载作业。
这些是基础,但现在变得更复杂了; 我们将使用前面提到的 节。
由于这是一个服务器应用程序,我们将在作业配置中加入一个日志记录元素。 因为我们想要记录 Node 应用程序何时启动和停止,所以我们将使用三个不同的节来分隔我们的服务操作 - script
、pre-start script
和 pre-stop script
。
如果您认为这些听起来很熟悉,那您是绝对正确的。 预启动和预停止是作业状态,但它们也适用于节。 这意味着可以根据作业所处的状态运行不同的命令。
但是,要编写的第一节是作业脚本本身。 这将获得 Node 后台服务器的进程 ID,然后运行应用程序脚本。 注意节内命令的缩进——这对于语法正确的格式是必不可少的。
script export HOME="/srv" echo $$ > /var/run/nodetest.pid exec /usr/bin/nodejs /srv/nodetest.js end script
Node 需要设置一个主目录变量,因此为什么 /srv
在该节的第一行中导出。 接下来,$$
用于获取可用的进程 ID 并为我们的作业创建一个 PID 文件。 准备好之后,加载 Node.js 应用程序,我们稍后再编写。
现在是时候关注 pre-start
和 pre-stop
,它们将用于我们简单的应用程序日志记录。 日期以及开始或停止消息将附加到我们工作的日志文件中:
pre-start script echo "[`date`] Node Test Starting" >> /var/log/nodetest.log end script
请注意 pre-stop 节包含另一行:删除 PID 文件作为关闭服务器过程的一部分(pre-stop 的作用)。
pre-stop script rm /var/run/nodetest.pid echo "[`date`] Node Test Stopping" >> /var/log/nodetest.log end script
这就是排序的整个 Upstart 作业配置; 这是整个事情再次供参考:
description "Test node.js server" author "Your Name" start on filesystem or runlevel [2345] stop on shutdown script export HOME="/srv" echo $$ > /var/run/nodetest.pid exec /usr/bin/nodejs /srv/nodetest.js end script pre-start script echo "[`date`] Node Test Starting" >> /var/log/nodetest.log end script pre-stop script rm /var/run/nodetest.pid echo "[`date`] Node Test Stopping" >> /var/log/nodetest.log end script
保存并关闭文件。
如 exec
行中所述,Node.js 脚本从服务器运行,因此在所需位置创建一个 nodetest.js
文件(此示例使用 /srv/
) :
sudo nano /srv/nodetest.js
由于这是一个 Upstart 教程,我们不会花太多时间查看 Node.js 代码,尽管这里是这个脚本将完成的内容的概要:
- 要求并加载 Node 的 HTTP 模块
- 创建 HTTP 网络服务器
- 在 Header 中提供状态 200 (OK) 响应
- 写“Hello World”作为输出
- 监听 8888 端口
这是运行 Node 应用程序所需的代码,可以直接复制以节省时间:
var http = require("http"); http.createServer(function(request, response) { response.writeHead(200, {"Content-Type": "text/plain"}); response.write("Hello World"); response.end(); }).listen(8888);
保存 Node.js 文件后,最后要检查的是 Upstart 作业语法是否有效。 像往常一样,运行配置检查命令,您应该会收到确认输出:
init-checkconf /etc/init/nodetest.conf File nodetest.conf: syntax ok
你已经完成了工作配置,检查了它的语法,并保存了你的 Node.js 代码——一切准备就绪,所以重新启动你的 Droplet,然后访问 http://IP:8888[ X181X],或相关的域。
如果您在窗口的左上角看到“Hello World”,则 Upstart 服务作业已经成功!
要确认基于状态的日志记录,请阅读预定义的日志文件,您应该会看到带有时间戳的 Starting
行。 关闭服务器或手动停止服务作业会在日志中写入 Stopping
行,您也可以根据需要进行检查。
cat /var/log/nodetest.log [Sun Aug 17 08:08:34 EDT 2014] Node Test Starting [Sun Aug 17 08:13:03 EDT 2014] Node Test Stopping
您可以运行标准启动、停止、重新启动等。 此服务以及任何其他类似的 Upstart 作业的命令,语法如下:
sudo service nodetest restart
结论
本教程仅涉及 Upstart 事件系统的皮毛。 您已经阅读了传统初始化的背景知识,了解了为什么开源 Upstart 解决方案是更强大的选择,并开始编写自己的作业。 既然您了解了基础知识,那么可能性是无穷无尽的。
来自Upstart官网的Logo,版权原创设计师/Canonical Ltd.