歡迎光臨
每天分享高質量文章

基於Docker和Kubernetes的最佳架構實踐

軟體開發領域在Docker和Kubernetes時代是如何變化的? 是否有可能使用這些技術搭建一勞永逸的架構? 當所有東西都被“打包”進容器中時,是否有可能統一開發及整合的流程? 這些決策的需求是什麼? 它們會帶來什麼限制? 它們會讓開發人員更輕鬆,或者相反,反而增加不必要的複雜性嗎?

現在是時候以文字和原始插圖方式闡明這些以及其他問題了!
這篇文章將帶您踏上從現實生活到開發流程再到架構最後回到現實生活的旅程,並一路為您解答在這些停靠站點上遇到的最重要問題。 我們將試圖確定一些應該成為架構一部分的元件和原則,並演示一些示例,但不會進入其實現領域。
文章的結論可能會讓你心煩意亂,或者無比開心,這一切都取決於你的經驗、你對這三章故事的看法,甚至在閱讀本文時你的心情。 在下麵可以發表評論或提出問題,讓我知道您的想法!


從現實生活到開發工作流

在大多數情況下,我所見過的或者很榮幸搭建的所有開發流程都只是為了一個簡單的標的——縮短從概念產生到交付生產環境之間的時間間隔,同時保持一定程度的程式碼質量。
想法的好壞無關緊要。 因為糟糕的想法來也匆匆,去也匆匆——你只要嘗試一下,就可以把它們丟進故紙堆裡。 這裡值得一提的是,從一個糟糕的想法回滾是可以落在自動化設施的肩膀上的,這可以自動化您的工作流程。
持續整合和交付看起來像是軟體開發領域的救命稻草。 究竟還有什麼比這更簡單呢? 如果你有一個想法,你有程式碼,那麼就去做吧! 如果不是輕微的問題,這將是完美無瑕的——整合和交付過程相對而言難以獨立於公司特有的技術和業務流程之外。
然而,儘管任務看起來很複雜,但在生活中不時會出現一些優秀的想法,這些想法可以讓我們(當然,我自己是確定的)更接近構建一個無瑕疵的並且幾乎可以在任何場合使用的機制。 對我來說,離這樣的機制最近的步驟是Docker和Kubernetes,他們的抽象層次和思想方法使我認為現在可以用幾乎相同的方法解決80%的問題。
其餘的20%的問題顯然還在原地踏步,但正因如此你才可以將你發自內心的創意天賦聚焦在有趣的工作上,而不是處理重覆的例行公事。 只要照料一次“架構框架”,就可以讓您忘掉已經解決的80%問題。
這一切意味著什麼?以及Docker是如何解決開發工作流程的問題的? 讓我們看一個簡單的過程,這對於大多數工作環境來說也足夠了:

透過適當的方法,您可以自動化並整合上面序列圖中的所有內容,併在未來幾個月內將其拋之腦後。


設定開發環境

一個專案應該包含一個docker-compose.yml檔案,這可以讓你省去考慮在本地機器上執行應用程式/服務需要做些什麼以及如何操作的問題。 一個簡單的命令docker-compose up應該啟動您的應用程式及其所有依賴項,使用fixtures填充資料庫,上傳容器內的原生代碼,啟用程式碼跟蹤以便即時編譯,並最終在期望的埠開始響應請求。 即使在設定新服務時,您也不必擔心如何啟動、在哪裡提交更改或使用哪個框架。 所有這些都應該提前在標準說明中描述,並由針對不同設定的服務模板指定:前端、後端和worker。


自動化測試

所有你想知道的關於“黑匣子”(至於為什麼我把容器稱之為如此的更多資訊,將在文章中的稍後部分闡明)的情況是,它裡面的一切都完好無損,是或否,1或0。您可以在容器內部執行有限數量的命令,而docker-compose.yml描述了它的所有依賴關係,您可以輕鬆自動化和整合這些測試,而不必過分關註實現細節。
比如,像這樣[1]!
在這裡,測試不僅意味著單元測試,還包括功能測試、整合測試、(程式碼樣式)測試和副本、檢查過時的依賴關係以及已使用軟體包的許可證正常與否等等。 關鍵是所有這些都應該封裝在Docker映象中。


系統交付

無論在何時何地想安裝您的專案都無所謂。 結果就像安裝行程一樣,應該始終如一。 至於您要安裝的是整個生態系統的哪個部分或者您將從哪個Git倉庫獲得程式碼也沒有區別。 這裡最重要的元件是冪等性。 唯一應該指定的是控制安裝過程的變數。
以下是我在解決這個問題時相當有效的演演算法:
從所有Dockerfiles收集映象(例如像這樣[2])
使用元專案,透過Kube API將這些映象交付給Kubernetes。 啟動交付通常需要幾個輸入引數:
  • Kube API端點

  • 一個“機密”物件,因不同的環境而異(本地/測試/預釋出/生產)

  • 要展示的系統名稱以及針對這些系統的Docker映象的標簽(在上一步中獲取)

作為一個涵蓋所有系統和服務的元專案的例子(換句話說,是一個描述生態系統如何編排以及如何交付更新的專案),我更願意使用Ansible playbooks,透過這個模組[3]來與Kube API整合。 然而,複雜的自動化可以參考其他選項,我稍後將詳細討論自己的選擇。 但是,您必須考慮中心化/統一的管理架構的方式。 這樣一個方式可以讓您方便、統一地管理所有服務/系統,並消除即將到來的執行類似功能的技術和系統叢林可能帶來的任何複雜情況。
通常,需要如下的安裝環境:
  • “測試”——用於對系統進行一些手動檢查或除錯

  • “預釋出”——用於近乎實時的環境以及與外部系統的整合(通常位於DMZ而不是測試環境)

  • “生產”——終端使用者的實際環境


整合和交付的連續性

如果你有一個統一的方式來測試Docker映象——或者“黑盒子”——你可以假設這些測試結果可以讓你無縫地(並且問心無愧)將功能分支整合到你的Git倉庫的上游或主分支中。
也許,這裡唯一的交易斷路器是整合和交付的順序。如果沒有發行版,那麼如何透過一組並行的功能分支阻止一個系統上的“競爭條件”?
因此,只有在沒有競爭的情況下才能開始這個過程,否則“競爭條件”會縈繞腦海:
  1. 嘗試將功能分支更新到上游(git rebase/ merge)

  2. 從Dockerfiles構建映象

  3. 測試所有構建的映象

  4. 開始並等待,直到系統交付了構建自步驟2的映象

  5. 如果上一步失敗,則將生態系統回滾到之前的狀態

  6. 在上游合併功能分支並將其傳送到儲存庫

在任何步驟中的任何失敗都應終止交付過程,並將任務傳回給開發人員以解決錯誤,無論是失敗的測試還是合併衝突。
您可以使用此過程來操作多個儲存庫。只需一次為所有儲存庫執行每個步驟(步驟1用於程式碼庫A和B,步驟2用於程式碼庫A和B等),而不是對每個單獨的儲存庫重覆執行整個流程(步驟1-6用於程式碼庫A ,步驟1-6用於程式碼庫B,等等)。
此外,Kubernetes允許您分批次地推出更新以進行各種AB測試和風險分析。 Kubernetes是透過分離服務(接入點)和應用程式在內部實現的。您可以始終以所需的比例平衡元件的新舊版本,以促進問題的分析併為潛在的回滾提供途徑。


系統回滾

架構框架的強制性要求之一是能夠回滾任何部署。反過來,這又需要一些顯式和隱式的細微差別。以下是其中最重要的一些事項:
  • 服務應該能夠設定其環境以及回滾更改。例如,資料庫遷移、RabbitMQ schema等等。

  • 如果無法回滾環境,則該服務應該是多型的,並支援舊版本和新版本的程式碼。例如:資料庫遷移不應該中斷舊版本的服務(通常是2或3個以前的版本)

  • 向後相容任何服務更新。通常,這是API相容性,訊息格式等。

在Kubernetes叢集中回滾狀態相當簡單(執行kubectl rollout undo deployment/some-deployment,Kubernetes將恢復先前的“快照”),但是為了讓此功能生效,您的元專案應包含有關此快照的資訊。但是更為複雜的交付回滾演演算法讓人望而生畏,儘管它們有時是必需的。
以下是可以觸發回滾機制的內容:
  • 釋出後應用程式錯誤的高比例

  • 來自關鍵監控點的訊號

  • 失敗的冒煙測試[4]

  • 手動樣式——人為因素


確保資訊保安和審計

沒有一個工作流程可以奇跡般地“搭建”刀槍不入的安全性並保護您的生態系統免受外部和內部威脅,因此您需要確保您的架構框架是在每個級別和所有子系統裡按照公司的標準和安全策略執行的。
我將在後面的關於監控和告警的章節討論有關解決方案的所有三個級別,它們本身也是系統完整性的關鍵。
Kubernetes擁有一套良好的針對訪問控制、網路策略、事件審計以及其他與資訊保安相關的強大工具的內建機制,可用於構建一個良好的防護邊界,以抵禦和阻止攻擊及資料洩露。


從開發流程到架構

應該認真考慮將開發流程與生態系統緊密整合的想法。將這種整合的需求新增到架構的傳統需求集(彈性、可伸縮性、可用性、可靠性、抵禦威脅等)中,可以大大提高架構框架的價值。 這是至關重要的一個方面,由此導致出現了一個名為“DevOps”(開發運維)的概念,這是實現基礎設施全面自動化並最佳化的合理步驟。 但是,如果有一個設計良好的架構和可靠的子系統,DevOps任務可以被最小化。


微服務架構

沒有必要詳細討論面向服務的架構——SOA[5]的好處,包括為什麼服務應該是“微”的。 我只會說,如果你決定使用Docker和Kubernetes,那麼你很可能理解(並接受)單體應用架構是很困難甚至根子上就是錯誤的。 Docker旨在執行一個行程並持久化,Docker讓我們聚焦於DDD框架(領域驅動開發)內進行思考。 在Docker中,打包後的程式碼被視為具有一些公開埠的黑盒子。


生態系統的關鍵元件和解決方案

根據我在設計具有更高可用性和可靠性的系統方面的經驗,有幾個元件對於微服務的運維是至關重要的,稍後我會列出並討論這些元件,我將在Kubernetes環境中取用它們,也可以參考我的清單作為其它任何平臺的檢查單。
如果你(像我一樣)會得出這樣的結論,即將這些元件作為常規的Kubernetes服務來管理,那麼我建議你在除“生產環境”之外的單獨叢集中執行它們。 比如“預釋出”叢集,因為它可以在生產環境不穩定並且你迫切需要其映象、程式碼或監控工具的來源時節省你的時間。 可以說,這解決了雞和雞蛋的問題。


身份認證

像往常一樣,它始於訪問——伺服器、虛擬機器、應用程式、辦公室郵件等。 如果您是或想成為主要的企業平臺(IBM、Google、Microsoft)之一的客戶,則訪問問題將由供應商的某個服務處理。 但是,如果您想擁有自己的解決方案,難道只能由您併在您的預算之內進行管理?
此串列[6]可幫助您確定適當的解決方案並估算設定和維護所需的工作量。 當然,您的選擇必須符合公司的安全政策並經資訊保安部門批准。


自動化服務配置

儘管Kubernetes在物理機器/雲虛擬機器(Docker、kubelet、kube proxy、etcd叢集)上只需要少量元件,但對於新機器的新增和叢集管理仍然需要自動化。 以下是一些簡單的方法:
  • KOPS——此工具允許您在兩個雲供應商(AWS或GCE)之一上安裝叢集

  • Teraform——這可以讓您管理任何環境的基礎設施,並遵循IAC(基礎架設施即程式碼)的思想

  • Ansible——用於任何型別的通用自動化工具

就個人而言,我更喜歡第三個選項(帶有一個Kubernetes的整合模組),因為它允許我使用伺服器和Kubernetes物件並執行任何型別的自動化。 但是,沒有什麼能阻止您使用Teraform及其Kubernetes模組。 KOPS在“裸機”方面效果不佳,但它仍然是與AWS/GCE一起使用的絕佳工具!


Git程式碼庫和任務跟蹤器

對於任何Docker容器,使其日誌可訪問的唯一方法是將它們寫入正在容器中執行的根行程的STDOUT或STDERR,服務開發人員並不關心日誌資料接下來的變化,而主要是它們應該在必要時可用,並且最好包含過去某個點的記錄。滿足這些期許的所有責任在於Kubernetes以及支援生態系統的工程師。
在官方檔案[7]中,您可以找到關於處理日誌的基本(和好的)策略的說明,這將有助於您選擇用於聚合和儲存大量文字資料的服務。
在針對日誌系統的推薦服務中,同一檔案提到fluentd用於收集資料(在叢集的每個節點上作為代理啟動時)以及用於儲存和索引資料的Elasticsearch。即使你可能不贊同這個解決方案的效率,但鑒於它的可靠性和易用性,我認為這至少是一個好的開始。
Elasticsearch是一個資源密集型的解決方案,但它可以很好地擴充套件並有現成的Docker映象,可以執行在單個節點以及所需大小的叢集上。


跟蹤系統

即使程式碼非常完美,然而還是會確實發生故障,接著你想在生產環境中非常仔細地研究它們,並試圖瞭解“如果在我的本地機器上一切工作正常,那麼在生產環境上究竟發生了什麼錯誤?”。比如緩慢的資料庫查詢、不正確的快取、較慢的磁碟或與外部資源的連線、生態系統中的交易,瓶頸以及規模不足的計算服務都是您不得不跟蹤和估算在實際負載下程式碼執行時間的一些原因。
Opentracing和Zipkin足以應付大多數現代程式語言的這一任務,並且在封裝程式碼之後不會增加額外的負擔。當然,收集到的所有資料應該儲存在適當的地方,並作為一個元件使用。
透過上述的開發標準和服務模板可以解決在封裝程式碼以及透過服務、訊息佇列、資料庫等轉發“Trace ID”時出現的複雜情況。後者也考慮到了方法的一致性。


監控和告警

Prometheus已經成為現代監控系統中事實上的標準,更重要的是,它在Kubernetes上獲得了開箱即用的支援。您可以參考官方Kubernetes檔案來瞭解更多關於監控和警報的資訊。
監控是必須安裝在叢集內的少數幾個輔助系統之一,叢集是一個受監控的物體。但是對於監控系統的監控(抱歉有些囉嗦)只能從外部進行(例如,從相同的“預釋出”環境)。在這種情況下,交叉檢查可作為一個針對任何分散式環境的便捷解決方案,這不會使高度統一的生態系統架構複雜化。
整個監控範圍可以分為三個完全邏輯隔離的層級。以下是我認為的在每個層級最重要的跟蹤點例子:
  • 物理層:網路資源及其可用性——磁碟(I/O,可用空間)——單個節點(CPU、RAM、LA)的基本資源

  • 叢集層:——每個節點上主集群系統的可用性(kubelet、kubeAPI、DNS、etcd等)——可用資源數量及其均勻分佈——允許的可用資源相對於服務消耗的實際資源的監控——pod的重新載入

  • 服務層:——任何型別的應用程式監控——從資料庫內容到API呼叫頻率——API閘道器上的HTTP錯誤數量——佇列大小和worker的利用率——資料庫的多個度量標準(複製延遲、事務的時間和數量、緩慢的請求等)——對非HTTP行程的錯誤分析——傳送到日誌系統請求的監控(可以將任何請求轉換為度量標準)

至於在每個層級的告警通知,我想推薦使用了無數次的其中一個外部服務,可以傳送通知電子郵件,簡訊或打電話給手機號碼。我還會提到另一個系統——OpsGenie[8]——它與Prometheus的alertmanaer是緊密整合的。
OpsGenie是一種彈性的告警工具,可幫助處理升級、全天候工作、通知渠道選擇等等。在團隊之間分發告警也很容易。例如,不同級別的監控應向不同的團隊/部門傳送通知:物理——Infra + Devops,叢集——Devops,應用程式——每一個相關的團隊。


API Gateway和單點登入

要處理諸如授權、認證、使用者註冊(外部使用者——公司客戶)和其他型別的訪問控制等任務,您需要高度可靠的服務,以保持與API Gateway的彈性整合。使用與“身份服務”相同的解決方案沒有什麼壞處,但是您可能需要分離這兩種資源以實現不同級別的可用性和可靠性。
內部服務的整合不應該很複雜,您的服務不應該擔心使用者和對方的授權和身份驗證。相反,架構和生態系統應該有一個處理所有通訊和HTTP流量的代理服務。
讓我們考慮一下最適合與API Gateway整合的方式,即整個生態系統——令牌。此方法適用於所有三種訪問方案:從UI、從服務到服務以及從外部系統。接著,接收令牌(基於登入名和密碼)的任務由使用者介面本身或服務開發人員完成。區分UI中使用的令牌的生命週期(較短的TTL)和其他情況(較長的和自定義的TTL)也是有意義的。
以下是API Gateway解決的一些問題:
  • 從外部和內部訪問生態系統服務(服務不直接相互通訊)

  • 與單點登入服務整合:令牌轉換和附加HTTPS請求,頭部包含所請求服務的使用者標識資料(ID、角色和其他詳細資訊)——根據從單點登入服務接收到的角色啟用/禁用對所請求服務的訪問控制

  • 針對HTTP流量的單點監控

  • 複合不同服務的API檔案(例如,複合Swagger的json/yml檔案[9])

  • 能夠根據域和請求的URI管理整個生態系統的路由

  • 用於外部流量的單一接入點,以及與接入供應商的整合


事件匯流排和企業整合/服務匯流排

如果您的生態系統包含數百個可在一個宏域中工作的服務,則您將不得不處理服務通訊的數千種可能方式。為了簡化資料流,您應該具備在發生特定事件時將資訊分發到大量收件人的能力,而不管事件的背景關係如何。換句話說,您需要一個事件匯流排來釋出基於標準協議的事件並訂閱它們。
作為事件匯流排,您可以使用任何可以操作所謂Broker的系統:RabbitMQ、Kafka、ActiveMQ等。一般來說,資料的高可用性和一致性對於微服務是至關重要的,但是由於CAP定理[10],您仍然不得不犧牲某些東西來實現匯流排的正確分佈和叢集化。
自然,事件匯流排應該能夠解決各種服務間通訊問題,但隨著服務數量從幾百個增加到幾千個甚至幾萬個,即使是最好的基於事件匯流排的架構也會望而卻步,您將需要尋找另一種解決方案。一個很好的例子就是整合匯流排方法,它可以擴充套件上述“Dumb管——智慧消費”策略的功能。
有幾十個使用“企業整合/服務匯流排[11]”方法的理由,其目的是減少面向服務架構的複雜性。以下是其中幾個理由:
  • 聚合多個訊息

  • 將一個事件拆分為幾個事件

  • 對於事件的系統響應的同步/事務分析

  • 介面的協調,這對於與外部系統的整合特別重要

  • 事件路由的高階邏輯

  • 與相同服務的多重整合(從外部和內部)

  • 資料匯流排的不可擴充套件中心化

作為企業整合匯流排的一款開源軟體,您可能需要考慮Apache ServiceMix[12],其中包含幾個對於此類SOA的設計和開發至關重要的元件。


資料庫和其他有狀態的服務

和Kubernetes一樣,Docker一次又一次地改變了所有用於需要資料持久化以及與磁碟緊密相關的服務的遊戲規則。有人說服務應該在物理伺服器或虛擬機器上以舊的方式“生存”。我尊重這一觀點,並且不會談論它的優點和缺點,但我相當肯定這種說法的存在僅僅是因為在Docker環境中暫時缺乏管理有狀態服務的知識、解決方案和經驗。
我還應該提到資料庫經常佔據儲存世界的中心位置,因此您選擇的解決方案應該完全準備好在Kubernetes環境中工作。
根據我的經驗以及市場情況,我可以區分以下幾組有狀態的服務以及每個服務最適合的Docker解決方案的示例:
  • 資料庫管理系統——PostDock是在任何Docker環境中PostgreSQL簡單可靠的解決方案

  • 佇列/訊息代理——RabbitMQ是構建訊息佇列系統和路由訊息的經典軟體。 RabbitMQ配置中的cluster_formation引數對於叢集設定是必不可少的

  • 高速快取服務——Redis被認為是最可靠和彈性的資料高速快取解決方案之一

  • 全文搜尋——我上面已經提到過的Elasticsearch技術棧,最初用於全文搜尋,但同樣擅長儲存日誌和任何具有大量文字資料的工作

  • 檔案儲存服務——用於任何型別的檔案儲存和交付(ftp,sftp等)的一般化服務組

依賴映象

如果您尚未遇到您需要的軟體包或依賴項已被刪除或暫時不可用的情況,請不要認為這種情況永遠不會發生。 為避免不必要的不可用性併為內部系統提供安全保護,請確保構建和交付服務都不需要Internet連線。 配置映象和複製所有的依賴項到內部網路:Docker映象、rpm包、原始碼庫、python/go/js/php模組。
這些以及其他任何型別的依賴關係都有自己的解決方案。 最常見的可以透過查詢“private dependency mirror for …”來Google搜尋。


從架構到真實生活

不管你喜不喜歡,你的整個架構命中註定遲早會難以為繼。它總是會發生:技術過時很快(1 – 5年),方法和方法論——有點慢(5 – 10年),設計原則和基礎——偶爾(10 – 20年),但終歸是不可避免的。
考慮到技術的過時,需要總是試圖讓自己的生態系統處於技術創新的高峰期,計劃並推出新的服務以滿足開發人員、業務和終端使用者的需求,向您的利益相關者推廣新的實用程式,交付知識來推動您的團隊和公司前進。
透過融入專業社群、閱讀相關文獻並與同事交流,保持自己處於生態鏈的頂端。註意專案中的新機會以及正確使用新趨勢。試驗並應用科學方法來分析研究結果,或依靠您信任和尊重的其他人的結論。
除非你是本領域的專家,否則很難為根本性的變化做好準備。我們所有人只會在我們的整個職業生涯中見證一些重大的技術變化,但並不是我們頭腦中的知識數量使得我們成為專業人士並讓我們攀登到頂峰的,而是我們思維的開放性以及接受蛻變的能力。
回到標題中的問題:“是否有可能搭建一個更好的架構?”。答案顯而易見:不,不是“一勞永逸”,但一定要在某種程度上積極爭取,在未來某個“很短的時間”,你一定會成功的!
相關連結:
  1. https://gist.github.com/paunin/3303c8cb8dd231f961c01c0b69188c59

  2. https://github.com/paunin/images-builder

  3. https://github.com/paunin/ansible-kubernetes-module

  4. https://en.wikipedia.org/wiki/Smoke_testing_%28software%29

  5. https://www.google.com/search?q=SOA

  6. https://en.wikipedia.org/wiki/List_of_single_sign-on_implementations

  7. https://kubernetes.io/docs/concepts/cluster-administration/logging/

  8. https://www.opsgenie.com/

  9. https://swagger.io/

  10. https://en.wikipedia.org/wiki/CAP_theorem

  11. https://en.wikipedia.org/wiki/Enterprise_service_bus

  12. http://servicemix.apache.org/

原文連結:https://hackernoon.com/the-best-architecture-with-docker-and-kubernetes-myth-or-reality-77b4f8f3804d

Kubernetes 實戰培訓

本次培訓內容包括:Docker容器的原理與基本操作;容器網路與儲存解析;Kubernetes的架構與設計理念詳解;Kubernetes的資源物件使用說明;Kubernetes 中的開放介面CRI、CNI、CSI解析;Kubernetes監控、網路、日誌管理;容器應用的開發流程詳解等,點選識別下方二維碼加微信好友瞭解具體培訓內容

3月23日開始上課,還剩最後5個名額,點選閱讀原文連結即可報名。
贊(0)

分享創造快樂