Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >在 Kubernetes 上编排 MongoDB 集群

在 Kubernetes 上编排 MongoDB 集群

作者头像
我是阳明
发布于 2020-08-11 03:55:57
发布于 2020-08-11 03:55:57
4.6K00
代码可运行
举报
文章被收录于专栏:k8s技术圈k8s技术圈
运行总次数:0
代码可运行

无状态应用在 Kubernetes 中的使用非常方便,但是对于一些有状态应用部署还是相对较麻烦,虽然也有单独的 StatefulSets 资源对象来处理有状态应用,但是毕竟不具有通用性,有状态应用的编排和具体的应用息息相关,比如 MongoDB、ElasticSearch、Redis、Zookeeper 等应用。我们这里不再对 StatefulSets 的具体使用展开介绍了,将通过部署一个可扩展的 MongoDB 集群为例进行说明。

首先我们运行一个 DaemonSet 的控制器来管理节点,禁用巨页,因为 MongoDB 是建议关闭掉 Transparent Hugepage 的,否则可能导致性能下降,内存锁,甚至系统重启等问题,当然最好的还是只调整 MongoDB 的 Pod 所在的节点:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# hostvm-ds.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: hostvm-configurer
  labels:
    app: startup-script
spec:
  selector:
    matchLabels:
      app: startup-script
  template:
    metadata:
      labels:
        app: startup-script
    spec:
      hostPID: true
      containers:
      - name: hostvm-configurer
        image: cnych/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

然后配置 ServiceAccount、Headless SVC 和 StatefulSet,资源清单文件如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# mongo.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: v1
kind: Service
metadata:
 name: mongo
 namespace: mongo
 labels:
   name: mongo
spec:
 ports:
 - port: 27017
   targetPort: 27017
 clusterIP: None
 selector:
   role: mongo
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mongo
  namespace: mongo
spec:
  serviceName: mongo
  replicas: 3
  selector:
    matchLabels:
      role: mongo
      environment: staging
  template:
    metadata:
      labels:
        role: mongo
        environment: staging
        replicaset: MainRepSet
    spec:
      affinity:
        podAntiAffinity:  # 添加 Pod 反亲和性,将副本打散在不同的节点
          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:4.0
          command:
            - mongod
            - "--wiredTigerCacheSizeGB"
            - "0.25"
            - "--bind_ip"
            - "0.0.0.0"
            - "--replSet"
            - MainRepSet
            - "--smallfiles"
            - "--noprealloc"
          ports:
            - containerPort: 27017
          volumeMounts:
            - name: mongo-data
              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-data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: rook-ceph-block  # 提供一个可用的 Storageclass
      resources:
        requests:
          storage: 10Gi

这里我们给 Mongo 的 Pod 添加了一个 sidecar 容器,主要用于副本集的配置,该 sidecar 会每5s检查一次新成员。通过几个环境变量配置指定了 Pod 的标签、命名空间和 Service。

为了保证应用的稳定性,我们通过 podAntiAffinity 指定了 Pod 的反亲和性,这样可以保证不会有两个副本出现在同一个节点上。

此外需要提供一个可用的 StorageClass,这样可以保证不同的副本数据持久化到不同的 PV。

直接运行上面的两个资源清单文件即可:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ kubectl apply -f hostvm-ds.yaml
$ kubectl apply -f mongo.yaml

部署完成后可以通过如下命令检查应用运行状态:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ kubectl -n mongo get all
kubectl -n mongo get all
NAME          READY   STATUS              RESTARTS   AGE
pod/mongo-0   2/2     Running             0          28m
pod/mongo-1   2/2     Running             0          23m
pod/mongo-2   2/2     Running             0          16m

NAME            TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)     AGE
service/mongo   ClusterIP   None         <none>        27017/TCP   51m

NAME                     READY   AGE
statefulset.apps/mongo   3/3     28m

由于我们这里的 Service 是无头服务,没有 ClusterIP,也没有 ExternalIP,这个 Service 会直接解析到 Pod 的 IP 列表,当应用完全部署到 Kubernetes 集群上后,我们就可以按照不同的节点来进行访问了:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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 部署一些内部的负载均衡器,或者使用 nginx-ingress、traefik 这些 Ingress 控制器来创建 Ingress 暴露出去。

我们集群中部署了 Traefik v2.2 版本,该版本是支持 TCP 服务的,我们可以通过创建一个如下所示的 IngressRoute 对象来暴露 mongo 服务:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# ingressroute-tcp.yaml
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRouteTCP
metadata:
  name: mongo
  namespapce: mongo
spec:
  entryPoints:
  - mongo  # 需要通过静态方式开启 mongo 的入口点
  routes:
  - match: HostSNI(`*`)
    services:
    - name: mongo
      port: 27017

由于 Traefik 暴露 TCP 服务需要 SNI 的支持,我们这里没有指定特定的域名,所以需要通过一个专门的入口点 mongo 来暴露,需要在 Traefik 中声明并开启这个入口点,类似于下面的这样静态配置:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
......
- name: mongo
  containerPort: 27017
  hostPort: 27017
args:
- --entryPoints.mongo.address=:27017
......

直接运行上面的 IngressRouteTCP 对象即可:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ kubectl apply -f ingressroute-tcp.yaml -n mongo

需要注意的是,应用程序至少要知道一个当前正在运行的 mongo 节点,这样才可以发现所有其他节点。

我这里本地是 Mac 系统,使用的是 Robo 3T 作为 mongo 客户端,连接到其中一个节点并运行 rs.status() 后,我们可以查看到副本集的详细信息,并检查其他两个 Pod 是否被配置并自动连接到副本集上。

rs.status() 显示副本集名称和成员数量

在成员列表中也可以看到每个成员的 FQDN 名称和状态,不过需要注意的是 FQDN 只能在 Kubernetes 集群内部访问:

FQDN 名称和状态

现在我们可以对 Mongo 进行扩容,以检查新的 Pod 是否被添加到副本集中去:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ kubectl -n mongo scale statefulsets mongo --replicas=4
statefulset.apps/mongo scaled
$ kubectl -n mongo get pods -o wide
NAME      READY   STATUS    RESTARTS   AGE     IP             NODE         NOMINATED NODE   READINESS GATES
mongo-0   2/2     Running   0          32m     10.244.8.29    ydzs-node6   <none>           <none>
mongo-1   2/2     Running   0          27m     10.244.7.175   ydzs-node5   <none>           <none>
mongo-2   2/2     Running   0          20m     10.244.2.175   ydzs-node2   <none>           <none>
mongo-3   2/2     Running   0          4m29s   10.244.3.95    ydzs-node3   <none>           <none>

由于上面我们配置了 Pod 的反亲和性,但是是软策略,所以4个 Pod 会经量分散到不同的节点上。扩容后同样新的 Pod 也会自动提供一个持久券:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ kubectl -n mongo get pvc
NAME                 STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS      AGE
mongo-data-mongo-0   Bound    pvc-ac306842-f6a9-413c-bf92-576dd6a3b092   10Gi       RWO            rook-ceph-block   56m
mongo-data-mongo-1   Bound    pvc-d319e5d2-ac99-4a2b-898c-feb4bdf0f256   10Gi       RWO            rook-ceph-block   27m
mongo-data-mongo-2   Bound    pvc-fc8ded1d-0649-4b64-963e-0b9e2fc1f27d   10Gi       RWO            rook-ceph-block   21m
mongo-data-mongo-3   Bound    pvc-762b4b91-432e-4409-8d8f-e3e809d6a159   10Gi       RWO            rook-ceph-block   4m51s

现在我们再去Robo 3T 客户端重新执行 rs.status() 检查新的 Pod 是否被添加到副本集中了:

已经变成4个成员了

新增的 Pod 与之前的成员都采用相同的 FQDN 方案,并同步到同一个 Primary 节点去。

到这里我们就成功地将 MongoDB 部署到了 Kubernetes 集群,而且还是可伸缩的。后续我们还可以考虑针对应用部署 VPA,或者增加一些网络策略或 Istio 来控制应用,当然这种方式整体来说是可行的,但是可维护性还不是非常高,如果可以,我们应该去根据自己的业务需求开发对应的 Operator,或者使用第三方高质量的 Operator 来编排 MongoDB。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-08-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 k8s技术圈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
vue3知识点:readonly 与 shallowReadonly
<font color='red'>如果使用readonly包裹的person对象的所有属性数据</font>都只读不可需改,即name、age、salary都只读无法修改。
刘大猫
2024/10/31
990
1小时构建Vu3知识体系-之工程化构建&响应式数据
要开启你的 Vue 之旅,最重要的是少走弯路,用最快的方式掌握从Node.js环境安装、基于Vite创建项目,再到单文件组件的定义和推荐项目结构。和方才兄一起来搞定这些基础吧,让你的 Vue 开发之路不再迷茫!
方才编程_公众号同名
2024/11/13
1460
1小时构建Vu3知识体系-之工程化构建&响应式数据
vue3知识点:自定义hook函数
答案:请看官方文档: https://v3.cn.vuejs.org/guide/composition-api-introduction.html
刘大猫
2024/10/31
1630
vue3知识点:响应式数据的判断
1.《vue3第三章》其它 Composition API(不常用,了解即可),包括shallowReactive 与 shallowRef、readonly 与 shallowReadonly等等
刘大猫
2024/10/31
1250
vue3知识点:reactive函数
答案:请看官方文档: https://v3.cn.vuejs.org/guide/composition-api-introduction.html
刘大猫
2024/10/31
1830
vue3知识点:Teleport组件
<font color='red'> 答案:</font>Teleport 是一种能够将我们的<strong style="color:#DD5145">组件html结构</strong>移动到指定位置的技术。
刘大猫
2024/10/30
2470
vue3 day4
vue3中依然可以使用v2的配置方式来定义生命周期钩子,但是有两个生命周期更改了名字
花花522
2023/03/07
2810
vue3 day4
vue3知识点:provide 与 inject
<font color='red'>provide函数:用于给自己的后代组件传递参数</font>
刘大猫
2024/10/31
1790
Vue3学习笔记
①性能的提升 打包大小减少41%、初次渲染快55%,更新渲染快133%,内存减少54%…… ②源码的升级
玖柒的小窝
2021/09/29
8920
Vue3学习笔记
简单说一下vue3中的那些晦涩难懂的概念(ref、reactive、unref、isRef、toRef、toRefs、shallowRef、triggerRef、custormRef)
何处锦绣不灰堆
2023/12/13
3370
简单说一下vue3中的那些晦涩难懂的概念(ref、reactive、unref、isRef、toRef、toRefs、shallowRef、triggerRef、custormRef)
最全系列的vue3入门教程『图文并茂』
Vue 3 是一个流行的开源JavaScript框架,用于构建用户界面和单页面应用。它带来了许多新特性和改进,包括更好的性能、更小的打包大小、更好的TypeScript支持、全新的组合式 API,以及一些新的内置组件。
linwu
2023/07/27
5.5K0
最全系列的vue3入门教程『图文并茂』
vue3 day02
reactive 作用: 定义一个对象类型的响应式数据(基本类型不要用它,要用ref函数) 语法: const 代理对象 = reactive(源对象) 接收一个对象(或数组),返回一个代理对象(Proxy的实例对象,简称proxy对象) reactive定义的响应式数据是深层次的 内部基于es6的proxy实现的,通过代理对象操作源对象内部数据进行操作 如果使用reactive来定义基本类型,会有如下报错 let number = reactive(666) 使用reactive代理ref 避免.v
花花522
2023/03/07
2580
vue3 day02
vue3知识点:ref函数
答案:请看官方文档: https://v3.cn.vuejs.org/guide/composition-api-introduction.html
刘大猫
2024/10/31
2790
通过10个实例小练习,快速入门熟练 Vue3 核心新特性
Vue3.0 发 beta 版都有一段时间了,正式版也不远了,所以真的要学习一下 Vue3.0 的语法了。
夜尽天明
2020/05/13
1.3K0
❤️[前端学习]大数据全栈工程师之一文快速上手vue3❤️
大家好,我是ChinaManor,直译过来就是中国码农的意思,我希望自己能成为国家复兴道路的铺路人,大数据领域的耕耘者,平凡但不甘于平庸的人。暑假给自己在家附近找了份实习,作为初级码农,啥都得懂点,于
Maynor
2021/08/25
1.6K0
Vue3基础
官方文档:https://cli.vuejs.org/zh/guide/creating-a-project.html#vue-create
六个周
2022/10/28
1.1K0
Vue3基础
面试官:你了解过Vue3吗?(Vue3知识点汇总)
vue3已成今年趋势,据我了解很多公司在今年都有计划将技术栈从vue2升级至vue3。所以在今年的金三银四过程中vue3也一定会是面试的大热门。在这里我汇总整理一些vue3必会知识点,持续更新,感谢关注!
inline705
2022/03/01
4.4K0
面试官:你了解过Vue3吗?(Vue3知识点汇总)
vue3简易入门剖析
,发音同 “veet”)是一种新型前端构建工具,能够显著提升前端开发体验。它主要由两部分组成:
张哥编程
2024/12/13
4930
快速使用Vue3最新的15个常用API
之前我写了一篇博客介绍了Vue3的新特性,简单了解了一下Vue3都有哪些特色,并且在文末带大家稍微体验了一下Vue3中 Compsition API 的简单使用
若川
2020/12/15
3.4K0
快速使用Vue3最新的15个常用API
【初学者笔记】整理的一些Vue3知识点
拒绝标题党,哈哈哈,看完你就基本可以上手搞开发了,本文适合Vue初学者,或者Vue2迁移者,当然还是建议Vue3官网完全过一遍。不适合精通原理,源码的大佬们。
一尾流莺
2022/12/10
2.4K0
【初学者笔记】整理的一些Vue3知识点
推荐阅读
相关推荐
vue3知识点:readonly 与 shallowReadonly
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验