1. 程式人生 > >DevOps 能力模型、演進及案例剖析

DevOps 能力模型、演進及案例剖析

作者介紹

王曉偉

2009年創辦麥圖科技,專注於電商行業的垂直搜尋, 受到多家天使、Pre-A投資機構的關注。
有10+年網際網路、遊戲、核心安全從業經驗。歷任軟體工程師、高階軟體工程師、技術經理和總監。
目前主要從事手機遊戲發行平臺的構建,推進公司DevOps的培養和運維自動化的實施。

主題簡介

本次分享主要分為兩部分:

  • 第一部分引入運維工程師的能力理論定義;
  • 第二部分介紹DevOps的能力模型,其中引用了第一部分的定義。

部分內容可能形而上學,所以帶好枕頭被褥,困了就眯一會兒,後面有點小精彩。

引言

運維工作是實踐性的學科和工作,即便沒有高深的理論也可以開展工作,繼而從事這個工作的朋友不缺乏實際動手的能力。

但從事物的發展規律性和普遍性來看,從實踐出發的Ops恰恰缺乏必要的理論指導和思想探究。

本文是我對運維工作的理論、思考和定義的總結,同時給出DevOps相關概念的定義,明確其工作範疇,能力要求,產出標準以及演進建議。一家之言尚未完善,拋磚引玉,歡迎討論。

從一次面試開始

問題1

問:如何通過Python或者Shell給Nginx新增/刪除一個虛擬站點?
答:通過Python或者Shell在nginx.conf裡新增server區塊,然後如何如何……

問題2

問:如何使用Python將文字日誌結構化
答:通過python的os.system呼叫awk。(哭,韓國的整容術用到運維上了,給awk整成python……)

這是最近真實的面試案例。上述兩個問題的回答,讓我很不開心:

  • 問題1的回答,說明面試者不具備運維的工程能力,更不具備架構能力;
  • 問題2的回答,說明面試者不具備程式的架構能力,甚至對語言理解和標準庫的學習都不到位。

從案例裡我總結了兩個核心的定義:工程能力和架構能力。下面先給出這兩個定義。

工程能力當然是運維工!程!師所必需具備的。我對工程能力的定義是:

  1. 分解問題的能力;
  2. 定義執行序列的能力;
  3. 制定可重入操作行為的能力。

架構能力,本人解釋為:

  • 懂“不該”懂的;
  • 想“不該”想的;
  • 做“不該”做的。

比如程式猿懂了業務,想了部署,做了高可用的規劃應該算得上架構獅了。

1. 分解問題的能力

針對問題1的分解邏輯如下:

  1. nginx是如何管理虛擬站點的,是否具有模組化能力?
  2. 在具有模組能力的情況下,如何實現虛擬站點模組的新增?
  3. 如何定義規則來命名虛擬站點,以保證可重入,在規則不變的情況不會再重複新增(還要支援upstream等等)?
  4. python要實現什麼樣的功能,shell要完成什麼樣的工作?
  5. 新增完成後,如何驗證其生效?
  6. 刪除的行為是否要徹底刪除配置檔案,抑或者留一個副本?

2. 定義執行序列的能力

有些操作是高危操作或者是不可逆的,比如修改sudoers檔案。在基於sudo管理的系統下,如果一旦sudoers被改壞是災難性的。因此定義執行序列是:

  1. 在 Terminal下開一個視窗切換到root下;
  2. 在另外的視窗下進行對sudoers/sudoers.d的修改或者新增;
  3. 一旦試驗過程中sudoers被改壞,可以用root賬戶直接改回來;
  4. 以上流程雖然簡單,但是這跟飛機起飛前拔掉起落架的閂是一樣致命的。

3. 制定可重入操作的能力

系統的管理和系統的狀態的獲取是兩個不同方向的工作:

管理是把指令傳遞給系統,修改系統的狀態和資訊;檢視系統的狀態是從系統獲取資訊。

這兩個不同向的操作行為就導致了狀態和資訊同步的問題。解決這個問題的方法有很多,但是穩定可靠,相容性好的方法不多,我的方法是保證操作的可重入性。

即在同等的條件下,對於系統發出的指令,執行n+1次(n>0)的效果是相同的。

這樣,即便我可能知道系統狀態和資訊是不一致的,但是由於操作行為是可重入的,我可以最終把狀態和資訊一致化。

以上展開了工程能力的解釋。

由於架構能力涉及面廣,交叉學科眾多,此處暫不作展開說明。

DevOps的能力模型

我們先介紹相關能力模型:作業系統能力模型和應用系統能力模型,然後再由此引出DevOps能力模型。

作業系統能力模型

除作業系統核心提供的基本功能外,還給我們提供了以下功能(以Linux為例):

  1. 訪問控制,實現基於角色的最小粒度訪問控制,此為系統管理的基礎,能力模型的關鍵之一;
  2. 權利托管,基於角色和命令的可配置授權機制,提供了可控的,可定製的提權的方案;
  3. 匯入式的可插拔配置能力(通過類include指令), 比如 /etc/security/limits.d,/etc/sudoers.d, 此為自動化重要設施;
  4. 包管理能力,包括二進位制和原始碼包的依賴管理等;
  5. shell程式設計的支援。

應用系統能力模型

除作業系統能力模型提供的功能之外,還給我們提供了以下功能:

  1. 匯入式配置能力,如nginx的 /etc/nginx/sites-available/;
  2. 系統狀態偵測能力,如php-fpm的ping/pong;
  3. 熱裝載能力,例如很多服務的reload功能;
  4. 高可用性以及故障恢復能力,例如MySQL的高可用配置,以及其binlog的恢復能力;
    5,其他必要特性,視不同的業務系統而定。

DevOps能力模型

由此,我們給出DevOps能力模型的定義:

  1. 瞭解其所管理的作業系統的能力模型(Linux,Windows),掌握系統程式語言(Shell)並能利用其能力用於DevOps工作;
  2. 瞭解其管理的應用系統的能力模型(Mysql, Nginx等),掌握系統程式語言(Shell)並能利用其能力用於DevOps工作;
  3. 具備前文提到的工程能力,掌握系統程式語言(Shell)和通用語言(Python/Ruby等),並能利用其程式設計能力將工程能力提到三種能力程式化,並進一步實現自動化;
  4. 瞭解工作場景和業務場景,以及業務的關鍵指標,使DevOps工作有的放矢,貼近業務。

評估DevOps是否合格的標準:

  1. 具備DevOps能力模型提到的各項要求;
  2. 其產出的程式碼指令碼能夠適應普遍需求,並且該程式碼指令碼符合前文的可重入要求,即執行n和n+1次的效果相同;
  3. 其產出的程式碼指令碼能夠供其他程式碼指令碼使用,此條尤為重要。

DevOps的級別:

符合DevOps能力模型1:為初級DevOps,可以使用shell做DevOps的一般性系統級別的工作,在一些第三方工具(Ansible/Fabric)的幫助下管理大量伺服器;

符合DevOps能力模型2:為中級DevOps,可以使用shell做DevOps的應用系統的部署和優化工作,並能通過其產出的指令碼大批量管理應用系統

符合DevOps能力模型3:為高階DevOps,可以使用shell和通用語言進行廣泛的DevOps的工作,可以完成完整的業務流程的定義和開發,能夠熟練抽象並編寫供其他DevOps使用的介面。

符合DevOps能力模型4:為架構師級別的DevOps,根據業務需求,規劃系統部署架構;根據業務指標要求優化部署結構和效能,保證高可用等;定義指令碼程式碼介面,制定開發規範和操作規範。

理論的東西說完了,下面是探討下Dev和Ops的現狀,Ops的演進,Dev的演進以及三項補充內容。

Dev和Ops的現狀

Dev和Ops是實踐性的工作,因此即便不是一名DevOps,或許你也在做著Dev或者Ops的工作。只是這不是真正的DevOps。讓我們看兩個場景:

  1. Dev的風格是力求用Python/Ruby這類通用程式語言整合一堆的API,實現一套大系統,搞定一切Ops的工作;他們每天的工作就是在找Libs和看各種API的文件,滿腦子設計思想。這種思維是Dev思維;
  2. Ops的風格是力求從命令列的角度,甚至指令碼都不用,一行一行的把命令敲下去完成工作;或者快速的寫一個一次性指令碼搞定;他們還喜歡自己編譯各種系統,滿世界下原始碼包,喜歡自己搞幾個引數優化一下;他們只關心當下的結果,不關心以後的重複利用和持續整合。

這是我以前的工作中遇到的真實情況。

現在情況變了,自從Dev和Ops弄在一起變成DevOps後,又出現了幾個自動化工具,搞的現在Dev不好好寫程式碼了,Ops也不好好的寫命令列,都去學習自動化工具去了。

這不是DevOps的王道。這是錯誤的。

即便把所有的自動化工具,不管是Ansible還是Puppet或者其他學的再熟,也只是學會了一個工具而已,很可能DevOps沒當成,卻變成工具的奴隸。

DevOps是先有思想,而後有工具。

現在崇尚工具的思路是非常可怕的,很多初學者誤以為學會了這些自動化工具就可以把運維做好,而忽視基本功的學習,空學工具,只重其招,不重其義。

下面分享下兩者的演進。

Ops的演進

案例1:以在RedHat上安裝Nginx為例子,網上很多文章的步驟大概如下:

  • PCRE庫的安裝:wget, tar, configure, make,make install
  • OpenSSL庫的安裝,wget, tar, configure, make,make install
  • nginx安裝,wget, tar, configure, make,make install

這種做法早些年是非常流行的,而且很多人對於在configure後面帶的那些引數很是自得,屢試不爽。

時至今日這種方法仍然在很多初學者那裡非常流行,而這種做法就是嚴重的反DevOps的做法。

案例2:以給Nginx增加一個虛擬站點www.devops.org為例,很多初學者一上來就開啟nginx.conf開始改,這同樣是嚴重反DevOps的。

這可能是因為一來nginx官方文件是這麼改的,二來很多文章也是這麼轉載,或者原創這麼寫的。

案例3:再以網路效能優化的為例,很多Ops同學直接衝到/etc/sysctl.conf這裡面瘋狂的修改一通,添加了各種引數。

這仍然是反DevOps的。一來過不久以後也不知道哪些是自己改的,哪些的預設的,二來如果想用指令碼批量更新也是大問題。

針對上面提到的,我認為DevOps應該是這麼做的:

對於案例1:首先根據自己的系統設定好nginx的源,而設定源的方法也不是直接衝到/etc/yum.conf,而是建立一個/etc/yum.repos.d/nginx.repo檔案,用於儲存nginx的源資訊。然後然後通過yum install nginx 安裝。(如果一定非得必須特定版本,稍後討論)。

對於案例2:給Nginx新增一個虛擬站點。RPM包的結構如下

儘管這個結構不是很令人滿意,但是仍然可以將就。

至少我們可以看出Redhat的潛在建議是讓我們把新的站點放在conf.d下面,我建議的命名是www.devops.org.conf。

那麼問題來了,如果我要暫時關閉這個站點怎麼辦呢?在這個結構下,我們只要把www.devops.org.conf從conf.d裡移出來再reload一下就可以了……對,是移出來,不是刪除。因為我們後面可能還要用。

此時www.devops.org.conf放在nginx目錄下,顯得有點格格不入,那麼我們乾脆建一個資料夾叫disabled-sites,把www.devops.org.conf放在disabled-sites下面得了,以後要是再啟用該站點,就直接符號連線到conf.d下面。

再演進一步我們就有了如下的結構:

把站點放在sites-*裡。available裡放置所有站點的配置檔案,通過符號連線到enabled目錄下啟用。

如果要臨時關閉站點,可以刪除enabled下的符號連線。這個結構就非常適合DevOps用指令碼進行管理。

對於案例3:關於sysctl的修改,DevOps方法是在/etc/sysctl.d下面,按照命名規則新增一個檔案,把需要新增的引數放到新檔案即可。

這樣一來可以方便檢視自己修改了哪些,便於確認,二來可以持續整合,通過檔案的形式保留自己思考的路徑。

通過上面3個事例的演進,我們已經清晰的感覺到,上面三個步驟現在可以馬上用指令碼自動化起來。但是演進之前確實很難辦到。

如果沒有Ops的演進,再牛X的Dev他也無法完成自動批量管理以上的業務需求。

Dev的演進

我作為Dev的時間要比作為Ops的時間長很多。8年前從Windows轉到Unix-like下,我們看下兩個不同系統下,Dev的思路的差別。

寫過Windows程式的人都有一個非常堅定的信念就是API,Windows系統下事無鉅細都會有對應的API,尤為著名的是登錄檔的API,還有一個典型的是服務API(Windows Services)。

你要改個啥配置,要建立一個Service都必須得用API來完成。複雜點的比如寫一個埠掃描的要用到socket和多執行緒的API等等。這個埠掃描說來業務邏輯本身很簡單,倒是程式邏輯搞的複雜的不得了。

而Unix-like的系統,沿襲著Unix的哲學其Dev的思路又是另外一套。修改配置,直接衝到檔案裡改,建立一個daemon/service直接寫個shell指令碼放到系統即可,完全不必要API。

所有的一切無論是在Dev還是Ops面前都是一目瞭然。前面提到的埠掃描更是直接用python/ruby/shell 直接呼叫nmap搞定,效率高,功能強大,穩定性和相容性都不錯。

我認為這是Dev要借鑑的,也是思想上最大的差別。

統統用API做出來的東西,一是容易讓Ops一頭霧水,搞不清楚,很難參與,二是有些功能實現起來要達到足夠的效能,強大,穩定以及良好的相容性是非常困難的。

nmap第一版本是1997.9釋出的,歷經18個年頭,這樣的工具我們一朝一夕是難以實現的。

關於Dev轉DevOps的建議

鑑於以上的討論,我給Dev即將轉到DevOps的同學們的建議是:

  1. 試做一個有經驗的Ops,放下程式語言,從命令列開始,從Shell開始;
  2. 理解作業系統的哲學,Unix-like下管道連線一切命令,檔案代表一切配置;
  3. 理解Ops的核心指標,比如高可用,相容穩定,可重入,故障容災;
  4. 在堅持Ops-style的前提下,通過程式設計思想將DevOps的程式碼指令碼的產出層次化,模組化,使之達到高複用;

Dev和Ops的另外一個區別是,以往Dev注重的是具體功能開發,而Ops天生要關注的是系統的整體管理。

功能開發注重邏輯的正確,1+1=2;但是Ops要求業務和結果導向,有時1+1可能是無窮大,比如磁碟滿了。

補充1:程式語言和Shell在DevOps的關係

從自動化部署工具來看他們的關係,Python/Ruby通過業務邏輯把產生出相關檔案和Shell語句通過下面兩種方式執行:

  1. 基於ssh;
  2. 基於Agent(姑且認為是RPC的一種方式)。

因此Python/Ruby作用是:編排和啟動Shell語句的作用;具體實現功能,則仍是Shell語句。

根據這種關係,我們不難發現以上兩種方式存在現實的侷限性:

  1. 眾多命令執行情況下,ssh效率不高;
  2. Agent效率雖然高,但是開發和除錯成本很高,另外Agent對於Ops是透明、不可控的,一線Ops在Agent出了問題後,很難介入除錯。

我的建議是在shell做文章,即基於shell指令碼的機制完成遠端業務邏輯的工作,通過ssh或者agent呼叫指令碼執行功能,這樣提高了效率又便於Ops參與指令碼的編寫和除錯。

結論:DevOps的落點是Ops,Python/Ruby的落點是shell和commands。

Python/Ruby的優勢是業務邏輯,檔案處理等,莫用Python/Ruby去實現shell和commands擅長的。

補充2:程式語言在DevOps的意義

Python/Ruby體現的重要性是程式設計的思想,shell和commands的重要性在於,系統最終由他們改變。

以前是Ops玩shell和commands,現在是DevOps通過Python/Ruby玩shell和commands,所以本質還是shell和commands。

就像網際網路和傳統行業一樣,有網際網路傳統行業轉的更好,但是沒有網際網路傳統行業一樣轉;而如果沒有傳統行業,估計飯都吃不上,網際網路也就不存在了。

補充3:作業系統能力模型

根據前面的結論,我認為DevOps的核心競爭是在Shell和Commands的競爭。而作業系統能力的提升也將是Shell和commands的提升。

試想如果沒有yum/apt,沒有sed,沒有iptables,沒有virsh這樣的指令,我們是否寸步難行?答案當然是肯定的。

有人說,可以通過c/python/ruby實現,反正都有api,這是錯誤的輪子思路。

我可以肯定的說,我們幾乎沒有能力超越先賢們歷經數十年累積的成果。即便可以我們做出來類似的東西,也很難超越這些既有的工具,這些工具優秀之處除了智慧,還有時間以及實踐的檢驗。

但是有一件事我們是可以做的,就是把作業系統業務能力提升起來。我認為的作業系統能力模型裡,唯缺此一項。

我們不需要再寫一個iptables,sed,yum/apt,我們可以包裝他們,通過命令的組合和邏輯的判斷,衍生出專用的業務能力。

RedHat下有不少好的例子,比如service iptables save的功能。此功能的意義如下:

  1. 提供了統一的呼叫方式,並且封裝業務邏輯,便於其他指令碼使用;
  2. 統一的檔案存放位置,便於自動載入,管理和備份;
  3. 同時提供了restore的命令。

這就是一種作業系統的能力。這種能力在Linux的一些分支上是沒有的,我們就必須自己編寫指令碼實現此功能。但是寫來寫去,寫得最好也就是跟RedHat大同小異,但是卻花了我們的寶貴的時間。

試想在擁有這種能力的RedHat上面,DevOps開發一個批量儲存iptables的功能是否更容易呢?

練手:

  1. 是否可以基於iptables實現一個命令,在新增一條iptables規則時,先檢測是否存在同樣的規則,避免重複?
  2. 是否可以基於sed實現兩個命令,delete_line和delete_line_by_no:第一個命令給定一個表示式和一個檔名刪除含有表示式的行;第二個命令根據行號刪除指定檔案行?
  3. 實現一個命令,安裝memcached,根據傳入的引數設定監聽地址,記憶體大小和監聽埠等。