構建與定製:唯品會PaaS基於Kubernetes的實踐
主要工作內容包括:平臺DevOps方案流程優化,持續部署,平臺日誌收集,Docker以及Kubernetes研究。
大家好,我是唯品會PaaS團隊的王成昌,與大家分享一下PaaS在Kubernetes的實踐。基於2014年底或2015年初PaaS沒有推廣的現狀,唯品會PaaS部門目前已經做了兩年的時間。
PaaS 主要工作將分為三個部分進行介紹,首先,PaaS定義的標準構建流程,持續 整合和持續部署的架構以及已有組建上的功能定製;第二部分,基於Kubernetes實現的網路方案,以及根據網路方案做的擴充套件定製;第三部分,PaaS如何做日誌收集和監控方案,最後列一下唯品會目前為止所遇到的問題和總結。
唯品會現狀
唯品會目前線上有一千多個域,每個域之間相互的依賴比較複雜,每次的部署釋出困難。線下有多套的測試環境,每套測試環境都要去維護單獨的應用升級和管理。公司層面也沒有統一的持續整合和部署的流程,大家各自去維護一個Jenkins或者一個Jenkins slave,看工程師的個人追求是否能夠寫一個完整的從原始碼、到打包、最後到部署的指令碼。
唯品會線上全部用物理機在跑,之前Openstack方式沒有線上上,只是在測試環境跑,物理機的使用效率還是比較低的。即使在7週年大促的高峰時段,60~80%的物理機利用率也均低於10%。
唯品會PaaS構建流程
基於前面提到的現狀,唯品會的PaaS定義了一個構建流程,整個流程不是一蹴而就,這是目前為止的定義,首先從原始碼的角度出發,即Git,所有的7個Phase全部包括在Jenkins Pipeline裡,由於是基於Kubernetes,所以Jenkins Pipeline的執行是通過Jenkins k8s Plugin去排程後臺的k8s Cluster,由k8s產生的Pod去執行Pipeline。整個Pipeline的幾個階段,除了傳統的編譯單元測試和打包之外,加入了烘焙映象、部署以及整合公司的整合測試(即VTP),打包和映象完成後會正常上傳到公司統一的包管理系統Cider和平臺維護的Docker registry。
部署完成後會觸發整合測試,如果通過測試的話,會把這個包或者是映象標記為可用的狀態,一般先從測試環境標記,然後通過到staging環境。目前PaaS 平臺主要是維護測試環境和staging環境,線上還沒有,但是已經定義了一個審批的流程,如果標記了這個包為可用的狀態,需要一個審批來決定它是否可以上線。部署後通過k8s client,由另外一套k8s的叢集來管理部署裡面所有的節點。
這是唯品會的PaaS架構,主要包含持續整合和持續部署。首先由一個統一UI的入口Dashboard,使用Nginx和Tomcat作為服務的閘道器。其背後有兩套系統——CPMS和API server,CPMS主要管理持續整合的各個流程,API server主要管理應用部署,在CPMS背後是使用多個Jenkins server統一連到一個Kubernetes叢集上產生Pod作為Jenkins slave去執行,不同的構建有多種語言也有不同的模板,這裡會提供各種方案讓不同的Jenkins Pipeline執行在不同的Kubernetes node裡面。
在部署實現一個Cloud Framework,可以接入各種cloud provider,目前使用的是k8s provider,背後的服務發現也是k8s推薦使用的Skydns。為了相容公司基於包釋出的這樣一套模式,映象管理這部分會把包管理系統Cider接入進入,平臺的Docker Registry,以及應公司安全方面的要求,通過Clair對映象的內容進行檢查。
在日誌收集方面,使用fluentd+ELK的組合,採用Prometheus做監控。在PaaS架構裡,安全是通過接入公司的CAS做認證的動作,有一個Oauth元件做鑑權機制,通過Gnats做訊息傳輸的系統。配額的問題在構建和部署中都會有所體現,包括使用者對於Pipeline的個數控制或者Pipeline觸發的個數,以及對應用上的物理配額或者邏輯資源配額等。
Docker Registry改造,主要在Middleware做了一些工作,做了一個接入公司的CAS和Oauth做的驗證和授權。也接入了當有新的映象Push進來的時候,會自動觸發應用的部署。Docker Registry本身對所有的repository不同的tag索引還是比較慢的,所以會針對push進來所有的映象資訊存入資料庫做一個索引,方便查詢映象。使用者行為記錄主要針對pull和push的動作,把它記錄下來。映象安全通過接入Clair做掃描,push映象layer完成之後在push映象的manifest時,會將映象layer資訊傳送到Clair做映象的安全掃描。
原來的Jenkins Kubernetes Plugin,預設把Jenkins slave排程在所有Kubernetes node上,我們做了一個node selecter,針對不同的Pipeline型別,需要跑在不同的節點上。排程上加入了node selecter,此外在每個Pipeline要去run的時候申請資源,加入了資源的request limit,防止單個的Pipeline在執行的時候佔用過多的資源,導致其他的應用或者是構建任務受影響。在掛載方面,像傳統的maven專案在下載過一個包之後,如果是同一個主機上會把.m2檔案會掛載在主機上,不同的Jenkins Pool在跑的時候,可以共享已經下載過的資原始檔。
最後,實現了Container slave pool的策略。當要run一個Pipeline的時候,每次告訴k8s要起一個Jenkins slave Pod,當需要執行一個job的時候,等待時間比較長,這裡會定一個池的策略,就是一個預先準備的過程,當有一個新的任務要run的時候,立刻就可以拿到一個可用的containerslave。
這是PaaS的功能點,包含三個主要的部分,構建,部署和測試集。構建是關於使用者定義Pipeline以及對Pipeline觸發的record的管理,以及Pipeline各個phase的管理。部署主要對應用配置的管理,這個應用包括服務的配置如何、資源的申請如何,以及應用例項的一些管理。測試集對接公司的整合測試環境,和平臺的應用進行關聯。
空間管理和映象管理,空間主要提供不同的隔離空間,提供應用快速的複製,比如你有一個測試環境,我也有一個測試環境,為了大家環境之間相互不干擾可以提供應用的快速複製。映象管理主要分三種,即平臺提供的基礎映象,業務部門一些特殊的需求會基於基礎映象做一些定製,以及具體業務映象。
PaaS網路方案和定製
PaaS採用的網路方案,網路方案最開始直接使用的k8s 1.0的版本加flannel的一套工作模式,後來由於業務需求,使用者需求能夠直接訪問到例項IP,而flannel當時是封閉的子網。目前採用Contiv這套網路模式,由公司統一分配Pod的IP網段。這裡做了一個kube-HAProxy,替換了節點上kube-proxy這個元件,用kube-HAProxy來做Service IP到end point的一個轉發。
在kube2sky,完成域名和服務IP的註冊。傳統的模式下,域名是短域名,Service的名字作為短域名,還有Service本身的IP會註冊到Skydns上。這裡做了一些定製,因為公司的應用比如兩個業務域A和B都有本身的域名——a.vip.com和b.vip.com,A如果要訪問B,不能讓這個訪問跑到線上或者其他環境去,於是通過kube-sky去解析規則,把b.vip.com加入到裡面,再加一個subdomain作為擴充套件的domain search,最終找到平臺內部部署的B域。
goroute 主要是平臺內部的應用,每個應用都會提供一個平臺的域名,這個域名主要是有一個元件叫做state aggregator,會watch k8s apiserver發出來的Service和end point的變化,最終通過Service的名字和end point的地址,把它寫到gorouter的route登錄檔資訊中,當我們訪問平臺域名時就可以找到真正的end point地址。這裡也有定製,採用HAproxy和KeepAlived替換了kube-proxy,之前從Service IP到end point IP的轉化,通過每個節點部署的kube-proxy,它會檢測到 Service和end point的變化,去寫IPtables的規則,來找到最終end point的地址的IP。
現在統一使用的HAproxy加上KeepAlived,有一個kube2HAproxy元件,功能和kube-proxy前面一部分相似,都要watch kube-apiserver的Service和 end point的event來動態的生成一個HAproxy最新的配置。KeepAlived主要為了高可用。有一個值得注意的細節,kube2HAproxy所在機器的IP,要和Service IP的網段在同一個網段裡,使用者在訪問真正的應用的時候直接使用Service IP是公共可見的,而不是隨便定義的Service IP。
對外應用訪問是由平臺提供的域名,字尾均為*.PaaS.vip.com,解析到之後會有公司的DNS統一轉發到gorouter這臺機器上,因為gorouter會監聽到Service和end point的變化,route表裡面會儲存每個域名對應的end point的地址,通過round robin的方式找到最終的Pod來完成http訪問。
最後一個定製關於Pod的IP固定,為什麼要做PodIP固定?因為之前的測試環境很多應用都是部署在VM甚至在物理機上,IP都是固定的,有一些應用是需要白名單訪問的,應用在這個部署機上,需要將IP提供給相應的呼叫方或者是公司的某個部門來告訴他加入白名單。Docker 預設情況下,每次銷燬和重建的過程中,IP都會隨機申請和釋放,所以IP有可能變化。IP固定主要在k8s apiserver做,加了兩個物件,即Pod IP Allocator和IP recycler,Pod IP Allocator是一個大的Pod的網段,可以認為它是Pod的IP池, IP recycler主要記錄一些臨時回收的IP,或者叫臨時暫存區,IP不是一直存在,否則是一種IP浪費,有一個TTL時效性的。
當應用重新部署的時候,原本的Pod會被刪掉,刪掉的過程中會先放在IP recycler中,當一個新的Pod啟動的時候,會通過namespace+RC name的規則去找是否有可用的IP,如果找到優先用這樣的IP記錄在Pod裡,這個Pod物件最終會交由kubelet去啟動,kubelet 啟動的時候會讀取這個Pod IP,然後告訴Docker 啟動的IP是什麼。最終有新的Pod啟動之後,它的IP是之前已經被銷燬的Pod IP,達到的效果就是Pod IP固定。在kubelet因為修改了Pod物件的結構,增加了Pod IP記錄使用IP的情況,根據Pod的IP告訴Docker run的時候執行剛剛的IP來啟動。kubelet 在刪除Pod的時候會告訴k8s去release這個IP。
日誌收集和監控
日誌收集主要分三種型別:首先是平臺自身的服務元件的收集,比如像jenkins、Docker 或者Kubernetes 相關元件的日誌收集,另一個是所有部署在平臺裡面應用的收集,最後還有一些域,因為公司一些已有系統(dragonfly)也是做日誌收集和監控的,有一些特定的規則對接公司。
平臺自身日誌收集的規則,包含系統元件還有平臺應用兩種設計。系統元件比較簡單,無外乎通過systemd或者是指定日誌檔案的路徑做日誌的收集,應用收集主要在k8snode上,k8s會把每一個Pod日誌link在一個特定的檔案路徑下,因為Docker會記錄每一個容器的日誌,可以從這個地方讀取應用的日誌,但是隻拿到namespace和Pod name這樣的結構,我們會通過fluentd裡的filter反向去k8s拿Pod所對應的meta data,最終傳送到kafka,通過logstash達到elastic search。
Kibana的展現做了一些定製,因為平臺的展現主要基於namespace和應用名稱的概念檢視日誌的,定製能夠展現特定的namespace下的特定應用的日誌,同時把自定義的告警加在了這裡,因為告警是通過elastalert來做的,在Kibana上做一個自定義告警的UI入口,由使用者來指定想要監聽什麼樣的日誌內容的告警,去配置監聽的間隔或者出現的次數,以及最終的郵件接收人。
有一個元件是當使用者建立了自定義告警的規則時會傳送到後面的elastalert ruler,ruler解析前臺UI的資訊,生成elastalert能夠識別的configure檔案,動態地讀取configure的加入。
對接公司的業務系統比較簡單,特定的收集規則都是特定的,比如具體的目錄規則,一般來講都是通過掛載容器的目錄到主機目錄上,在主機上統一部署一個agent去run,主要體現在k8s node上,所以仍然使用Daemonset的方式去跑agent。
監控有兩種,一種是對單個Pod的例項監控,在頁面上是可以直接看這樣的例項的,單個Pod是一個應用例項了,然後通過node agent去包裝了cAdviser,前端去統一訪問,獲取對應的CPU和Memory使用資訊。cAdviser對Network收集到的資料是不正確的,通過node agent 讀取Linux file獲取Network的資訊。Websocket Server 是為了提供網頁上直接對容器進行網頁控制檯的登入。
另一個是看整個的應用,因為應用是有多個例項的,通過Graphana去定製,去展現namespace的應用,有多個例項,就把多個例項的監控都展現出來。此處有一個promethus plugin的定製,之前有一些Swarm的節點加入,持續部署提到過它是一個多個cloud framework都可以接入的。唯品會接入了一些Swarm的資訊,針對Swarm建立的容器的話,也要能夠監控到它的容器監控資訊的資料。在Promethus plugin通過Docker info獲取不同的Swarm node的資訊,在每個Swarm node上部署cAdviser,獲取由Swarm建立的容器的監控資訊。
本文轉自中文社群-構建與定製:唯品會PaaS基於Kubernetes的實踐
相關文章
- Flink在唯品會的實踐
- Apache Flink在唯品會的實踐Apache
- 數倉服務平臺在唯品會的建設實踐
- 基於Kubernetes的Serverless PaaS穩定性建設萬字總結Server
- 基於 KubeVela 與 Kubernetes 打造“無限能力”的開放 PaaS
- 唯品會架構師是如何實現架構重構的架構
- 基於kubernetes構建混合雲的利弊
- 唯品會iOS程式碼覆蓋率的應用實踐iOS
- 長文解讀:Flink在唯品會的實踐應用!
- 基於Ceph物件儲存構建實踐物件
- Gradle For Android(2)--基礎的定製構建GradleAndroid
- 基於 eBPF 的 Kubernetes 可觀測實踐eBPF
- kubernetes實踐之六:CFSSL構建本地CA
- Active Network實踐:構建Kubernetes平臺的最佳工具
- Yocto實踐(1): 基於Dunfell 構建Yocto專案
- 基於Kubernetes 構建.NET Core 的技術體系
- 利用 Kubernetes 降本增效?EasyMR 基於 Kubernetes 部署的探索實踐
- 唯品會的“成年煩心事”
- 基於Kafka和Elasticsearch構建實時站內搜尋功能的實踐KafkaElasticsearch
- 快手基於 Flink 構建實時數倉場景化實踐
- 基於 Kubernetes 實踐彈性的 CI/CD 系統
- 基於Kubernetes和OpenKruise的可變基礎設施實踐UI
- 多利熊基於分散式架構實踐穩定性建設分散式架構
- Uber基於Apache Hudi構建PB級資料湖實踐Apache
- 基於 Golang 構建高可擴充套件的雲原生 PaaS(附 PPT 下載)Golang套件
- 銀行基於雲原生架構的 DevOps 建設實踐經驗架構dev
- 使用Spring Cloud Kubernetes基於Kubernetes、Spring Boot和Docker構建微服務架構 - MoriohCloudSpring BootDocker微服務架構
- 基於Docker和Kubernetes構建的部署管理和叢集管理Docker
- 乾貨|EasyMR 基於 Kubernetes 應用的監控實踐
- Spark UI (基於Yarn) 分析與定製SparkUIYarn
- 基於SPA架構的GraphQL工程實踐架構
- eBay 基於 Apache Kyuubi 構建統一 Serverless Spark 閘道器的實踐ApacheServerSpark
- 基於 Nebula Graph 構建百億關係知識圖譜實踐
- Grafana監控系統的構建與實踐Grafana
- 阿里雲的“終端雲化”實踐,基於ENS進行邊緣架構構建阿里架構
- 基於 Serverless 的部署平臺構建與思考Server
- 基於kubernetes自研容器管理平臺的技術實踐
- 基於 GraphQL 的雲音樂 BFF 建設實踐