Kiada 套件中的三個服務中的每一個現在都利用一個Deployment物件進行部署。Kiada 和 Quote 服務各有三個副本,而 Quiz 服務只有一個,因為它的資料不允許它輕鬆擴展。 在本章中,您將學習如何正確部署和擴展有狀態工作負載,例如使用StatefulSet的 Quiz 服務。
在開始之前,建立kiada命名空間,切換到Chapter15/目錄並使用以下指令apply SETUP/目錄中的所有yaml:
<aside> 💡 本章中的範例假設物件是在Kiada命名空間中創建的。如果在不同地方建立它們,則必須在多個地方更新DNS domain名稱。
</aside>
在了解 StatefulSet 以及它們與Deployment有何不同之前,最好了解有狀態工作負載的需求與其無狀態對應物的需求有何不同。
有狀態工作負載是必須儲存和維護狀態才能運作的軟體。當工作負載重新啟動或重新搬遷時,必須保持此狀態。這使得有狀態的工作負載更難操作。
有狀態工作負載也更難擴展,因為您不能像無狀態工作負載那樣簡單地增加和刪除副本而不考慮它們的狀態。 如果副本可以讀取和寫入相同的檔案來共享狀態,那麼增加新副本不是問題。但是,要實現這一點,底層儲存技術必須支援它。 另一方面,如果每個副本都將它狀態儲存在自己擁有的檔案中,則您需要為每個副本分配一個單獨的volume。 使用您至今為止遇到的k8s資源,說起來容易做起來難。讓我們看看這兩個選項來了解與兩者相關的問題。
在k8s中, 您可以使用PV和ReadWriteMany存取模式來跨多個Pod共用資料。 但是,在大多數雲端環境中,底層儲存技術通常只支援ReadWriteOnce和ReadOnlyMany存取模式,不支援ReadWriteMany。 這表示您無法將volume以讀/寫模式掛載到多個節點上。因此,不同節點上的Pod無法讀寫同一個PV。
讓我們使用 Quiz 服務來展示這個問題。你可以將quiz Deployment擴展到三個副本嗎?讓我們看看發生了什麼。kubectl scale
指令如下:
$ kubectl scale deploy quiz --replicas 3
deployment.apps/quiz scaled
現在像這樣檢查 Pod:
$ kubectl get pods -l app=quiz
NAME READY STATUS RESTARTS AGE
quiz-6f4968457-2c8ws 2/2 Running 0 10m
quiz-6f4968457-cdw97 0/2 CrashLoopBackOff 1 (14s ago) 22s
quiz-6f4968457-qdn29 0/2 Error 2 (16s ago) 22s
如您所見,只有在scale-up之前存在的Pod正在運行,而兩個新Pod則沒有。根據您使用的叢集類型,這兩個Pod可能根本不啟動,或者它們可能啟動但立刻被終止並顯示錯誤訊息。 例如,在GKE中,Pod中的容器無法啟動,因為PV無法附加到新Pod,因為它的存取模式是ReadWriteOnce,並且volume不能同時附加到多個節點。 在 kind 建立的叢集中,容器會啟動,但mongo容器會失敗並且顯示錯誤訊息,如下:
$ kubectl logs quiz-6f4968457-cdw97 -c mongo
..."msg":"DBException in initAndListen, terminating","attr":{"error":"DBPathInUse: Unable to lock the lock file: /data/db/mongod.lock (Resource temporarily unavailable). Another mongod instance is already running on the /data/db directory"}}
錯誤訊息表明您不能在MongoDB的多個實例中使用相同的資料目錄。三個quiz Pod使用相同的目錄,因為它們都使用相同的PVC,因此也使用相同的PV,如下圖。
圖 15.1 Deployment中的所有Pod都使用相同的PVC和PV。
由於這種方法不能運作,另一種方法是為每個Pod副本使用單獨的PV。讓我們看看這表示什麼,以及您是否可以使用單個Deployment物件來做到這一點。
正如您在上一節中所了解的,MongoDB預設只支援單個實例。 如果要部署具有相同資料的多個MongoDB實例,則必須建立一個跨這些實例複製資料(replicates the data)的MongoDB副本集(replica set)(這裡的術語“副本集”是MongoDB特定的術語,並不是指k8s ReplicaSet資源)。 每個實例都需要自己的儲存volume和其他副本和客戶端可以用來連接到它的固定位址。因此,要在k8s中部署MongoDB副本集,您需要確保: