使用Ansible自动更换磁盘



大家好 我是OK的主要系统管理员,负责门户的稳定运行。 我想谈一谈我们如何构建自动更换磁盘的过程,然后,由于管理员被排除在此过程之外,而是用机器人代替了它。

本文是HighLoad + 2018 表现的一种音译

建立光盘更换过程


前几个数字


OK是数百万人使用的一项巨大服务。 它由位于4个不同数据中心的约7,000台服务器提供服务。 服务器成本超过7万个驱动器。 如果将它们堆叠在一起,您将得到一个高度超过1公里的塔。

硬盘驱动器是服务器最容易崩溃的组件。 有了这样的容量,我们每周必须更换大约30张光盘,而此过程已成为一种不太愉快的例行程序。



突发事件


我们在公司中引入了全面的事件管理。 我们在Jira中记录的每个事件,然后解决并分解。 如果该事件对用户产生了影响,那么我们肯定会考虑在这种情况下如何更快地做出响应,如何减少影响以及当然如何防止再次发生。

驱动器也不例外。 他们的状态由Zabbix监控。 我们会监视Syslog中的消息以查看写入/读取错误,分析硬件/软件突袭的状态,监视SMART并计算SSD的磨损。

光盘之前如何更换


当Zabbix中的触发器点亮时,将在Jira中创建一个事件,并自动将其发送给数据中心的相应工程师。 我们处理所有硬件事件,即那些需要对数据中心中的设备进行某种物理工作的事件。
数据中心的工程师是解决与硬件有关的问题的人员,负责服务器的安装,维护和拆卸。 收到票后,工程师开始工作。 在磁盘架上,他自己更换磁盘。 但是,如果他无法访问所需的设备,则工程师会向值班的系统管理员寻求帮助。 首先,您需要从旋转中取出磁盘。 为此,您需要在服务器上进行必要的更改,停止应用程序,卸载磁盘。

值班期间的值班系统管理员负责整个门户的操作。 他调查事件,进行维修,帮助开发人员执行小任务。 他不仅处理硬盘驱动器。

以前,数据中心工程师与系统管理员聊天。 工程师发送了指向Jira票证的链接,管理员仔细检查了这些票证,并在记事本中保存了工作日志。 但是聊天对于这样的任务是不方便的:那里的信息没有结构化,并且会很快丢失。 管理员可能只是离开计算机而在一段时间内不响应请求,工程师带着一堆磁盘站在服务器旁等待。

但是最糟糕的是,管理员并没有看到整体情况:存在哪些磁盘事件,可能在何处出现问题。 这是因为我们将所有硬件事件都交给了工程师。 是的,可以在管理仪表板上显示所有事件。 但是它们很多,而管理员只参与其中的一些。

此外,工程师无法正确地确定优先级,因为他对特定服务器的用途以及驱动器之间的信息分配一无所知。

新的更换程序


我们要做的第一件事是将所有磁盘事件归为“ HW磁盘”的单独类型,并在其中添加“块设备名称”,“大小”和“磁盘类型”字段,以便将该信息保存在故障单中,而不必不断聊天。


我们还同意,在一次事件的框架内,我们将仅更改一个磁盘。 这大大简化了自动化过程,统计信息的收集和工作。

此外,添加了“负责的管理员”字段。 系统管理员将在那里自动替换。 这非常方便,因为现在工程师总是可以看到谁负责。 无需转到日历并进行搜索。 正是这个字段允许将票证放在管理员的仪表板上,也许需要他的帮助。


为了确保所有参与者都能从创新中获得最大的收益,我们创建了过滤器和仪表板,并告诉他们。 当人们了解这些变化时,他们不会将自己与不必要的事物保持距离。 对于工程师而言,了解服务器所在的机架号,磁盘的大小和类型非常重要。 管理员首先需要了解这是哪种服务器组,以及更换磁盘时可能产生的影响。

字段及其显示很方便,但这并没有使我们免于使用聊天的需要。 为此,我不得不更改工作流程。

以前是这样的:


如今,工程师在不需要管理员帮助的情况下仍可以继续这样工作。

我们要做的第一件事是引入新的调查身份。 当工程师尚未决定他是否需要管理员时,票证处于此状态。 通过此状态,工程师可以将票证传递给管理员。 此外,当需要更换磁盘但站点上本身没有磁盘时,我们会将票证标记为此状态。 CDN和远程站点会发生这种情况。

我们还添加了就绪状态。 更换磁盘后,票证将传输到该票证。 也就是说,一切都已经完成,但是硬件/软件RAID已在服务器上同步。 这可能会非常耗时。

如果涉及管理员,则该方案会更加复杂。


在“ 打开”状态下,系统管理员和工程师均可转让故障单。 在“ 进行中”状态下,管理员可以将磁盘从旋转中移出,以便工程师可以轻松地将其移出:根据特定的服务器组,它可以打开背光灯,卸下磁盘并停止应用程序。

然后,票证将转换为“ 准备更改” :这是向工程师发出的信号,表明可以拉出磁盘。 Jira中的所有字段均已填满,工程师知道磁盘的类型和大小。 此数据将自动或由管理员附加到以前的状态。

更换磁盘后,票证将转移到“ 已更改”状态。 检查是否已插入正确的磁盘,完成标记,启动应用程序以及执行了一些数据恢复任务。 同样,可以将票证转移到“ 就绪”状态,在这种情况下,管理员将继续负责,因为他启动了旋转磁盘。 完整轮廓如下所示。


添加新的字段使我们的生活更加轻松。 他们开始使用结构化信息,很清楚在什么阶段进行什么工作。 优先级已经变得越来越重要,因为它们现在由管理员设置。

聊天的需求已经消失。 当然,管理员可以写信给工程师“您需要在这里更换得更快”或“已经晚上,您有时间更换吗?”。 但是我们不再每天都在这些问题上聊天。

磁盘开始打包更换。 如果管理员早一点上班,他有空闲时间,什么都没发生,则他可以准备更换许多服务器:放下字段,从旋转中取出磁盘,然后将任务转移给工程师。 工程师随后到达数据中心,看到任务,从仓库中取出必要的驱动器并立即进行更改。 结果,替换速度提高了。

建筑工作流程中的经验教训


  • 建立过程时,您需要从不同来源收集信息。
    我们的一些管理员不知道工程师是自己更换了磁盘。 一些人以为工程师监视了MD RAID同步,尽管其中一些甚至没有访问权限。 一些领先的工程师这样做,但并非总是如此,因为该过程没有在任何地方描述。
  • 该过程应简单明了。
    一个人很难保持很多步伐。 Jira中最重要的邻居状态需要显示在主屏幕上。 您可以重命名它们,例如,“进行中”我们称为“准备更改”。 其余的状态可以隐藏在下拉菜单中,这样它们就不会伤眼。 但是最好不要限制人员,要有机会进行过渡。
    解释创新的价值。 当人们理解后,他们最好接受新程序。 对于我们而言,非常重要的是人们不要调用整个过程,而要遵循整个过程。 然后我们以这种自动化为基础。
  • 等待,分析,了解。
    我们花了大约一个月的时间来制定程序,技术实施,会议和讨论。 并实施-超过三个月。 我看到人们是如何慢慢开始使用这项创新的。 在早期阶段,存在很多消极因素。 但是他完全独立于程序本身,即程序的技术实施。 例如,一个管理员没有使用Jira,但是使用了Confluence中的Jira插件,并且有些东西对他不可用。 向他展示了吉拉,管理员提高了工作效率和整体任务,并提高了更换磁盘的能力。

驱动器更换自动化


我们多次进行了自动更换磁盘的工作。 我们已经有了操作时间和脚本,但是它们全部都以交互方式或手动方式工作,因此需要启动它们。 只是在引入新程序之后,我们才意识到这只是我们所缺少的。

由于现在替换过程分为多个阶段,每个阶段都有一个执行程序和一系列操作,因此我们可以分阶段而不是一次全部打开自动化。 例如,最简单的步骤-就绪(检查RAID /数据同步)可以很容易地委派给机器人。 当机器人学到一点东西时,您可以给它一个更负责任的任务-旋转磁盘等。

动物园设置


在讨论机器人之前,我们将简短地参观我们的安装动物园。 首先,这是由于我们的基础设施规模巨大。 其次,对于每种服务,我们都尝试选择最佳的铁质配置。 我们大约有20种硬件RAID模型,主要是LSI和Adaptec,但是HP和DELL都有不同的版本。 每个RAID控制器都有其自己的管理实用程序。 每个RAID控制器的版本和命令集可能不同。 如果不使用HW-RAID,可能会很麻烦。

我们几乎所有新安装都没有磁盘备份。 我们尝试不再使用硬件和软件RAID,因为我们将系统保留在数据中心级别,而不是服务器级别。 但是,当然有许多旧服务器需要得到支持。

RAID控制器中的某个位置的磁盘会抛出原始设备;而JJOD则用于某个位置。 服务器中有一个系统驱动器的配置,如果您需要更换它,则必须通过安装具有相同版本的OS和应用程序来重新格式化服务器,然后添加配置文件,启动应用程序。 在很多服务器组中,冗余不是在磁盘子系统级别上而是在应用程序本身中执行的。

总共,我们有400多个唯一的服务器组,它们运行大约100个不同的应用程序。 为了涵盖如此众多的选项,我们需要一个多功能的自动化工具。 建议使用简单的DSL,这样不仅编写此语言的人可以支持它。

我们选择Ansible是因为它是无代理的:无需准备基础架构,快速启动。 此外,它是用Python编写的,已被团队接受为标准。

一般方案


让我们以一个事件为例看一下通用自动化方案。 Zabbix检测到sdb驱动器故障,触发器点亮,在Jira中创建了票证。 管理员查看了一下,意识到这不是重复的并且不是误报,也就是说,您需要更换磁盘,并转换进行中的票证。


用Python编写的DiskoBot应用程序会定期向Jira轮询新票证。 它注意到出现了一个新的正在进行中的凭单,触发了相应的线程,该线程在Ansible中启动该剧本(对Jira中的每个状态都完成了此操作)。 在这种情况下,Prepare2change启动。

Ansible进入主机,从旋转中删除磁盘,然后通过回调向应用程序报告状态。


根据结果​​,自动程序将票证自动转移到“准备更改”。 工程师收到通知,然后去更换磁盘,然后将故障单转移到“已更改”。


根据上述方案,票证将返回到机器人,它启动另一个剧本,然后到达主机,并使磁盘旋转。 机器人关闭了罚单。 万岁!


现在让我们讨论系统的某些组件。

Diskobot


该应用程序是用Python编写的。 它根据JQL从吉拉选择门票。 根据票证状态,后者进入相应的处理程序,该处理程序又启动相应的Ansible剧本状态。

JQL和轮询间隔在应用程序配置文件中定义。

jira_states: investigate: jql: '… status = Open and "Disk Size" is EMPTY' interval: 180 inprogress: jql: '… and "Disk Size" is not EMPTY and "Device Name" is not EMPTY' ready: jql: '… and (labels not in ("dbot_ignore") or labels is EMPTY)' interval: 7200 

例如,在处于“进行中”状态的票证中,仅填写具有“磁盘大小”和“设备名称”字段的票证。 设备名称是运行剧本所需的块设备的名称。 需要磁盘大小,以便工程师知道需要什么大小的磁盘。

在具有就绪状态的故障单中,带有dbot_ignore标签的故障单会被过滤掉。 顺便说一下,我们将Jira标签用于这种过滤,标记重复票证以及收集统计信息。

如果剧本崩溃,那么Jira会分配dbot_failed标签,以便您稍后进行查找。

与Ansible互动


该应用程序通过Ansible Python API与Ansible进行交互。 在playbook_executor中,我们传递文件名和变量集。 这使您可以将Ansible项目保留为常规yml文件的形式,而不用Python代码进行描述。

同样在通过* extra_vars *的Ansible中,使用块设备的名称,票证的状态以及在其中链接了发行密钥的callback_url -它用于HTTP中的回调。

对于每次启动,都会生成一个临时清单,该清单由一个主机和该主机所属的组组成,因此可以应用group_vars。

这是在其中实现HTTP回调的任务的示例。

我们使用Callaback获得的剧本的结果。 它们有两种类型:

  • Ansible回调插件 ,它提供有关剧本结果的数据。 它描述了已启动,成功或未成功执行的任务。 该回调在剧本的末尾被调用。
  • HTTP回调以在播放剧本时获取信息。 在Ansible中,我们向应用程序一侧执行POST / GET请求。

通过HTTP回调,可以传输在执行剧本过程中定义的变量,我们要保存并在后续运行中使用的变量。 我们将此数据写入sqlite。

同样通过HTTP回调,我们留下评论并更改票证状态。

HTTP回调
 # Make callback to Diskobot App # Variables: # callback_post_body: # A dict with follow keys. All keys are optional # msg: If exist it would be posted to Jira as comment # data: If exist it would be saved in Incident.variables # desire_state: Set desire_state for incident # status: If exist Proceed issue to that status - name: Callback to Diskobot app (jira comment/status) uri: url: "{{ callback_url }}/{{ devname }}" user: "{{ diskobot_user }}" password: "{{ diskobot_pass }}" force_basic_auth: True method: POST body: "{{ callback_post_body | to_json }}" body_format: json delegate_to: 127.0.0.1 


像许多相同类型的任务一样,我们将其放在单独的公用文件中,并在必要时将其包括在内,以免在游戏本中不断重复。 Callback_ url出现在此处,其中发布密钥和主机名受到保护。 当Ansible执行此POST请求时,机器人会意识到它是此类事件的一部分。

这是一个剧本示例,其中我们显示了MD设备的磁盘:

  # Save mdadm configuration - include: common/callback.yml vars: callback_post_body: status: 'Ready to change' msg: "Removed disk from mdraid {{ mdadm_remove_disk.msg | comment_jira }}" data: mdadm_data: "{{ mdadm_remove_disk.removed }}" parted_info: "{{ parted_info | default() }}" when: - mdadm_remove_disk | changed - mdadm_remove_disk.removed 

此任务会将Jira票证置于“准备更改”状态,并添加评论。 另外,mdam_data变量存储从中删除磁盘的md设备的列表,以及parted_info中parted分区的parted_ dump。

当工程师插入新磁盘时,我们将能够使用这些变量来还原分区转储,以及将磁盘插入从中删除磁盘的md设备中。

Ansible检查模式


开启自动化令人恐惧。 因此,我们决定在模式下运行所有​​剧本
试运行 ,其中Ansible不会在服务器上执行任何操作,而只是模拟它们。

这样的启动是通过一个单独的回调模块运行的,该剧本的结果作为注释保存在Jira中。



首先,它允许验证机器人程序和剧本的工作。 其次,它增加了管理员对机器人的信任。

当我们进行验证并意识到您不仅可以在空运行模式下运行Ansible时,我们在Jira中创建了Run Diskobot按钮,可以在正常模式下在同一主机上启动具有相同变量的同一剧本。

另外,该按钮用于在发生故障时重新启动剧本。

剧本结构


我已经提到过,根据吉拉车票的状态,该机器人会启动不同的剧本。

首先,安排参赛非常容易。
其次,在某些情况下,这仅仅是必要的。

例如,更换系统磁盘时,首先需要转到部署系统,创建一个任务,然后在正确部署之后,可以通过ssh访问该服务器,然后可以将应用程序滚动到该服务器上。 如果我们在一本剧本中完成所有这些操作,由于主机无法访问,Ansible将无法执行它。

我们为每个服务器组使用Ansible角色。 在这里,您可以查看其中的剧本的组织方式。



这很方便,因为可以立即清楚地将什么任务放在何处。 在main.yml(这是Ansible角色的输入)中,我们仅可以按票证状态或每个人所需的常规任务包括,例如,传递身份证明或接收令牌。

调查文件


以调查和开放状态运行票证。 对于这本剧本,最重要的是块设备的名称。 此信息并非始终可用。

为了得到它,我们分析了Jira摘要,这是Zabbix触发器的最后一个值。 它可能包含阻止设备的名称-幸运。 或者它可能包含一个安装点,然后-您需要转到服务器,解析并计算所需的驱动器。 同样,触发器可以发送scsi地址或其他信息。 但是也有没有线索的情况,您必须进行分析。

找出块设备的名称后,我们收集有关磁盘类型和大小的信息,以填写Jira中的字段。 我们还将删除有关供应商,型号,固件,ID,SMART的信息,并将所有这些信息插入Jira票证的注释中。 管理员和工程师不再需要查找此数据。 :)



prepare2change.yml


磁盘的输出从旋转开始,准备更换。 最困难,最关键的阶段。 在无法停止的情况下,您可以在此处停止该应用程序。 或拉出没有足够副本的磁盘,从而对用户产生影响,丢失一些数据。 在这里,我们在聊天中拥有最多的检查和通知。

在最简单的情况下,我们正在谈论从HW / MD RAID中删除驱动器。

在更复杂的情况下(在我们的存储系统中),在应用程序级别执行备份时,您需要使用API​​转到应用程序,报告磁盘输出,将其停用并开始恢复。

我们现在正在大规模迁移到 ,如果服务器多云,那么Diskobot将访问云API,并表示它将与运行服务器的服务器(服务器)一起使用,并要求“从该服务器迁移所有容器”。 同时,它打开了背光灯,以便工程师立即看到要拉出哪个背光灯。

更改后的


更换磁盘后,我们首先检查其可用性。

工程师并非总是会放入新光盘,因此我们添加了对我们满意的SMART值的检查。

我们在看什么属性
重新分配的部门数(5)<100
当前待处理的扇区数(107)== 0

如果驱动器测试失败,则会将更换通知工程师。 如果一切正常,则背光关闭,应用标记,然后将磁盘旋转插入。

ready.yml


最简单的情况是:检查硬件/软件RAID同步或结束应用程序中的数据同步。

应用程式API


我多次提到该漫游器经常访问应用程序API。 当然,并非所有应用程序都具有必需的方法,因此我不得不对其进行完善。 这是我们使用的最重要的方法:
  • 现况 集群或磁盘的状态,以了解是否可以使用它;
  • 启动/停止。 激活/禁用磁盘;
  • 迁移/还原。 更换期间和之后的迁移和数据恢复。

Ansible的经验教训


我真的很喜欢Ansible。 但是通常,当我查看不同的开源项目并看到人们如何编写剧本时,我会有些害怕。 来自when / loop的复杂逻辑编织,由于频繁使用shell / command而缺乏灵活性和幂等性。

我们决定利用Ansible-模块化来尽可能简化一切。 最高层是剧本,它们可以由任何管理员(对Ansible有点了解的第三方开发人员)编写。

 - name: Blink disk become: True register: locate_action disk_locate: locate: '{{ locate }}' devname: '{{ devname }}' ids: '{{ locate_ids | default(pd_id) | default(omit) }}' 


如果很难在剧本中实现任何逻辑,则将其放在Ansible模块或过滤器中。 脚本可以用Python或任何其他语言编写。

它们易于编写且快速。 例如,磁盘突出显示模块(上面给出了使用示例)由265行组成。



最底层是库。 对于这个项目,我们编写了一个单独的应用程序,一种对执行相应请求的硬件和软件RAID的抽象。



Ansible的最大优势在于其简单易懂的剧本。 我相信您需要使用它,而不要生成可怕的Yaml文件以及大量的条件,shell代码和循环。

如果您想重复使用Ansible API的经验,请记住两点:

  • Playbook_executor和通常的playbook无法超时。 ssh会话有超时,但剧本没有超时。 如果我们尝试卸载系统中尚不存在的驱动器,则该剧本将无限期运行,因此我们必须将其包装在单独的包装中并通过超时终止。
  • Ansible是分叉的,因此其API并非线程安全的。 我们启动所有的剧本和单线程。

结果,我们能够自动更换约80%的驱动器。 总的来说,更换率翻了一番。 今天,管理员仅查看事件并决定是否更换磁盘,然后单击一下。

但是现在我们开始面临另一个问题:一些新管理员不知道如何更换驱动器。 :)

Source: https://habr.com/ru/post/zh-CN452110/


All Articles