這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
【編者的話】本次分享包括以下4方面:
- SAP Anywhere產品特性及Team Dev簡介——CD需要解決的問題是什麼
- Jenkins、Docker、Kubernetes——CD基礎組件的組成
- Jenkins Pipeline、自動化測試、自動化部署——CD的實現
- 排錯、診斷、監控、分析——CD的後勤保障
SAP Anywhere產品特性及Team Dev簡介——CD需要解決的問題是什麼
大家好,我是來自SAP中國研究院SME部門的系統架構師,目前從事SAP Anywhere產品的CI/CD工作。今天的分享主題是SAP Anywhere產品背後CD的實現。我們在這方面還剛起步,分享內容頗有疏漏,還請見諒。
首先,請允許我使用隻言片語介紹一下SAP Anywhere的產品特性,以及CD需要解決什麼樣的問題。我們的產品SAP Anywhere是一套基於Cloud的ERP SaaS解決方案,產品UI是純HTML5實現的WebUI以及Hybrid模式的MobileUI,後端由接近三十個微服務組成,通過API-Gateway向外統一暴露。
由於大公司的原因,我們的Team Dev分散在世界各地,總共有超過200人提交代碼,平均每天提交300多次。CI要解決的問題是提供一個穩定高效的平台使每一位開發人員的每一次提交可以得到即時的構件,進而阻擋那些“有害”提交。當代碼通過CI自動構件及測試後,會被合并到主分支,下一步是自動化搭建一個DEMO系統以供開發及測試人員進一步測試。
而搭建DEMO系統的痛點在於微服務化的架構 – 部署一個巨石服務(Monolithic)相比部署一堆分布式“微服務”是要簡單很多的。事實上,當引入服務之間的依賴關係和服務發現之後,會把問題更加複雜化。
為瞭解決這些問題,我們引入了Jenkins Pipeline, Kubernetes等一系列組建來協助我們搭建CD系統。
Jenkins、Docker、Kubernetes——CD基礎組件的組成
再來介紹一下組成CD的基礎組件。我們搭建了多套Kubernetes叢集,分別用於跑Jenkins,跑CI的slow-test,以及部署DEMO環境。所以我們的基礎組建是Docker, Jenkins和Kubernetes。除了Jenkins叢集使用的是物理機,其他機器全部是vSphere的虛擬機器。此外,我們也在AWS上搭建了叢集。
使用物理機是為了得到更好的IO效能(從而加速構件過程),而使用虛擬機器是為了得到更方便的管理能力。這裡是一處典型的需要平衡考慮的地方。
作業系統方面我們選擇了CoreOS及少量的Ubuntu用做build machine。網路方案是常用的flannel overlay network,backend是vxlan。
Kubernetes Admission Controller使用了推薦的ServiceAccount, LimitRanger及NamespaceLifecycle。Addon選擇了dashboard, heapster, grafana monitoring以及skydns。
事實上,我們強制要求每個微服務必須至少使用HTTP協議提供REST API,且其連接埠必須是80,這樣我們可以讓服務之間相互發現變得簡單及統一 – 使用skydns作為服務發現!(比如擷取所有未開發票可以調用http://invoice:80/api/v1/Invoices?status=open,按地區查詢客戶資訊則調用http://customer:80/api/v1/Customers?location=CN,當然,連接埠號碼80可以省略)
與ZooKeeper解決方案不同的是,我們並沒有使用服務註冊機制來實現服務發現,算不上是創新,只是另一種思路而已。
Jenkins Pipeline,自動化測試、自動化部署——CD的實現
跑題了,我們繼續講CD。為了使得每一位開發人員的每一次提交能快速準確的通過CI構件及自動化測試,我們在Jenkins 2.0 Pipeline外掛程式的基礎上,構件了我們自己的CD Pipeline,用於驗證我們的每一次提交。
,每一橫條代表一次代碼提交的完整過程。核心步驟是Build & Fast Test及Slow-Test。前者負責構件及單元測試(通常是mvn install、gradle build、gulp build),後者負責搭建一個“半完整”環境執行“整合測試”。任何一步失敗會導致當前這次提交被拒絕。我們為60多個git repo分別搭建了對應的CD Pipeline,是其中一個微服務,名字叫Productivity。
CD Pipeline的最後一步post-build裡面,我們會觸發一次基於當前提交的DEMO系統搭建。通常10分鐘左右就可以部署出一套完整的DEMO系統交付給開發測試人員了。通過這種方式,可以大幅度縮短我們的開發迭代周期。
排錯、診斷、監控、分析——CD的後勤保障
任何系統都少不了監控,尤其是分布式系統。為了協助開發人員在DEMO系統中快速定位問題,我們使用了ELK系統來回收並展現微服務日誌。與此同時,我們把大量的記錄檔扔進HADOOP系統做大資料分析以進而最佳化產品本身。
我們還使用Kubernetes原生的health check機制來監控服務健康情況,這意味著每個微服務必須要提供一個HTTP REST API,如/health,以告知其健康情況。當/health返回非200狀態代碼時,服務會被殺掉並重啟。
通常,一套30個節點的叢集可以跑20套DEMO系統,我們使用Kubernetes Namespace隔離每個系統。前面有提到LimitRanger,我們為每個Namespace分配一個預設的resource limits,比如執行每個Container至少需要64M記憶體及0.2個邏輯CPU,而每個container最多隻能消費1G記憶體及1個邏輯CPU。自從使用LimitRanger以來,我們的叢集穩定性大為提升。
經過長期的營運觀察,我們發現節點上的Docker Daemon會時不時死亡。其表現為不能建立銷毀Container,不能docker ps。為了緩解這個問題,我們使用Kubernetes DaemonSet開發了watchdog跑在每個節點上,但凡遇到Daemon死亡就暴力重啟節點。
Q&A
Q1:我想瞭解下你們開發的DaemonSet可不可以用Supervisor這樣的去替代,如果可以需要注意些什麼,之前監控Web遇到過Web服務200,實際Web服務已經掛起的情況,如何監控類似事件?
A:DaemonSet是Kubernetes的一種功能,用來把POD調度到所有滿足條件的節點上。我們的使用情境是把看家狗程式調度到每一個叢集裡的節點,以起到監控作用。
Q:你們主要跑的什麼類型的應用?
A:我們的業務是基於WEB-UI的ERP產品。
Q:請問Kubernetes使用health check http請求的時候有沒有遇到容器可能本身需要好久才能啟動完畢那麼這個人機制就會一直死迴圈…請問這個有沒有好的方式解決?
A:Kubernetes health check分成readinessProbe和livenessProbe。前者決定容器是否ready,後者當檢查失敗後直接暴力殺死容器。某些容器啟動較慢,所以需要設定一個等待時間。我們的容器等待時間是readiness->15s, liveness->2min。
Q:後來,我們按功能把原先的一個叢集拆分成了多個,分別營運,如此一來,穩定性大為提升,這個怎麼拆的呢?
A:根據功能拆。比如一個叢集專門跑Jenkins,另一個叢集專門跑slow-test。BTW、slow-test是用來進一步驗證當前提交是否存在bug的一種測試,由於跑的時間比較長,所以叫slow-test。
Q:Kubernetes API server經常宕機?到規模上限了?API server可以起多個做負載平衡吧,API server宕機的時候Scheduler和controller-manager到瓶頸了嗎?
A:早期的宕機可能是我們自己使用不當,比如把API server交給每一個開發人員(我們有200多人),然後大家都去玩kubectl各種命令,裡面有幾個命令比較吃資源,一種是port-forward,另一種是watch kubectl get pod。
Q:對於應用的配置你們如何管理?
A:這是個好問題。我們內部討論的比較激烈。目前有兩種極端,一類人傾向於每個服務自己管理配置;另一類人傾向提供一個專門的配置微服務。各有利弊吧。
Q:一個DEMO系統是否包括依賴的服務?如果依賴,那假如DEMO系統中多個服務需要發布,要每個都起一套DEMO系統嗎?
A:前文提到我們有接近30個微服務,是的,每一套DEMO系統都包含那麼多微服務,所以做一套DEMO系統挺“重”的。當然我們在搭建DEMO系統時,主要還是利用了Kubernetes的調度能力來平行處理任務的。
Q:Web UI應用有沒有涉及到負載平衡可以介紹一下的?
A:我們使用Nginx作為反向 Proxy,Kubernetes的deployment/rs作為負載平衡。nginx upstrea/server編寫服務的內部網域名稱,被SkyDNS解析成cluster IP,再被IP tables做round robin路由到真實pod。
Q:『根據功能拆。比如一個叢集專門跑Jenkins,另一個叢集專門跑slow-test。BTW,slow-test是用來進一步驗證當前提交是否存在bug的一種測試,由於跑的時間比較長,所以叫slow-test』,你們原來是混在一個叢集裡的啊?
A:是的,早期我們是跑在一個叢集裡的。那時候我們膜拜Kubernetes,認為Google大師級的產品一定能很好的利用異構系統組成叢集,並且良好的管理裡面的應用的。事實比較令人遺憾,當然不排除我們自己代碼的問題,總之跑在一起比較不穩定,而且遇到故障時比較難恢複(因為影響面比較大)。
Q:您好,我想瞭解下你們開發的DaemonSet可不可以用Supervisor這樣的去替代,如果可以需要注意些什麼,之前監控Web遇到過Web服務200,實際Web服務已經掛起的情況,如何監控類似事件?
A:補充一下第一個問題的回覆:監控web服務,這個需要服務自己暴露(實現)一個特殊的API,通常可以是 /heath,然後服務自己在API裡面完成健康掃描。那麼k8s就知道服務是否處於殭屍狀態了。
Q:你們的Kubernetes API有沒開啟HTTPS?如果開啟是否有在Pod訪問API的案例介紹一下?
A:事實上,我們開啟了HTTPS,但是在大部分情況下,我們仍然使用HTTP連接埠串連API server。我們下一個目標就是全面啟用授信的安全模式。至於Pod訪問API server只要有service token即可。
Q:你好,把Jenkins和Slow Tests拆分叢集是按命名空間分了,還是再單獨部署了另外一套Kubernetes?
A:我說的拆分是指物理上的拆分,變成兩個Kubernetes叢集了。這方面我們仍然在摸索,到底是多個小叢集容易管理還是一個大叢集容易管理。
Q:有考慮過使用Docker官方的Swarm嗎?新手,不知道該選擇哪個。
A:Kubernetes和Docker Swarm天生就是兩種教派,有點“正邪不兩立”的味道。事實上,我們早期做原型的時候有考慮過Mesosphere。個人觀點:從目前的發展來看Kubernetes和Swarm很難走到一起去,這意味著選擇其中之一必然會放棄另一個。而Kubernetes是Google主推的,考慮到Google內部Borg系統是Kubernetes的原型,每天跑著百萬級的應用,應該不會有錯的。
以上內容根據2016年7月28日晚群分享內容整理。分享人
陳贇喆(Miles Chen),資深開發工程師、全棧工程師、系統架構師。從業十年有餘,目前就職SAP中國研究院,擔任架構師一職,負責SAP Anywhere產品的CI/CD工作。 DockOne每周都會組織定向的技術分享,歡迎感興趣的同學加:liyingjiesz,進群參與,您有想聽的話題或者想分享的話題都可以給我們留言。