创建容器

使用docker-compose部署mongoDB副本集环境。

docker-compose.yml文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
version: "3"
services:
mongo0:
hostname: mongo0
container_name: mongo0
image: mongo:4.4.2
expose:
- 27017
ports:
- 27017:27017
restart: always
entrypoint: [ "/usr/bin/mongod", "--bind_ip_all", "--replSet", "rs0"]
volumes:
- /data/volume-mongo-rs/db0:/data/db
- /data/volume-mongo-rs/db0-config:/data/configdb

mongo1:
hostname: mongo1
container_name: mongo1
image: mongo:4.4.2
expose:
- 27017
ports:
- 27018:27017
restart: always
entrypoint: [ "/usr/bin/mongod", "--bind_ip_all", "--replSet", "rs0"]
volumes:
- /data/volume-mongo-rs/db1:/data/db
- /data/volume-mongo-rs/db1-config:/data/configdb
depends_on:
- mongo0

mongo2:
# Host name = Container name
hostname: mongo2
container_name: mongo2
image: mongo:4.4.2
expose:
- 27017
ports:
- 27019:27017
restart: always
entrypoint: [ "/usr/bin/mongod", "--bind_ip_all", "--replSet", "rs0"]
volumes:
- /data/volume-mongo-rs/db2:/data/db
- /data/volume-mongo-rs/db2-config:/data/configdb
depends_on:
- mongo0

配置副本集

进入mongo0的容器内。

1
2
3
4
$ docker exec -it mongo0 /bin/bash

# 进入mongo shell
$ mongo

输入配置副本集命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
rs.initiate({_id:"rs0",members:[{_id:0,host:"mongo0:27017", "priority": 2},{_id:1,host:"mongo1:27017"},{_id:2,host:"mongo2:27017"}]})

# 也就是:
rs.initiate(
{
_id : 'rs0',
members: [
{ _id : 0, host : "mongo0:27017", "priority": 2 },
{ _id : 1, host : "mongo1:27017" },
{ _id : 2, host : "mongo2:27017" }
]
}
)

priority是当选为主节点的优先级,这里因为想要启动的时候,固定mongo0,也就是端口为27017作为primary(主节点)。

修改Hosts

mongo0mongo1mongo2是作为容器内的IP,容器外是识别不了的,配置文件中,我们已经将这些容器的端口暴露到宿主机上了,可以直接使用本机port去访问,那容器的IP也就对应着是localhost,故这里需要修改下hosts文件,做下对应。

1
2
3
127.0.0.1   mongo0
127.0.0.1 mongo1
127.0.0.1 mongo2

测试副本集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package main

import (
"context"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"log"
"os"
)

const dbName = "argos"
const collectionExamples = "examples"

func getMongoClient() (*mongo.Client, error) {
uri := "mongodb://localhost:27017/argos?replicaSet=rs0"
if os.Getenv("DATABASE_URL") != "" {
uri = os.Getenv("DATABASE_URL")
}
return getMongoClientByURI(uri)
}

func getMongoClientByURI(uri string) (*mongo.Client, error) {
var err error
var client *mongo.Client
opts := options.Client()
opts.ApplyURI(uri)
opts.SetMaxPoolSize(5)
if client, err = mongo.Connect(context.Background(), opts); err != nil {
return client, err
}
client.Ping(context.Background(), nil)
return client, err
}

func main() {
var err error
var client *mongo.Client
var collection *mongo.Collection
var ctx = context.Background()
var id = primitive.NewObjectID()
var doc = bson.M{"_id": id, "hometown": "Atlanta", "year": int32(1998)}
var result *mongo.UpdateResult
var session mongo.Session
var update = bson.D{{Key: "$set", Value: bson.D{{Key: "year", Value: int32(2000)}}}}
if client, err = getMongoClient(); err != nil {
log.Fatal(err)
}
defer client.Disconnect(ctx)
collection = client.Database(dbName).Collection(collectionExamples)
if _, err = collection.InsertOne(ctx, doc); err != nil {
log.Fatal(err)
}

if session, err = client.StartSession(); err != nil {
log.Fatal(err)
}
if err = session.StartTransaction(); err != nil {
log.Fatal(err)
}
if err = mongo.WithSession(ctx, session, func(sc mongo.SessionContext) error {
if result, err = collection.UpdateOne(sc, bson.M{"_id": id}, update); err != nil {
log.Fatal(err)
}
if result.MatchedCount != 1 || result.ModifiedCount != 1 {
log.Fatal("replace failed, expected 1 but got", result.MatchedCount)
}

if err = session.CommitTransaction(sc); err != nil {
log.Fatal(err)
}
return nil
}); err != nil {
log.Fatal(err)
}
session.EndSession(ctx)

var v bson.M
if err = collection.FindOne(ctx, bson.D{{Key: "_id", Value: id}}).Decode(&v); err != nil {
log.Fatal(err)
}
if v["year"] != int32(2000) {
log.Println(v)
log.Fatal("expected 2000 but got", v["year"])
}

res, _ := collection.DeleteOne(ctx, bson.M{"_id": id})
if res.DeletedCount != 1 {
log.Fatal("delete failed, expected 1 but got", res.DeletedCount)
}
}