本文發表於一年多前。舊文章可能包含過時內容。請檢查頁面中的資訊自發布以來是否已變得不正確。
在 Kubernetes 上使用 StatefulSets 執行 MongoDB
警告
這篇帖子已有幾年歷史。程式碼示例需要修改才能在當前的 Kubernetes 叢集上執行。傳統觀點認為你不能在容器中執行資料庫。“容器是無狀態的!”他們說,“沒有狀態的資料庫毫無意義!”
當然,這根本不是真的。在 Google,一切都在容器中執行,包括資料庫。你只需要正確的工具。Kubernetes 1.5 包含了新的 StatefulSet API 物件(在之前的版本中,StatefulSet 被稱為 PetSet)。有了 StatefulSets,Kubernetes 讓執行有狀態工作負載(如資料庫)變得容易得多。
如果你閱讀過我之前的文章,你就會知道如何使用 Docker 建立一個 MEAN Stack 應用程式,然後 將其遷移到 Kubernetes 以提供更簡單的管理和可靠性,以及 建立 MongoDB 副本集 以提供冗餘和高可用性。
雖然我之前部落格文章中的副本集有效,但你還需要遵循一些煩人的步驟。你必須手動為每個副本建立一個磁碟、一個 ReplicationController 和一個服務。向上或向下擴充套件副本集意味著手動管理所有這些資源,這很容易出錯,並將使你的有狀態應用程式面臨風險。在前面的例子中,我們建立了一個 Makefile 來簡化這些資源的管理,但如果 Kubernetes 能為我們處理所有這些事情,那就太棒了。
有了 StatefulSets,這些麻煩終於消失了。你可以在 Kubernetes 中原生建立和管理你的 MongoDB 副本集,無需指令碼和 Makefile。讓我們看看如何實現。
注意:StatefulSets 目前是 Beta 資源。用於自動配置的sidecar 容器也不受支援。
先決條件和設定
在開始之前,你需要 Kubernetes 1.5+ 和 Kubernetes 命令列工具。如果你想按照本教程並在 Google Cloud Platform 上操作,你還需要 Google Cloud SDK。
建立 Google Cloud 專案並設定好 Google Cloud SDK 後(提示:gcloud init),我們就可以建立叢集了。
要建立 Kubernetes 1.5 叢集,請執行以下命令
gcloud container clusters create "test-cluster"
這將建立一個三節點的 Kubernetes 叢集。您可以根據需要自定義命令。
然後,登入到叢集
gcloud container clusters get-credentials test-cluster
設定 MongoDB 副本集
要設定 MongoDB 副本集,您需要三樣東西:一個 StorageClass、一個 無頭服務 (Headless Service) 和一個 StatefulSet。
我已經為這些建立了配置檔案,您可以從 GitHub 克隆示例
git clone https://github.com/thesandlord/mongo-k8s-sidecar.git
cd /mongo-k8s-sidecar/example/StatefulSet/
要建立 MongoDB 副本集,請執行以下兩個命令
kubectl apply -f googlecloud\_ssd.yaml
kubectl apply -f mongo-statefulset.yaml
就這樣!透過這兩個命令,您已經啟動了執行高可用和冗餘 MongoDB 副本集所需的所有元件。
從高層次來看,它看起來像這樣
讓我們更詳細地檢查每個部分。
StorageClass
儲存類(StorageClass)告訴 Kubernetes 資料庫節點使用哪種儲存。您可以在許多不同的環境中設定許多不同型別的 StorageClass。例如,如果您在自己的資料中心執行 Kubernetes,您可以使用 GlusterFS。在 GCP 上,您的儲存選擇是 SSD 和硬碟。目前有適用於 AWS、Azure、Google Cloud、GlusterFS、OpenStack Cinder、vSphere、Ceph RBD 和 Quobyte 的驅動程式。
StorageClass 的配置如下:
kind: StorageClass
apiVersion: storage.k8s.io/v1beta1
metadata:
name: fast
provisioner: kubernetes.io/gce-pd
parameters:
type: pd-ssd
此配置建立了一個名為“fast”的新 StorageClass,由 SSD 卷支援。StatefulSet 現在可以請求一個卷,StorageClass 將自動建立它!
部署此儲存類
kubectl apply -f googlecloud\_ssd.yaml
無頭服務 (Headless Service)
現在您已經建立了儲存類,您需要建立一個無頭服務。它們就像普通的 Kubernetes 服務,只是它們不為您做任何負載均衡。當與 StatefulSets 結合使用時,它們可以為您提供獨特的 DNS 地址,讓您可以直接訪問 Pod!這非常適合建立 MongoDB 副本集,因為我們的應用程式需要單獨連線到所有 MongoDB 節點。
無頭服務的配置如下:
apiVersion: v1
kind: Service
metadata:
name: mongo
labels:
name: mongo
spec:
ports:
- port: 27017
targetPort: 27017
clusterIP: None
selector:
role: mongo
您可以透過 clusterIP 設定為“None”來判斷這是一個無頭服務。除此之外,它看起來與任何普通的 Kubernetes Service 完全相同。
StatefulSet
壓軸大戲。StatefulSet 實際上執行 MongoDB 並將所有內容協調在一起。StatefulSet 與 Kubernetes ReplicaSet(不要與 MongoDB 副本集混淆!)在某些方面有所不同,使其更適合有狀態應用程式。與 Kubernetes ReplicaSet 不同,在 StatefulSet 下建立的 Pod 具有一些獨特的屬性。Pod 的名稱不是隨機的,而是每個 Pod 都有一個有序名稱。結合無頭服務,這使得 Pod 具有穩定的標識。此外,Pod 是一個接一個地建立,而不是一次性全部建立,這在引導有狀態系統時會有所幫助。您可以在文件中閱讀有關 StatefulSet 的更多資訊。
就像之前一樣,這個“邊車”容器將自動配置 MongoDB 副本集。“邊車”是一個輔助容器,它幫助主容器完成其工作。
StatefulSet 的配置如下:
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
name: mongo
spec:
selector:
matchLabels:
role: mongo
environment: test
serviceName: "mongo"
replicas: 3
template:
metadata:
labels:
role: mongo
environment: test
spec:
terminationGracePeriodSeconds: 10
containers:
- name: mongo
image: mongo
command:
- mongod
- "--replSet"
- rs0
- "--smallfiles"
- "--noprealloc"
ports:
- containerPort: 27017
volumeMounts:
- name: mongo-persistent-storage
mountPath: /data/db
- name: mongo-sidecar
image: cvallance/mongo-k8s-sidecar
env:
- name: MONGO_SIDECAR_POD_LABELS
value: "role=mongo,environment=test"
volumeClaimTemplates:
- metadata:
name: mongo-persistent-storage
spec:
storageClassName: "fast"
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 100Gi
有點長,但相當直接。
第一部分描述了 StatefulSet 物件。然後,我們進入元資料部分,您可以在其中指定標籤和副本數量。
接下來是 Pod 規範。`terminationGracePeriodSeconds` 用於在縮減副本數量時優雅地關閉 Pod,這對於資料庫非常重要!然後顯示兩個容器的配置。第一個容器執行 MongoDB,帶命令列標誌,配置副本集名稱。它還將持久儲存卷掛載到 `/data/db`,這是 MongoDB 儲存資料的位置。第二個容器執行 sidecar。
最後是 volumeClaimTemplates。這就是我們之前建立的 StorageClass 用來提供卷的。它將為每個 MongoDB 副本提供一個 100 GB 的磁碟。
使用 MongoDB 副本集
此時,您的叢集中應該已建立了三個 Pod。這些對應於您的 MongoDB 副本集中的三個節點。您可以使用以下命令檢視它們
kubectl get pods
NAME READY STATUS RESTARTS AGE
mongo-0 2/2 Running 0 3m
mongo-1 2/2 Running 0 3m
mongo-2 2/2 Running 0 3m
由無頭服務支援的 StatefulSet 中的每個 Pod 都將擁有一個穩定的 DNS 名稱。模板遵循以下格式:<pod-name>.<service-name>
這意味著 MongoDB 副本集的 DNS 名稱為
mongo-0.mongo
mongo-1.mongo
mongo-2.mongo
您可以在應用程式的連線字串 URI 中直接使用這些名稱。
在這種情況下,連線字串 URI 將是
mongodb://mongo-0.mongo,mongo-1.mongo,mongo-2.mongo:27017/dbname\_?
就是這樣!
擴充套件 MongoDB 副本集
StatefulSets 的一個巨大優勢是你可以像 Kubernetes ReplicaSets 一樣對其進行擴縮。如果你想要 5 個 MongoDB 節點而不是 3 個,只需執行擴縮命令
kubectl scale --replicas=5 statefulset mongo
sidecar 容器將自動配置新的 MongoDB 節點加入副本集。
將兩個新節點 (mongo-3.mongo & mongo-4.mongo) 包含在您的連線字串 URI 中,即可開始使用。太簡單了!
清理
要清理已部署的資源,請刪除 StatefulSet、無頭服務和已提供的卷。
刪除 StatefulSet
kubectl delete statefulset mongo
刪除服務
kubectl delete svc mongo
刪除卷
kubectl delete pvc -l role=mongo
最後,您可以刪除測試叢集
gcloud container clusters delete "test-cluster"
祝您程式設計愉快!