如何在Kubernetes上扩展MongoDB?

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/M2l0ZgSsVc7r69eFdTj/article/details/84453047

640


Kubernetes主要用于无状态应用程序。 但是,在1.3版本中引入了PetSets,之后它们演变为StatefulSets。 官方文档将StatefulSets描述为“StatefulSets旨在与有状态应用程序和分布式系统一起使用”。
对此最好的用例之一是对数据存储服务进行编排,例如MongoDB,ElasticSearch,Redis,ZooKeeper等。
我们可以把StatefulSets的特性归纳如下:
  1. 有序索引Pod

  2. 稳定的网络ID

  3. 有序并行的Pod管理

  4. 滚动更新


这些细节可以在这里[1]找到。
StatefulSets的一个非常明显的特征是提供稳定网络ID,与Headless Services[2]一起使用时,功能可以更加强大。
我们在Kubernetes文档中随时可以查看的信息上不会花费很多时间,让我们专注于运行和扩展MongoDB集群。
你需要一个可以运行的Kubernetes群集并启用RBAC(推荐)。 在本教程中,我将使用GKE集群,但是,AWS EKS或Microsoft的AKS或Kops管理的Kubernetes也是可行的替代方案。
我们将为MongoDB集群部署以下组件:
  1. 配置HostVM的Daemon Set

  2. Mongo Pod的Service Account和ClusterRole Binding

  3. 为Pod提供永久性存储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
 
  
  1. kind: DaemonSet

  2. apiVersion: extensions/v1beta1

  3. metadata:

  4.  name: hostvm-configurer

  5.  labels:

  6.    app: startup-script

  7. spec:

  8.  template:

  9.    metadata:

  10.      labels:

  11.        app: startup-script

  12.    spec:

  13.      hostPID: true

  14.      containers:

  15.      - name: hostvm-configurer-container

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

  17.        securityContext:

  18.          privileged: true

  19.        env:

  20.        - name: STARTUP_SCRIPT

  21.          value: |

  22.            #! /bin/bash

  23.            set -o errexit

  24.            set -o pipefail

  25.            set -o nounset

  26.            # Disable hugepages

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

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


Configuration for ServiceAccount, Storage Class, Headless SVC and StatefulSet
 
  
  1. apiVersion: v1

  2. kind: Namespace

  3. metadata:

  4.  name: mongo

  5. ---

  6. apiVersion: v1

  7. kind: ServiceAccount

  8. metadata:

  9.  name: mongo

  10.  namespace: mongo

  11. ---

  12. apiVersion: rbac.authorization.k8s.io/v1beta1

  13. kind: ClusterRoleBinding

  14. metadata:

  15.  name: mongo

  16. subjects:

  17.  - kind: ServiceAccount

  18.    name: mongo

  19.    namespace: mongo

  20. roleRef:

  21.  kind: ClusterRole

  22.  name: cluster-admin

  23.  apiGroup: rbac.authorization.k8s.io

  24. ---

  25. apiVersion: storage.k8s.io/v1beta1

  26. kind: StorageClass

  27. metadata:

  28.  name: fast

  29. provisioner: kubernetes.io/gce-pd

  30. parameters:

  31.  type: pd-ssd

  32.  fsType: xfs

  33. allowVolumeExpansion: true

  34. ---

  35. apiVersion: v1

  36. kind: Service

  37. metadata:

  38. name: mongo

  39. namespace: mongo

  40. labels:

  41.   name: mongo

  42. spec:

  43. ports:

  44. - port: 27017

  45.   targetPort: 27017

  46. clusterIP: None

  47. selector:

  48.   role: mongo

  49. ---

  50. apiVersion: apps/v1beta1

  51. kind: StatefulSet

  52. metadata:

  53.  name: mongo

  54.  namespace: mongo

  55. spec:

  56.  serviceName: mongo

  57.  replicas: 3

  58.  template:

  59.    metadata:

  60.      labels:

  61.        role: mongo

  62.        environment: staging

  63.        replicaset: MainRepSet

  64.    spec:

  65.      affinity:

  66.        podAntiAffinity:

  67.          preferredDuringSchedulingIgnoredDuringExecution:

  68.          - weight: 100

  69.            podAffinityTerm:

  70.              labelSelector:

  71.                matchExpressions:

  72.                - key: replicaset

  73.                  operator: In

  74.                  values:

  75.                  - MainRepSet

  76.              topologyKey: kubernetes.io/hostname

  77.      terminationGracePeriodSeconds: 10

  78.      serviceAccountName: mongo

  79.      containers:

  80.        - name: mongo

  81.          image: mongo

  82.          command:

  83.            - mongod

  84.            - "--wiredTigerCacheSizeGB"

  85.            - "0.25"

  86.            - "--bind_ip"

  87.            - "0.0.0.0"

  88.            - "--replSet"

  89.            - MainRepSet

  90.            - "--smallfiles"

  91.            - "--noprealloc"

  92.          ports:

  93.            - containerPort: 27017

  94.          volumeMounts:

  95.            - name: mongo-persistent-storage

  96.              mountPath: /data/db

  97.          resources:

  98.            requests:

  99.              cpu: 1

  100.              memory: 2Gi

  101.        - name: mongo-sidecar

  102.          image: cvallance/mongo-k8s-sidecar

  103.          env:

  104.            - name: MONGO_SIDECAR_POD_LABELS

  105.              value: "role=mongo,environment=staging"

  106.            - name: KUBE_NAMESPACE

  107.              value: "mongo"

  108.            - name: KUBERNETES_MONGO_SERVICE_NAME

  109.              value: "mongo"

  110.  volumeClaimTemplates:

  111.  - metadata:

  112.      name: mongo-persistent-storage

  113.      annotations:

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

  115.    spec:

  116.      accessModes: [ "ReadWriteOnce" ]

  117.      storageClassName: fast

  118.      resources:

  119.        requests:

  120.          storage: 10Gi


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

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

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

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


上面提到的两个配置文件也可以在这里[4]找到。
部署MongoDB集群
 
  
  1. kubectl apply -f configure-node.yml

  2. kubectl apply -f mongo.yml


你可以通过以下命令查看所有组件状况:
 
  
  1. root$ kubectl -n mongo get all

  2. NAME                 DESIRED   CURRENT   AGE

  3. statefulsets/mongo   3         3         3m

  4. NAME         READY     STATUS    RESTARTS   AGE

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

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

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

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

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


如你所见,该服务没有Cluster-IP,也没有External-IP,它是Headless服务。 此服务将直接解析为StatefulSets的Pod-IP。
让我们来验证一下DNS解析。 我们在集群中启动了一个交互式shell:
 
  
  1. kubectl run my-shell --rm -i --tty --image ubuntu -- bash

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

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

  4. ;; global options: +cmd

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

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

  7. 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来测试。
 
  
  1. root@my-shell-68974bb7f7-cs4l9:/# nslookup 10.56.6.17

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

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

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

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

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


如果你的应用程序部署在Kubernetes的群集中,那么它可以通过以下方式访问节点:
 
  
  1. Node-0: mongo-0.mongo.mongo.svc.cluster.local:27017

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

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


如果要从集群外部访问Mongo节点,你可以为每个Pod部署内部负载平衡或使用Ingress Controller(如NGINX或Traefik)创建一个内部Ingress。
GCP Internal LB SVC Configuration(可选)
 
  
  1. apiVersion: v1

  2. kind: Service

  3. metadata:

  4.  annotations:

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

  6.  name: mongo-0

  7.  namespace: mongo

  8. spec:

  9.  ports:

  10.    -

  11.      port: 27017

  12.      targetPort: 27017

  13.  selector:

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

  15.  type: LoadBalancer


为mongo-1和mongo-2也部署2个此类服务。
你可以将内部负载均衡的IP提供给MongoClient URI。
 
  
  1. root$ kubectl -n mongo get svc

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

  3. mongo     ClusterIP      None            <none>        27017/TCP         15m

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

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

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


mongo-0/1/2的外部IP是新创建的TCP负载均衡器的IP。 这些是您的子网或对等网络,如果有的话。
通过Ingress访问Pod(可选)
也可以使用诸如Nginx之类的Ingress Controller来定向到Mongo StatefulSets的流量。 确保Ingress服务是内部服务,而不是通过PublicIP公开。 Ingress对象的配置看起来像这样:
 
  
  1. ...

  2. spec:

  3.  rules:

  4.  - host: mongo.example.com

  5.    http:

  6.      paths:

  7.      - path: '/mongo-0'

  8.        backend:

  9.          hostNames:

  10.          - mongo-0

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

  12.          servicePort: '27017'


请务必注意,您的应用程序至少应该知道一个当前处于启动状态的Mongo节点,这样可以发现所有其他节点。
我在本地mac上使用Robo 3T作为mongo客户端。 连接到其中一个节点后并运行rs.status(),您可以查看副本集的详细信息,并检查是否已配置其他2个Pod并自动连接到副本集。 
640 rs.status()查看副本集名称和成员个数
640 每个成员都可以看到FQDN和状态。 此FQDN只能从群集内部访问。
640 每个secondary成员正在同步到mongo-0,mongo-0是当前的primary。
现在我们扩展mongo Pods的Stateful Set以检查新的Mongo容器是否被添加到ReplicaSet。
 
  
  1. root$ kubectl -n mongo scale statefulsets mongo --replicas=4

  2. statefulset "mongo" scaled

  3. root$ kubectl -n mongo get pods -o wide

  4. NAME      READY     STATUS    RESTARTS   AGE       IP           NODE

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

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

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

  8. 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的数据目录。
 
  
  1. root$ kubectl -n mongo get pvc

  2. NAME                               STATUS    VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE

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

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

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

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


要检查名为mongo-3的Pod是否已添加到副本集,我们将在同一节点上再次运行rs.status()并观察其差异。 
640 对于同一个的Replicaset,成员数现在为4。
640 新添加的成员遵循与先前成员相同的FQDN方案,并且还与同一主节点同步。
进一步的考虑
  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,并希望你们中的许多人觉得它很有用。 我们非常欢迎您提出反馈、意见或建议。:)
相关链接:

  1. https://kubernetes.io/docs/tutorials/stateful-application/basic-stateful-set/

  2. https://kubernetes.io/docs/concepts/services-networking/service/#headless-services

  3. https://github.com/cvallance/mongo-k8s-sidecar

  4. https://github.com/Thakurvaibhav/k8s/tree/master/databases/mongodb


原文链接:https://medium.com/@thakur.vaibhav23/scaling-mongodb-on-kubernetes-32e446c16b82


Kubernetes线下实战培训

640?


Kubernetes应用实战培训将于2018年12月21日在北京开课,3天时间带你系统学习Kubernetes 本次培训包括:容器特性、镜像、网络;Docker特性、架构、组件、概念、Runtime;Docker安全;Docker实践;Kubernetes架构、核心组件、基本功能;Kubernetes设计理念、架构设计、基本功能、常用对象、设计原则;Kubernetes的实践、运行时、网络、插件已经落地经验;微服务架构、DevOps等,点击下方图片查看详情。

640?

猜你喜欢

转载自blog.csdn.net/M2l0ZgSsVc7r69eFdTj/article/details/84453047
今日推荐