從入門到精通Puppet的實踐之路


本文有感於《精通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能做這件事,至於怎么做,書上蜻蜓點水,怎么做得更好,那就要靠你自己的摸索了。
  
  在我看來, 
  當你帶着偏見看待一件事情的時候,或許你還沒有了解它。 
   


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM