在Kubernetes上扩展MongoDB,这样可以吗?

本文涉及的产品
云数据库 MongoDB,通用型 2核4GB
简介: Kubernetes主要用于无状态应用程序。 但是,在1.3版本中引入了PetSets,之后它们演变为StatefulSets。 官方文档将StatefulSets描述为“StatefulSets旨在与有状态应用程序和分布式系统一起使用”。

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

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

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

有序索引Pod

稳定的网络ID

有序并行的Pod管理

滚动更新

这些细节可以在这里[1]找到。

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

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

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

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

配置HostVM的Daemon Set

Mongo Pod的Service Account和ClusterRole Binding

为Pod提供永久性存储SSDs的Storage Class

访问Mongo容器的Headless Service

Mongo Pods Stateful Set

GCP Internal LB:从Kubernetes集群外部访问MongoDB(可选)

使用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:mongosubjects:  -
 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:           - mongo           -"--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

关键点:

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

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

Inter-Pod Anti-Affinity确保在同一个工作节点上不会安排2个Mongo Pod,从而使其能够适应节点故障。 此外,建议将节点保留在不同的可用区中,以便集群能够抵御区域故障。
当前部署的Service Account具有管理员权限。 但是,它应该仅限于DB的命名空间。
上面提到的两个配置文件也可以在这里[4]找到。

部署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
; <<>>DiG9.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.local30 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.1010.7.56.10.in-addr.arpa name = mongo-1.mongo.
mongo.svc.cluster.local.
root@my-shell-68974bb7f7-cs4l9:/# nslookup 10.56.8.1111.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并自动连接到副本集。
image

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


image

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


image

每个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           

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

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


image

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

进一步的考虑

给Mongo Pod的Node Pool打上合适的label并确保在StatefulSets和HostVM配置的DaemonSets的Spec中指定适当的Node Affinity会很有帮助。 这是因为DaemonSet将调整主机操作系统的一些参数,并且这些设置应仅限于MongoDB Pod。 没有这些设置,对其他应用程序可能会更好。

在GKE中给Node Pool打Label非常容易,可以直接从GCP控制台进行。

虽然我们在Pod的Spec中指定了CPU和内存限制,但我们也可以考虑部署VPA(Vertical Pod Autoscaler)。

可以通过实施网络策略或服务网格(如Istio)来控制从集群内部到我们的数据库的流量。

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

原文发布时间为:2018-12-13
本文作者: kelvinji2009 译
本文来自云栖社区合作伙伴“ 数据和云”,了解相关信息可以关注“OraNews”微信公众号

相关实践学习
容器服务Serverless版ACK Serverless 快速入门:在线魔方应用部署和监控
通过本实验,您将了解到容器服务Serverless版ACK Serverless 的基本产品能力,即可以实现快速部署一个在线魔方应用,并借助阿里云容器服务成熟的产品生态,实现在线应用的企业级监控,提升应用稳定性。
云原生实践公开课
课程大纲 开篇:如何学习并实践云原生技术 基础篇: 5 步上手 Kubernetes 进阶篇:生产环境下的 K8s 实践 相关的阿里云产品:容器服务&nbsp;ACK 容器服务&nbsp;Kubernetes&nbsp;版(简称&nbsp;ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情:&nbsp;https://www.aliyun.com/product/kubernetes
相关文章
|
3月前
|
运维 Kubernetes Cloud Native
OpenKruise是一个基于Kubernetes的扩展套件
OpenKruise是一个基于Kubernetes的扩展套件【1月更文挑战第14天】【1月更文挑战第68篇】
19 2
|
4月前
|
Kubernetes 负载均衡 Cloud Native
猿创征文|云原生|kubernetes二进制1.18单master扩展为多master
猿创征文|云原生|kubernetes二进制1.18单master扩展为多master
53 0
|
弹性计算 Kubernetes 安全
在K8S上部署可扩展的基于Occlum的安全推理实例
机密计算是指通过在基于硬件的可信执行环境(TEE)中执行计算来保护数据应用中的隐私安全,是目前最火热的隐私保护技术之一。在云上运行TEE应用也得到了云厂商的广泛支持,包括阿里云,微软Azure云,都提供了基于SGX技术的机密安全实例服务。用户可以在这些云上申请带SGX支持的安全实例,然后部署自己的机密安全服务,既可以避免隐私数据泄露,也无需操心繁琐的基础架构层的配置。无论哪种云,最流行的分布式部署
在K8S上部署可扩展的基于Occlum的安全推理实例
|
21天前
|
Kubernetes API 调度
总结归纳Kubernetes | 一站式速查知识,助您轻松驾驭容器编排技术(水平扩展控制)
总结归纳Kubernetes | 一站式速查知识,助您轻松驾驭容器编排技术(水平扩展控制)
45 0
|
2月前
|
监控 关系型数据库 MySQL
利用容器编排工具实现员工电脑监控软件系统的横向扩展
随着企业规模的不断扩大,员工电脑监控软件系统的横向扩展成为一项迫切的需求。为了更有效地管理和监控员工的工作环境,容器编排工具的运用成为一种值得考虑的解决方案。在本文中,我们将探讨如何利用容器编排工具实现监控软件系统的横向扩展,并通过一些实际的代码示例来说明。
175 0
|
5月前
|
Kubernetes Cloud Native 测试技术
在云计算平台上部署Kubernetes:无缝管理和弹性扩展
Kubernetes已成为云计算平台上部署和管理容器化应用程序的首选解决方案。无论您选择使用Google Cloud Platform(GCP)、Amazon Web Services(AWS)、Microsoft Azure或其他云计算提供商,Kubernetes都为您提供了一种灵活、可移植且可扩展的方式来管理容器化应用程序。本文将深入探讨如何在云计算平台上部署Kubernetes,并为您提供一些实际的示例。
|
8月前
|
存储 Kubernetes Cloud Native
全面掌握 Kubernetes:部署、管理和扩展云原生应用
Kubernetes 是一个强大的云原生应用部署、管理和扩展平台,提供了丰富的功能和工具。通过本文的介绍,您应该能够了解 Kubernetes 的基本概念、核心组件,以及如何使用 Kubernetes 部署、管理和扩展云原生应用。同时,了解到 Kubernetes Dashboard 作为一个图形化工具,可以更方便地管理集群中的资源和应用程序。在实际应用中,深入学习和实践 Kubernetes 将有助于更好地掌握云原生应用的部署和管理。
185 1
全面掌握 Kubernetes:部署、管理和扩展云原生应用
|
9月前
|
Kubernetes NoSQL 持续交付
使用Terraform/Ansible/Kubernetes在阿里云上自动部署MongoDB
Terraform, Ansible, Kubernetes, MongoDB, AliCloud
290 1
|
9月前
|
存储 Kubernetes NoSQL
Kubernetes在AliCloud上部署并优化MongoDB
Kubernetes, 阿里云, MongoDB, 优化
194 0
|
9月前
|
运维 负载均衡 Kubernetes
基于 Stork 和 Quarkus 扩展 Kubernetes 服务发现
在传统的单体架构中,应用程序已经通过静态主机名、IP 地址和端口知道后端服务的存在位置。IT运维团队为服务可靠性和系统稳定性维护静态配置。自从微服务开始在分布式网络系统中运行以来,其维护发生了显著变化。之所以发生这种变化,是因为微服务需要与多个后端服务进行通信,以提高负载均衡和服务弹性。
83 0