一个purge参数引发的惨案——从线上hbase数据被删事故说起

在写这篇blog前,我的心情久久不能平静,虽然明白运维工作如履薄冰,但没有料到这么一个细小的疏漏会带来如此严重的灾难。这是一起其他公司误用puppet参数引发的事故,但是这个参数我也曾被“坑过”。

先说说这起事故,在周二下午,安静了一天的某个技术交流群,突然有个惊慌失措的同学在群里说,他拿第三方的puppet hbase module来管理线上hbase集群,结果这个模块在管理数据文件夹时,使用了一个purge参数把几乎所有的线上数据都删完了。他已经和领导汇报了情 况,那边正在紧急讨论处理方案。他在做好打包走人的准备的同时,仍抱有一丝希望来询问我们有没有办法恢复数据,大家纷纷为他献计献策... 我就想起两年前,我第一次尝试使用puppet-apache模块管理apache服务,apache::init类中默认设置了purge_configs参数为True,导致我把apache目录下的所有vhost文件删掉了,万幸的是我是在开发环境发现了这个问题。   那么,我们来看看这个“邪恶”的purge参数是什么样子的:

  1. file {'/var/lib/data_directory':
  2. xxxx => xxx,
  3. ......
  4. recurse => true,
  5. purge => true
  6. }

file是puppet的默认resource type,用于管理文件或者文件夹。在管理文件夹时,只有当设置了recurse为true的情况下,purge参数才会生效。这段逻辑的意思是要清空 /var/lib/data_directory目录下所有非puppet管理的文件,purge参数通常的目的是清理管理目录以及防止被他人恶意添加本不该存在的文件。但也因为这段逻辑,就把hbase数据目录下的文件全部清空了。 从这次事故中,我们可以看到很多问题: 1. 部署代码的上线居然没有通过开发和测试环境的验证2. 使用第三方模块时,竟然不阅读源码或者README文件,也没有运行测试3. 上线没有审批流程,上线负责人的失职4. .....  首先,有一个观念需要矫正,有些人认为部署逻辑不属于开发范畴,往往编写后就直接上线,其实只要涉及到代码的变更,无论是业务逻辑还是部署逻辑,都需要通过开发环境和测试环境的验证。那么如何做好部署逻辑的验证工作? 对于编写puppet来实现部署逻辑的工程师来说:少一个花括号或者分号,就可能导致代码无法运行;遗漏某个class或者某个参数就会使节点 无法到达期望的状态;错误的执行顺序,甚至可能会导致系统崩溃或者网络不可达。为如何保证所编写的manifests符合你的预期?

1. 语法检查

和其他的编程语言一样,语法检查是基本步骤,因此使用puppet解析器做语法检查是最基础也是必不可少的验证工作。你可以使用puppet parser validate命令来检查某个manifest文件: 例如,我在logserver.pp中的$eth0_netmask变量后面漏掉了逗号:

  1. puppet parser validate logserver.pp
  2. Error: Could not parse for environment production: Syntax error at 'eth0_netmask' at sunfire/manifests/logserver.pp:6:3

对于erb template,你可以使用 erb -P -x -T '-' $1 | ruby -c命令来做检查。我在route-eth.erb中漏掉了if判断语句的结束标记,此时执行语法检测会发生以下提示:

  1. route-eth.erb:1: syntax error, unexpected '<'
  2. <%= @internal_network %> via <%= @internal_gateway %>

2. 代码风格检查

每个语言都有一套规范的语法风格指南,puppet也不例外:https://docs.puppetlabs.com/guides/style_guide.htm我们可以使用Github的Tim sharpe所开发的puppet-lint工具来分析你所写的manifests文件。 例如检查一个manifests文件:

  1. puppet-lint manifests/init.pp
  2. WARNING: class inheriting from params class on line 339
  3. WARNING: line has more than 80 characters on line 47
  4. WARNING: line has more than 80 characters on line 167

如果你希望检查整个puppet mainifest目录,你需要添加: require 'puppet-lint/tasks/puppet-lint' 到Rakefile里,然后运行rake lint即可。 在某些情况下,你不得不关闭某些检查,例如,想要关闭80 character check,你可以如下运行:

  1. puppet-lint --no-80chars-check /path/to/my/manifest.pp

需要注意的是,puppet-lint仅作代码风格的检查,不能替代语法检查。

3. 模块测试

你可以使用rspec来确保所有的模块符合预期。举一个例子,你希望编写一个测试来确保当使用puppet-keystone模块时,keystone包被正确地安装,系统中添加了keystone用户和组,可以编写一个keystone_spec.rb文件来做测试:

  1. it { should contain_package('keystone').with(
  2. 'ensure' => param_hash['package_ensure']
  3. ) }
  4. it { should contain_group('keystone').with(
  5. 'ensure' => 'present',
  6. 'system' => true
  7. ) }
  8. it { should contain_user('keystone').with(
  9. 'ensure' => 'present',
  10. 'gid' => 'keystone',
  11. 'system' => true
  12. ) }

随后执行rspec来验证这些测试能否通过。

如果希望集成到rake命令中去,我们可以在Rakefile里添加:

  1. require 'puppetlabs_spec_helper/rake_tasks'

随后使用以下命令来完成相应的spec执行模块测试:

  1. rake spec # Run spec tests in a clean fixtures directory
  2. rake spec_clean # Clean up the fixtures directory
  3. rake spec_prep # Create the fixtures directory
  4. rake spec_standalone # Run spec tests on an existing fixtures directory

因此,在使用从github或者puppetforge下载的module时,阅读README和测试用例是非常重要的,如果我当时仔细阅读了 apache::init的测试用例,也不会出现所谓被坑的问题,因为人家明明在apache_spec.rb里写有对/etc/apache /sites-enabled目录的测试:

  1. it { should contain_file("/etc/httpd/conf.d").with(
  2. 'ensure' => 'directory',
  3. 'recurse' => 'true',
  4. 'purge' => 'true',
  5. 'notify' => 'Class[Apache::Service]',
  6. 'require' => 'Package[httpd]'
  7. )
  8. }

4.开发环境和测试环境的验证

最终部署逻辑能否上线到生产环境,还需要在开发环境和测试环境进行验证。可以使用目前流行的vagrant,Openstack等工具搭建一个测试 平台,调用API创建符合生产环境的集群,通过puppet做软件安装和配置,验证部署逻辑是否符合预期。开发环境和测试环境的不同点在于,测试环境的所 有变更与线上环境完全一致,不允许有任何的人工干预。

至此,一个通过验证的puppet部署逻辑可以release了,打上tag,可以准备发布到线上了。当然不能少了线上变更流程,写下在此次线上变更的详细操作以及回滚机制。

原文发布时间:2014-08-13

本文来自云栖合作伙伴“linux中国”

一个purge参数引发的惨案——从线上hbase数据被删事故说起相关推荐

  1. 二手车数据分析-爬取人人车二十余万条线上二手车数据

    我国汽车保有量近年来持续高速增长,二手车交易也正蓬勃发展,涌现出瓜子.优信.人人车,等大量二手车交易网站. 这次就通过在线抓取人人车发布的线上二手车数据,对目前二手车的交易情况进行分析. 使用工具: ...

  2. 友盟-统计不到线上应用数据的坑

    原文链接: 友盟-统计不到线上应用数据的坑 简书主页:http://www.jianshu.com/users/37f2920f6848 Github主页:https://github.com/Maj ...

  3. 一个 JVM 参数引发的频繁 CMS GC

    了解 CMS GC 的同学,一定知道 -XX:CMSScavengeBeforeRemark 参数,它是用来开启或关闭在 CMS-remark 阶段之前的清除(Young GC)尝试. 大家都知道CM ...

  4. 一个 Google 汉堡引发的惨案

    Emoji,即表情符号,最早是由日本人栗田穰崇创作,在日本网络及手机用户中流行.自苹果公司发布的 iOS 5 输入法中加入了 emoji 后,这种表情符号开始席卷全球.小伙伴们也都热衷于在聊天信息中使 ...

  5. BUG总结——【构造函数写逻辑】引发的极大的线上问题

    刚才排查出一个线上问题,极为严重,但是引发点却非常小,让人深省. 构造函数不写逻辑 这句话一直说,但是一直不理解原因,也确实没遇到过有问题的代码.但是今天却实实在在被坑了一大把,还是很长记性的,在这里 ...

  6. 线上写入数据不成功,本地没问题的解决方法

    1.在本地环境直接链接线上的数据库,看是不是数据库表结构的原因导致入库不成功 2.切换原来的分支代码,看看是不是代码上线后导致的入库不成功 3.查看代码打印对应的代码抛出的异常,一定得打印这个$e,这 ...

  7. Bug本地接口不返回数据 线上返回数据

    本地不可以,线上可以,很奇怪: 各种怀疑之后,都不行,聚焦问题,应该是服务器的原因:怀疑到phpstudy,突然想到php的版本问题 原来我为了测试, 把本地切换到了PHP7.2版本,项目是5.6版本 ...

  8. 百度EasyDate线上协同数据标注平台使用

    文章目录 一.管理员部分 1.建立数据集 2.建立标注团队 3.发布标注任务 4.(补充)数据扩增 1.标注前扩增 2.标注后扩增 二.标注员部分 1.进入标注 2.标注注意 1.标注标签格式 2.快 ...

  9. 线上分享 | 数据产品经理:如何突破现状,更进一层?

    "不会数据分析?你out了!"."会数据分析的人有多吃香?"相信你肯定见过这样的广告和文案.懂数据真的能高薪吗?数据从业者真实的日常是怎样的?又会面临着怎样的机 ...

最新文章

  1. PyTorch 1.5发布,与AWS联手推出TorchServe
  2. java泛型bean copy list
  3. ElasticSearch—基本概念
  4. 快速理解和使用 ES7 await/async
  5. webview跟html通信的原理,1.iOS: webView与html的交互
  6. python语言的模块化
  7. 输入字符串,找出该字符串中abc出现的位置
  8. delphi7 获取dll的类_上传quot;定时任务quot;获取系统权限
  9. excel图表工具的元素
  10. 蚂蚁金服java二面_蚂蚁金服Java开发二面
  11. c语言编程输出等腰三角形,C语言输出等腰三角形
  12. 汽车嵌入式软件自动化测试的方法及推荐工具
  13. php imap 安装_PHP安装IMAP扩展
  14. python派森编程软件_派森Python官方下载_派森Python最新版_派森Python官方版-华军软件园...
  15. python中的多线程 GIL(全局解释器锁) 死锁与递归锁
  16. 普元中间件部署应用程序
  17. 开放源码易语言摄像头拍照自动重命名拍学籍照和证件照
  18. AHB-SRAM简单设计之 顶层模块sram_top.v
  19. 5-5 圆周率Java
  20. 2021年学什么技术比较吃香?当然IT咯

热门文章

  1. php 5.6 新特性,PHP5.6新特性介绍
  2. Vue+axios 实现http拦截及vue-router拦截
  3. [ CCO 2015 ] Artskjid
  4. python3 基本书写规范
  5. Web APi之控制器选择Action方法过程(九)
  6. 【CF】556D A Lot of Games
  7. oracle学习第一天
  8. 如何高效地去调试UGUI的源码
  9. selenium模拟H5触摸滑动之-TouchAction
  10. [HNOI2002]彩票