1. 程式人生 > >kubernetes系列之七:一些將legacy應用遷移到kubernetes的經驗

kubernetes系列之七:一些將legacy應用遷移到kubernetes的經驗

一、前言

基於kubernetes的應用實際上是微服務在container方向的例項,所以很多微服務的設計原則在kubernetes框架內依然具有參考價值,比如The Twelve Factors

在legacy應用從基於VM的部署向基於kubernetes部署的遷移過程中,需要根據container和微服務的特點,對legacy系統的諸多方面進行調整,滿足kubernetes平臺微服務的一些基本要求和模式:

  • 功能實現
  • 服務分割
  • 配置管理
  • 叢集狀態管理
  • 日誌監控報警
  • 負載均衡和資料流
  • 整合釋出
  • 服務資源配置
  • 規模部署和管理

轉載自https://blog.csdn.net/cloudvtech

二、legacy系統

原有的系統狀態:
  • 具有一個專有的平臺進行計算網路資源管理和應用配置的管理,資源管理是基於VMWare的vSphere而應用配置管理子系統使用指令碼語言編寫
  • 叢集的通訊和狀態管理使用zookeeper和API
  • 使用釋出的ova進行軟體安裝和配置之後,生成不同功能的虛擬機器節點
  • 日誌經本地收集之後轉發到ELK
  • 使用IPVS進行請求接入負載均衡
  • 該系統具有動態組合的配置資訊,但是沒有持久化的需求

轉載自https://blog.csdn.net/cloudvtech

三、向kubernetes遷移:容器化

1.系統拆分:將鬆耦合的子系統拆分成獨立的服務,不同的服務由一系列的容器組合而成,這樣便於和後面kubernetes的service和POD的概念進行對應。

2.容器映象:選擇合適的based映象,對現有系統的RPM依賴進行分析,去掉不必要的模組,以減少構建出來的應用映象的大小,中間經過優化,從2.5GB減少到700MB。

3.程序管理:在VM裡面,應用程式程序的狀態由supervisord進行維護;但是在容器中,kubernetes管理框架需要直接感知容器裡面程序的狀態,所以需要直接讓應用程式作為容器裡面的一號程序,使得容器的狀態和應用程式的狀態保持一致。這裡其實也有另外一個選擇,就是使用一個指令碼管理應用程式程序的生命週期並通過檢測程式狀態並向外暴露來代理程式的執行狀態向容器外部暴露;如果應用程式本身是面向微服務架構設計的,則應用程式可以作為主程式直接對外暴露,對於一些legacy的系統,可能需要這樣一個代理機制以能夠更好的對外反饋容器內服務的狀態。

4.CICD:建立獨立的pipeline對映象進行自動建構和sanity測試。

5.映象安全性:對於使用的基礎映象,需要遵循內部安全性測試的流程,或者使用公司基礎設施部門釋出的可信基礎映象。

轉載自https://blog.csdn.net/cloudvtech

四、向kubernetes遷移:定義kubernetes服務

在容器化的過程中,已經將系統進行根據鬆耦合進行拆分,然後對於拆分之後的子系統服務,需要按照kubernetes的原則封裝成POD並且通過定義kubernetes的service進行暴露。這裡需要說明的是在容器化的過程中,我們只是將應用程式對應的業務服務模組進行容器化,而對於原有系統中計算網路資源管理和應用配置的管理的功能,並沒有遷移過來;計算網路資源管理將代理給kubernetes,而應用配置的管理的功能就需要定義和開發新的kubernetes服務了。

所以在系統遷移到kubernetes之後,核心的應用程式被拆分成了三個服務,其中兩個應用程式業務邏輯服務只是將原有程式容器化,而應用程式配置管理程式需要開發新的基於kubernetes的服務。

而對於日誌監控,將使用運維kubernetes平臺的部門提供的基礎設施服務。

另外,對於應用程式在容器化之後額外需要的一些服務比如redis或者etcd,可以根據資料儲存和訪問的需求自行部署或者使用平臺提供的服務。這裡需要說明的是使用平臺服務和使用自定義的服務,在部署、維護、管理和使用各方面各有利弊,需要進行權衡。

轉載自https://blog.csdn.net/cloudvtech

五、向kubernetes遷移:應用程式配置管理

原有平臺的應用程式配置管理服務是基於虛擬機器和多應用進行混合部署的,所以配置管理是在主機和應用,是較粗級別的管理,使用的是zookeeper進行配置和狀態的互動。我們並沒有將這套和基於VMWare虛擬化平臺和基於主機應用程式架構的配置方案遷移到kubernetes,而是重新開發了一套可以使用kubernetes和容器化配置管理功能的新的配置管理系統。

對於基於容器的應用程式配置管理,如果是基於微服務的概念進行開發的,比較好的策略是使用immutable模式,所有的配置在kubernetes的deployment部署和容器啟動的時候載入,任何配置的更新其實都是deployment版本的更新,deployment對應的POD都會刪除舊的容器並啟動帶有新的配置的容器。但是在lagecy的系統中,對配置可能具有動態組合、動態增減等複雜需求,需要對應服務的後端POD根據新的配置在不重啟的情況下調整配置。

對於配置的管理,這邊需要考慮的是配置如何從kubernetes外部傳輸給容器內部的應用程式。一種方案是使用kubernetes自帶的ConfigMap服務,將配置資料作為檔案直接mount到容器內部,由應用程式或者配置agent感知並載入,這種方案實現簡單,並藉助kubernetes儲存配置,缺點在於ConfigMap的資料傳輸存在時延不可控和擴充套件性的問題。另一種方案是使用etcd等具有事件通知功能的中介軟體作為訊息儲存和通知的媒介,由API接受外部的配置、儲存到etcd並觸動容器內部的監聽模組進行配置更新;這個方案具有時效性強、擴充套件性好等特點,缺點在於實現比較複雜,需要前端API和etcd模組、容器內要有agent跟蹤etcd節點狀態。


在實際應用場景中,不同規模和部署方式的客戶,可能需要不同的配置方式,所以我們在實現過程中對兩種方式都進行了支援。

轉載自https://blog.csdn.net/cloudvtech

六、向kubernetes遷移:負載均衡和資料流

在kubernetes service裡面,提供了基於iptabels的針對service後端POD的簡單負載均衡方案,見文章《Kubernetes如何利用iptables對外暴露service》。這個負載均衡的方案僅僅是保證將資料和請求能在不同節點上的POD中間通訊,並沒有考慮精細控制和效能效率的問題。

對於提供網際網路服務的大規模分散式系統,上行流量一本都會遠遠小於下行流量,對於提供視訊流服務的系統而言,這個規律會更加明顯(可能在100K:10MB這個級別)。所以在這樣的系統中,負載均衡需要考慮更多的是使用三角模式的負載均衡(IPVS的DR模式是一個很好的例子,請求、轉發和返回三個路徑連線client、IPVS director和後端real server組成一個三角形)來控制資料流。我們的應用系統恰恰是這樣一個小請求返回比的系統,所以基於七層的kubernetes Ingress代理方案和預設的基於iptables的kube-porxy負載均衡方案(這個方案存在cross node traffic,對於小請求返回比的系統幾乎是災難)都不能滿足系統大流量和線性擴充套件的需求:


基於kubernetes Ingress的七層負載均衡


基於kubernetes service的四層負載均衡

所以在我們的系統向kubernetes遷移的過程中,基於kubernetes的基礎能力和IPVS開發了這樣一套負載均衡系統:

  • 作為kubernetes的service進行部署
  • 動態感知kubernetes service後端的能力變化而調整負載均衡權重
  • 沒有cross node traffic
  • 跟隨node增減能達到流量支援的線性擴充套件

在這個的解決方案中,資料流從IPVS服務進入,然後根據負載均衡路由方案進入特定的kubernetes節點和節點上的POD進行請求響應,之後直接返回客戶,是典型的三角資料傳輸模型,具有很強的接入能力和擴充套件能力。

轉載自https://blog.csdn.net/cloudvtech

七、向kubernetes遷移:日誌監控報警

1.日誌

使用由於lagecy系統依賴於td-agent進行log的格式轉換,所以加入了一個log處理的side car進行日誌的各式處理和向Fluentd匯出並轉發至ELK,至於新開發的配置管理服務,則直接使用Fluentd對於POD的STD輸出向ELK匯出日誌。

2.監控

對於不同的POD,有不同的metrics exporter翻譯並匯出,雖然這些exporter都有開源的實現,但是還是有必要根據應用和業務的特點定製一些匯出資料。我們使用promethes匯聚資料並根據監控需求對這些資料進行關聯計算,prometheus可以通過API向exporter pull資料或者由exporter向prometheus push資料。最後,使用grafana將監控資料在基於Web的GUI上進行展示,並且可以設立簡單的告警。


3.報警

應用程式使用sensu client收集不同服務的POD的執行狀態資料或者程序直接上報的告警資訊,這些資訊經由平臺的RabbitMQ訊息匯流排服務傳送至sensu server,由uchiwa進行展示或者使用pageduty等將告警資訊匯出至外部通知系統。

轉載自https://blog.csdn.net/cloudvtech

八、向kubernetes遷移:叢集狀態管理

在kubernetes遷移之後,我們的應用程式服務被分割成了幾個kubernetes的service,而service實際上是一個虛擬的概念,實際支撐service的是一系列後端POD,這些POD根據service的定義被選為某個service的後端。同時,service會根據POD的狀態來決定是否將POD加入到服務可達的列表裡面。所以我們需要定義好POD裡面每個container的liveness和rediness檢測介面,如果rediness通過了,POD便會被加入service的服務列表,如果liveness失敗了,POD就會被kubernetes刪掉重新啟動。

所以先抓整個叢集的服務狀態和程序狀態本質上都是由kubernetes進行管理,我們唯一需要關注的是一些檢測介面的實現,以保證liveness和rediness檢測介面能準確反應單個服務程序的狀態。同時,service後端是由一系列POD replica組成,這個replica數目代表了service的服務能力,如果某個節點或者一些POD出現問題,kubernetes會在其它節點啟動新的POD replica來保證需求的服務能力。

轉載自https://blog.csdn.net/cloudvtech

九、向kubernetes遷移:服務資源配置

我們的服務本身需要同時處理很大的上行和下行流量,所以對於不同業務層面的需求,需要為POD裡面的容器配置不同的處理器和記憶體資源。為了滿足這個需求,我們基於不同的資源配置對POD的能力進行測試,比如一個物理機node配置不同數目不同資源需求的POD,來檢視併發服務能力、吞吐率和時延,以此決定不同業務需求場景下推薦的POD配置。


轉載自https://blog.csdn.net/cloudvtech

十、向kubernetes遷移:規模部署和管理

在規模部署的時候,需要定義kubernetes的ConfigMap、service和POD deployment配置檔案,同時還要定義業務邏輯上的引數,全部加起來應該在一百個引數以上,這些引數多數需要根據特定業務特定部署來設定,所以需要由一個強大的輔助工具對引數進行組合、生成相應配置檔案並進行部署。

在生產環境,我們使用ansible來編排這些配置並進行部署。我們編寫了眾多的ansible role來編排不同的服務,從系統整合、配置轉換到服務啟動,都有對應的ansible role,這樣的話,整個編排部署流程儘量解藕,降低了維護的複雜度。但是由於我們lagecy系統的複雜性,所以導致我們的配置最後集成了普通text、xml、json、yaml和j2 template,而這些不同格式的檔案具有不同的文法需求,所以也帶來了很多相容性問題,因此在有條件的情況下,儘量使用一致的配置格式。

同時,在規模部署的時候,經過仔細測試,我們發現kubernetes在一個node上啟動一系列POD的時候,是一個近乎線性的過程,並且由於大量讀取容器映象檔案,所以存在巨大的disk負載。因此,我們也對於同時部署和擴充套件給出了一些指導,保證不會由於大量併發對系統服務造成影響。

轉載自https://blog.csdn.net/cloudvtech

總的來說,應用向kubernetes遷移的過程中,有很多不適應容器雲服務的技術點,需要一一梳理使用創造性的方案進行相容和解決;但是隻要有機會和條件,應該毫不猶豫的向容器雲切換,因為現在很多客戶都會有內部容器雲平臺,並且更傾向於統一的平臺解決方案,所以應用應該及時擁抱這個趨勢。

轉載自https://blog.csdn.net/cloudvtech