本文有感於《精通Puppet配置管理工具》在豆瓣上的某些差評而順手寫的書評。 html
故事要從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? 編排器?這是什麼玩意?
這書搞得我一頭霧水,很快就把它丟到了一旁。 python
我當時的第一個任務是在青島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程序員編寫的代碼,我掌握瞭如何使用邏輯判斷,選擇器,鏈式語法,各類數據類型,函數的用法。
mysql
在這個時候,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模塊的影響很大。
git
後來公司開始作一個私有云的項目,有我來負責部署邏輯的實現。
私有云部署的要求一是對用戶簡單,二是速度要快。我開始閱讀書上的第七章,使用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一無所知。
github
隨着模塊和節點的增長,Puppet性能成爲詬病,經常被站在背後的老大盯到發毛,因而性能優化提上日程。web
最初咱們使用的版本是2.7.x系列,當時Puppet發佈3.2.x,經過測試,我發如今處理catalog的時候,性能提高了近50%,然而當時使用的諸多模塊並無升級到Puppet3,因而花費數天修復全部不兼容的代碼。sql
然而,總體速度並無很高的提高,緣由是在於代碼中使用了一些高級特性,這些特性依賴於storeconfig。最初選擇ActiveRecord + MySQL的方式來作storeconfigs嚴重拖了後腿,隨後我開始調研PuppetDB+PostgreSQL,性能提高很是明顯。shell
每次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能作這件事,至於怎麼作,書上走馬觀花,怎麼作得更好,那就要靠你本身的摸索了。 在我看來, 當你帶着偏見看待一件事情的時候,或許你尚未了解它。