02.25 某股份制銀行:容器雲平臺建設實踐

容器雲平臺建設行業背景

當前銀行業普遍的共識之一是要以金融科技為依託,通過科技創新引領銀行的轉型升級。雲計算、大數據、人工智能成為各銀行科技部門重點的投資建設領域。雲計算領域的建設主要集中在IaaS和PaaS,目標是降低數據中心成本的同時,為上層應用的創新、快速迭代和穩定運行提供有效支撐。傳統的IaaS調度的是虛擬機或者物理機,粒度較大,相對傳統的虛擬化技術,在資源使用率、靈活性和彈性方面提升度並不高。依託傳統IaaS建設而成的PaaS,也會面臨同樣的問題。而容器技術恰好可以比較好的解決這些問題,並且在微服務、DevOps、分佈式等方面天生具備優勢,因此成為數據中心新一代雲基礎架構的選擇。


建設容器雲平臺的意義

1.讓應用真正意義上彈性擴縮容

傳統方式下應用和基礎環境資源(計算、網絡、存儲、監控等) 是緊耦合的關係,應用的擴容、縮容意味著基礎環境資源的擴容和縮容。基礎環境的擴、縮容耗時會非常長,因為涉及到非常多需要人工介入的環境,而且都是串行的,比如創建主機、分配存儲、網絡接入、操作系統安裝、網絡訪問關係開通、應用部署、監控審計部署、接入負載均衡等等。整個流程走下來通常需要數天到數週的時間。後來我們通過IaaS、虛擬化、自動化工具已經大幅度縮減了基礎環境資源擴容的時間,但是整個流程下來仍然需要數個小時到數天,這對於真正需要彈性的應用來說還是不夠。


容器雲環境下,應用和基礎環境資源是解耦的,應用的擴縮容不需要涉及基礎環境資源的擴縮容,僅僅需要修改應用部署模板文件中的副本數,然後在容器雲平臺執行即可。容器雲平臺會根據副本數來自動創建或者刪除副本,使得最終的副本數是部署模板文件中定義的副本數。整個擴容或縮容流程可以在數秒到數十秒內完成。這樣當應用面臨突發業務量增長,需要緊急擴容的時候,就可以非常快的完成,實現了真正意義上的彈性擴容。


2.為應用微服務化提供有力支撐

應用微服務化是當前應用改造的一個重點方向,因為大家都看到了微服務的好處,就是迭代效率高、資源使用率高(單一微服務可自行擴容)、單一微服務故障 對全局影響有限。但是傳統方式下的應用微服務化開發運營是缺乏體系支撐的,成本高昂、便捷性差。比如一個應用由20個微服務組成,每個微服務需要2個副本保持高可用,傳統方式下就需要申請20個負載均衡、40個虛擬機來確保隔離性,同時還要為這40個虛擬機分配相應的網絡、存儲,部署配套的監控審計等,消耗了大量的資源。傳統方式下的這套架構沒有彈性擴縮容能力,也缺乏自動化的部署管理工具,對運維人員來說,管理的應用從1個變為20個,大大增加了工作量和複雜度,便利性會很差。從應用開發人員的角度看,傳統方式下做微服務化改造,隨著微服數量的增加,服務之間依賴關係的增加,開發人員會面臨很大的挑戰。需要部署專門的服務註冊發現系統,需要對應用層代碼做侵入實現服務的註冊發現機制,需要對應用代碼做修改以實現服務的探活和依賴性處理。這些服務治理方面的工作牽扯了開發人員很大的精力,使得應用人員無法將精力集中在業務開發本身上,是一種低效率的做法。


容器雲環境提供了一套成熟的支撐體系,可以很好的支撐應用的微服務化改造,成本低廉、便捷性好。還是以之前的應用為例,20個微服務中,僅僅對外部提供服務的微服務需要申請負載均衡,內部微服務之間的調用通過service機制即可實現。如果很多微服都需要對外提供服務,也可以通過ingress將所有服務收斂到一個入口上,這樣對負載均衡的需求數量就大幅度下降。容器化的微服務都是運行在一個計算機群內,可以共享計算節點,擴容、縮容都不需要申請虛擬機,資源的使用效率可以最高。容器雲也為應用的部署運行提供很好的編排工具,可以實現應用變更的完全自動化、滾動升級、一鍵回滾。對應用開發人員來說,容器雲環境可以提供比較完善的可配置化的微服治理框架,包括服務註冊發現、服務探活、依賴性處理等,不需要對應用代碼做侵入修改,這樣可以讓應用開發人員將更多精力集中在業務開發本身。


3.讓應用實現自動化故障探測、隔離和恢復

傳統方式下的應用故障判斷、隔離和恢復完全依賴人工介入,耗時很長。比如一旦出現某個應用節點的故障,需要運維人員人工判斷是哪一個節點出了問題,然後人工將該節點從負載均衡摘除。隨後人工恢復故障節點,再掛到負載均衡下面。這就導致很長的故障窗口期,對業務連續性並不友好.


容器方式下,應用的故障判別、隔離和恢復完全自動化實現,無需人工干預。容器雲環境提供一套應用服務的自主探測和處理機制,同時也會檢測每一個節點,一旦發現某個應用副本異常,會立即將其從service摘除,之後自動刪除故障副本,並在可用的節點上新建新的副本。當探測到新建副本已經可以提供服務後,會自動將新建副本掛載到service下面。這種完全自動化的故障處理恢復機制為應用提供了故障自愈能力,將故障窗口減小到最小。


4.大幅度提升資源使用效率

在沒有虛擬機之前,我們使用裸機部署應用,一個裸機部署一個應用,造成了大量的 資源閒置。後來使用虛擬機後,一個裸機上可以虛擬出多個主機,可以部署多個應用,資源使用效率得到了很大的提升。虛擬機之間可以共享CPU,但是無法共享內存和存儲,比如一個虛擬機申請了32GB內存和100GB存儲,這些資源只能被這個虛擬機獨佔,無法和其它虛擬機共享。


容器的本質是進程,進程間是可以共享宿主機的CPU、內存、存儲和網絡的,資源使用效率得到最充分的利用。當然做到這一點的前提是容器能夠確保進程運行的基本資源不被搶佔,資源層面實現良好的隔離性。同時允許設置資源使用配額上限,避免影響其它應用進程。


容器雲平臺架構設計

1.總體架構設計

總體架構圖如下:

某股份制銀行:容器雲平臺建設實踐


hnzut12lza


自服務管理平臺提供8大板塊服務,都是按照支持多租戶的目標設計實現。其中資源申請板塊是租戶申請容器資源的入口,包含帳號申請,K8S和鏡像庫資源申請,日誌接入申請。資源變更板塊是租戶進行資源變更的入口,包括K8S資源擴容和回收,以及帳號權限的修改。集群管理板塊為雲平臺管理員和租戶提供集群範圍資源的管理,鏡像庫管理板塊提供鏡像庫和鏡像的管理,應用管理板塊主要為租戶提供K8S namespace內資源的管理,模板管理板塊包含K8S資源模板和Helm模板,運維助手提供Pod歷史查詢以及集群健康檢查管理,帳號授權管理板塊為雲平臺管理員提供租戶授權管理。


自服務管理平臺南向通過K8S API和鏡像庫API對接多個K8S集群和兩個鏡像庫,實現容器資源的統一納管。最右邊的是行內的運營支撐工具體系,其中統一身份認證為自服務管理平臺提供租戶帳號的登陸鑑權服務,流程系統(即ITOMS)通過API和自服務管理平臺的資源申請板塊對接,提供統一的資源申請入口。CMDB和自服務管理平臺自身的CMDB交互,提供應用、容器、資源之間的關係視圖;DevOps工具鏈可以從自服務平臺獲取用戶和權限,然後通過K8S API和鏡像庫API實現應用的自動化流水線發佈。ELK日誌系統用於存儲容器應用的日誌,集中監控告警系統接收來自K8S節點和容器應用的監控數據,提供告警推送、置維護、統一監控視圖的能力。


2.多集群管理設計

根據銀行內網絡安全的要求,K8S集群不能通過Overlay網絡跨網絡隔離區。因此一個K8S集群只能限定在一個網絡隔離區內。目前生產和災備數據中心的每個網絡隔離區部署一套或多套K8S集群,所有集群統一由自服務管理平臺納管。同一網絡隔離區內,生產和災備數據中心各部署K8S集群,為應用提供雙活容災部署架構支撐。生產和災備數據中心分別部署一套鏡像庫系統,為各自數據中心內的K8S集群提供鏡像服務。允許租戶跨集群管理自己的容器資源。整體示意圖如下:

某股份制銀行:容器雲平臺建設實踐


qsgqjlpf4u


3.多租戶管理設計

通過K8S命名空間和鏡像庫命名空間實現租戶資源隔離,一個租戶對應於一個或者多個命名空間。雲平臺管理員可以通過RBAC機制為租戶授予相應命名空間的管理權限。租戶對授權命名空間內的資源具有管理員權限,但是無法訪問非授權命名空間。對於一個租戶來說,管理員可以授予他一個K8S集群內一個或多個命名空間的管理權限,也可以授予他多個K8S集群內命名空間的管理權限。整體示意圖如下:

某股份制銀行:容器雲平臺建設實踐


i855qvjyodt


4.專用和共享計算節點

容器雲平臺為應用提供兩種類型的K8S集群,分別是計算節點共享的K8S集群和計算節點專用的K8S集群。從資源利用率角度,首推共享計算節點的K8S集群。計算節點直接採用物理機,多個應用共享計算節點組成的資源池,資源的彈性和使用效率最高。


如應用需要調整缺省Linux Kernel參數,或者有特殊的敏感的出網絡訪問關係,或者有很高的安全隔離性要求,可以考慮採用計算節點專用的K8S集群。專用的計算節點考慮資源利用率,主要以虛擬機為主。特殊的應用場景(如GPU)可以使用物理機。通過給計算節點打應用標籤的方式,然後在應用部署模板裡指定nodeSelector的方式,實現計算節點的獨佔。


5.存儲後端實現

使用Ceph分佈式存儲作為容器雲平臺的後端存儲,為應用提供持久化的數據存儲能力。在生產和災備數據中心各部署一個Ceph集群,為所屬數據中心的K8S集群提供持久化存儲後端服務。每個K8S集群創建2個Storage Class。rbd-class提供ReadWriteOnce類型PVC,後臺對接的是Ceph RBD;cephfs-class提供ReadWriteMany類型PVC,後臺對接的是CephFS。租戶可動態申請PVC,僅有創建權限,沒有刪除權限。整體示意圖如下:

某股份制銀行:容器雲平臺建設實踐


z1jejzxjnog


6.應用監控告警

每一個計算節點上會部署一個監控Agent。應用如需監控,需要在應用部署模板的環境變量裡聲明監控類型。應用容器啟動後,監控Agent會通過容器接口獲得容器監控類型環境變量,並自動匹配監控模板(腳本)。監控Agent將監控數據發送到監控服務器。監控服務器根據觸發條件判斷是否發送告警信息到集中告警平臺。在集中告警平臺上為每個應用創建虛擬節點,和IP解耦。告警平臺收到告警信息後,根據告警數據包含的應用名稱字段自動匹配到虛擬節點。虛節點上可設置維護狀態,應用變更的時候為了避免告警可以設置虛節點為維護狀態,變更完成後可以解除維護狀態。示意圖如下:

某股份制銀行:容器雲平臺建設實踐


opefduny42j

目前可監控的應用指標如下:


1.應用容器狀態。如果容器狀態異常會觸發告警;


2.應用Deployment副本數,如果副本數和期望的不一致,會觸發告警;


3.應用Statefulset副本數, 如果副本數和期望的不一致,會觸發告警;


4.應用Pod狀態,如異常,會觸發告警;


5.應用容器內部文件系統使用率,如超過80%,會觸發告警;


7.應用日誌處理

每個計算節點部署一個日誌收集代理,該代理面向節點上所有的容器。如應用容器需要監控,就需要在Pod yaml裡通過環境變量聲明日誌路徑和kafka topic。容器啟動後,日誌代理會根據容器環境變量定義的日誌路徑自動匹配對應的宿主機日誌文件路徑,並將日誌抓取後發送到kafka topic。當前的日誌代理以換行符作為分割符,如應用的一條日誌裡有多行紀錄,這條日誌會被切分成多個消息來處理,在Kibana上也會呈現多條記錄。為了適配這類一條日誌有多行紀錄的應用,我們也正在設計開發一種可定製化分隔符的日誌引擎,可以允許應用在Pod的yaml裡聲明日誌分隔符。


8.應用雙活容災部署架構

生產、災備中心每個網絡區都建設一個K8S集群,都有各自獨立的鏡像庫和後端分佈式存儲。應用雙活要求應用同時運行在生產、災備中心的兩個K8S集群上,前端可以通過負載均衡引流。任意一個數據中心的集群故障不影響應用的可用性。示意圖如下:

某股份制銀行:容器雲平臺建設實踐


ev6i39ygdkg


應用容器化最佳實踐總結

1.鏡像和配置分離原則:製作應用鏡像時,需要將配置分離出來,這樣做可以讓應用鏡像在不同環境(比如測試和生產)都一致,變得只是配置信息。配置信息可通過環境變量或者加載卷的方式注入容器。在K8S環境下,除了環境變量注入,還可以通過ConfigMap和Serect方式注入配置。ConfigMap和Secret都支持通過卷加載的方式掛載到容器。Secret通常用於保存敏感信息(如密碼).


2.微服務原則:容器環境天生要求微服務化,一個容器只提供一種服務。每個容器原則上只對外提供一個服務監聽端口。


3.使用第三方基礎鏡像製作應用鏡像的時候必須包含必要的系統trouleshooting工具,至少包括ps、netstat、ping、curl。否則出現問題的時候會妨礙排錯。


4.支持通過NodePort和Ingress對外發布服務。NodePort適用於對外服務較少場景;Ingress適用於對外服務較多,需要統一入口場景。Ingress需要作為應用的的一部分部署在應用命名空間。使用Ingress只需要對外通過一個NodePort暴露服務。


5.NodePort需要向容器平臺管理員申請。請僅僅使用分配給項目組的NodePort,禁止使用未經申請的NodePort,否則容易其它項目組產生端口衝突 .


6.如使用StatefulSet部署有狀態應用,副本數必須大於等於2,並且在驗證了單個Pod失效不影響服務的前提下,才可以生產上線。原因是StatefulSet的Pod在宿主機故障情況下沒有自動HA能力,需要人為干預殺死Pod才能觸發重建。


7.Deployment/StatefulSet/Pod的yaml裡,必須配置liveness/readiness探測,並通過測試才能生產上線。這對於應用的可用性非常重要,請一定重視 。


8.Deployment/StatefulSet/Pod的yaml裡,必須對Container的resources做設置。因為生產環境出於考慮極端情況(一半節點不可用)下的應用高可用。對於獨佔計算節點的應用,要求應用namespace下所有Pod的request總合不能超過分配總資源(CPU,內存)的50%-1,單個Pod的limit不能超過單個節點資源的60%。


9.對於可以和其它應用共享計算節點(通常是物理節點)的應用,namespace下所有Pod的request總合和limites總合不能超過分配的總資源(比如分配了16C/64G,那麼request總合/limites總合不能超過16C/64G)。


10.對於使用獨佔宿主機節點的應用,Deployment/StatefulSet/Pod的yaml裡,必須配置NodeSelector。生產環境NodeSelector的value值是項目的英文名,測試環境統一是testapp。對於和其它應用共享宿主機節點的應用,可以不配置NodeSelector。


11.對於重要系統,Deployment/StatefulSet裡,副本(replica)數必須大於2(包含2),禁止為1。這樣才能確保服務在單個副本故障的情況下依然可用。對於可靠性要求不高的系統,在資源充足的情況下儘量也保持副本數大於等於2。如資源受限,並且上線前明確說明對可靠性要求不高,可以允許副本數為1 。


12.Pod產生的日誌,推薦通過直接寫入stdout並配置Kafka Topic的方式,轉發到ELK。如果一定要持久化保存,有如下三種方案,但是都要求首先應用層面要做好日誌輪循(rotation),控制好總量大小,因為PVC和HostPath用的宿主機目錄通常是無法擴容的。目前僅寫入stdout、HostPath的日誌,才可以被日誌引擎處理發往ELK,HostPath需要掛載到日誌目錄。HostPath方式受限使用,需要一事一議。寫入PVC或者直接寫入容器自身的日誌將不能被日誌引擎抓取。


a)使用StatefulSet方式部署Pod,需要在yaml裡聲明PVC容量和StorageClass(名字為rbd-class,提供ReadWriteOnce類型的PV),並且通過將日誌同時寫入stdout,且在yaml裡聲明stdout日誌路徑和Kafka Topic的方式,將日誌發往ELK。一旦使用PVC,Pod的可用性就會和PVC的可用性關聯起來。對於可用性要求很高的系統(A/B類系統),如果使用PVC,前提條件是應用實現了災備雙活部署。


b)使用Deployment方式部署Pod,需要在yaml裡聲明共享型(ReadWriteMany類型)PVC的名字,並且通過將日誌同時寫入stdout,且在yaml裡聲明stdout日誌路徑和Kafka Topic的方式,將日誌發往ELK。在多副本情況下,需要應用做好日誌文件區分,避免多副本寫同一個日誌文件。一旦使用PVC,Pod的可用性就會和PVC的可用性關聯起來。對於可用性要求很高的系統(A/B類系統),如果使用PVC,前提條件是應用實現了災備雙活部署。


c)使用HostPath,將日誌寫入宿主機的某個目錄。這需要應用在多副本的情況下,能夠做好日誌區分,將所有Pod的日誌放到同一個父目錄下。如需使用此種方式,請提前聯繫容器平臺管理員創建目錄。即使使用HostPath存放日誌,可直接通過在yaml裡聲明日誌文件路徑和Kafka Topic的方式,將日誌發往ELK。使用HostPath存放日誌主要的問題是Pod一旦遷移到新的節點,日誌寫入也會遷移到新的節點,舊節點上的日誌文件寫入會中斷。HostPath僅僅適用於專用計算節點場景,並且需要一事一議。


13.如果兩個服務之間有依賴關係,必須在上線前解決啟動順序問題。可以考慮使用K8S的initcontainer機制做探測。


14.對於重要系統,原則上要求應用層面必須實現災備雙活部署,也即應用同時運行在生產、災備的兩個K8S集群上,前端可通過負載均衡引流。任意一個集群的故障不影響應用的可用性


15.生產上線前,請確保在測試環境完成應用HA測試驗證,具體的要求是:


a) 殺死任意服務中的單個Pod不影響整體業務


b) 殺死任意服務中的所有Pod,待Pod重啟完成後,整體業務服務不受影響


c) 節點故障不影響整體業務


16. 儘可能通過配置prestop或者處理SIGTERM信號,來實現應用容器的優雅停止。缺省情況下,沒有配置優雅停止的話,K8S會在grace-period時間(缺省30秒,可在Pod Yaml裡調整)到期後,通過SIGKILL殺死Pod內進程。


應用容器化改造案例(某支付類系統)

1.改造背景

支付類系統作為銀行的核心繫統之一,為了保證可用性和性能,之前都是運行在小型機上,運行成本高昂、可擴展性較差。為了解決這些問題,支付類系統需要進行分佈式改造,把應用程序從小型機遷移到X86 PC服務器上,導致服務器的規模從幾臺擴展為幾十臺,使得部署環節更加複雜、容易出錯。因此希望利用容器平臺提供的服務註冊發現、動態伸縮以及快速故障檢測恢復等能力,降低分佈式系統的部署和管理難度。


2.技術實現

如下是某支付類系統容器化後的部署架構,該系統的後端採用容器化方式部署運行。後端也根據微服務的方式,從一個大模塊拆分成幾個微服務模塊,更便於分佈式的部署。

某股份制銀行:容器雲平臺建設實踐


bllnwnnjmrt

行內現有的支付類系統大多是有狀態的,因為要生成和節點相關的交易流水號。容器化改造時,為了儘可能不影響現有業務邏輯,也需要維持這種有狀態的方式。可以利用K8S提供的StatefulSet實現有狀態的部署,每個Pod會有固定的名字,比如payapp-01、payapp-02。這樣可以根據Pod名字中的索引(01、02等)自動生成交易流水號。


由於現有前置應用和後端應用之間是長連接,只能採用一個Pod一個Service的方式提供服務。每一個Pod都要通過NodePort Service對外提供服務。後端Pod在啟動後,會將Pod所在的節點IP地址和自己的NodePort註冊到前置應用裡,然後由前置應用校驗適配後,發起到後端Pod的連接,並一直保持這個連接。為了保持較好的可擴展性,可以預先在前置應用裡配置額外的服務端口,這樣需要擴展的時候,只需要擴容後端的副本(Pod)數量和Service數量即可。當然,後期如果可以改造為短連接方式,就可以採用1個Service對應多個副本的方式,擴容會更方便,也可省略服務向前置應用的註冊環節。


支付類系統是銀行的重要系統,必須具備雙活容災能力,具體實現是在生產和同城災備數據中心的兩個K8S集群上分別部署一個多副本的StatefulSet,各副本(Pod)僅和所在數據中心的前置交互。任意數據中心的故障不影響整體業務。


3.效果總結

通過上述容器化改造,達到了如下目的和效果:

  1. 支付類應用可以順利從小型機遷移到X86的虛擬機上。之前只能縱向擴展的問題得到解決,應用得以分佈式部署,橫向擴展。
  2. 應用的彈性擴容能力得到大幅提供,只需要修改部署模板裡的副本數即可實現橫向擴展。
  3. 資源使用效率得到大幅提高,因為做了服務拆分,可以針對模塊來匹配資源,擴容所需的資源力度更細,避免了資源的浪費。
  4. 應用分佈式改造後的部署管理更加簡便和高效、可以實現全自動化的部署、升級和回滾。



分享到:


相關文章: