在寫這篇blog前,我的心情久久不能平靜,雖然明白運維工作如履薄冰,但沒有料到這麼一個細小的疏漏會帶來如此嚴重的災難。這是一起其他公司誤用puppet參數引發的事故,但是這個參數我也曾被“坑過”。

先說說這起事故,在周二下午,安靜了一天的某個技術交流群,突然有個驚慌失措的同學在群裡說,他拿第三方的puppet hbase module來管理線上hbase叢集,結果這個子產品在管理資料檔案夾時,使用了一個purge參數把幾乎所有的線上資料都删完了。他已經和上司彙報了情 況,那邊正在緊急讨論處理方案。他在做好打包走人的準備的同時,仍抱有一絲希望來詢問我們有沒有辦法恢複資料,大家紛紛為他獻計獻策... 我就想起兩年前,我第一次嘗試使用puppet-apache子產品管理apache服務,apache::init類中預設設定了purge_configs參數為true,導緻我把apache目錄下的所有vhost檔案删掉了,萬幸的是我是在開發環境發現了這個問題。 那麼,我們來看看這個“邪惡”的purge參數是什麼樣子的:
file {'/var/lib/data_directory':
xxxx => xxx,
......
recurse => true,
purge => true
}
<a target="_blank"></a>
和其他的程式設計語言一樣,文法檢查是基本步驟,是以使用puppet解析器做文法檢查是最基礎也是必不可少的驗證工作。你可以使用puppet parser validate指令來檢查某個manifest檔案: 例如,我在logserver.pp中的$eth0_netmask變量後面漏掉了逗号:
puppet parser validate logserver.pp
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判斷語句的結束标記,此時執行文法檢測會發生以下提示:
route-eth.erb:1: syntax error, unexpected '<'
<%= @internal_network %> via <%= @internal_gateway %>
puppet-lint manifests/init.pp
warning: class inheriting from params class on line 339
warning: line has more than 80 characters on line 47
warning: line has more than 80 characters on line 167
如果你希望檢查整個puppet mainifest目錄,你需要添加: require 'puppet-lint/tasks/puppet-lint' 到rakefile裡,然後運作rake lint即可。 在某些情況下,你不得不關閉某些檢查,例如,想要關閉80 character check,你可以如下運作:
puppet-lint --no-80chars-check /path/to/my/manifest.pp
需要注意的是,puppet-lint僅作代碼風格的檢查,不能替代文法檢查。
你可以使用rspec來確定所有的子產品符合預期。舉一個例子,你希望編寫一個測試來確定當使用puppet-keystone子產品時,keystone包被正确地安裝,系統中添加了keystone使用者群組,可以編寫一個keystone_spec.rb檔案來做測試:
it { should contain_package('keystone').with(
'ensure' => param_hash['package_ensure']
) }
it { should contain_group('keystone').with(
'ensure' => 'present',
'system' => true
it { should contain_user('keystone').with(
'gid' => 'keystone',
随後執行rspec來驗證這些測試能否通過。
如果希望內建到rake指令中去,我們可以在rakefile裡添加:
require 'puppetlabs_spec_helper/rake_tasks'
随後使用以下指令來完成相應的spec執行子產品測試:
rake spec # run spec tests in a clean fixtures directory
rake spec_clean # clean up the fixtures directory
rake spec_prep # create the fixtures directory
rake spec_standalone # run spec tests on an existing fixtures directory
是以,在使用從github或者puppetforge下載下傳的module時,閱讀readme和測試用例是非常重要的,如果我當時仔細閱讀了 apache::init的測試用例,也不會出現所謂被坑的問題,因為人家明明在apache_spec.rb裡寫有對/etc/apache /sites-enabled目錄的測試:
it { should contain_file("/etc/httpd/conf.d").with(
'ensure' => 'directory',
'recurse' => 'true',
'purge' => 'true',
'notify' => 'class[apache::service]',
'require' => 'package[httpd]'
)
最終部署邏輯能否上線到生産環境,還需要在開發環境和測試環境進行驗證。可以使用目前流行的vagrant,openstack等工具搭建一個測試 平台,調用api建立符合生産環境的叢集,通過puppet做軟體安裝和配置,驗證部署邏輯是否符合預期。開發環境和測試環境的不同點在于,測試環境的所 有變更與線上環境完全一緻,不允許有任何的人工幹預。
至此,一個通過驗證的puppet部署邏輯可以release了,打上tag,可以準備釋出到線上了。當然不能少了線上變更流程,寫下在此次線上變更的詳細操作以及復原機制。
原文釋出時間:2014-08-13
本文來自雲栖合作夥伴“linux中國”