Docker 搭建集群MongoDB的實(shí)現(xiàn)步驟
由于公司業(yè)務(wù)需要,我們打算自己搭建 MongoDB 的服務(wù),因?yàn)?MongoDB 的云數(shù)據(jù)庫(kù)好貴,我們這次采用副本集的方式來搭建集群,三臺(tái)服務(wù)器,一主、一副、一仲裁
基本概念
Replica Set 副本集:一個(gè)副本集就是一組 MongoDB 實(shí)例組成的集群,由一個(gè)主(Primary)服務(wù)器和多個(gè)備份(Secondary)服務(wù)器構(gòu)成
- 主節(jié)點(diǎn)(master):主節(jié)點(diǎn)接收所有寫入操作。主節(jié)點(diǎn)將對(duì)其數(shù)據(jù)集所做的所有更改記錄到其 oplog。
- 副節(jié)點(diǎn)(secondary):復(fù)制主節(jié)點(diǎn)的 oplog 并將操作應(yīng)用到其數(shù)據(jù)集,如果主節(jié)點(diǎn)不可用,一個(gè)合格的副節(jié)點(diǎn)將被選為新的主節(jié)點(diǎn)。
- 仲裁節(jié)點(diǎn)(arbiter):負(fù)載選舉,當(dāng)主節(jié)點(diǎn)不可用,它將從副節(jié)點(diǎn)中選一個(gè)作為主節(jié)點(diǎn)。
Sharding 分片:
Master-slave 主備
- MongoDB 4.0 以上版本運(yùn)行時(shí)提示:[main] Master/slave replication is no longer supported,也就是 MongoDB 4.0 后不在支持主從復(fù)制
一、環(huán)境準(zhǔn)備
使用 CentOS 7.6 64bit 系統(tǒng),安裝 Docker、Docker-compose、Docker-Swarm
二、生成 KeyFile
- MongoDB 使用 KeyFile 認(rèn)證,副本集中的每個(gè) MongoDB 實(shí)例使用 KeyFile 內(nèi)容作為認(rèn)證其他成員的共享密碼。MongoDB 實(shí)例只有擁有正確的 KeyFile 才可以加入副本集。
- keyFile 的內(nèi)容必須是 6 到 1024 個(gè)字符的長(zhǎng)度,且副本集所有成員的 KeyFile 內(nèi)容必須相同。
- 有一點(diǎn)要注意是的:在 UNIX 系統(tǒng)中,KeyFile 必須沒有組權(quán)限或完全權(quán)限(也就是權(quán)限要設(shè)置成 X00 的形式)。Windows 系統(tǒng)中,keyFile 權(quán)限沒有被檢查。
- 可以使用任意方法生成 keyFile。例如,如下操作使用 openssl 生成復(fù)雜的隨機(jī)的 1024 個(gè)字符串。然后使用 chmod 修改文件權(quán)限,只給文件擁有者提供讀權(quán)限。
- 這是 MongoDB 官方推薦 keyFile 的生成方式:
# 400權(quán)限是要保證安全性,否則mongod啟動(dòng)會(huì)報(bào)錯(cuò) openssl rand -base64 756 > mongodb.key chmod 400 mongodb.key
二、創(chuàng)建跨主機(jī)網(wǎng)絡(luò)
搭建集群我們肯定是跨主機(jī)通訊,要搭建 Overlay Network 網(wǎng)絡(luò),我們就要用到 Docker Swarm 這個(gè)工具了。Docker Swarm 是 Docker 內(nèi)置的集群工具,它能夠幫助我們更輕松地將服務(wù)部署到 Docker daemon 的集群之中。
既然要將 Docker 加入到集群,我們就必須先有一個(gè)集群,我們?cè)谌我庖粋€(gè) Docker 實(shí)例上都可以通過 docker swarm init 來初始化集群。
$ sudo docker swarm init Swarm initialized: current node (t4ydh2o5mwp5io2netepcauyl) is now a manager. To add a worker to this swarm, run the following command: docker swarm join --token SWMTKN-1-4dvxvx4n7magy5zh0g0de0xoues9azekw308jlv6hlvqwpriwy-cb43z26n5jbadk024tx0cqz5r 192.168.1.5:2377
在集群初始化后,這個(gè) Docker 實(shí)例就自動(dòng)成為了集群的管理節(jié)點(diǎn),而其他 Docker 實(shí)例可以通過運(yùn)行這里所打印的 docker swarm join 命令來加入集群。
加入到集群的節(jié)點(diǎn)默認(rèn)為普通節(jié)點(diǎn),如果要以管理節(jié)點(diǎn)的身份加入到集群中,我們可以通過 docker swarm join-token 命令來獲得管理節(jié)點(diǎn)的加入命令。
$ sudo docker swarm join-token manager To add a manager to this swarm, run the following command: docker swarm join --token SWMTKN-1-60am9y6axwot0angn1e5inxrpzrj5d6aa91gx72f8et94wztm1-7lz0dth35wywekjd1qn30jtes 192.168.1.5:2377
我們通過這些命令來建立用于我們服務(wù)開發(fā)的 Docker 集群,并將相關(guān)開發(fā)同事的 Docker 加入到這個(gè)集群里,就完成了搭建跨主機(jī)網(wǎng)絡(luò)的第一步。
建立跨主機(jī)網(wǎng)絡(luò)
接下來,我們就通過 docker network create
命令來建立 Overlay 網(wǎng)絡(luò)。
$ sudo docker network create --driver overlay --attachable mongodbs
在創(chuàng)建 Overlay 網(wǎng)絡(luò)時(shí),我們要加入 --attachable 選項(xiàng)以便不同機(jī)器上的 Docker 容器能夠正常使用到它。
在創(chuàng)建了這個(gè)網(wǎng)絡(luò)之后,我們可以在任何一個(gè)加入到集群的 Docker 實(shí)例上使用 docker network ls 查看一下其下的網(wǎng)絡(luò)列表。我們會(huì)發(fā)現(xiàn)這個(gè)網(wǎng)絡(luò)定義已經(jīng)同步到了所有集群中的節(jié)點(diǎn)上。
$ sudo docker network ls NETWORK ID NAME DRIVER SCOPE ## ...... y89bt74ld9l8 mongodbs overlay swarm ## ......
接下來我們要修改 Docker Compose 的定義,讓它使用這個(gè)我們已經(jīng)定義好的網(wǎng)絡(luò),而不是再重新創(chuàng)建網(wǎng)絡(luò)。
我們只需要在 Docker Compose 配置文件的網(wǎng)絡(luò)定義部分,將網(wǎng)絡(luò)的 external 屬性設(shè)置為 true,就可以讓 Docker Compose 將其建立的容器都連接到這個(gè)不屬于 Docker Compose 的項(xiàng)目上了。
networks: mesh: external: true
通過這個(gè)實(shí)現(xiàn),我們?cè)陂_發(fā)中就使整個(gè)服務(wù)都處于一個(gè)可以使用別名映射網(wǎng)絡(luò)中,避免了要對(duì)不同功能聯(lián)調(diào)時(shí)切換服務(wù) IP 的煩瑣流程。在這種結(jié)構(gòu)下,我們只需要讓我們開發(fā)的 Docker 退出和加入不同的集群,就能馬上做到切換不同聯(lián)調(diào)項(xiàng)目。
二、編寫 docker-compose 文件
主節(jié)點(diǎn)
version: "3" services: master: image: mongo:4.1 container_name: master environment: MONGO_INITDB_ROOT_USERNAME: root MONGO_INITDB_ROOT_PASSWORD: 123456 TZ: "Asia/Shanghai" volumes: # 掛載 MongoDB 數(shù)據(jù)目錄 - "/data/docker/mongodb/data/mongo:/data/db:rw" # 掛載 KeyFile - "/data/docker/mongodb/data/mongodb.key:/data/mongodb.key" ports: - "27018:27017" networks: - mongodbs command: # 密碼 --auth # 副本集名稱 --replSet testSet --oplogSize 128 --keyFile /data/mongodb.key # Swarm 跨主機(jī)網(wǎng)絡(luò)網(wǎng)絡(luò) networks: mongodbs: external: true
副節(jié)點(diǎn)
version: "3" services: secondary: image: mongo:4.1 container_name: secondary environment: MONGO_INITDB_ROOT_USERNAME: root MONGO_INITDB_ROOT_PASSWORD: 123456 TZ: "Asia/Shanghai" volumes: - "/data/docker/mongodb/data/mongo:/data/db:rw" - "/data/docker/mongodb/data/mongodb.key:/data/mongodb.key" ports: - "27018:27017" networks: - mongodbs command: --auth --replSet testSet --oplogSize 128 --keyFile /data/mongodb.key networks: mongodbs: external: true
仲裁節(jié)點(diǎn),因?yàn)橹俨霉?jié)點(diǎn)不需要存儲(chǔ)數(shù)據(jù),他只是用來當(dāng)主節(jié)點(diǎn)掛掉后選舉新的主節(jié)點(diǎn),所以不需要密碼、映射端口等操作
version: "3" services: arbiter: image: mongo:4.1 container_name: arbiter restart: always volumes: - "/data/docker/mongodb/data/mongo:/data/db:rw" - "/data/docker/mongodb/data/mongo_key:/mongo:rw" networks: - mongodbs command: mongod --replSet testSet --smallfiles --oplogSize 128 networks: mongodbs: external: true
三、啟動(dòng)容器
接下來我們分別在三臺(tái)服務(wù)器中使用容器編排啟動(dòng)容器
docker-compose up -d
四、配置副本集
進(jìn)入主節(jié)點(diǎn)容器內(nèi)部
docker exec -it master mongo
在 mongo shell 里執(zhí)行:
> rs.initiate() { "info2" : "no configuration specified. Using a default configuration for the set", "me" : "7abd89794aa7:27017", "ok" : 1 }
繼續(xù)執(zhí)行:
testSet:SECONDARY> rs.add('secondary:27017') { "ok" : 1, "$clusterTime" : { "clusterTime" : Timestamp(1599562800, 1), "signature" : { "hash" : BinData(0,"wrxMUIX/0bEyLgCVoQqdLvH59T0="), "keyId" : NumberLong("6870069879538450434") } }, "operationTime" : Timestamp(1599562800, 1) }
繼續(xù)執(zhí)行,其中 true 表示這個(gè)節(jié)點(diǎn)是仲裁節(jié)點(diǎn)
testSet:PRIMARY> rs.add('arbiter:27017',true) { "ok" : 1, "$clusterTime" : { "clusterTime" : Timestamp(1599562838, 1), "signature" : { "hash" : BinData(0,"p9ub49lLD8ij8nkxpfu2l/AvRRY="), "keyId" : NumberLong("6870069879538450434") } }, "operationTime" : Timestamp(1599562838, 1) }
查看配置
testSet:PRIMARY> rs.conf() { "_id" : "testSet", "version" : 3, "protocolVersion" : NumberLong(1), "writeConcernMajorityJournalDefault" : true, "members" : [ { "_id" : 0, "host" : "7abd89794aa7:27017", "arbiterOnly" : false, "buildIndexes" : true, "hidden" : false, "priority" : 1, "tags" : { }, "slaveDelay" : NumberLong(0), "votes" : 1 }, { "_id" : 1, "host" : "secondary:27017", "arbiterOnly" : false, "buildIndexes" : true, "hidden" : false, "priority" : 1, "tags" : { }, "slaveDelay" : NumberLong(0), "votes" : 1 }, { "_id" : 2, "host" : "arbiter:27017", "arbiterOnly" : true, "buildIndexes" : true, "hidden" : false, "priority" : 0, "tags" : { }, "slaveDelay" : NumberLong(0), "votes" : 1 } ], "settings" : { "chainingAllowed" : true, "heartbeatIntervalMillis" : 2000, "heartbeatTimeoutSecs" : 10, "electionTimeoutMillis" : 10000, "catchUpTimeoutMillis" : -1, "catchUpTakeoverDelayMillis" : 30000, "getLastErrorModes" : { }, "getLastErrorDefaults" : { "w" : 1, "wtimeout" : 0 }, "replicaSetId" : ObjectId("5f576426fe90ef2dd8cd2700") } }
查看狀態(tài)
testSet:PRIMARY> rs.status() { "set" : "testSet", "date" : ISODate("2020-09-08T11:45:12.096Z"), "myState" : 1, "term" : NumberLong(1), "syncingTo" : "", "syncSourceHost" : "", "syncSourceId" : -1, "heartbeatIntervalMillis" : NumberLong(2000), "optimes" : { "lastCommittedOpTime" : { "ts" : Timestamp(1599565502, 1), "t" : NumberLong(1) }, "lastCommittedWallTime" : ISODate("2020-09-08T11:45:02.775Z"), "readConcernMajorityOpTime" : { "ts" : Timestamp(1599565502, 1), "t" : NumberLong(1) }, "readConcernMajorityWallTime" : ISODate("2020-09-08T11:45:02.775Z"), "appliedOpTime" : { "ts" : Timestamp(1599565502, 1), "t" : NumberLong(1) }, "durableOpTime" : { "ts" : Timestamp(1599565502, 1), "t" : NumberLong(1) }, "lastAppliedWallTime" : ISODate("2020-09-08T11:45:02.775Z"), "lastDurableWallTime" : ISODate("2020-09-08T11:45:02.775Z") }, "lastStableRecoveryTimestamp" : Timestamp(1599565492, 1), "lastStableCheckpointTimestamp" : Timestamp(1599565492, 1), "members" : [ { "_id" : 0, "name" : "7abd89794aa7:27017", "ip" : "10.0.1.41", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 2784, "optime" : { "ts" : Timestamp(1599565502, 1), "t" : NumberLong(1) }, "optimeDate" : ISODate("2020-09-08T11:45:02Z"), "syncingTo" : "", "syncSourceHost" : "", "syncSourceId" : -1, "infoMessage" : "", "electionTime" : Timestamp(1599562790, 2), "electionDate" : ISODate("2020-09-08T10:59:50Z"), "configVersion" : 3, "self" : true, "lastHeartbeatMessage" : "" }, { "_id" : 1, "name" : "secondary:27017", "ip" : "10.0.1.233", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 2711, "optime" : { "ts" : Timestamp(1599565502, 1), "t" : NumberLong(1) }, "optimeDurable" : { "ts" : Timestamp(1599565502, 1), "t" : NumberLong(1) }, "optimeDate" : ISODate("2020-09-08T11:45:02Z"), "optimeDurableDate" : ISODate("2020-09-08T11:45:02Z"), "lastHeartbeat" : ISODate("2020-09-08T11:45:11.494Z"), "lastHeartbeatRecv" : ISODate("2020-09-08T11:45:11.475Z"), "pingMs" : NumberLong(0), "lastHeartbeatMessage" : "", "syncingTo" : "7abd89794aa7:27017", "syncSourceHost" : "7abd89794aa7:27017", "syncSourceId" : 0, "infoMessage" : "", "configVersion" : 3 }, { "_id" : 2, "name" : "arbiter:27017", "ip" : null, "health" : 0, "state" : 8, "stateStr" : "(not reachable/healthy)", "uptime" : 0, "lastHeartbeat" : ISODate("2020-09-08T11:45:10.463Z"), "lastHeartbeatRecv" : ISODate("1970-01-01T00:00:00Z"), "pingMs" : NumberLong(0), "lastHeartbeatMessage" : "Error connecting to arbiter:27017 :: caused by :: Could not find address for arbiter SocketException: Host not found (authoritative)", "syncingTo" : "", "syncSourceHost" : "", "syncSourceId" : -1, "infoMessage" : "", "configVersion" : -1 } ], "ok" : 1, "$clusterTime" : { "clusterTime" : Timestamp(1599565502, 1), "signature" : { "hash" : BinData(0,"7/ei+8UrhlpIny9zKeWuAFpn46c="), "keyId" : NumberLong("6870069879538450434") } }, "operationTime" : Timestamp(1599565502, 1) }
五、驗(yàn)證 MongoDB 可用性
先進(jìn)入主節(jié)點(diǎn)服務(wù)器添加一條數(shù)據(jù)
docker exec -it master mongo use admin db.auth('root', '123456') use test db.test.insert({name:"muyang",age:20})
在來副節(jié)點(diǎn)服務(wù)器查看是否已經(jīng)同步了這條數(shù)據(jù)
[root@linux secondary] docker exec -it secondary mongo testSet:SECONDARY> use admin testSet:SECONDARY> db.auth('root', '123456') testSet:SECONDARY> use test testSet:SECONDARY> db.test.find() 2020-09-08T19:03:02.295+0800 E QUERY [js] uncaught exception: Error: listCollections failed: { "operationTime" : Timestamp(1599562972, 1), "ok" : 0, "errmsg" : "not master and slaveOk=false", "code" : 13435, "codeName" : "NotMasterNoSlaveOk", "$clusterTime" : { "clusterTime" : Timestamp(1599562972, 1), "signature" : { "hash" : BinData(0,"mhsrpGHRl7qZg2QOjyS3RbBb/Yc="), "keyId" : NumberLong("6870069879538450434") } } } : testSet:SECONDARY> rs.slaveOk() testSet:SECONDARY> db.users.find() { "_id" : ObjectId("5f5764b1f909544b783696c2"), "name" : "muyang", "age" : 20 }
在 secondary 查詢時(shí)報(bào)如下錯(cuò)誤:
not master and slaveok=false
這是正常的,因?yàn)?secondary 是不允許讀寫的,如果非要解決,方法如下:
testSet:SECONDARY> rs.slaveOk()
到此這篇關(guān)于Docker 搭建集群MongoDB的實(shí)現(xiàn)步驟的文章就介紹到這了,更多相關(guān)Docker 搭建集群MongoDB內(nèi)容請(qǐng)搜索本站以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持本站!
版權(quán)聲明:本站文章來源標(biāo)注為YINGSOO的內(nèi)容版權(quán)均為本站所有,歡迎引用、轉(zhuǎn)載,請(qǐng)保持原文完整并注明來源及原文鏈接。禁止復(fù)制或仿造本網(wǎng)站,禁止在非www.sddonglingsh.com所屬的服務(wù)器上建立鏡像,否則將依法追究法律責(zé)任。本站部分內(nèi)容來源于網(wǎng)友推薦、互聯(lián)網(wǎng)收集整理而來,僅供學(xué)習(xí)參考,不代表本站立場(chǎng),如有內(nèi)容涉嫌侵權(quán),請(qǐng)聯(lián)系alex-e#qq.com處理。