本文发表于一年多前。旧文章可能包含过时内容。请检查页面中的信息自发布以来是否已变得不正确。
在 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"
祝您编程愉快!