MongoDB(四)安装Mongo副本集
- July 28, 2023

本文将指导您在 Kubernetes 环境中搭建 MongoDB 副本集。MongoDB 副本集是为了确保数据持久性和高可用性,即使在节点故障或迁移后,仍能恢复数据。
文章首先介绍了使用 NFS 存储为 MongoDB 提供稳定的后端存储,然后创建持久卷和部署 MongoDB 服务。接着,您将了解如何配置副本集,将多个 Pod 实例组建成集群。最后,为了增强安全性,我们会创建 root 用户。通过这些步骤,您可以在 Kubernetes 上成功建立一个可靠的、高可用的 MongoDB 副本集,为您的应用程序提供强大的数据库支持。跟随本文,轻松搭建稳定高效的 MongoDB 副本集,让您的数据管理更加可靠。
配置NFS
NFS 存储主要是为了给 MongoDB 提供稳定的后端存储,当 MongoDB 的 Pod 发生故障重启或迁移后,依然能获得原先的数据。
/etc/exports
文件是用于配置 NFS(Network File System)共享的配置文件。NFS 是一种在网络上共享文件系统的协议,允许不同的计算机共享文件,就像这些文件是本地文件一样。NFS 提供了一种简单且有效的方法,使多个计算机可以共享文件,并且这些文件对其他计算机可读可写。
在 Linux 系统中,/etc/exports
文件定义了要共享的文件系统和共享选项。每行描述一个共享,包含以下格式:
<共享目录> <允许访问的主机列表>(选项)
其中:
<共享目录>
:指定要共享的目录路径。<允许访问的主机列表>
:指定可以访问该共享目录的主机列表。可以使用 IP 地址或主机名。(选项)
:指定额外的共享选项,如读写权限、同步方式等。
当 NFS 服务启动时,它会读取 /etc/exports
文件,并根据其中的配置提供共享服务,允许其他计算机访问和操作指定的共享目录。通过在 /etc/exports
中定义共享,管理员可以灵活地控制网络上共享的文件系统,实现文件的共享和访问管理。
- 选择一台主机作为 NFS 存储,首先执行如下命令安装 NFS:
yum -y install nfs-utils
yum -y install rpcbind
- 接着要创建共享文件夹,因为本次要搭建一个主节点,两个副本节点的副本集。所以我们执行如下命令创建 3 个文件夹:
mkdir -p /usr/local/k8s/mongodb/pv1
mkdir -p /usr/local/k8s/mongodb/pv2
mkdir -p /usr/local/k8s/mongodb/pv3
- 编辑**/etc/exports**文件,往里面添加
echo "/usr/local/k8s/mongodb/pv1 *(rw,sync,no_root_squash)" >> /etc/exports
echo "/usr/local/k8s/mongodb/pv2 *(rw,sync,no_root_squash)" >> /etc/exports
echo "/usr/local/k8s/mongodb/pv3 *(rw,sync,no_root_squash)" >> /etc/exports
- 保存退出后执行如下命令重启服务:如果执行
systemctl restart rpcbind
systemctl restart nfs
systemctl enable nfs
- 执行
exportfs -v
命令可以显示出所有的共享目录:
[root@dev-cce-24693-23he5 ~]# exportfs -
/usr/local/k8s/mongodb/pv1
<world>(sync,wdelay,hide,no_subtree_check,sec=sys,rw,secure,no_root_squash,no_all_squash)
/usr/local/k8s/mongodb/pv
<world>(sync,wdelay,hide,no_subtree_check,sec=sys,rw,secure,no_root_squash,no_all_squash)
/usr/local/k8s/mongodb/pv3
<world>(sync,wdelay,hide,no_subtree_check,sec=sys,rw,secure,no_root_squash,no_all_squash
- 为保证副本集的每个pod被调度到任意节点均可用,需要在集群上的所有 Node 节点上需要执行如下命令安装
nfs-utils
客户端:
yum -y install nfs-util
- 然后其他的 Node 节点上可执行如下命令(ip 为 NFS IP)查看 Master 节点上共享的文件夹:
showmount -e 10.168.12.196
[root@dev-cce-24693-23he5 ~]# showmount -e 10.168.12.196
Export list for 10.168.12.196:
/usr/local/k8s/mongodb/pv3 *
/usr/local/k8s/mongodb/pv2 *
/usr/local/k8s/mongodb/pv1 *
创建持久卷
- 创建一个名为
mongodb-pv.yaml
的文件。
以上下YAML 文件部分描述了 Kubernetes 中用于创建三个 PersistentVolume(PV)的配置。PersistentVolume 是 Kubernetes 中用于持久化存储数据的对象,它可以独立于 Pod 存在,并且可以在多个 Pod 之间共享数据。在这个配置中,每个 PV 都使用 NFS(Network File System)来提供存储。
注意:配置里的 IP 地址改成实际 NFS 主机地址。
#创建第1个PV
apiVersion: v1
kind: PersistentVolume
metadata:
name: mongodb-pv1
labels:
app: mongodb
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
storageClassName: mongodb-storage
nfs:
server: 10.168.12.196
path: "/usr/local/k8s/mongodb/pv1"
persistentVolumeReclaimPolicy: Retain
---
#创建第2个PV
apiVersion: v1
kind: PersistentVolume
metadata:
name: mongodb-pv2
labels:
app: mongodb
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
storageClassName: mongodb-storage
nfs:
server: 10.168.12.196
path: "/usr/local/k8s/mongodb/pv2"
persistentVolumeReclaimPolicy: Retain
---
#创建第3个PV
apiVersion: v1
kind: PersistentVolume
metadata:
name: mongodb-pv3
labels:
app: mongodb
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
storageClassName: mongodb-storage
nfs:
server: 10.168.12.196
path: "/usr/local/k8s/mongodb/pv3"
persistentVolumeReclaimPolicy: Retain
这些 YAML 配置用于创建三个不同的 PersistentVolume(mongodb-pv1、mongodb-pv2 和 mongodb-pv3),每个 PV 的容量为 1Gi,访问模式为 ReadWriteOnce,表示它们只能被单个 Pod 以读写模式挂载。存储类名称为 mongodb-storage,用于将这些 PV 分类到相同的存储类。每个 PV 使用 NFS 作为后端存储,NFS 服务器的 IP 地址为 10.168.12.196,分别映射到服务器上的三个不同目录(/usr/local/k8s/mongodb/pv1、/usr/local/k8s/mongodb/pv2 和 /usr/local/k8s/mongodb/pv3)。此外,persistentVolumeReclaimPolicy 设置为 Retain,表示在 PV 对象被删除后,其底层的存储资源不会被自动回收。
这些 PV 的创建使得 MongoDB 在 Kubernetes 集群中的三个 Pod 可以共享这些持久化的存储资源,从而实现数据的稳定存储和高可用性。这在 MongoDB 构建副本集(Replica Set)时尤为重要,因为它们需要共享相同的数据并保持一致性。
- 创建pv并且查看pv
kubectl apply -f mongodb-pv.yaml
[root@dev-cce-24693-23he5 ~]# kubectl get pv | grep mongo
mongodb-pv1 1Gi RWO Retain Bound dev-1-344183902174187520/mongdb-persistent-storage-mongodb-0 mongodb-storage 86d
mongodb-pv2 1Gi RWO Retain Bound dev-1-344183902174187520/mongdb-persistent-storage-mongodb-2 mongodb-storage 86d
mongodb-pv3 1Gi RWO Retain Bound dev-1-344183902174187520/mongdb-persistent-storage-mongodb-1 mongodb-storage 86
部署mongo服务
-
创建一个名为
mongodb-sts.yaml
的文件。YAML 配置文件通过 StatefulSet 部署有状态的 MongoDB 副本集,使用 PersistentVolume 存储数据,并通过 Service 暴露服务供内部和外部访问。这样,就能在 Kubernetes 上快速搭建一个可靠的 MongoDB 副本集环境。
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mongodb
spec:
selector:
matchLabels:
app: mongodb
serviceName: "mongodb-hs"
replicas: 3
template:
metadata:
labels:
app: mongodb
spec:
terminationGracePeriodSeconds: 10
containers:
- name: mongodb
image: swr.cn-north-4.myhuaweicloud.com/lstack-common/mongo:4.2.1
env:
- name: MONGO_INITDB_ROOT_USERNAME
value: root
- name: MONGO_INITDB_ROOT_PASSWORD
value: '123456'
- name: MONGO_INITDB_DATABASE
value: admin
command:
- mongod
- "--replSet"
- rs0
- "--bind_ip"
- 0.0.0.0
ports:
- containerPort: 27017
volumeMounts:
- name: mongdb-persistent-storage
mountPath: /data/db
volumeClaimTemplates:
- metadata:
name: mongdb-persistent-storage
spec:
storageClassName: mongodb-storage
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
# headless 无头服务(提供域名供StatefulSet内部pod访问使用)
apiVersion: v1
kind: Service
metadata:
name: mongodb-hs
labels:
name: mongodb
spec:
ports:
- port: 27017
targetPort: 27017
clusterIP: None
selector:
app: mongodb
---
# 标准服务(供外部访问)
apiVersion: v1
kind: Service
metadata:
name: mongodb-cs
labels:
name: mongodb
spec:
ports:
- port: 27017
targetPort: 27017
nodePort: 30100
selector:
app: mongodb
type: NodePort
-
StatefulSet
部分定义了 MongoDB 副本集的有状态部署。它创建了 3 个有唯一标识的 Pod,每个 Pod 都有稳定的网络标识。这些 Pod 使用 MongoDB 镜像,并配置了环境变量和命令,以便正确启动 MongoDB 副本集。每个 Pod 还挂载了持久卷,用于持久化存储数据。 -
Service
部分定义了两个服务,一个是 Headless Service(“mongodb-hs”),用于在 StatefulSet 内部提供域名解析。另一个是普通的服务(“mongodb-cs”),用于供外部访问 MongoDB 副本集。
-
创建工作负载
kubectl apply -f mongodb-sts.yaml [root@ecs-caa3 ~]# kubectl get pod NAME READY STATUS RESTARTS AGE mongodb-0 1/1 Running 0 39s mongodb-1 1/1 Running 0 39s mongodb-2 1/1 Running 0 39s
配置副本集
- 虽然我们已经创建了三个 Pod实例,但它们目前还是相互独立的,接下来我们要将它们组建成集群。首先进入任意一个 Pod
kubectl exec -it mongodb-0 /bin/bash
- 接着执行如下命令连接上任意一个 MongoDB 数据库
mongo
-
连接成功后执行如下命令:
-
接着执行如下命令开始配置副本集:
cfg = {_id: "rs0",members:[{_id: 0,host: 'mongodb-0.mongodb-hs.default.svc.cluster.local:27017',priority: 3},{_id: 1,host: 'mongodb-1.mongodb-hs.default.svc.cluster.local:27017',priority: 2},{_id: 2,host: 'mongodb-2.mongodb-hs.default.svc.cluster.local:27017',priority: 1}]};
-
各参数说明:
-
cfg 是可以任意的名字,当然最好不要是 mongodb 的关键字,conf,config 都可以。
-
最外层的 _id 表示 replica set 的名字(由于前面yaml文件中我们设置 replica set 的名字为 rs0,所以这里也要保持一致)
-
members 里包含的是所有节点的地址以及优先级。优先级最高的即成为主节点,即这里的
mongodb-0.mongodb-hs.default.svc.cluster.local:27017
。 -
mongodb-0.mongodb-hs.default.svc.cluster.local:27017
其中的default
为默认命名空间,根据自己所创建的命名空间进行更改。
-
-
最后执行如下命令使配置生效:
rs.initiate(cfg)
-
确认副本集创建成功
rs.status()
,节点出现(PRIMARY)并且显示以下信息即为成功。rs0:PRIMARY> rs.status() { "set" : "rs0", "date" : ISODate("2023-07-29T02:38:32.924Z"), "myState" : 1, "term" : NumberLong(4), "syncingTo" : "", "syncSourceHost" : "", "syncSourceId" : -1, "heartbeatIntervalMillis" : NumberLong(2000), "majorityVoteCount" : 2, "writeMajorityCount" : 2, "optimes" : { "lastCommittedOpTime" : { "ts" : Timestamp(1690598311, 1), "t" : NumberLong(4) }, "lastCommittedWallTime" : ISODate("2023-07-29T02:38:31.181Z"), "readConcernMajorityOpTime" : { "ts" : Timestamp(1690598311, 1), "t" : NumberLong(4) }, "readConcernMajorityWallTime" : ISODate("2023-07-29T02:38:31.181Z"), "appliedOpTime" : { "ts" : Timestamp(1690598311, 1), "t" : NumberLong(4) }, "durableOpTime" : { "ts" : Timestamp(1690598311, 1), "t" : NumberLong(4) }, "lastAppliedWallTime" : ISODate("2023-07-29T02:38:31.181Z"), "lastDurableWallTime" : ISODate("2023-07-29T02:38:31.181Z") }, "lastStableRecoveryTimestamp" : Timestamp(1690598306, 1), "lastStableCheckpointTimestamp" : Timestamp(1690598306, 1), "electionCandidateMetrics" : { "lastElectionReason" : "priorityTakeover", "lastElectionDate" : ISODate("2023-07-27T10:40:25.158Z"), "termAtElection" : NumberLong(4), "lastCommittedOpTimeAtElection" : { "ts" : Timestamp(1690454420, 1), "t" : NumberLong(3) }, "lastSeenOpTimeAtElection" : { "ts" : Timestamp(1690454420, 1), "t" : NumberLong(3) }, "numVotesNeeded" : 2, "priorityAtElection" : 3, "electionTimeoutMillis" : NumberLong(10000), "priorPrimaryMemberId" : 1, "numCatchUpOps" : NumberLong(1919251571), "newTermStartDate" : ISODate("2023-07-27T10:40:25.280Z"), "wMajorityWriteAvailabilityDate" : ISODate("2023-07-27T10:40:26.297Z") }, "members" : [ { "_id" : 0, "name" : "mongodb-0.mongodb-hs.idp.svc.cluster.local:27017", "ip" : "172.16.189.123", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 143960, "optime" : { "ts" : Timestamp(1690598311, 1), "t" : NumberLong(4) }, "optimeDate" : ISODate("2023-07-29T02:38:31Z"), "syncingTo" : "", "syncSourceHost" : "", "syncSourceId" : -1, "infoMessage" : "", "electionTime" : Timestamp(1690454425, 1), "electionDate" : ISODate("2023-07-27T10:40:25Z"), "configVersion" : 1, "self" : true, "lastHeartbeatMessage" : "" }, { "_id" : 1, "name" : "mongodb-1.mongodb-hs.idp.svc.cluster.local:27017", "ip" : "172.16.61.99", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 143901, "optime" : { "ts" : Timestamp(1690598311, 1), "t" : NumberLong(4) }, "optimeDurable" : { "ts" : Timestamp(1690598311, 1), "t" : NumberLong(4) }, "optimeDate" : ISODate("2023-07-29T02:38:31Z"), "optimeDurableDate" : ISODate("2023-07-29T02:38:31Z"), "lastHeartbeat" : ISODate("2023-07-29T02:38:31.613Z"), "lastHeartbeatRecv" : ISODate("2023-07-29T02:38:32.860Z"), "pingMs" : NumberLong(1), "lastHeartbeatMessage" : "", "syncingTo" : "mongodb-0.mongodb-hs.idp.svc.cluster.local:27017", "syncSourceHost" : "mongodb-0.mongodb-hs.idp.svc.cluster.local:27017", "syncSourceId" : 0, "infoMessage" : "", "configVersion" : 1 }, { "_id" : 2, "name" : "mongodb-2.mongodb-hs.idp.svc.cluster.local:27017", "ip" : "172.16.117.44", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 143901, "optime" : { "ts" : Timestamp(1690598311, 1), "t" : NumberLong(4) }, "optimeDurable" : { "ts" : Timestamp(1690598311, 1), "t" : NumberLong(4) }, "optimeDate" : ISODate("2023-07-29T02:38:31Z"), "optimeDurableDate" : ISODate("2023-07-29T02:38:31Z"), "lastHeartbeat" : ISODate("2023-07-29T02:38:31.535Z"), "lastHeartbeatRecv" : ISODate("2023-07-29T02:38:32.482Z"), "pingMs" : NumberLong(0), "lastHeartbeatMessage" : "", "syncingTo" : "mongodb-0.mongodb-hs.idp.svc.cluster.local:27017", "syncSourceHost" : "mongodb-0.mongodb-hs.idp.svc.cluster.local:27017", "syncSourceId" : 0, "infoMessage" : "", "configVersion" : 1 } ], "ok" : 1, "$clusterTime" : { "clusterTime" : Timestamp(1690598311, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } }, "operationTime" : Timestamp(1690598311, 1) }
-
创建root用户
use admin;
db.createUser( { user: "root", pwd: "123456", roles: [ { role: "userAdminAnyDatabase", db: "admin" } ] } );
# 输出1即为成功
db.auth("root","123456");
