本文有感于《精通Puppet配置管理工具》在豆瓣上的某些差评而顺手写的书评。

半路出家

   
  故事要从12年初说起。 
  某天,部门老大让我所在team的老大调研一下当下业界的配置管理工具。于是我的老大给我分配了一个棘手的任务,要求我转型去做devops,并尝试在本季度内使用Puppet来管理现有的IAAS内部平台上的所有业务,工作成果计入KPI。 
   
  于是,我半路出家从dev转成了ops。 
   
  我花了几天的时间把learning Puppet动手练习了一遍,在会使用几个基础的resource type对系统资源进行管理之后,我自觉已经入门了,于是开始找书看,兴奋地发现京东上只有这一本书:精通Puppet配置管理工具。那看来puppet比较简单呀,看完一本书就能精通了。 
   
  起初拿到这本书的时候很兴奋,哟呵,原来这么薄,看完这本书就能成为一名精通puppet的运维人员了。 
   
  前几章比较容易,边看边动手一下就到了第三章。 
  看到第四章就有点瞌睡了,扩展?为什么要做扩展?一台puppet master难道不够吗? 
  第五章更是纳闷,什么是ENC?用site.pp不就可以管理节点了吗? 
  第六章让我困惑不已:什么是配置的导出和存储? 
  第七章是说Puppet的面板,我安装完Puppet dashboard却不知道它由什么用,还有foreman,又是什么? 
  Report是干嘛的,看日志不就行了嘛? 
  ... 
  后面还有一个Marionette Collective? 编排器?这是什么玩意? 
   
  这书搞得我一头雾水,很快就把它丢到了一旁。

实践出真知 

我当时的第一个任务是在青岛IDC部署一套小规模的Openstack集群用于支持内部的开发环境。 
  虽然我从11年开始接触Openstack,但一直围绕对象存储系统(Swift)做研发工作,对于nova和glance了解的不多,好在有大牛的指导和帮助下,我花了一周的时间把每个服务都详细地了解一遍并手动配置成功后,使用puppet对openstack的包,服务,静态配置文件经行了管理。在这个阶段中,我熟悉了puppet 常见的resource的用法,以及C/S架构puppet的配置,但还是属于初级阶段。 
   
  下一个任务仍是与openstack集群部署相关,我发现之前写的puppet代码并不合理: 
  1. 首先配置文件中许多参数是需要配置的,于是我开始研究使用template来替换原先的静态文件。 
  2. 其次其他服务都是手动安装和配置的,比如mysql和rabbitmq,每台机器上还需要安装ntp服务等等。于是我又添加上了管理相关服务的代码。 
  3. 然后我发现把所有的类放到一个module里实在是不太合理,于是开始进行初步的分离,把每个服务都抽象成一个单独的模块,例如puppet-mysql,puppet-openstack等等。 
  在这个阶段,我掌握了如何根据实际情况将逻辑抽象为class,define和module。 
   
  随后,我发现github的puppetlabs project已经有许多比较成熟的module,于是开始使用upstream的代码来替代原先旧有的代码。阅读这些代码使得我掌握了一些新知识,通过阅读这些有经验的puppet程序员编写的代码,我掌握了如何使用逻辑判断,选择器,链式语法,各种数据类型,函数的用法。 
   
 

参与社区

   
  在这个时候,Puppetlabs的Dan Bode在社区发起了一个项目叫做puppet-openstack,目的是使用puppet来完成openstack的部署,最初这个项目大约由8个相关的module组成,参与人员有cisco,red hat等公司的工程师。这个过程中,我学会了如何使用这些模块来管理现有的集群,掌握了如何使用收集器,配置的存储和导出等等一些高级用法。 
   
  在此同时,我又发现其实这些模块并不完美,存在很多的bug,于是我对代码进行了修改,并在本地进行验证后,发送pull request到了puppet社区。社区的人很快就给我回复了,态度很nice,但指出了我非常低级的错误,老外很严谨,小到多一个多行,少一个空格都会在那标记。 
  我在此过程中,逐渐熟悉了puppet的代码风格,学习了在提交代码前如何对puppet代码和erb模板做语法检查,使用puppet-lint对代码风格进行检查。时至今日,我每看到新人写的代码明显带有其他语言引入的奇怪风格时,都会严格地纠正,即使只是一个空格。 
   
  因为openstack是一个迭代频繁的项目,因此配置文件的管理一直是让我们头疼的地方。从最初的模板到后来的concat方式来拼接配置文件,一直没有找到一个可以灵活管理配置文件的方法。后来iweb的magne提了一个patch,使用了自定义resource可以做到对每个选项灵活地管理。在这个过程中,我开始学习如何编写自定义resource,自定义function,自定义facter。 
   
  当时又来了一个新任务,部署一个multi region的openstack集群(6个IDC)。我当时兴冲冲地使用site.pp开始定义每个机房的每台服务器的角色。当我写到第2个机房的时候,site.pp已经突破500行了。于是我开始对site.pp进行分割,使用import函数将每个机房节点的配置划分到一个文件中去。但我很快发现这仍然不适合做大规模的管理,于是我开始拿起这本书研究起ENC来,我编写了一个python脚本使用yaml格式的文件来管理节点的配置。现在仍然存在一个问题,那就是节点的配置和数据都存在一起,并不方便管理,并且好多参数的值其实是相同的,何必要重复定义呢?于是我又开始研究了hiera。 
   
  那时,我是通过中心的一台puppet master节点来管理所有机房,有时会因为cpu跑满,导致complie catalog失败的情况,于是我又拿起了这本开始研究如何做HA。多台puppet master前面加个LB+KeepAlived解决了这个问题。在这个过程中,我掌握了如何解决多master节点的证书配置和证书同步。 
   
  在此过程中,我把对于puppet-openstack的bug修复反馈到了社区,并且开始积极参与社区的ML和IRC中的讨论,涉及puppet的技术细节和openstack业务逻辑的抽象,这对我后来在开发内部项目puppet模块的影响很大。 
  

业务需求

  后来公司开始做一个私有云的项目,有我来负责部署逻辑的实现。 
  私有云部署的要求一是对用户简单,二是速度要快。我开始阅读书上的第七章,使用foreman来做provision,配合puppet来部署。这个阶段,我掌握了运用facter,resource collect and export,将许多变量变为自动设置的。 
   
  当时有一个痛苦的地方是,每次部署的耗时非常久,令老大不满,部署一台all-in-one的节点大约要半小时。我发现造成这个问题的原因是因为使用了storeconfig这一特性,我使用了mysql + mysql2 adapter作为后端存储。在我查阅了资料后发现原来activerecord在3.x已经弃用了,我当时使用的puppet版本是2.7.x,同时,3.x带来的性能提升大约有40%。 
  于是我开始了两个计划: 
  1. 把puppet升级到3.x 
  2. 使用PuppetDB来代替旧有的ActiveRecord 
   
  这个过程中,我掌握了必须要及时了解社区项目的最新进展,去比较版本的新增特性,puppetdb的安装和配置。 
  

核心开发者 

  在这段时间里,我参与了大量的社区开发和代码审查,深入参与每个项目的开发。 
  也许是因为我在社区的良好表现,在13年的5月,我被推选进入了openstack社区puppet-manager-core team,成为了一名core developer。 
   
  我在使用puppet的过程中,开始对puppet的作者Luke Kanies开始感到好奇,为什么他能写成这么NB的CMS呢?于是我花了一周的业余时间,开始阅读相关的资料,博文,采访以及推特,写下了一篇博文: 
  关于puppet不得不说的故事     同时刊登在《码农》第7期 
  
  接着我就更加好奇了,我想了解puppet背后的架构细节和设计哲学,我开始阅读puppet的源码,并在公司内部分享了两篇文章。 
   
  好奇是没有止境的,我开始对CMS背后的原理感到好奇了,开始阅读Cfengine作者的著作以及DSOM等国际会议上相关的论文,同时温习了读研时候学的自动机理论,这时候对于CMS的认识豁然开朗。 
   
  11月的时候,在HK openstack Icehouse summit的puppet-openstack design summit上和社区的core dev碰了面,我见到了team leader Dan Bode, 我的好基友magne,法国小哥EmilienM, PuppetLabs的Chris, packstack的作者dvorak,RH大名鼎鼎的Dan Prince,Cisco的ChamP... 
   
  我们讨论了在 Icehouse release的milestone和各自的分工,很难想象在一年前的我对于Puppet一无所知。 
  

性能优化

  随着模块和节点的增加,Puppet性能成为诟病,常常被站在背后的老大盯到发毛,于是性能优化提上日程。

最初我们使用的版本是2.7.x系列,当时Puppet发布3.2.x,通过测试,我发现在处理catalog的时候,性能提升了近50%,然而当时使用的诸多模块并没有升级到Puppet3,于是花费数天修复所有不兼容的代码。

然而,整体速度并没有很高的提升,原因是在于代码中使用了一些高级特性,这些特性依赖于storeconfig。最初选择ActiveRecord + MySQL的方式来做storeconfigs严重拖了后腿,随后我开始调研PuppetDB+PostgreSQL,性能提升非常明显。

每次Puppetmaster在处理agent的请求时,cpu负载非常高,为了缓解压力,我将消耗CPU运算的ssl证书验证迁移到了负载均衡节点上,使用传统的Web横向扩展将后端扩展到多台Puppetmaster。

  在管理多个机房的时候,我对于使用ssh登陆服务器批量操作puppet运行的方式渐渐不满起来,而puppet kick的主动触发方式在puppet 3.x轰轰烈烈的大讨论中正式被弃用了。

  最初我使用python写了一个叫dispatcher的小工具,后来使用cluster替换了它。ssh在单个机房内的执行时间还算理想,但是跨多个机房的时候,就可能会出现连接超时的情况,另外还有安全隐患。

于是,我发现一个叫Marionette Collective的工具,号称可以做并发执行任务的框架。它使用MQ作为middleware,通过C/S架构实现并发地异步执行多作业,而且支持各种filter,可以自定义plugin等等,在几番测试后,mco替换了原先的ssh工具,大大提高了执行效率。 
   
  

代码重构

  14年春季过后,我开始对以前编写的代码进行重构,理由是不够抽象,参数冗余,不够智能。 
   
  我对于主要业务的逻辑经行了抽象与合并,举例来说:mysql模块负责mysql的安装和配置,galera类负责主主模式的配置,但是它涉及galera包的安装以及大量参数的配置和一些exec类的操作,应该单独划分成一个模块,而主从模式只是my.cnf中部分参数的配置,抽象为一个类更为合理,线上业务的数据库初始化全部抽取称为一个独立的类。 
   
  削减冗余参数是我重构的最大动力,直到今天下班,我把目前线上业务划分成27种角色,大约1200多个参数,实际需要配置的参数只有40个,但仍没有达到我的预期。 
   
  智能化就更有趣了: 
  整个集群的各种角色根据facter自动配置IP,netmask和gateway,如果绑有公网IP,自动配置高级路由。 
  通道机每增加一个用户,他的ssh publickey就会添加到他有权限访问的服务器上。 
  负载均衡每加一个新节点,其他机器会自动更新自己的配置文件。 
  Gaelra集群每添加一台机器会按照正确的顺序启动。 
  在虚拟机上以qemu形式启动虚拟机,在物理机上以kvm启动虚拟机。 
  如果起了网桥,就把绑定网卡的IP去掉。 
   
      

结尾

   
  截止今天晚上12点,我通过git submodule的方式管理着67个puppet module,43698行puppet代码,59868行ruby代码,这还是DSL的代码行数,如果换成python,估计破百万不是问题,看看Canoical的juju就明白了(那玩意真是太扯了)。 
  通过一年多的努力,我实现了自动化地管理开发,测试,线上环境所有物理服务器和虚拟机上的所有业务,即使细小到vim的配置,.bashrc中的环境变量也纳入管理之中。

有人觉得精通puppet配置管理这本书很烂,有人觉得配置管理没有技术含量shell脚本都可以做,又有人... 
   
  我觉得书是死的,人是活的,技术的更迭很快,如果你觊觎靠一本纸质书精通一门技术的话,那就有点滑稽了。这本书的最大优点是在每一个重要领域都给了你一个指引,告诉你puppet能做这件事,至于怎么做,书上蜻蜓点水,怎么做得更好,那就要靠你自己的摸索了。
  
  在我看来, 
  当你带着偏见看待一件事情的时候,或许你还没有了解它。 
  

从入门到精通Puppet的实践之路的更多相关文章

  1. redis入门到精通系列(二):redis操作的两个实践案例

    在前面一篇博客中我们已经学完了redis的五种数据类型操作,回顾一下,五种操作类型分别为:字符串类型(string).列表类型(list).散列类型(hash).集合类型(set).有序集合类型(so ...

  2. <程序员从入门到精通> -- How

    定位 自己才是职业生涯的管理者,想清楚自己的发展路径: 远期的理想是什么?近期的规划是什么?今日的任务和功课又是什么? 今日之任务或功课哪些有助于近期之规划的实现,而近期之规划是否有利于远期之理想? ...

  3. 从入门到精通C++需要学的10本书

    学习C++从入门到精通的的十本最经典书籍  文章来源中国IT实验室收集整理作者佚名更新时间2009-5-16 12:27:05 保存本文保存本文推荐给好友推荐给好友收藏本页收藏本页 欢迎进入C/C++ ...

  4. Android开发书籍推荐:从入门到精通系列学习路线书籍介绍

    Android开发书籍推荐:从入门到精通系列学习路线书籍介绍 很多时候我们都会不断收到新手的提问"Android开发的经典入门教材和学习路线?"."Android 开发入 ...

  5. Jenkins pipeline 入门到精通系列文章

    Jenkins2 入门到精通系列文章. Jenkins2 下载与启动jenkins2 插件安装jenkins2 hellopipelinejenkins2 pipeline介绍jenkins2 jav ...

  6. Azure Blob Storage从入门到精通

    今天推荐的是一个系列文章,让读者阅读完成后可以对Azure Blob Storage的开发有一个全面的了解,可谓是从入门到精通. Azure在最初的版本里面就提供了非结构化数据的存储服务,也即Blob ...

  7. 学java入门到精通,不得不看的15本书

    学java入门到精通,不得不看的15本书 一.Java编程入门类1.<Java编程思想>2.<Agile Java>中文版 二.Java编程进阶类1.<重构 改善既有代码 ...

  8. Java入门-浅析Java学习从入门到精通【转】

    一. JDK (Java Development Kit)  JDK是整个Java的核心,包括了Java运行环境(Java Runtime Envirnment),一堆Java工具和Java基础的类库 ...

  9. 【转载】google搜索从入门到精通

    原文地址:http://www.cnblogs.com/helloIT/articles/5095668.html /***************************************** ...

随机推荐

  1. python-随机操作(random)

    random模块作用是返回随机数,只要跟随机元素相关的,都可以使用它. Python标准库中的random函数,可以生成随机浮点数.整数.字符串,甚至帮助你随机选择列表序列中的一个元素,打乱一组数据等 ...

  2. linux常用软件安装,常用命令

    jdk [root@localhost]# tar -zxvf jdk-8u144-linux-x64.tar.gz [root@localhost]# vi /etc/profile 在profil ...

  3. 谷歌云ssh开启root密码登录

    修改配置 1.先选择从浏览器打开ssh连接服务器 连接登录成功后,输入以下命令 sudo -i #切换到root passwd #修改密码 然后会要求输入新密码,然后再重复一次密码,输入密码的时候不会 ...

  4. 异常Cannot get a text value from a numeric cell

    POI操作Excel时偶尔会出现Cannot get a text value from a numeric cell的异常错误. 异常原因:Excel数据Cell有不同的类型,当我们试图从一个数字类 ...

  5. Mysql 账号过期问题

    1.ALTER USER 'root'@'localhost' PASSWORD EXPIRE; 一旦某个用户的这个选项设置为”Y”,那么这个用户还是可以登陆到MySQL服务器,但是在用户未设置新密码 ...

  6. 通过工具SecureCRTPortable将项目部署到服务器上

    1.将项目打包 2.打开工具连接指定的ip 下面是一些命令 tab键可以有一些提示功能 ls 查看服务器当前目录 lls 查看硬盘当前目录 其实就是linux系统命令 ,服务器是正常命令  ,操作本电 ...

  7. ubuntu18.04 lts重装VMware Tools实现主机文件共享等功能

    ubuntu18.04 lts重装VMware Tools实现主机文件共享等功能 在VMWare 14.x上安装ubunuu18.04 lts后发现,可以实现全屏显示,但是没有与主机共享文件的功能,然 ...

  8. Linux学习之挂载光盘和U盘(六)

    Linux下挂载光盘和U盘 挂载 linux下硬盘.U盘.软盘.移动硬盘都必须挂载后才能使用,不过硬盘的挂载是系统自动进行的. linux中每一个硬件都有一个设备文件名,就是将U盘什么的设备文件名与挂 ...

  9. springboot springcloud 父项目pom工程创建pom文件

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/20 ...

  10. Git学习笔记:基础篇

    git可以说是所有开发者出开发语言之外的最基本的基本功了,熟悉git可以方便的进行代码版本控制,以及与其他开发者进行合作开发.本文内容是我以往学习git时做的笔记,主要是关于git最基本的操作,但 只 ...