本文發表於一年多前。舊文章可能包含過時內容。請檢查頁面中的資訊自發布以來是否已變得不正確。

在 Kubernetes 上使用 StatefulSets 執行 MongoDB

傳統觀點認為你不能在容器中執行資料庫。“容器是無狀態的!”他們說,“沒有狀態的資料庫毫無意義!”

當然,這根本不是真的。在 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 和硬碟。目前有適用於 AWSAzureGoogle CloudGlusterFSOpenStack CindervSphereCeph RBDQuobyte 的驅動程式。

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"

祝您程式設計愉快!

想要了解更多 Kubernetes 和容器相關的精彩部落格文章,請在 TwitterMedium 上關注我。