1. 程式人生 > >從持續整合到彈性縮擴容:一個容器案例落地問題的思考

從持續整合到彈性縮擴容:一個容器案例落地問題的思考

容器是這兩年最熱的一個話題,去年大家都在談 Mesos、Kubernetes、Swarm,究竟哪家的挖掘技術強,今年容器技術的進一步普及,更多的人更關心容器技術如何落地,下面我們就基於一個實際的案例來聊一下容器落地遇到的問題。

背景:某銀行資料中心計劃搭建一個基於容器的PaaS平臺

  持續整合

持續整合是容器一個繞不過去的話題,無論哪家容器廠商都一定會談到,數人云關於持續整合,最開始用的是drone,一個小眾的持續整合工具,將drone內建在平臺上,通過平臺的持續整合功能可以方便的實現持續整合的配置和管理。

drone 的坑

一開始我們覺得這是一個很好的工具,但是後來發現其實沒有想象中的那麼美好,它的問題:

  • 對SVN的支援不好
  • 容易出問題,因為數人云平臺所有的元件都是容器化的,所以若使用drone,則需要使用docker-in-docker技術,但是該技術已經是一個不再被維護的技術了,所以繼續使用的風險很大。

Jenkins是個好工具

Jenkins是一個好工具,功能強大且穩定,基於Jenkins實現的持續整合基本沒有花費什麼開發的時間,通過指令碼將程式碼構建和平臺連線在一起即可輕鬆實現CI/CD。

總結
往往使用者需要的並不是那些看起來很酷的功能,真正需要的是能夠實際解決問題的方案,即使這個方案很普通。

  配置管理

在我看來,容器是一個革命性的產物,改變了軟體交付的方式,它開箱即用的特性消滅了程式設計師常說的一句話 “在我這裡執行時正常的啊!”; 它快速部署,環境無關的特性幫助運維人員提高了工作效率,但是任何事情都有其兩面性,它的開箱即用,環境無關帶來好處的同時,也帶來了問題——配置檔案。

傳統應用在容器時代面臨的第一個問題

一般而言,每個程式都會有一個或多個配置檔案,裡邊記錄著DB地址、賬號、密碼、快取地址等資訊,在容器時代之前,應用程式一般的流轉方式是“從開發->測試->生產”:

  • 開發同學交付一個編譯之後的二進位制檔案,原始檔(解釋執行)或者程式碼倉庫中某一個tag,同時附帶一個release notes;
  • 測試同學拿到開發同學交付的內容後,就將其部署在自己的測試環境中,如果release notes中說明了有配置資訊需要更新或依賴檔案版本需要升級,會依照檔案進行調整;
  • 如果測試通過,確定可以投產,那麼就將其交付給運維同學進行生產部署。

此時有一個問題,開發、測試、運維每個環節都會自己維護配置檔案,如果使用了容器,那麼配置檔案管理就是很麻煩的問題了,因為配置檔案被放到了容器裡,若想修改配置檔案就不是那麼簡單的事情了,所以這就是傳統應用在容器化時面臨的第一個問題,當然這個問題也不是不能解決,一般而言,有以下幾種解決方案:

  • 掛盤,將配置檔案放到外部儲存中,然後將該目錄掛到容器中;
  • 生成新的映象,基於Docker檔案系統的特性,使用測試環境的配置檔案覆蓋開發環境的映象,從而得到測試環境的映象,同理,使用生產環境的配置檔案覆蓋開發環境的配置檔案得到生產環境的映象,使用該方案會導致每個環境都有一個映象。

容器時代配置管理的正確開啟方式

以上分析了傳統應用容器化基本都會遇到的一個問題,而且也沒有給出很好的解決方案,下面我們來談下容器化時代配置管理的正確開啟方式。

其實通過上面問題的描述,我們可以很容易的找到問題的根本原因:配置檔案本身是一個本地儲存狀態,要對其做無狀態改造,對於配置管理的無狀態改造一般是通過配置中心來完成的,即應用通過配置中心獲取配置資訊,無需讀取本地配置檔案,但是這個問題更麻煩,要解決這個問題需要首先解決兩個問題:

  • 要先有個配置中心
  • 要改程式碼,使其可以適配配置中心

隨著容器的普及,未來配置中心肯定會逐漸成為程式的標配。

最終選擇的解決方案

關於容器時代配置檔案的問題,上邊大概提到了3種方案,在最終落地的時候選擇的是哪一種呢?答案是第二種——生成新的映象。這是一個很保守的方案,為什麼沒有選擇另外兩種呢? 我們來解釋下原因:

  • 方案一[掛盤], 這個方案會給容器產生另外一個狀態,外部檔案,不符合cloud 的思想,pass;
  • 方案三[配置中心],成本太高,週期太長,而且需要改程式碼,往往之前的應用已經被維護了很多年,修改其配置介面,風險太大。

總結
雖然這個選擇從技術上來看很保守,但是個人認為,使用一個不太優雅的方案幫助一個新技術快速落地,然後推動其快速前進,比一直糾結於方案是否高大上,是否優雅等,而導致新的技術一直被懸在空中更好,就像大家一直在爭論Mesos、Kubernetes、Swarm究竟哪個更好,現在也沒有一個結論,與其爭論這麼多虛的,不如仔細想一下自己的問題是什麼,究竟哪個技術更適合自己。

  日誌

目前使用ELK作為日誌方案。

傳統應用的坑

一般而言,傳統的應用都是把日誌寫到一個指定的路徑下,然後通過Logstash採集日誌並送入Elasticsearch進行儲存,但是這種應用如果直接容器化之後就會帶來一個問題——應用的日誌檔案應該如何儲存。

  • 方案一:放到容器裡
  • 方案二:掛盤,寫到外部儲存上

兩種方案都有一些問題:

  • 放到容器裡,邏輯上最簡單,不需要做任何改動,但是它的問題是,怎麼從容器中把日誌取出來。
  • 通過掛盤,把容器日誌寫到外部儲存,然後沿用傳統的Logstash + ES 的方式處理日誌,聽起來很美好,但是如何建立容器和日誌的對應關係?

容器時代日誌的正確開啟方式

按照之前的慣例,我們先提出在容器時代,日誌的正確處理方式,如果應用使用Docker進行交付,不建議寫日誌檔案,直接將日誌寫入標準輸出即可,然後Logstash通過Docker的log-driver捕獲日誌,這樣日誌檔案既不需要落盤,也使日誌檔案擺脫了狀態,可以更容易的橫向擴縮。

最終選擇的解決方案

最終我們實現的是方案三,因為使用者在我們的建議下,選擇了將日誌輸出到標準輸出。

新的問題

寫日誌的目的是為了看的,這是一個無比正確的廢話,但是如何實時的看到需要的日誌卻成了我們面臨的一個新問題。在容器時代之前,我們一般是通過tail來實時的看日誌或者通過Kibana來分析日誌。

在容器的時代,通過Kibana看日誌的方式沒什麼變化,但是看實時日誌就有了一些問題,在使用者採取了我們的建議將日誌寫入標準輸出後可以比較優雅的處理日誌了,但是另外一個問題出現了,實時日誌沒有了,因為日誌已經被log-driver收走了,怎麼辦?雖然依然可以從ES中找到日誌,但是由於ELK本身的機制,不能通過ELK看到實時日誌。

新的解決辦法

新的問題,需要新的辦法來解決,如何解決,其實說穿了也簡單,實現了一個log-agent的功能,可以將日誌送到兩個地方,Logstash和實時日誌。

總結

事情就是這樣,我們以為解決了一個問題的時候,往往一個新的問題又擺在前面,像容器落地這種事情,對傳統應用的整體工作方式和流程都有很大的衝擊,所以一定也會遇到同等規模的問題需要解決。

監控

銀行對監控是非常重視的,尤其是運維部門,所以為了滿足客戶的需求,我們實現了:

  • 平臺自身監控
  • 宿主機監控
  • 中介軟體監控

監控本身是我們平臺很重要的一個部分,但是在實際實施過程中發現,客戶其實不是很在意做的監控頁面,儀表盤等監控資料,他們自身有健全的監控平臺,其實我們需要做的事情就是將我們的資料吐到他的平臺上即可。

總結

世事難料,你永遠不知道下一塊巧克力什麼味道,這個我們自身投入了很大精力和時間來實現的功能在使用者那裡就變成了一個對接的任務。

彈性擴縮

彈性擴縮一直是容器廠家喜歡談的一個口號,曾經有一度我們認為基於Docker的特性來實行彈性擴縮是一件很容易的事情,但是後來發現,這裡其實有一個大坑。

擴很容易,縮很難

彈性擴容是一件比較容易的事情,我們只要對接監控資料,然後配置一些規則,即可觸發應用容器個數增加,實現擴容,但是縮容就會面臨幾個問題:

  • 什麼時候縮容?
  • 如何安全的縮容?

什麼時候縮容,這個問題相對來說還不是特別麻煩,可以設定一個指標,比如CPU,記憶體,IO等指標來觸發縮容,這裡只要做一些帶有緩衝的規則,避免由於規則簡單而導致的擴縮抖動即可。

如何安全的縮容相當麻煩,縮容在本質上是要停掉一些容器的,如何判斷這個容器是可以停止的,如果一個容器沒有流量了,那麼應該是可以被停止的,如何讓一個容器的流量停止?可以通過前端負載進行控制,不往這個容器分發流量,那麼前端的負載是如何判斷應該如何往後端分發流量呢?這個有多重因素:

  • 自身演算法
  • 應用程式本身是有狀態的,需要保持會話

從以上簡單的分析中我們可以發現,縮容不是簡單的條件符合了就可以做的事情,要想在不影響業務的情況下實現縮容,是一件非常麻煩的事情,它與平臺架構,執行的程式的業務邏輯有很深的耦合。

總結
要實現自動的擴縮容,不是一件簡單的事情,而是一個系統的工程。

以上內容是基於數人云在某銀行實施過程中總結出來的一些感悟,如果能給大家一些幫助,我們非常高興,如果有問題,請指出來,我們共同提高,Docker到現在大概有3年多的歷史,個人看來它距離真正落地還有很大一段路程要走,我們必須不停的摸索。

Q&A

Q:我想問一下,日誌打兩份的話具體是怎麼實現的呢,用到了哪些技術或現有的工具呢?
A:我們自己實現了一個log-agent, 然後log-agent 可以實現這個功能。

Q:如果應用有自己的寫的日誌,如log4j的,輸出不到標準輸出,還怎麼處理?

A:log4j貌似是可通過配置輸出到標準輸出的,另外如果有些應用不能輸出到標準輸出的,可以配置日誌檔案路徑,我們會去讀檔案。

Q:縮容的產生條件是否有比較好的解決方案,比如根據CPU、記憶體甚至業務規則多維度的進行考察?

A:縮容很容易,但是麻煩的是如何安全的縮容,我理解這個環節其實是跟應用的邏輯有直接關係的,如果應用是一個無狀態的應用,那麼縮容非常簡單,只需要在前端控制流量,然後停止容器即可,但是如果是有狀態的應用,那麼就有可能對使用者造成影響。

Q:配置管理這塊,不斷的覆蓋會增加映象體積,如何最大化減少映象大小呢?

A:首先,一個映象最多被覆蓋2,3次,測試映象一次,生產映象一次,而且配置檔案一般是很小的,幾乎對映象大小沒有影響。

Q:測試環境配置檔案覆蓋開發環境映象,是隻用測試環境的docket file 嗎? 如果每天打版,會很麻煩嗎?

A:通過覆蓋測試檔案來解決環境問題,只是一個思路,不一定非要使用開發測試環境的資訊,這個可以具體情況具體分析。

Q:log-agent具體實現呢,日誌直接打給log-agent還是log-agent讀取本地日誌檔案呢?或者說log-agent讀取標準輸出的內容呢?

A:log-agent可以通過Docker的log-driver獲取標準輸出的日誌,同時也可以直接讀取日誌檔案的日誌。
文章來自微信公眾號:高可用架構