觸控DevOps,從現在開始DevOps之旅

edithfang發表於2014-06-05

伴隨著網際網路時代的真正到來和雲端計算市場的興起,DevOps這個詞越來越多的進入了我們的視野。我們可以認為DevOps是一組方法論的統稱,它擴大了開發和運維的外延,促進開發、運維、質量保障、運營等各部門的協調與整合,它定義了簡明、自動化的流程,使我們可以承擔更快的變更、更小的風險,可以使開發人員更多的控制生產環境,讓我們更多的以基礎設施為中心來理解應用,同時也讓我們更多的以應用為主心來理解基礎設施。可以說,DevOps就是不斷優化的生產過程。可是在微觀層面,大家對DevOps的理解又不盡相同,也有人可能會對這個名詞望而生畏,覺得它有些不可接近。其實DevOps既不高深也不復雜,它只是由一些簡單的概念和工具鏈構成的工作流程,我們可以暫時忘掉那些教科書式的理論,開始一次務實又輕鬆的DevOps之旅。 從現在開始,su root,你就是掌控一切的上帝,讓我們看看你是如何從一點一滴做起,為你的小夥伴們準備一套DevOps體系的。

-- 開始吧!

創世之初,你得建造一個跳板機

一個好的跳板機可以作為DevOps體系的總入口,它為每個人提供運維的個人帳號,並負責精細化的運維許可權管理。它提供DevOps工具鏈的執行環境,還可以記錄、審計所有人的操作歷史。

跳板機對許可權管理的思路是:跳板機的root帳號擁有最高的運維許可權,它獲得了所有伺服器的各種授權,包括ssh authorized_keys授權,管理埠訪問授權,拷貝、部署授權,命令操作授權等,每一臺伺服器都無條件信任跳板機的root帳號。而你的每個小夥伴都在跳板機上擁有一個屬於他自己的普通帳號,該帳號可以執行所有的DevOps工具,每個DevOps工具都是執行在root許可權下,它根據自己具體的許可權配置來決定是否允許某人執行某個命令。

舉一個具體的例子,跳板機最基本的功能就是登陸其它伺服器,假如這個登陸的命令叫qssh,它需要提供qssh some_server這樣的功能,我們如何實現呢?

qssh是一個C語言編寫的可執行檔案,這個可執行檔案用於提權,它的核心虛擬碼是

uid = getuid(); // 得到當前使用者
setuid(0); // 提升為root使用者
exec(“_ssh”, [uid, args...]); //執行_ssh外部程式,並將原始使用者名稱傳遞給_ssh程式。

當然,這個qssh的執行檔案需要賦予suid許可權:chmod a+s

經過了qssh的提權動作,_ssh就是執行在root下的了,_ssh比較靈活,可以用任何語言編寫,比如bash,值得注意的是_ssh程式需要做使用者的授權控制,通常它會有一個如下形式的配置檔案:

Tom  web_server1 web_server2   # Tom有兩臺web伺服器的登陸許可權
Bob  db_server1                # Bob有一臺資料庫伺服器的登陸許可權
Jo   web_server*               # Jo有所有web伺服器的登陸許可權

上面可以看到,_ssh被fork的時候,第一個引數便是使用者名稱,_ssh內部使用傳入的使用者名稱查詢許可權配置表,以決定是否繼續執行。

_ssh中還需要做一件重要的工作,就是以root身份記下所有人的操作歷史,這份記錄要保證是普通使用者無法修改的。記錄的形式大概為:

Thu Oct 10 02:51:38 CST 2013 -- 188.60.175.3 -- Tom -- login  -- web_service1 
Thu Oct 10 02:59:01 CST 2013 -- 188.60.175.3 -- Tom -- logout -- web_service1

我們後面會看到,DevOps體系會提供很多命令,它們都執行在跳板機上。我們以qssh為例說明跳板機上程式的工作原理,這個原理對其它的命令基本是一樣的。

有了跳板機為基礎,我們有了工具執行的環境,有了精細化許可權管理的能力,下面就可以放開手腳大幹一場,補充各種DevOps的工具,讓大家的工作更方便了。

部署,讓所有人頭疼?

部署,是DevOps中最重要的一個環節,弄好了跳板機,我們開始去構建一個安全、方便的部署系統吧。好訊息是你同樣不需要做太多的開發工作,我們的部署系統是基於puppet的。

首先,我們需要把部署的資訊用版本控制工具管理起來,這裡推薦git。來看看我們的deploy.git是什麼樣子的

deploy.git/nodes/
    web_server1/
        puppet/memcached.p
        root/home/app/memcached/memcached.conf
    db_server1/
上面的例子展示了deploy.git大致的目錄結構,nodes下是代表每臺伺服器的子目錄,每臺伺服器的目錄下有兩個最核心的目錄,分別是puppet和root,puppet下放置puppet的配置檔案,root目錄下的所有子目錄與伺服器上的/一樣,root目錄下放置需要部署到伺服器上的所有檔案。對於上面的例子,我們在web_server1上部署了一套memcached服務,現在看看memcached.p是什麼樣子的:
qbin {"/home/app/memcached":
    packagepath => "op/baseline/memcached-1.4.15-linux-x86_64.tar.gz",
}

qfile {"/home/app/memcached/memcached.conf":
    owner => "app",
}

在這個檔案中,qbin和qfile是我們寫的puppet擴充套件類,他們的實現方式很簡單,這裡就不贅述了。我們用qbin部署memcached的二進位制檔案,部署系統將memcached-1.4.15-linux-x86_64.tar.gz解壓縮到伺服器上的/home/app/memcached目錄。我們用qfile放置memcached的配置檔案,部署系統將deploy.git/nodes/web_server1/root/home/app/memcached/memcached.conf這個檔案部署到伺服器上的對應位置:/home/app/memcached/memcached.conf。

準備好的部署的配置,我們可以開始部署了,方式很簡單,在跳板機上執行下面的命令便可: deploy web_server1

這個命令會做以下幾件事件:

  1. 將deploy.git切到上一次成功部署web_server1的版本。
  2. 檢查伺服器上的狀態是否與該版本的deploy.git一致,如果不一致,則報告衝突,並中止執行。這一步主要是防止伺服器上的檔案被繞過部署系統直接修改。
  3. 衝突檢查通過後,該命令將deploy.git切換到master,將最新的內容部署到伺服器上。

deploy命令支援如下的引數:

-t 不實際部署,只列印將要部署的內容
-f 跳過沖突檢查的步驟
-i 互動模式,進行每一步前詢問使用者
瞭解了工具,我們看看流程,基於上述部署工具鏈的流程大致是:
  1. fork deploy.git
  2. 做自己希望的變更
  3. 提交pull request,請求合併到master
  4. pull requset經過管理者review後,被合併
  5. 由pull request發起者登陸到跳板機上進行實際部署動作
由於有了pull request和code review流程,所以deploy的許可權可以很開放,基本每個運維和開發人員都可以有。設想一下,一個第一天入職的運維或開發就可以放心地線上上升級服務,或部署新服務,是多麼美妙的事情!通過使用一些簡單的工具鏈,並建立適當的流程,部署再也不是一件讓人頭疼的事情了。

指令編排,解放大家的手指

部署系統本質上是對伺服器狀態的維持,除此之外,我們還需要對伺服器進行一些操作,比如重啟某個服務、重新載入某個配置、檢視伺服器的狀態等,這就需要指令編排系統。指令編排系統提供了一系列預設好的指令,和與之配套的許可權控制,這些指令可以由操作員來呼叫,並作用於伺服器。我們基於salt來構建指令系統,先看看指令系統是如何使用的吧:

do web_server1 nginx.op.reload # 重新載入web_server1的nginx配置
do web_server* nginx.op.reload # 重新載入所有web_server的nginx配置
do db_server1 system.view.ps # 檢視db_server1的程式列表
do db_server* mysql.view.logs 1h # 檢視最近1小時的所有db_server上的mysql日誌
它的許可權控制大致是如下形式:
Tom *:system.view web_server*:nginx.op # Tom有所有機器的系統檢視許可權,有所有web_server的nginx操作許可權
Bob *:* # Bob有所有許可權(超級管理員)
Jo web_server1:nginx.view.logs # Jo只有web_server1這臺伺服器的nginx日誌檢視許可權

do命令只需要很少的編碼工作,它基本上是直接轉調salt命令,salt維護了所有伺服器到跳板機之間的長連線,所以指令的執行是非常快的。

如果你需要的命令系統沒有提供怎麼辦?其實所有預設的指令都是在一個程式碼庫裡,你隨時可以提交自己的命令,salt會自動把指令碼部署到每臺伺服器,非常方便。

善待你的日誌

日誌的處理是DevOps中另一個比較大的話題,好的日誌處理方式可以讓大家方便的檢視、分析日誌,可以支援各種分析系統以準實時的方式分析日誌,並輸出我們想要的任何結果。讓我們來看看如何使用開源的工具鏈構建一套強大的日誌處理系統。

一個系統的日誌通常有多個部分組成,比如程式的日誌,用於審計的事務日誌,第三方程式(比如nginx、mongodb、memcached等)的日誌,甚至還可能包括第三方合作伙伴(比如支付寶、CDN等)的日誌,這些日誌分散在很多的地理位置、很多的伺服器、很多的磁碟目錄或其它介質中,我們第一個需求是把這些日誌收集、彙總,並按照合理的形式存放,方便大家隨時檢視,也方便後續的程式進行分析。我們使用logstash來實現這個需求。

logstash是一個日誌管理工具,它可以用來收集,分析,儲存日誌。logstash採用外掛機制,它的所有功能都以外掛的形式提供,它的外掛分為三種:輸入、過濾、輸出。輸入外掛常用的有file、tcp、log4j、redis等,過慮外掛常用的有grep、json、ruby等,輸出外掛常用的有file、tcp、redis、stdout等,更多的外掛可以到它的官網上http://logstash.net/ 查詢,我們也可以使用ruby語言方便的擴充套件它的外掛。

假設我們有兩臺伺服器產生日誌,我們使用logstash的input:file外掛在伺服器本地收集日誌,並通過output:tcp發往日誌彙集伺服器,在日誌彙集伺服器上,使用input:tcp來收集網路上發過來的日誌,並用output:file將日誌存放在本地。這樣,我們就實現了多處日誌的傳輸、彙總。

通過上面的例子看到,用logstash實現最簡單的日誌彙集的需求是非常容易的。除了日誌彙集,還有日誌全文搜尋有需求,這裡我們使用redis 、elasticsearch、kibana三個工具配合來實現。上面提到在日誌彙集伺服器上我們使用input:tcp來收集日誌,使用output:file將日誌組織在本地磁碟上,現在我們再配置logstash把日誌儲存在本地之外,再使用output:redis外掛將日誌傳送到redis中一份,然後啟動一個新的logstash例項,使用input:redis外掛從上面的redis中讀取,使用output:elasticsearch輸出到elasticsearch中建立索引,最後,我們使用kibana執行一個圖形化的搜尋介面,供大家使用。整個架構不需要寫一行程式碼。

配圖:日誌搜尋介面

提到日誌的處理,就必須要提opentsdb。opentsdb是一個時間序列的分散式資料庫,是日誌分析的神器。我們用它存放分析日誌後得到的資料點。從上面描述的架構中,我們看到最終收集到的日誌輸出了兩份,一份是本地磁碟,一份是redis,進而輸入到索引系統。現在我們再引入一個redis,作為日誌分析系統的待處理佇列,將日誌匯入這個佇列中,再由opentsdb的處理程式從這個佇列中讀取。日誌灌入redis的過程與上面一樣,不再贅述。在將日誌輸入到redis後,我們啟動一個新的logstash例項,這個例項的input是從redis讀取,並用output:exec外掛來執行自己的分析指令碼,分析指令碼的輸入是標準輸入中的一行一行的原始日誌,指令碼對日誌分析後,將結果存入opentsdb。logstash支援多個output並聯,所以我們可以配置很多分析指令碼,用於分析各種我們關心的數值,比如效能、可用率、命中率、流量等。資料匯入opentsdb後,我們可以用它來繪圖、告警等。

配圖:opentsdb繪圖

保證質量!

質量永遠是我們的終極訴求。


沒有對質量的保證,一切都是空談,DveOps也只是浮華的空中樓閣。幸運的是,DevOps實踐並不是質量的敵人,相反,我們可以把一些簡單有效的保證質量的手段融入DevOps實踐中。

首先,我們需要持續整合和單元測試,這是質量保障最基本的手段。jenkins是非常好用的持續整合工具,也很容易配置,我們用jenkins配置一個定時的編譯任務,每10分鐘pull最新的master程式碼,編譯、執行單元測試、分析單元測試覆蓋率,如果有某項沒有通過或不滿足要求,則立刻發郵件通知到大家,並要求相關的責任人及時處理。

OK,現在對質量有了最基本的保障,可這還遠遠不夠。下面我們來構建整合測試系統。主要使用的工具有travis-ci和docker.io,travis-ci是一個雲端的持續整合服務,通常與github.com配合使用,docker.io是一套lxc工具鏈,可以方便得實現系統級資源的隔離,比如記憶體、檔案系統、網路、CPU等,它類似於虛擬機器技術,但比虛擬機器更輕量級,對資源的消耗也更少。

整合測試的流程大概是:當github.com上有新的pull request提交,可以觸發travis-ci啟動構建,travis-ci構建成功後,使用指令碼將構建出的程式發往整合測試伺服器,整合測試伺服器使用docker.io啟動一個獨立的沙箱,按預設的配置將所有服務執行起來。服務執行正常後,整合測試伺服器取得testing.git中的所有整合測試指令碼並逐個執行,最後將成功或失敗的訊息返回給travis-ci,travis-ci會根據整合測試的結果,在pull request上標記'travis-ci passed'或'travis-ci failied'。

有了整合測試流程,當我們看到一個pull request時,就可以很方便的知道這個功能或bugfix的整合測試有沒有通過,大大降低了code review的壓力,既加快研發速度,又提升產品質量。

配圖:travis-ci與github.com整合


你真的瞭解你的系統嗎?

走完了上面的流程,我們的服務已經順利上線執行啦!現在還有最後一個問題,你真的瞭解你係統的執行狀態嗎?---- 系統有沒有出故障?網站的速度如何?可用性怎麼樣?哪些地區的訪問還需要優化?某個業務的轉化率是高是低?使用者流失最多的是哪個功能或頁面?是什麼原因?

在一個公司中,需要有人回答上面的問題,我們認為這是DevOps的職責所在。那麼,去了解一個線上的系統,有哪些手段呢?

線上監控是監控系統中最重要的一環,它提供最實時的系統執行狀態的資訊,通常資訊反饋的速度是按秒來計算。線上監控最重要的功能是告警,當系統的某些指標不符合預期,或基礎設施出現故障,線上監控系統都應該立刻告警,告警的方式通常是郵件和簡訊。構建線上監控系統,我推薦使用zabbix,原是是:

  1. 軟體成熟度較高,社群活躍,使用也比較廣泛
  2. 內建多IDC方案,非常適合多IDC場景使用,擴充套件方便
  3. 介面友好,上手容易
  4. 內建的監控專案和模板很多,基礎設施的監控基本不需要自己處理
  5. 擴充套件自己監控指令碼很方便
  6. 告警條件非常豐富
  7. 除告警外,資料包表,數值曲線等功能也很強大

使用zabbix來構建基本的線上監控系統十分方便和簡單,這裡不再展開討論,官方文件 zabbix.com 可以解答幾乎所有疑問。

第三方線上監控

從事故的預警來看,線上監控可以覆蓋大部分的故障,但有一些IDC一級的網路問題內部監控是無法察覺的,這時我們需要使用一些外部監控來更全面的覆蓋可能發生的故障。第三方的監控我推薦使用監控寶一類的監控服務,這類監控服務可以在全國多個地區發起監控請求,我們只需要將自己的業務邏輯,比如開啟頁面,登陸,上傳,下載等的http請求方式配置好,這類服務就可以模擬真實的使用者發起請求,如果出現機房網路故障或區域性的網路故障,或者請求的返回不符合預期,這類監控服務就會立刻通過郵件和簡訊告警。適當使用第三方的監控服務,成本不高,但可以有效得彌補內部監控的缺陷,值得一試。

第三方測量

除了告警外,監控系統還應該關注最終的使用者體驗,這也是監控系統中最難測量的一塊。幸運的是現在出現了一些第三方的測量服務,比如基調、博銳等,這類測量服務在全國擁有大量的真實客戶端,可以支援從這些客戶端發起預設的請求,使用最真實的方式還原終端使用者的訪問,收集效能、可能性等指標。我推薦大家使用這類服務,把自己最核心的業務流程監控起來,通常這類服務都有自己的資料展示和報表頁面,也支援傳送日報、週報和月報。當時,如果你對它的報表不滿意,或者有自己特殊的報表需求,也可以通過api將最原始的監測資料匯出,自己進行分析和展示。

嗯,差不多了,還有什麼?

我們花了一點時間,聊了幾個DevOps的話題,這幾個話題串起來,基本構成了DevOps的流程。我們也看到了DevOps並不複雜,使用一些常見的工具就可以方便地構建自己的DevOps架構,我鼓勵大家從現在開始就動手嘗試,邊完善邊推動,邊推邊使用,邊使用邊完善,在生產中摸索適用於自己公司的DevOps實踐。

運維二字承載了太多的內容,DevOps極大的豐富了運維的外延,但我認為運維的內涵始終沒有變過,流程固然重要,但也不能忘記本質。所以說DevOps並不是運維的全部內容,我也想請各位從事運維工作的朋友時刻謹記這點,抓住運維工作的核心,輔以不斷優化的生產過程,定是如虎添翼,成為業務和產品的強有力的守護神。

本文轉載自:https://gist.github.com/hantuo/99a97b60f1c0472b149b

評論(2)

相關文章