如何在Kubernetes上扩展MongoDB?

本文涉及的产品
传统型负载均衡 CLB,每月750个小时 15LCU
云数据库 MongoDB,独享型 2核8GB
推荐场景:
构建全方位客户视图
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
简介: Kubernetes主要用于无状态应用程序。 但是,在1.3版本中引入了PetSets,之后它们演变为StatefulSets。 官方文档将StatefulSets描述为“StatefulSets旨在与有状态应用程序和分布式系统一起使用”。
Kubernetes主要用于无状态应用程序。 但是,在1.3版本中引入了PetSets,之后它们演变为StatefulSets。 官方文档将StatefulSets描述为“StatefulSets旨在与有状态应用程序和分布式系统一起使用”。

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

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


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

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

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

我们在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

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

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集群

kubectl apply -f configure-node.yml
kubectl apply -f mongo.yml

你可以通过以下命令查看所有组件状况:
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:
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来测试。
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.


如果你的应用程序部署在Kubernetes的群集中,那么它可以通过以下方式访问节点:
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(可选)

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。
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访问Pod(可选)

也可以使用诸如Nginx之类的Ingress Controller来定向到Mongo StatefulSets的流量。 确保Ingress服务是内部服务,而不是通过PublicIP公开。 Ingress对象的配置看起来像这样:
...
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个Pod并自动连接到副本集。
01.jpeg

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

02.jpeg

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

03.jpeg

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

现在我们扩展mongo Pods的Stateful Set以检查新的Mongo容器是否被添加到ReplicaSet。
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的数据目录。
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()并观察其差异。
04.jpeg

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

05.jpeg

新添加的成员遵循与先前成员相同的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,并希望你们中的许多人觉得它很有用。 我们非常欢迎您提出反馈、意见或建议。:)

本文转自DockOne-如何在Kubernetes上扩展MongoDB?

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
17天前
|
弹性计算 人工智能 Serverless
阿里云ACK One:注册集群云上节点池(CPU/GPU)自动弹性伸缩,助力企业业务高效扩展
在当今数字化时代,企业业务的快速增长对IT基础设施提出了更高要求。然而,传统IDC数据中心却在业务存在扩容慢、缩容难等问题。为此,阿里云推出ACK One注册集群架构,通过云上节点池(CPU/GPU)自动弹性伸缩等特性,为企业带来全新突破。
|
25天前
|
NoSQL 安全 Linux
MongoDB PHP 扩展
10月更文挑战第19天
12 0
MongoDB PHP 扩展
|
2月前
|
存储 监控 NoSQL
*MongoDB的水平扩展主要通过分片技术实
*MongoDB的水平扩展主要通过分片技术实
44 5
|
2月前
|
存储 监控 NoSQL
MongoDB的水平扩展能力
MongoDB的水平扩展能力
49 5
|
2月前
|
存储 监控 负载均衡
MongoDB的水平扩展能力
MongoDB的水平扩展能力
55 3
|
6月前
|
存储 负载均衡 NoSQL
MongoDB分片技术:实现水平扩展的利器
【4月更文挑战第30天】MongoDB的分片技术是应对数据增长和复杂业务需求的解决方案,它将数据水平拆分存储在多个实例上,实现数据库的水平扩展。分片带来水平扩展性、负载均衡、高可用性和灵活的数据管理。分片工作涉及mongos路由进程、config server和shard实例。设置分片包括部署配置服务器、添加分片、启动mongos、配置分片键和开始分片。选择合适的分片键和有效管理能确保系统性能和稳定性。
|
3月前
|
存储 Kubernetes NoSQL
k8s快速创建MongoDB
k8s快速创建MongoDB
|
3月前
|
Kubernetes 负载均衡 算法
如何在kubernetes中实现分布式可扩展的WebSocket服务架构
如何在kubernetes中实现分布式可扩展的WebSocket服务架构
70 1
|
4月前
|
Kubernetes 持续交付 Python
Kubernetes(通常简称为K8s)是一个开源的容器编排系统,用于自动化部署、扩展和管理容器化应用程序。
Kubernetes(通常简称为K8s)是一个开源的容器编排系统,用于自动化部署、扩展和管理容器化应用程序。
|
6月前
|
NoSQL Linux 网络安全
【专栏】在 RHEL 8 或者 CentOS 8 上顺利安装并运行MongoDB,以处理非结构化数据和扩展技术栈
【4月更文挑战第28天】本文档介绍了如何在RHEL或CentOS 8上安装MongoDB,包括环境准备(系统更新、依赖安装、硬件需求和sudo用户)、导入MongoDB GPG公钥、创建Yum仓库、安装MongoDB社区版,以及后续的基本配置和验证(启动服务、防火墙设置和连接验证)。通过这些步骤,用户可以顺利安装并运行MongoDB,以处理非结构化数据和扩展技术栈。
263 1