如何在Kubernetes上扩展MongoDB

栏目: 数据库 · 发布时间: 5年前

内容简介:Kubernetes主要用于无状态应用程序。 但是,在1.3版本中引入了PetSets,之后它们演变为StatefulSets。 官方文档将StatefulSets描述为“StatefulSets旨在与有状态应用程序和分布式系统一起使用”。对此最好的用例之一是对数据存储服务进行编排,例如MongoDB,ElasticSearch,Redis,Zookeeper等。

如何在Kubernetes上扩展MongoDB

原文

Kubernetes主要用于无状态应用程序。 但是,在1.3版本中引入了PetSets,之后它们演变为StatefulSets。 官方文档将StatefulSets描述为“StatefulSets旨在与有状态应用程序和分布式系统一起使用”。

对此最好的用例之一是对数据存储服务进行编排,例如MongoDB,ElasticSearch,Redis,Zookeeper等。

我们可以把StatefulSets的特性归纳如下:

  1. 有序索引Pods
  2. 稳定的网络ID
  3. 有序并行的Pods管理
  4. 滚动更新

这些细节可以在 这里 找到。

StatefulSets的一个非常明显的特征是提供稳定网络ID,与 headless-services 一起使用时,功能可以更加强大。

我们不花费很多时间在Kubernetes文档中随时可以查看的信息,让我们专注于运行和扩展 MongoDB 集群。

您需要一个可以运行的Kubernetes群集并启用RBAC(推荐)。 在本教程中,我将使用GKE集群,但是,AWS EKS或Microsoft的AKS或Kops管理的K8S也是可行的替代方案。

我们将为MongoDB集群部署以下组件:

  1. 配置HostVM的Daemon Set
  2. Mongo Pods的Service Account和ClusterRole Binding
  3. 为Pods提供永久性存储SSDs的Storage Class
  4. 访问Mongo容器的Headless Service
  5. Mongo Pods Stateful Set
  6. GCP Internal LB: 从kubernetes集群外部访问MongoDB(可选)
  7. 使用Ingress访问Pod(可选)

值得注意的是,每个MongoDB Pod都会运行一个sidecar,以便动态配置副本集。Sidecar每5秒检查一次新成员。

Daemon Set for HostVM Configuration:

```yaml

kind: DaemonSet

apiVersion: extensions/v1beta1

metadata:

name: hostvm-configurer

labels:

app: startup-script

spec:

template:

metadata:

labels:

app: startup-script

spec:

hostPID: true

containers:

- name: hostvm-configurer-container

image: gcr.io/google-containers/startup-script:v1

securityContext:

privileged: true

env:

- name: STARTUP_SCRIPT

value: |

#! /bin/bash

set -o errexit

set -o pipefail

set -o nounset

# Disable hugepages

echo 'never' > /sys/kernel/mm/transparent_hugepage/enabled

echo 'never' > /sys/kernel/mm/transparent_hugepage/defrag

```

Configuration for ServiceAccount, Storage Class, Headless SVC and StatefulSet:

yaml

apiVersion: v1

kind: Namespace

metadata:

name: mongo

apiVersion: v1

kind: ServiceAccount

metadata:

name: mongo

namespace: mongo

apiVersion: rbac.authorization.k8s.io/v1beta1

kind: ClusterRoleBinding

metadata:

name: mongo

subjects:

- kind: ServiceAccount

name: mongo

namespace: mongo

roleRef:

kind: ClusterRole

name: cluster-admin

apiGroup: rbac.authorization.k8s.io

apiVersion: storage.k8s.io/v1beta1

kind: StorageClass

metadata:

name: fast

provisioner: kubernetes.io/gce-pd

parameters:

type: pd-ssd

fsType: xfs

allowVolumeExpansion: true

apiVersion: v1

kind: Service

metadata:

name: mongo

namespace: mongo

labels:

name: mongo

spec:

ports:

- port: 27017

targetPort: 27017

clusterIP: None

selector:

role: mongo

apiVersion: apps/v1beta1

kind: StatefulSet

metadata:

name: mongo

namespace: mongo

spec:

serviceName: mongo

replicas: 3

template:

metadata:

labels:

role: mongo

environment: staging

replicaset: MainRepSet

spec:

affinity:

podAntiAffinity:

preferredDuringSchedulingIgnoredDuringExecution:

- weight: 100

podAffinityTerm:

labelSelector:

matchExpressions:

- key: replicaset

operator: In

values:

- MainRepSet

topologyKey: kubernetes.io/hostname

terminationGracePeriodSeconds: 10

serviceAccountName: mongo

containers:

- name: mongo

image: mongo

command:

- mongod

- "--wiredTigerCacheSizeGB"

- "0.25"

- "--bind_ip"

- "0.0.0.0"

- "--replSet"

- MainRepSet

- "--smallfiles"

- "--noprealloc"

ports:

- containerPort: 27017

volumeMounts:

- name: mongo-persistent-storage

mountPath: /data/db

resources:

requests:

cpu: 1

memory: 2Gi

- name: mongo-sidecar

image: cvallance/mongo-k8s-sidecar

env:

- name: MONGO_SIDECAR_POD_LABELS

value: "role=mongo,environment=staging"

- name: KUBE_NAMESPACE

value: "mongo"

- name: KUBERNETES_MONGO_SERVICE_NAME

value: "mongo"

volumeClaimTemplates:

- metadata:

name: mongo-persistent-storage

annotations:

volume.beta.kubernetes.io/storage-class: "fast"

spec:

accessModes: [ "ReadWriteOnce" ]

storageClassName: fast

resources:

requests:

storage: 10Gi

关键点:

1. 应该使用适当的环境变量仔细配置Mongo的Sidecar,以及为pod提供的标签,和为deployment和service的命名空间。 有关sidecar容器的详细信息,请点击 此处

2. 默认缓存大小的指导值是:“50%的RAM减去1GB,或256MB”。 鉴于所请求的内存量为2GB,此处的WiredTiger缓存大小已设置为256MB。

3. Inter-Pod Anti-Affinity确保在同一个工作节点上不会安排2个Mongo Pod,从而使其能够适应节点故障。 此外,建议将节点保留在不同的可用区中,以便集群能够抵御区域故障。

4. 当前部署的Service Account具有管理员权限。 但是,它应该仅限于DB的命名空间。

上面提到的两个配置文件也可以在 这里 找到。

部署MongoDB集群

shell

kubectl apply -f configure-node.yml

kubectl apply -f mongo.yml

你可以通过以下命令查看所有组件状况:

shell

kubectl -n mongo get all
shell

root$ kubectl -n mongo get all

NAME                 DESIRED   CURRENT   AGE

statefulsets/mongo   3         3         3m

NAME         READY     STATUS    RESTARTS   AGE

po/mongo-0   2/2       Running   0          3m

po/mongo-1   2/2       Running   0          2m

po/mongo-2   2/2       Running   0          1m

NAME        TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)     AGE

svc/mongo   ClusterIP   None         <none>        27017/TCP   3m

如您所见,该服务没有Cluster-IP,也没有External-IP,它是Headless服务。 此服务将直接解析为StatefulSets的Pod-IP。

让我们来验证一下DNS解析。 我们在集群中启动了一个交互式shell:

shell

kubectl run my-shell --rm -i --tty --image ubuntu -- bash

root@my-shell-68974bb7f7-cs4l9:/# dig mongo.mongo +search +noall +answer

; <<>> DiG 9.11.3-1ubuntu1.1-Ubuntu <<>> mongo.mongo +search +noall +answer

;; global options: +cmd

mongo.mongo.svc.cluster.local. 30 IN A 10.56.7.10

mongo.mongo.svc.cluster.local. 30 IN A 10.56.8.11

mongo.mongo.svc.cluster.local. 30 IN A 10.56.1.4

服务的DNS规则是<服务名称>.<服务的命名空间>,因此,在我们的例子中看到的是mongo.mongo。

IPs(10.56.6.17,10.56.7.10,10.56.8.11)是我们的Mongo StatefulSets的Pod IPs。 这可以通过在集群内部运行nslookup来测试。

shell

root@my-shell-68974bb7f7-cs4l9:/# nslookup 10.56.6.17

17.6.56.10.in-addr.arpa name = mongo-0.mongo.mongo.svc.cluster.local.

root@my-shell-68974bb7f7-cs4l9:/# nslookup 10.56.7.10

10.7.56.10.in-addr.arpa name = mongo-1.mongo.mongo.svc.cluster.local.

root@my-shell-68974bb7f7-cs4l9:/# nslookup 10.56.8.11

11.8.56.10.in-addr.arpa name = mongo-2.mongo.mongo.svc.cluster.local.

如果您的应用程序部署在K8的群集中,那么它可以通过以下方式访问节点:

Node-0: mongo-0.mongo.mongo.svc.cluster.local:27017 

Node-1: mongo-1.mongo.mongo.svc.cluster.local:27017 

Node-2: mongo-2.mongo.mongo.svc.cluster.local:27017

如果要从集群外部访问mongo节点,你可以为每个pod部署内部负载平衡或使用Ingress Controller(如NGINX或Traefik)创建一个内部Ingress。

GCP Internal LB SVC Configuration (可选)

yaml

apiVersion: v1

kind: Service

metadata: 

  annotations: 

    cloud.google.com/load-balancer-type: Internal

  name: mongo-0

  namespace: mongo

spec: 

  ports: 

    - 

      port: 27017

      targetPort: 27017

  selector: 

    statefulset.kubernetes.io/pod-name: mongo-0

  type: LoadBalancer

为mongo-1和mongo-2也部署2个此类服务。

您可以将内部负载均衡的IP提供给MongoClient URI。

shell

root$ kubectl -n mongo get svc

NAME      TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)           AGE

mongo     ClusterIP      None            <none>        27017/TCP         15m

mongo-0   LoadBalancer   10.59.252.157   10.20.20.2    27017:30184/TCP   9m

mongo-1   LoadBalancer   10.59.252.235   10.20.20.3    27017:30343/TCP   9m

mongo-2   LoadBalancer   10.59.254.199   10.20.20.4    27017:31298/TCP   9m

mongo-0/1/2的外部IP是新创建的TCP负载均衡器的IP。 这些是您的子网或对等网络,如果有的话。

通过Ingress访问Pods(可选)

也可以使用诸如Nginx之类的Ingress Controller来定向到Mongo StatefulSets的流量。 确保ingress服务是内部服务,而不是通过PublicIP公开。 Ingress对象的配置看起来像这样:

yaml

...

spec:

  rules:

  - host: mongo.example.com

    http:

      paths:

      - path: '/mongo-0'

        backend:

          hostNames:

          - mongo-0

          serviceName: mongo # There is no extra service. This is the headless service.

          servicePort: '27017'

请务必注意,您的应用程序至少应该知道一个当前处于启动状态的mongo节点,这样可以发现所有其他节点。

我在本地mac上使用Robo 3T作为mongo客户端。 连接到其中一个节点后并运行rs.status(),您可以查看副本集的详细信息,并检查是否已配置其他2个Pods并自动连接到副本集。

rs.status()查看副本集名称和成员个数:

如何在Kubernetes上扩展MongoDB

每个成员都可以看到FQDN和状态。 此FQDN只能从群集内部访问。

如何在Kubernetes上扩展MongoDB

每个secondary成员正在同步到mongo-0,mongo-0是当前的primary。

如何在Kubernetes上扩展MongoDB

现在我们扩展mongo Pods的Stateful Set以检查新的mongo容器是否被添加到ReplicaSet。

shell

root$ kubectl -n mongo scale statefulsets mongo --replicas=4

statefulset "mongo" scaled

root$ kubectl -n mongo get pods -o wide

NAME      READY     STATUS    RESTARTS   AGE       IP           NODE

mongo-0   2/2       Running   0          25m       10.56.6.17   gke-k8-demo-demo-k8-pool-1-45712bb7-vfqs

mongo-1   2/2       Running   0          24m       10.56.7.10   gke-k8-demo-demo-k8-pool-1-c6901f2e-trv5

mongo-2   2/2       Running   0          23m       10.56.8.11   gke-k8-demo-demo-k8-pool-1-c7622fba-qayt

mongo-3   2/2       Running   0          3m        10.56.1.4    gke-k8-demo-demo-k8-pool-1-85308bb7-89a4

可以看出,所有四个pod都部署到不同的GKE节点,因此我们的Pod-Anti Affinity策略工作正常。

扩展操作还将自动提供持久卷,该卷将充当新pod的数据目录。

shell

root$ kubectl -n mongo get pvc

NAME                               STATUS    VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE

mongo-persistent-storage-mongo-0   Bound     pvc-337fb7d6-9f8f-11e8-bcd6-42010a940024   11G        RWO            fast           49m

mongo-persistent-storage-mongo-1   Bound     pvc-53375e31-9f8f-11e8-bcd6-42010a940024   11G        RWO            fast           49m

mongo-persistent-storage-mongo-2   Bound     pvc-6cee0f97-9f8f-11e8-bcd6-42010a940024   11G        RWO            fast           48m

mongo-persistent-storage-mongo-3   Bound     pvc-3e89573f-9f92-11e8-bcd6-42010a940024   11G        RWO            fast           28m

要检查名为mongo-3的pod是否已添加到副本集,我们将在同一节点上再次运行rs.status()并观察其差异。

对于同一个的Replicaset,成员数现在为4。

如何在Kubernetes上扩展MongoDB

新添加的成员遵循与先前成员相同的FQDN方案,并且还与同一主节点同步:

如何在Kubernetes上扩展MongoDB

进一步的考虑

  1. 给Mongo Pod的Node Pool打上合适的label并确保在StatefulSets和HostVM配置的DaemonSets的Spec中指定适当的Node Affinity会很有帮助。 这是因为DaemonSet将调整主机操作系统的一些参数,并且这些设置应仅限于MongoDB Pod。 没有这些设置,对其他应用程序可能会更好。
  2. 在GKE中给Node Pool打Label非常容易,可以直接从GCP控制台进行。
  3. 虽然我们在Pod的Spec中指定了CPU和内存限制,但我们也可以考虑部署VPA(Vertical Pod Autoscaler)。
  4. 可以通过实施网络策略或服务网格(如Istio)来控制从集群内部到我们的数据库的流量。

如果你已经看到这里,我相信你已经浏览了整个博文。 我试图整理很多分散的信息并将其作为一个整体呈现。 我的目标是为您提供足够的信息,以便开始使用Kubernetes上的Stateful Sets,并希望你们中的许多人觉得它很有用。 我们非常欢迎您提出反馈、意见或建议。:)


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Practical JavaScript, DOM Scripting and Ajax Projects

Practical JavaScript, DOM Scripting and Ajax Projects

Frank Zammetti / Apress / April 16, 2007 / $44.99

http://www.amazon.com/exec/obidos/tg/detail/-/1590598164/ Book Description Practical JavaScript, DOM, and Ajax Projects is ideal for web developers already experienced in JavaScript who want to ......一起来看看 《Practical JavaScript, DOM Scripting and Ajax Projects》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

URL 编码/解码
URL 编码/解码

URL 编码/解码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具