1. 程式人生 > >豬八戒網DevOps容器雲與流水線

豬八戒網DevOps容器雲與流水線

640

Kubernetes已經成為容器叢集管理領域的事實標準,如何將傳統應用遷移到Kubernetes,讓中小企業也能輕鬆實現容器化是大家關注的熱點。 本次將分享豬八戒網是如何實現專案容器化與CI/CD,以及在容器化實踐過程中遇到的問題和解決方案。
專案容器化改造

640

豬八戒網是一家成立有12年的網際網路公司,歷史包袱較多,最初以PHP語言為主,前幾年在微服務化的趨勢下,進行了SOA微服務化的改造,逐漸轉向了以Java和Node.js為主的技術形態,公司從14年開始進行容器的研究與實踐,於16年以Kubernetes為編排平臺,將業務容器運行於生產環境中。
也得益於這些改造,推動了專案容器化的進展。初期Kubernetes對有狀態應用的支援不是很好,想要順利的遷移到Kubernetes平臺,需要完成業務專案的無狀態化,有狀態的資料向外遷移,我們在微服務轉型的過程中,打造了統一的配置中心,CacheCloud叢集,資料庫叢集,訊息佇列等等,將與業務無關的中介軟體獨立出來,做到專案容器可隨時重啟,遷移,伸縮等。
我們也為業務專案打造了統一的標準容器執行環境,為了做到與專案之前在虛擬機器中的執行保持一致,我們基於CentOS系統做了JDK、Jetty、Node.js等基礎映象,這樣可以做到業務專案在虛擬機器到容器平滑遷移,我們在每個專案中內嵌了Dockerfile,Dockerfile可以由開發負責人配置,基於基礎映象,只需要將編譯生成的jar包copy到我們指定的位置即可,基礎映象的啟動指令碼會自動啟動這些專案並內建Supervisor守護程序。如果開發有特殊需求,他們也可以在Dockerfile中新增自己的配置和指令碼,這樣既保持了Dockerfile的簡潔,也允許開發靈活配置,無論開發是否熟悉Dockerfile,都可以做到專案的一鍵編譯構建與自啟動執行。並且統一了映象交付標準,可以做到一次構建,處處執行。
專案在做容器化改造的同時,我們的容器叢集也需要為適配專案而改造。首先,容器化的遷移不是一蹴而就的,必然存在容器與虛擬機器並存執行的的情況,我們業務專案使用的Dubbo+ZooKeeper框架,眾所周知,Dubbo是客戶端服務發現並且直接通過IP地址發起RPC呼叫的,為了做到開發無感知遷移,首先要解決的就是虛擬機器與容器之間的網路通訊問題,在調研了眾多網路方案後,我們選擇了Calico網路方案來解決,Calico是一個純三層的路由轉發方案,幾乎沒有效能損耗,並且可以使用calico routereflector路由反射器來與核心交換機建立bgp連線,進行路由交換,這樣虛擬機器就可以感知容器網段的存在,從而進行路由轉發,也就打通了虛擬機器與容器間的網路互通。示意圖如下:

640


Calico是我們在私有云的解決方案,在公有云上也有同樣的問題,並且大多數公有云都不支援Calico BGP的網路方案,但公有云都對容器叢集VPC網路進行了支援,同樣的原理,VPC網路的實質就是將容器的路由資訊寫入到VRouter中,使外部虛擬機器能夠感知到容器網段的路由,從而實現互相通訊。


打造DevOps流水線

640

解決了專案容器化的問題,公司也組建了DevOps團隊來推進自動化運維,我們開發了DevOps平臺來實現專案的統一管理,CI/CD,灰度釋出以及專案監控等功能。
640
第一代DevOps流水線是基於Jenkins和Shell指令碼來做的CI/CD,示意如下:
  1. git clone project

  2. mvn compile || npm install || composer install

  3. docker build && docker push

  4. sed –i deployment.yaml

  5. kubectl apply –f deployment.yaml

  6. kubectl get pod –o wide


使用檔案來管理deployment模板和使用shell指令碼來控制釋出流程,是很方便靈活的,但這種方式的缺點也很明顯。
小規模的情況下還算可以,但當專案增長到1000個時,如何管理這些專案的deployment模板,並且每個專案的每個環境配置要求是不一樣的,比如:
A專案測試環境需要1c1g1個節點,生產環境就需要2c2g4個節點,測試環境的DNS配置,滾動更新策略等與生產環境均不同,這些專案模板的人工維護成本是很高的,一旦出錯就會帶來嚴重的後果。
並且對於使用者及運維人員來說,他們不會關心deployment檔案,只有Kubernetes才會關心。
我們打造了第二代DevOps流水線,Sahaba-MetaData專案,順便說下,Sahaba是我們團隊的代號,所有的專案都以Sahaba開頭命名,Sahaba來自阿拉伯語,雲的意思。
Sahaba-MetaData專案,使用etcd資料庫作為後端儲存,我們將deployment檔案的資料分成了三部分,對使用者解耦:
  • 使用者資料:如專案名/CPU/記憶體/節點數等使用者可配置的引數

  • 流水線資料:映象名稱/專案域名/健康檢測配置/機房環境等,這些由DevOps流水線在構建時實時生成,然後傳遞過來

  • 容器雲資料(策略模板):滾動更新配置/資源超開策略/DNS/日誌元件配置/deployment基礎資訊等,這些是我們的釋出策略配置,由我們容器團隊來維護,其他使用者不需要關心這些資料


這三部分資料會通過Sahaba-MetaData生成最終的部署檔案,呼叫Kubernetes的api進行專案容器的建立。因為各個語言對json都有良好的支援,所以我們使用json格式來處理,下面是幾張資料模板的截圖:
640 640
在容器化遷移過程中,以儘可能的做到自動化運維管理為目標,這裡借用來自阿里的DevOps八榮八恥:
640


讓你的容器應用更健壯

640

接下來分享一些容器相關的實踐與遇到的坑。
一、使用Resource: request/limit控制容器的資源超開比例,建議一定要為每個專案容器都要配置,不配置容器預設可以使用整個宿主機的資源,從而影響宿主機上其他專案的執行。
Java專案JVM的引數設定,在JDK8U131,JDK9版本以後,新增了一個引數可以自動感知容器記憶體大小限制。我們的Java專案主要以JDK7、8為主,JVM預設會以整個宿主機的CPU記憶體來初始化,建議加上Java –server –xms –xmx –xmn等引數,防止JVM爆記憶體,被容器殺死。我們是將容器CPU記憶體的限制寫入到環境變數裡,JVM啟動指令碼從環境變數裡讀取引數啟動。
二、做好容器磁碟使用的限制,不要相信你們的開發,你不知道他們會向容器裡輸出什麼,應用日誌做好輪轉,限制docker stdout標準輸出,可以使用Docker的引數配置;限制容器rootfs,目前DeviceMapper儲存驅動支援較好;限制所有掛載到容器的資料卷,不要讓一個容器壞掉整個節點;並且為節點新增自動驅逐引數,新版本kubelet是預設啟用的。
三、應用上線,做好滾動更新與健康檢測配置。
配置ReadinessProbe,我們要求每個專案都內建http健康檢測路徑,滾動更新會根據ReadinessProbe狀態來決定是否繼續更新以及是否允許接入流量,這樣在整個滾動更新過程中可保證始終會有可用節點的存在,達到無縫更新。
四、容器日誌收集方案
640
比較常見的有這麼幾種,可能也有專案日誌直接寫入ES叢集,不需要容器內收集的。
這裡我推薦使用第三種收集方案,以DaemonSet的方案部署日誌收集元件,做到業務容器的完全無侵入,節省伺服器資源,不必為每個業務容器都啟動一個日誌收集元件。
五、定時備份etcd資料庫
etcd叢集的穩定是Kubernetes叢集穩定的根本,一旦etcd發生問題,整個Kubernetes叢集都將不可用,我們曾有etcd叢集故障導致容器叢集崩潰的慘痛教訓,做到定時備份etcd資料,包括etcd snapshot快照和etcd資料目錄的備份,有條件的還可以做etcd伺服器的映象備份以及遠端備份,做到發生故障時能夠快速恢復。


讓使用者玩轉容器雲

640

專案容器化之後,需要讓開發及運維與容器進行互動操作,kubectl工具學習成本高,許可權不好管理,不適合直接給使用者使用,我們開發了Sahaba api & cli工具,對接LDAP登入,自己做了精確的許可權管理。
Sahaba api基於kubernetes api開發,cli端只保留了使用者需要的功能,比如:get/exec/logs/describe/scale/delete等命令。
我們也同樣開發了web terminal介面,當用戶不習慣使用命令列時,可以從網頁端進入容器控制檯操作。
同時對接了公司的CMDB,可以在CMDB的介面中實時看到容器的狀態。


打造現代化監控系統

640

最初我們使用Heapster+InfluxDB+Grafana做容器的資源監控,但當叢集增長到一定規模時,資料量太大會導致InfluxDB資料庫崩潰,Heapster專案也被Kubernetes官方放棄,所以我們轉向了Prometheus監控,Prometheus可以使用自定義的exporter,收集自己想要的資料,從叢集元件,到叢集節點再到每一個容器,都可以做到精準的監控,以及配置相應的告警規則,做到自動告警。
後續我們還在考慮根據容器應用的資源監控以及APM實時的業務負載,達到自動伸縮的目的,目前我們沒有使用Kubernetes官方的HPA資源,因為單一的CPU記憶體指標不一定能夠做到準確的伸縮,所以我們想要根據實際的業務場景來自己做。
Q&A

640

Q:Ingress是用的那個組建?A:這裡我再詳細補充下,我們沒有使用到Ingress Service這些物件,為了維護與虛擬機器專案的統一管理,方便運維使用,我們的Nginx是部署在叢集外部的,與nginx-ingress-controller一樣,使用Lua擴充套件自己做服務發現,Nginx直接向Pod轉發流量。
Q:Nginx和PHP-FPM採用什麼方法部署和更新,Nginx和FPM有分開部署嗎?A:Nginx部署在叢集外部虛擬機器裡,虛擬機器網路與容器內部網路是打通的,直接轉發流量給Pod;PHP是老專案,有一小部分做了容器化,基於PHP基礎映象使用deployment部署,PHP專案是無狀態的,跟其他專案一樣進行滾動更新;Nginx與FPM是分開部署的。
Q:請問下你們有沒有使用API閘道器,自己開發的還是使用Kubernetes自帶的,使用者許可權是做在API閘道器嗎? A:目前沒有用到API閘道器專案,自己使用Nginx做的簡單API閘道器,sahaba api是我們自己開發的Kubernetes管理工具,使用client-go元件向Kubernetes API發起請求呼叫;使用者許可權我們對接了DevOps許可權管理系統,區分超級管理員,運維人員,專案負責人,普通使用者等,確定某個使用者對某個專案容器guest或admin許可權。
Q:你們的Kubernetes管理平臺,考慮用360開源的wayne嗎?https://github.com/Qihoo360/wayne可以滿足使用者上線需求,也集成了webshell之類的,看起來挺不錯的。A:360的wayne專案,我們也關注了,把原始碼下下來看了一下。我們DevOps平臺與wayne的一大不同之處在於:wayne給使用者的釋出是把Kubernetes的deployment模板放上去了,讓使用者去填寫;我們是用sahaba-metadata專案將deployment模板抽象出來,只給使用者填寫Git專案分支,以及需要釋出的CPU/記憶體/節點等,映象url,超開策略等資料不需要使用者填寫,開發人員不需要關心這些。我們也參考了wayne的webshell實現,跟kube dashboard專案一樣的,我們也正在基於他們的程式碼優化我們自己的webshell。
Q:etcd用哪個版本的,3節點以上的etcd叢集崩潰後如何用映象快速恢復?A:我們的叢集各個版本都有,從1.4到1.11,都是使用當時最新的穩定版部署,具體可以看Kubernetes release note裡的dependencies;etcd叢集恢復,只要有一個節點etcd的資料在,就可以恢復,先將這個節點force-new,其他節點join進來,資料會自動從leader同步到slave。你提到的使用虛擬機器映象恢復,這個我還沒有使用過,我理解的整個雲硬碟的資料都可以備份下來,資料恢復也是沒問題的,參照公有云資料備份恢復方案。
Q:etcd資料備份是怎麼做的,Crontab嗎,還是使用Kubernetes裡的Job,如何確保備份的資料是沒有問題的?A:因為etcd是二進位制檔案部署的,目前我們是使用Crontab定時任務每天備份一次資料,備份的內容包括etcd snapshot,etcd的資料目錄,同時備份到本地及遠端伺服器,公有云上還有云硬碟映象備份,多種備份方案保證資料正常。
Q:日誌收集工具是否用了Fluentd,日誌收集到ES裡,用Kibana查詢有沒有遇到過日誌亂序的問題?A:我們使用的是Filebeat,將日誌收集到Kafka,再轉給Logtash,Logtash處理後才轉給ES, Filebeat -> Kafka -> Logstash -> ES -> Kibana,亂序問題我沒遇到過,應該可以在Logstash處理的時候確認。
Q:可否實現Kubernetes上容器與主機通訊?A:容器與主機通訊是可以的,具體可以參見Calico的網路方案,使用calico routereflect路由反射功能與核心交換機做bgp peer進行路由交換,公有云上使用VPC網路方案。
Q:JVM Xmx是堆記憶體,硬限制是實體記憶體,你們的配置是直接讀環境變數設定一樣了嗎?會不會出現記憶體不足?堆外記憶體怎麼辦?A:我們的環境變數配置的是Pod容器的limit大小,JVM Xmx是使用limit大小*0.6配置啟動的,出現過記憶體不足,OOM等情況,一般是讓開發去調整permsize大小,或不要有記憶體洩露。
Q:容器rootfs大小怎麼限制的?A:在安裝Docker時,使用Devicemapper驅動安裝,會預設限制大小10G,overlya驅動對rootfs大小的限制不是很完善。
Q:什麼時候升級叢集,Kubernetes大版本升級的時候怎麼做?A:我們一般會在進行機房業務遷移的時候去升級叢集,如從私有云遷到公有云,直接新建一套新版本叢集,把舊叢集的deployment檔案更新過去。
Q:相關中介軟體和DB都沒有上嗎?有的話請介紹一下。A:是的,中介軟體和DB資料庫都有專門的團隊來維護,在沒有必要的情況下沒有去做容器化,我們叢集對接了Ceph儲存,但IO效能不高,資料庫容器化還是應該使用local volume。
Q:DevOps的資料都存在etcd中的嗎? 這個是怎麼做的 能否講講設計思路?A:是我們的Deployment釋出模組及元資料都存在了etcd中,把etcd當做一個K-V資料庫來用,當時在資料庫選型時也考慮過MySQL,但是我們的資料型別適合KV儲存,如我們的每個專案Deployment模板都是不一樣的,存放在/deployment/region/env/projectname/這樣的路徑下,並且etcd更加穩定高可用。


Kubernetes線下實戰培訓

640?


Kubernetes應用實戰培訓將於2018年12月21日在北京開課,3天時間帶你係統學習Kubernetes 本次培訓包括:容器特性、映象、網路;Docker特性、架構、元件、概念、Runtime;Docker安全;Docker實踐;Kubernetes架構、核心元件、基本功能;Kubernetes設計理念、架構設計、基本功能、常用物件、設計原則;Kubernetes的實踐、執行時、網路、外掛已經落地經驗;微服務架構、DevOps等,點選下方圖片檢視詳情。

640?


12月21日開課,點選閱讀原文連結即可報名。