目錄
- 背景
- 啟動步驟
- 可能遇到的問題
- 解決辦法
背景
在開發中,我們很容易通過docker啟動一個普通的mongodb數據庫服務。但是有時候為了保持與線上環境一致,或者為了利用mongodb副本集的某些特性,我們需要在本地部署mongodb副本集。副本集往往需要啟動多個mongodb服務作為副本集成員,而通常用于開發的筆記本資源比較有限。鑒于此,官方文檔給了解決辦法,可以直接將一個單節點mongodb服務轉換為單節點副本集(standlone replica set
)(https://www.mongodb.com/docs/manual/tutorial/convert-standalone-to-replica-set/)
啟動步驟
按照官方文檔的說明,如果利用docker部署服務,那么依次有如下步驟:
-
第一步, 假如已經存在一個運行中的普通mongodb容器服務。此時,需要關閉服務,并通過指定
--replSet
參數重啟該服務或者重新啟動一個新的mongodb容器。假如mongodb的服務名及容器名均為
mongodb_rs
,運行端口映射為27017:27017
,副本集名稱為rs0
,數據存儲目錄指定為/srv/mongodb/db0
,數據卷掛載目錄為./data:/srv/mongodb/db0
。那么docker-compose.yaml
文件可編寫如下:version: "3" services: mongodb_rs: network_mode: bridge container_name: mongodb_rs image: mongo:latest ports: - "27017:27017" restart: always # environment: # MONGO_INITDB_ROOT_USERNAME: username # MONGO_INITDB_ROOT_PASSWORD: pwd command: mongod --port 27017 --replSet rs0 --dbpath /srv/mongodb/db0 volumes: - ./data:/srv/mongodb/db0
-
第二步,執行如下命令啟動mongodb服務
docker-compose up -d mongodb_rs
-
第三步,進入容器mongosh,執行初始化副本集命令
docker exec -it mongodb_rs mongo
# mongosh rs.initiate() # --- # > rs.initiate() # { # "info2" : "no configuration specified. Using a default configuration for the set", # "me" : "f76081e20602:27017", # "ok" : 1 # } # rs0:SECONDARY> # rs0:PRIMARY>|
-
第四步,退出容器,容器服務正常運行
可能遇到的問題
按照上述步驟執行后,通常情況下容器服務可以正常運行,應用程序可以正常進行連接,到這里基本就成功了。以golang代碼測試:
package main import ( "context" "fmt" "log" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" ) func main() { clientOpts := options.Client().ApplyURI("mongodb://localhost:27017/?replicaSet=rs0") client, err := mongo.Connect(context.TODO(), clientOpts) if err != nil { log.Fatal(err) } colls, _ := client.Database("admin").ListCollectionNames(context.TODO(), bson.M{}) fmt.Printf("colls: %v\n", colls) } // colls: [system.keys system.version]
但是有時候可能會出現本地程序代碼無法連接副本集服務,控制臺會報類似連接錯誤的問題,報錯的原因在于副本集無法識別成員host
。
在單節點副本集下,本機既是主也是從,在容器的mongo shell
中可進行查看, members
只有一個成員,其name
為"f76081e20602:27017"
, 所以如果你遇到無法連接或者其他類似錯誤,根本原因在于本地啟動的這個副本集無法識別f76081e20602
這個host
。
rs.status() --- rs0:PRIMARY> rs.status() { "set" : "rs0", "date" : ISODate("2022-05-06T18:59:21.417Z"), # ... "members" : [ { "_id" : 0, "name" : "f76081e20602:27017", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 1433, "optime" : { "ts" : Timestamp(1651863555, 1), "t" : NumberLong(1) }, # ... } ], # ... }
解決辦法
曾經遇到上述問題,百度csdn上有多篇內容一樣的文章,都說這種情況需要將應用程序也通過容器進行啟動,并將應用程序與mongdb副本集服務置于同一個docker網絡中,就可以正常連接了。這樣做確實也可行,但似乎過于麻煩了,有點走歪路的感覺。
從上述內容已經知道是副本集成員host
的識別問題,那么在初始化mongodb副本集時,我們可以顯式的去指定成員host
,不使用默認的副本集配置。具體而言,將啟動步驟中的第三步更改為:
-
進入
mongosh
docker exec -it mongodb_rs mongo
-
自定義配置
# mongosh conf = { _id : "rs0", members: [ { _id: 0, host: "<本機ip地址>:27017" }, ] }
-
初始化副本集
# mongosh rs.initiate(conf)
如此,通過指定成員ip,mongo單節點副本集就可以準確的識別到副本集成員,對于多節點副本集如果出現連接問題,此方法同樣適用。