大約兩年前,我們決定放棄基于Ansible的配置管理設置,以便在EC2上部署應用程序,并轉向使用Kubernetes進行容器化和編排應用程序。我們已將大部分基礎架構遷移到Kubernetes。這是一項艱巨的任務,也有其自身的挑戰-從運行混合基礎架構的技術挑戰到完成大部分遷移,再到以全新的運營模式培訓整個團隊,僅舉幾例。
在這篇文章中,我們想反思我們的經驗,并與您分享我們在這次旅程中的經驗,以幫助您做出更好的決定并增加成功的機會。
明確說明您遷移到Kubernetes的原因
所有那些無服務器和容器的東西都很好。如果您要開始一項新業務并從頭開始構建所有內容,請務必使用容器來部署應用程序,并在擁有帶寬(或可能不具備)的情況下使用Kubernetes來編排應用程序,并且擁有配置和配置技術的技能。操作Kubernetes以及在Kubernetes上部署應用程序。
即使您將Kubernetes的操作卸載到諸如EKS,GKE或AKS之類的Kubernetes托管服務上,在Kubernetes上正確部署和操作應用程序也需要學習。您的開發團隊應該應對挑戰。只有您的團隊遵循DevOps理念,才能實現很多好處。如果您有中央sysadmin團隊為其他團隊開發的應用程序編寫清單,那么從DevOps的角度來看,我們個人認為Kubernetes的好處較小。當然,您可以選擇Kubernetes帶來許多其他好處,例如成本,更快的實驗,更快的自動縮放,彈性等。
如果您已經在云VM或其他PaaS上進行部署,那么為什么真正考慮從現有基礎架構遷移到Kubernetes?您是否相信Kubernetes是解決問題的唯一方法?您必須清楚自己的動機,因為將現有基礎架構遷移到Kubernetes是一項艱巨的任務。
我們在這方面犯了一些錯誤。我們遷移到Kubernetes的主要原因是建立一個持續集成的基礎架構,該基礎架構可以幫助我們快速重新構建微服務,而這些年來,這些微服務一直困擾著許多架構。大多數新功能都需要涉及多個代碼庫,因此,一起開發和測試所有這些功能會使我們慢下來。我們認為有必要為每個開發人員和每個變更提供一個集成的環境,以幫助加快開發和測試周期,而無需協調誰來獲得“共享階段環境”。
> One of our continuous integration pipelines that provisions a new integrated environment with all the microservices and runs automated tests
我們今天做得很好。我們今天在8分鐘內在Kubernetes上的集成環境中提供了21種微服務。任何開發人員都可以使用我們自己開發的工具來執行此操作。對于為這21個微服務中的任何一個創建的每個拉取請求,我們還提供了該環境的子集。整個測試周期(提供環境和運行測試)需要不到12分鐘的時間。可能感覺很長,但它阻止了我們在當前所處的體系結構混亂中進行重大更改。
> Continuous Integration pipeline execution report
贊!建立所有這些需要什么?我們花了將近1.5年的時間。那值得嗎?
通過構建其他工具,遙測并重新部署每個應用程序的方式,我們花了將近1.5年的時間來穩定這種復雜的CI設置。為了實現開發/產品平價,我們也必須將所有這些微服務都部署到生產中,否則,基礎架構和部署設置之間的偏差將使應用程序難以為開發人員辯護,并且本應為開發人員做出選擇一個噩夢。
我們對這個話題有不同的看法。回顧過去,我們認為解決連續集成的問題變得更加糟糕,因為將所有微服務推向生產以實現開發/產品平價的復雜性使得實現更快的CI的挑戰變得更加復雜和困難。在使用Kubernetes之前,我們將Ansible與Hashicorp Consul和Vault一起用于基礎架構供應,配置管理和部署。慢嗎?是的,一點沒錯。但是我們認為我們可以通過Consul引入服務發現并優化Ansible部署,從而在合理的較短時間內就足夠接近我們的目標。
我們應該遷移到Kubernetes嗎?是的,一點沒錯。使用Kubernetes有很多好處-服務發現,更好的成本管理,彈性,治理,對云基礎架構基礎架構的抽象等等。今天,我們也收獲了所有這些好處。但這并不是我們開始時的主要目標,也許沒有必要施加自己的壓力和痛苦來實現自己的方式。
對我們來說,一大收獲是,我們本可以采用另一種且抗性較小的方式來采用Kubernetes。我們只是被Kubernetes收購,這是我們甚至不在乎評估其他選項的唯一解決方案。
我們將在此博客文章中看到,在Kubernetes上進行遷移和操作與在云VM或裸機上進行部署不同。您的云工程和開發團隊有一條學習曲線。對于您的團隊來說,值得一試。但是,現在您需要做的是這個問題。您必須嘗試清楚地回答。
開箱即用的Kubernetes幾乎對任何人來說都是遠遠不夠的
許多人對Kubernetes作為PaaS解決方案感到困惑,這不是PaaS解決方案。它是構建PaaS解決方案的平臺。OpenShift就是這樣一個例子。
開箱即用的Kubernetes對于幾乎任何人來說都是遠遠不夠的。這是一個學習和探索的絕佳游樂場。但是您很可能需要在頂部放置更多基礎結構組件,并將它們很好地結合在一起,作為應用程序的解決方案,以使其對您的開發人員更有意義。通常,這種帶有附加基礎設施組件和策略的Kubernetes捆綁包稱為內部Kubernetes平臺。這是一個非常有用的范例,并且有幾種擴展Kubernetes的方法。
度量標準,日志,服務發現,分布式跟蹤,配置和秘密管理,CI / CD,本地開發經驗,對自定義度量標準的自動擴展都是需要照顧和做出決定的事情。這些只是我們要呼吁的一些事情。肯定會有更多的決策和更多的基礎架構要建立。一個重要的方面是您的開發人員將如何使用Kubernetes的資源和清單-在本博客文章的后面將對此進行更多介紹。
這是我們的一些決定和理由。
指標
我們最后確定了Prometheus。Prometheus幾乎是事實上的度量標準基礎結構。CNCF和Kubernetes非常喜歡它。它在Grafana生態系統中非常有效。而且我們喜歡Grafana!我們唯一的問題是我們正在使用InfluxDB。我們已決定從InfluxDB遷移并完全致力于Prometheus。
日志
日志一直是我們的大難題。我們一直在努力使用ELK創建一個穩定的日志記錄平臺。我們發現ELK具有我們團隊無法實際使用的功能。這些功能需要付出一定的代價。另外,我們認為將Elasticsearch用于日志存在固有的挑戰,使其成為昂貴的日志解決方案。我們由Grafana最終確定了Loki。這很簡單。它具有滿足我們團隊需求的必要功能。極具成本效益。但最重要的是,由于它的查詢語言與PromQL非常相似,因此它具有出色的UX。此外,它與Grafana搭配使用也很好。這樣一來,就可以將整個指標監視和日志記錄體驗集中到一個用戶界面中。
An example of a Grafana dashboard with visualization over metrics and corresponding logs side-by-sid
配置和密鑰
您會發現大多數文章在Kubernetes中使用configmap和密鑰對象。我們的學習是,它可以幫助您入門,但是對于我們的用例而言,我們發現它還遠遠不夠。將configmap與現有服務一起使用需要一定的費用。Configmap可以通過某種方式安裝到pod中-使用環境變量是最常見的方式。如果您有大量的舊式微服務從配置管理工具(如Puppet,Chef或Ansible)提供的文件中讀取配置,則您將不得不在所有代碼庫中重做配置處理,以便現在從環境變量中進行讀取。我們沒有找到足夠的理由在合理的情況下執行此操作。此外,配置或機密的更改意味著您將必須通過打補丁來重新部署您的部署。這將是kubectl命令的額外命令性編排。
> Design by Asif Jamal
為了避免所有這些情況,我們決定使用Consul,Vault和Consul模板進行配置管理。今天,我們將Consul模板作為初始化容器運行,并計劃將其作為Pod中的Sidecar運行,以便它可以監視Consul中的配置更改并刷新Vault中即將過期的密鑰并優雅地重新加載應用程序進程。
CI / CD
在遷移到Kubernetes之前,我們一直在使用Jenkins。遷移到Kubernetes之后,我們決定堅持使用詹金斯。到目前為止,我們的經驗是,Jenkins并不是使用云原生基礎架構的最佳解決方案。我們發現自己使用Python,Bash,Docker和腳本化/聲明性Jenkins管道做了很多工作,以使其全部正常工作。建立和維護這些工具和管道開始變得昂貴。我們現在正在探索Tekton和Argo工作流作為我們的新CI / CD平臺。您可以在CI / CD環境中探索更多選項,例如Jenkins X,Screwdriver,Keptn等。
開發經驗
在開發工作流程中有多種使用Kubernetes的方法。我們主要將選擇權歸零到兩個選項-Telepresence.io和Skaffold。Skaffold能夠監視您的本地更改并將其不斷部署到您的Kubernetes集群中。另一方面,網真允許您在與Kubernetes集群建立透明網絡代理的同時在本地運行服務,以便您的本地服務可以與Kubernetes中的其他服務進行通信,就好像它已部署在集群中一樣。這是個人意見和偏好的問題。很難決定一種工具。目前,我們主要在嘗試網真,但我們并沒有放棄Skaffold對我們來說是更好的工具的可能性。只有時間會告訴我們我們決定使用什么,或者也許我們會同時使用。還有其他解決方案,例如草稿值得一提。
分布式跟蹤
我們暫時還沒有進行分布式跟蹤。但是,我們計劃很快就對該領域進行投資。像日志記錄一樣,我們希望在Grafana旁邊提供度量標準和日志記錄旁邊的分布式跟蹤,以便為我們的開發團隊提供更加集成的可觀察性體驗。
應用程序打包,部署和工具
Kubernetes的一個重要方面是考慮開發人員如何與集群進行交互并部署其工作負載。我們希望使事情簡單易擴展。我們正在向Kustomize,Skaffold以及一些本地CRD匯聚,以作為開發人員部署和管理應用程序的方式。話雖如此,只要團隊是開源的并且建立在開放標準之上,那么任何團隊都可以自由地使用他們想與集群進行交互的任何工具。
操作Kubernetes集群很困難
我們主要在AWS的新加坡地區以外運營。在我們開始使用Kubernetes的旅程時,在新加坡地區還沒有提供EKS服務。因此,我們必須使用kops在EC2上建立自己的Kubernetes集群。
建立一個基本集群也許并不那么困難。我們能夠在一周內建立起第一個集群。當您開始部署工作負載時,大多數問題都會發生。從調整群集自動縮放器到在正確的時間配置資源,再到正確配置網絡以實現正確的性能,您必須自己研究和配置。在大多數情況下,默認設置在大多數情況下都不會起作用(或者至少在那時對我們不起作用)。
我們的學習是,操作Kubernetes是復雜的。有很多活動部件。而且,學習如何操作Kubernetes很可能不是您業務的核心。盡可能將負載卸載到云服務提供商(EKS,GKE,AKS)。自己進行此操作沒有任何價值。
您仍然必須考慮升級
Kubernetes非常復雜,即使您使用的是托管服務,升級也不會一帆風順。
即使使用托管的Kubernetes服務,也要盡早投資基礎架構即代碼的設置,以使災難恢復和升級過程在未來的痛苦相對較小,并且能夠在發生災難時快速恢復。
如果愿意,您可以嘗試推動GitOps。如果您無法做到這一點,那么將手動步驟減少到最低限度是一個很好的開始。我們結合使用eksctl,terraform和我們的群集配置清單(包括平臺服務的清單)來建立所謂的“ Grofers Kubernetes平臺”。為了使設置和部署過程更簡單,可重復,我們建立了一個自動化管道來設置新集群并將更改部署到現有集群。
資源請求和限制
開始遷移后,由于配置錯誤,我們在群集中觀察到許多性能和功能問題。其結果之一是在資源請求和限制中添加了許多緩沖區,以消除資源限制,從而降低性能。
最早的觀察之一是由于節點上的內存限制而導致的逐出。原因是與資源請求相比,資源限制過高。隨著流量的激增,內存消耗的增加可能導致節點上的內存飽和,從而進一步導致Pod逐出。
我們的學習是將資源請求保持在足夠高的水平,但又不要過高,以便在低流量時間內浪費資源,并使資源限制相對接近資源請求,以便為尖峰流量留出一定的喘息空間,而不會由于節點上的內存壓力而驅逐Pod。限制與請求之間的接近程度取決于您的流量模式。
這不適用于非生產環境(例如開發,登臺和CI)。這些環境不會帶來任何流量高峰。從理論上講,如果將CPU請求設置為零并為容器設置足夠高的CPU限制,則可以運行無限個容器。如果您的容器開始占用大量CPU,它們將受到限制。您也可以對內存請求和限制執行相同的操作。但是,達到內存限制的行為與CPU不同。如果您使用的內存超過了設置的內存限制,則容器將被殺死OOM,然后容器將重新啟動。如果您的內存限制異常高(例如高于節點的容量),則可以繼續使用內存,但是最終,當節點可用內存不足時,調度程序將開始逐出Pod。
在非生產環境中,我們通過保持極低的資源請求和極高的資源限制來盡可能安全地超額分配資源。在這種情況下,限制因素是內存,即無論內存請求有多低和內存限制有多高,pod逐出都是節點上調度的所有容器使用的內存總和的函數。
安全與治理
Kubernetes旨在為開發人員解鎖云平臺,使其更加獨立,并推動DevOps文化。向開發人員開放平臺,減少云工程團隊(或系統管理員)的干預以及使開發團隊獨立應該是重要目標之一。
有時,這種獨立性可能會帶來嚴重的風險。例如,默認情況下,在EKS中使用LoadBalancer類型服務會配置面向ELB的公共網絡。添加某些注釋將確保提供內部ELB。我們在早期就犯了一些錯誤。
我們使用開放策略代理來減少各種安全風險,以及降低成本,安全和技術債務相關的風險。
部署Open Policy Agent以構建正確的控件有助于自動化整個變更管理過程,并為我們的開發人員構建正確的安全網。借助Open Policy Agent,我們可以限制如前所述的方案-除非存在正確的注釋,否則可以限制創建服務對象,以免開發人員意外創建公共ELB。
成本
遷移后,我們看到了巨大的成本優勢。但是,并非所有好處都會立即產生。
注意:我們正在整理有關我們最近的成本優化計劃得更詳細的文章。提防Lambda。
更好地利用資源容量
這是最明顯的一個。今天,我們的基礎架構所配置的計算,內存和存儲遠遠少于以前。除了由于更好地包裝容器/過程而提高了容量利用率之外,我們還能夠比以前更好地利用我們的共享服務,例如過程的可觀察性(指標,日志)。
但是,最初,我們在遷移時浪費了大量資源。由于我們無法正確調整自我管理的Kubernetes集群,從而導致大量性能問題,因此我們最終要求在Pod中使用大量資源作為緩沖區,更像是保險,以減少因出現故障或性能問題而導致的機會缺乏計算或內存。
由于存在較大的資源緩沖區,導致高昂的基礎架構成本是一個大問題。由于我們應該擁有Kubernetes,我們并沒有真正實現容量利用的任何好處。在遷移到EKS之后,觀察到它帶來的穩定性使我們變得更加自信,這幫助我們采取了必要的步驟來糾正資源需求并大幅度減少資源浪費。
實例
與Kubernetes一起使用競價型實例比在原始VM上使用競價型實例要容易得多。使用VM,您可以自己管理競價型實例,這可能會有些復雜性,無法確保您的應用程序具有適當的正常運行時間,或者使用SpotInst等服務。Kubernetes同樣適用,但是Kubernetes帶來的資源效率可以為您留出足夠的空間來保留一些緩沖區,以便即使集群中的幾個實例被中斷,在其上安排的容器也可以在其他地方快速重新安排。有一些選項可以有效地管理現場中斷。
競價型實例幫助我們節省了大量資金。今天,我們整個階段的Kubernetes集群都在競價型實例上運行,而我們的生產Kubernetes集群的99%都由預留實例,節省計劃和競價型實例覆蓋。
優化的下一步是如何在競價型實例上運行整個生產集群。在另一篇博客文章中,有關此主題的更多信息。
ELB合并
我們使用Ingress在舞臺環境中整合了ELB,并大幅降低了ELB的固定成本。為了避免這種情況導致代碼之間出現開發/產品差異,我們決定實現一個控制器,該控制器會將LoadBalancer類型服務與我們階段集群中的入口對象一起更改為NodePort類型服務。
對于我們來說,向Nginx入口的遷移相對簡單,并且由于采用了控制器方法,因此無需進行大量更改。如果我們也將ingress用于生產中,則可以節省更多的錢。這不是一個簡單的變化。在以正確的方式配置生產的入口時,必須考慮幾個方面,并且還必須從安全性和API管理的角度來考慮。這是我們打算在不久的將來工作的領域。
增加跨可用區AZ數據傳輸
盡管我們節省了很多基礎架構支出,但仍有一部分基礎架構成本增加了-跨可用區數據傳輸。
可以在任何節點上配置Pod。即使您控制Pod在群集中的分布方式,也沒有一種簡單的方法來控制服務如何以一種服務的Pod與同一AZ中的另一服務的Pod交談的方式來發現彼此,以減少跨可用區的數據轉移。
經過與其他公司的同行進行大量研究和交談之后,我們了解到可以通過引入服務網格來控制如何將流量從Pod路由到目標Pod來實現。我們還沒有準備好為了節省跨可用區數據傳輸的成本而自己承擔操作服務網格的復雜性。
CRD,Operator和控制器–邁向簡化運營的一步和更全面的體驗
每個組織都有自己的工作流程和運營挑戰。我們也有我們的。
在我們使用Kubernetes的兩年旅程中,我們了解到Kubernetes很棒,但是當您使用控制器,Operator和CRD等功能來簡化日常操作并為開發人員提供更集成的體驗時,Kubernetes會更好。
我們已經開始投資大量的控制器和CRD。例如,LoadBalancer服務類型到入口的轉換是控制器操作。同樣,只要部署了新服務,我們就會使用控制器在DNS提供程序中自動創建CNAME記錄。這些是幾個例子。我們還有其他5個單獨的用例,它們依靠我們的內部控制器來簡化日常操作并減少工作量。
我們還建立了一些CRD。通過聲明指定應使用哪些監視儀表板,其中之一已在當今廣泛用于在Grafana上生成監視儀表板。這使開發人員可以在其應用程序代碼庫旁邊嵌入其監視儀表板,并使用相同的工作流(kubectl apply -f)部署所有內容。。
我們正在大量看到控制者和CRD的好處。當我們與云供應商AWS緊密合作以簡化集群基礎架構操作時,我們就騰出了更多精力專注于構建“ Grofers Kubernetes平臺”,該平臺旨在以最佳方式支持我們的開發團隊。
原文鏈接:https://lambda.grofers.com/learnings-from-two-years-of-kubernetes-in-production-b0ec21aa2814