使用StatefulSet在Kubernetes上运行MongoDB

编者注:今天的帖子由Google Cloud Platform开发人员倡导者Sandeep Dinesh撰写,展示了如何在容器中运行数据库。

警告: 这个帖子已经有好几年了。这些代码示例需要更改才能在当前的Kubernetes集群上工作。

传统观点认为,您不能在容器中运行数据库。 “容器是无状态的!”他们说,“没有状态的数据库毫无意义!”

当然,这根本不是真的。在Google,一切都在包含数据库的容器中运行。您只需要正确的工具。 Kubernetes 1.5 包括新 有状态集 API对象(在以前的版本中,StatefulSet被称为PetSet)。借助StatefulSets,Kubernetes使运行有状态工作负载(例如数据库)变得更加容易。

如果您按照我以前的帖子进行操作,就会知道如何创建一个 带有Docker的MEAN Stack应用, 然后 迁移到Kubernetes 提供更轻松的管理和可靠性,以及 创建一个MongoDB副本集 提供冗余和高可用性。

在我上一篇博客文章中设置的副本有效的同时,您需要执行一些令人讨厌的步骤。您必须手动为每个副本创建磁盘,ReplicationController和服务。缩放设置意味着要手动管理所有这些资源,这是一个出错的机会,并且会使您的状态应用程序处于风险中。在前面的示例中,我们创建了一个Makefile来简化对这些资源的管理,但是如果Kubernetes能够为我们解决所有这些问题,那就太好了。

使用StatefulSets,这些头痛终于消失了。您可以在Kubernetes中本地创建和管理MongoDB副本集,而无需脚本和Makefile。让我们看看如何。

注意:StatefulSets当前是一个beta资源。的 边柜 用于自动配置的也不支持。

先决条件和设置

在开始之前,您需要安装Kubernetes 1.5+和 Kubernetes命令行工具。如果您想按照本教程进行操作并使用Google Cloud Platform,则还需要 谷歌云 SDK.

一旦你有一个 谷歌云项目已创建 并设置好您的Google Cloud SDK(提示:gcloud init),我们可以创建集群。

要创建Kubernetes 1.5集群,请运行以下命令:

gcloud container clusters create "test-cluster"

这将构成一个三节点的Kubernetes集群。随意地 自定义命令 如您所见。

然后,对集群进行身份验证:

gcloud container clusters get-credentials test-cluster

设置MongoDB副本集

要设置MongoDB副本集,您需要三件事:A 存储类, 一种 无头服务有状态集.

我已经为它们创建了配置文件,您可以从GitHub克隆示例:

git clone //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副本集所需的所有组件。

从高层次看,它看起来像这样:

让我们更详细地研究每件作品。

存储类

存储类告诉Kubernetes用于数据库节点的存储类型。您可以在大量不同的环境中设置许多不同类型的StorageClass。例如,如果您在自己的数据中心中运行Kubernetes,则可以使用 GlusterFS。在GCP上,您的 存储选择 是SSD和硬盘。当前有驱动程序 AWS, 蔚蓝, 谷歌云, GlusterFS, OpenStack煤渣, 的vSphere, Ceph RBD兆字节.

存储类的配置如下所示:

kind: 存储类
apiVersion: storage.k8s.io/v1beta1
metadata:
 name: fast
provisioner: kubernetes.io/gce-pd
parameters:
 type: pd-ssd

此配置将创建一个称为“快速”的新StorageClass,该类由SSD卷支持。 有状态集现在可以请求一个卷,并且StorageClass将自动创建它!

部署此StorageClass:

kubectl apply -f googlecloud\_ssd.yaml

无头服务

现在,您已经创建了存储类,您需要进行无头服务。这些就像普通的Kubernetes服务一样,除了它们不为您做任何负载平衡。与StatefulSets结合使用时,它们可以为您提供唯一的DNS地址,使您可以直接访问吊舱!这对于创建MongoDB副本集非常理想,因为我们的应用程序需要单独连接到所有MongoDB节点。

无头服务的配置如下所示:

apiVersion: v1
kind: Service
metadata:
  name: mongo
  labels:
    name: mongo
spec:
  ports:
    - port: 27017
      targetPort: 27017
  clusterIP: None
  selector:
    role: mongo

您可以说这是无头服务,因为clusterIP设置为“无”。除此之外,它看起来与任何普通的Kubernetes服务完全相同。

有状态集

抵抗之城。 有状态集实际上运行MongoDB并将所有内容编排在一起。状态集不同于Kubernetes 副本集 (不要与MongoDB副本集混淆!),使它们更适合有状态应用程序。与Kubernetes 副本集不同,在StatefulSet下创建的Pod具有一些唯一的属性。吊舱的名称不是随机的,而是每个吊舱都有一个序数名称。结合无头服务,可以使吊舱具有稳定的标识。此外,可以一次创建一个Pod,而不是一次创建一个Pod,这对引导有状态系统很有帮助。您可以在中阅读有关StatefulSet的更多信息。 文件资料.

就像从前一样, 这个“边车”的容器 将自动配置MongoDB副本集。 “边车”是一个辅助容器,可以帮助主容器完成其工作。

有状态集的配置如下所示:

apiVersion: apps/v1beta1
kind: 有状态集
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保存其数据的位置)。第二个容器运行边车。

最后,还有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

Each pod in a 有状态集 backed by a 无头服务 will have a stable DNS name. The template follows this format: <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副本集

有状态集s的一个巨大优势是您可以像Kubernetes 副本集一样扩展它们。如果要使用5个MongoDB节点而不是3个,只需运行scale命令:

kubectl scale --replicas=5 statefulset mongo

sidecar容器将自动配置新的MongoDB节点以加入副本集。

在您的连接字符串URI中包含两个新节点(mongo-3.mongo和mongo-4.mongo),您很高兴。太容易了!

打扫干净

要清理已部署的资源,请删除StatefulSet,Headless Service和预配置的卷。

删除StatefulSet:

kubectl delete statefulset mongo

删除服务:

kubectl delete svc mongo

删除卷:

kubectl delete pvc -l role=mongo

最后,您可以删除测试集群:

gcloud container clusters delete "test-cluster"

快乐黑客!

有关更酷的Kubernetes和Container博客文章,请关注我 推特.

-Google Cloud Platform开发倡导者Sandeep Dinesh。