最近閒了點,寫個大活:部署Dotnet應用到K8s。
寫在前邊的話
一直想完成這個主題。但這個主題實在太大了,各種拖延症的小宇宙不時爆發一下,結果就拖到了現在。
這個主題,會是一個系列。在這個系列中,我會討論將應用部署到K8s時需要的各個內容和知識,以及各種刨過的坑。
為了避免這個系列被擴得過大,我不深入討論K8s的技術,也不去解釋如何建立K8s叢集之類的問題。這個主題會側重在開發人員方面,側重於如何開發適合K8s的應用,以及在K8s上部署。
另外,這個主題也不會關注Docker。在我看來,Docker是一個附加技術,而不是必要內容。
在專案中,是否需要使用K8s,算是一個問題。從各個方面來看,很多中大型的專案都傾向於往這個方面去做,但我們必須清楚,使用K8s增加了專案的複雜度。如果構建的是一個獨立的應用程式,那用K8s實在沒有必要。而即便是一個大的系統,其實也沒有必要從開頭就加入K8s。
本主題中的內容大多來自我自己部署Dotnet Core到K8s叢集的經驗。如果有任何問題,可以在評論中告訴我。
為防止非授權轉發,這兒給出本文的原文連結:https://www.cnblogs.com/tiger-wang/p/13956098.html
K8s(Kubernetes)面向開發的元件
前邊說了,這個主題我們僅關注部署應用程式相關的部分,而不討論K8s的全部。
面向開發,面向部署,我們需要了解下面幾個概念:
- 節點(Node)
- Pod
- 部署(Deployment)
- 服務(Service)
- 入口(Ingress)
這幾個概念,是整個內容的基礎。
1. 節點(Node)
在K8s中,Node對應的是虛擬機器或物理硬體,是K8s實際執行容器的地方。
一般來說,有兩類節點:
- 主節點(Master),用來執行所有的控制級(Control-plane)服務。主節點也可以執行應用程式,但一般來說,主節點只處理控制管理服務,不執行工作負載。
- 其它節點,用來執行真正的應用程式。一個節點可以執行多個應用程式或應用程式容器。
一個典型的K8s叢集會像下面圖中的樣子:
當然,在實際應用中,看K8s的規模。必要時,也可以做成單機,主節點執行控制服務的同時,也執行應用程式。
在叢集中,節點越多,可以執行的應用或容器就越多,節點當機時的容錯能力也就越大。
2. Pod
K8s中最小的管理單元,不是一個個獨立的容器,而是Pod。
要在K8s中執行應用程式,需要將其打包到一個容器(通常是Docker容器)中,並讓K8s執行它。Pod是可以讓K8s執行的最小單元。它包含一個或多個容器。當一個Pod被建立或銷燬時,它裡面的所有容器也會被建立或銷燬。
在網上,很多的文章都介紹說:如果有一個依賴於資料庫的應用,那應該把應用容器和資料庫容器部署在同一個Pod中,以便同步建立或銷燬。
以我的經驗來說,這個說法很不準確,而且容易造成對K8s應用的誤解。在K8s的實際應用中,只包含單個容器的Pod會更常用,也更好用。就好像“支付API”或“訂單API”這樣的,每個API都有不同的擴充套件需求、部署要求和迭代速度,因此單獨設定Pod給它們是非常合理的。同樣,資料庫容器也應該部署在獨立的Pod中,因為它與應用/服務/API會有不同的生命週期。
還有一個比較常用的是SideCar模式,就是在一個Pod下的主容器旁邊部署“SIdeCar“容器,用來充當代理,為主應用程式進行身份證認處理,或服務發現,以及服務通訊,甚至能充當應用效能監控的接收器來用。
一個典型的節點下的Pod是下面的樣子:
再重申一下:一個節點下面可以有多個Pod。一個Pod在K8s中會作為一個整體單元進行排程。一個Pod可能包含一個容器,也可能包含多個容器。容器用於部署應用或API。
3. 部署
在我的概念中,K8s主要做了兩件事:
- 管理容器的生存期
- 管理容器之間的通訊
K8s的部署,主要完成的是第一件事,即管理容器的生存週期。所以,部署可以看做是定義K8s如何部署Pod以及如果管理Pod的一組規則。
比方,我們可能這樣定義一個部署:
- Pod包含支付API應用Docker映像的一個例項;
- 我們要執行這個Pod的三個副本
- 保證每個容器至少有200Mb的可用記憶體,並限制它最多不超過400Mb;
- 當我們部署Pod新版本時,採用滾動更新策略
定義完後,K8s就會嚴格執行這個規則。如果應用崩潰了,K8s會刪除Pod並安排一個新的Pod,以保證規則規定的副本數量。如果Pod需要更多記憶體,K8s會選擇一個執行容器較少的節點上執行它,或者結束並重新部署它。當應用更新一個新版本時,K8s會建立一個新的部署,來替換舊版本,並將執行轉到新的版本。
當然,上面這個例子做了一定的簡化。不過,基本上K8s的基本工作就是這麼做的。
這裡的關鍵就是:部署定義了規則,K8s在這個部署的整個生命週期中維護並保持這個規則。
4. 服務
前面說過,部署可以用來建立跨多個節點(Node)的Pod的多個副本。這其實就是K8s提高效能及提高可用性的主要原理。
服務是應用對外的部分,供其它API去呼叫。而在K8s內部,服務可以看作是Pod在叢集內的負載均衡器。當我們建立部署時,通常還會建立一個與該應用的Pod關聯的服務。
在上面的例子中,當我們建立部署時,也會建立一個“Payment API”的服務,供其它API呼叫。
而當其它Pod需要與這個支付API的Pod通訊時,實際不會與支付API的一個Pod直接聯絡,而是將請求發給服務,然後由服務將請求傳遞給某一個Pod的例項。
這個過程參見下面的圖:
服務與網路相關。因此,服務有多種不同的網路模式。這裡不詳細說了,只拿一個常用的模式舉個例子:
K8s將服務分配到一個DNS記錄,並通過這個記錄將請求從一個Pod轉發到另一個Pod。
假設我們有一個支付服務,而我們的購買服務需要呼叫這個服務。K8s不需要知道Pod的真實IP,我們只需要分配一個DNS記錄給服務:
payment-api.xxx.local
通過這個域名,購買服務可以呼叫支付服務,而不需要知道支付服務對應的Pod的真正IP。
這個工作方式與Dotnet體系完全一樣。通過這種方式,可以實現對資源的邏輯分組,這是題外話。
5. 入口
入口與服務很像,但有本質的不同。
服務本質上是K8s叢集內部的東西,用來實現Pod之間的內部呼叫。而入口將HTTP/HTTPS從叢集外部路由到內部的服務,這樣,外部應用,例如前端、APP或小程式就可以通過這個入口,呼叫內部服務來處理請求。
同時,入口也可以當成提供外部負載均衡,即跨多個節點平衡對給定服務的請求。
除此之外,入口也可以提供其它一些特性,例如主機名或基於路徑的路由。通常,我們可以為每個應用或API配置一個入口。
還有,入口設定也可以用來做應用的反向代理。例如通過一個Nginx例項來配置入口。這都是可以的,而且這樣的方式,可以讓API隱藏在反向代理之後,而不用直接暴露在外網。這個部分,在後面的文章,我會專門寫。
總結一下
這篇文章是這個系列的一個引子。
當我們在K8s中部署一個Dotnet Core的應用時,我們需要配置Pod部署,新增服務來在K8s內部公開這些Pod,並新增一個入口來公開服務。
本系列的後續文章中,我會從開發的各個環節來解釋如何使用這些元件來部署Dotnet Core應用到K8s。
敬請關注!!!
(未完待續)
微信公眾號:老王Plus 掃描二維碼,關注個人公眾號,可以第一時間得到最新的個人文章和內容推送 本文版權歸作者所有,轉載請保留此宣告和原文連結 |