はじめに
KubernetesのStatefulsetを利用して3つのMongoDBを用意し、PrimaryとSecondaryとArbiterにてレプリケーションを組む手順について解説します。
環境情報
- MongoDB v4.4
- kubectl v1.18
事前準備
以下のyamlを展開することで3台もMongoDBがレプリカセット名repltestという名前で作成されます。
apiVersion: apps/v1 kind: StatefulSet metadata: name: mongod spec: serviceName: mongodb-service replicas: 3 selector: matchLabels: role: mongo template: metadata: labels: role: mongo replicaset: MainRepSet spec: terminationGracePeriodSeconds: 10 containers: - name: mongod-container image: mongo command: - "mongod" - "--bind_ip" - "0.0.0.0" - "--replSet" - "repltest" ports: - containerPort: 27017
apiVersion: v1 kind: Service metadata: name: mongodb-service labels: name: mongo spec: ports: - port: 27017 targetPort: 27017 selector: role: mongo
以下のようになれば全Podが正常に起動しています。
$ kubectl get pod NAME READY STATUS RESTARTS AGE mongod-0 1/1 Running 0 .. mongod-1 1/1 Running 0 .. mongod-2 1/1 Running 0 ..
レプリカセットの設定(プライマリー)
mongo-0に入ってレプリカセットの状態を確認するとno replset config has been received
と表示されます。
> rs.status() { "operationTime" : Timestamp(0, 0), "ok" : 0, "errmsg" : "no replset config has been received", "code" : 94, "codeName" : "NotYetInitialized", "$clusterTime" : { "clusterTime" : Timestamp(0, 0), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } }
よって以下にて初期化を行いレプリカセットに加えるDBサーバを指定します。引数としてはPod_Name.Service_Name
です。
> rs.initiate({_id: "repltest",members: [{_id:0,host:"mongod-0.mongodb-service:27017"}]}) { "ok" : 1, "$clusterTime" : { "clusterTime" : Timestamp(1603700291, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } }, "operationTime" : Timestamp(1603700291, 1) }
同設定が完了するとmembersとして_idが0のPodが追加されています。
> rs.status() { "set" : "repltest", "date" : ISODate("xx"), "myState" : 1, "term" : NumberLong(1), "syncSourceHost" : "", "syncSourceId" : -1, "heartbeatIntervalMillis" : NumberLong(2000), "majorityVoteCount" : 1, "writeMajorityCount" : 1, "votingMembersCount" : 1, "writableVotingMembersCount" : 1, "optimes" : { "lastCommittedOpTime" : { "ts" : Timestamp(1603700291, 8), "t" : NumberLong(1) }, "lastCommittedWallTime" : ISODate("xx"), "readConcernMajorityOpTime" : { "ts" : Timestamp(1603700291, 8), "t" : NumberLong(1) }, "readConcernMajorityWallTime" : ISODate("xx"), "appliedOpTime" : { "ts" : Timestamp(1603700291, 8), "t" : NumberLong(1) }, "durableOpTime" : { "ts" : Timestamp(1603700291, 8), "t" : NumberLong(1) }, "lastAppliedWallTime" : ISODate("xx"), "lastDurableWallTime" : ISODate("xx") }, "lastStableRecoveryTimestamp" : Timestamp(1603700291, 7), "electionCandidateMetrics" : { "lastElectionReason" : "electionTimeout", "lastElectionDate" : ISODate("xx"), "electionTerm" : NumberLong(1), "lastCommittedOpTimeAtElection" : { "ts" : Timestamp(0, 0), "t" : NumberLong(-1) }, "lastSeenOpTimeAtElection" : { "ts" : Timestamp(1603700291, 1), "t" : NumberLong(-1) }, "numVotesNeeded" : 1, "priorityAtElection" : 1, "electionTimeoutMillis" : NumberLong(10000), "newTermStartDate" : ISODate("2020-10-26T08:18:11.338Z"), "wMajorityWriteAvailabilityDate" : ISODate("2020-10-26T08:18:11.372Z") }, "members" : [ { "_id" : 0, "name" : "mongod-0.mongodb-service:27017", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 174, "optime" : { "ts" : Timestamp(1603700291, 8), "t" : NumberLong(1) }, "optimeDate" : ISODate("xx"), "syncSourceHost" : "", "syncSourceId" : -1, "infoMessage" : "Could not find member to sync from", "electionTime" : Timestamp(1603700291, 2), "electionDate" : ISODate("xx"), "configVersion" : 1, "configTerm" : 1, "self" : true, "lastHeartbeatMessage" : "" } ], "ok" : 1, "$clusterTime" : { "clusterTime" : Timestamp(1603700291, 8), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } }, "operationTime" : Timestamp(1603700291, 8) }
プロンプトも以下のように変化しプライマリーであることが分かります。
repltest:PRIMARY>
セカンダリーを追加する
以下で2つ目のPodをSecondaryとして追加できます。
repltest:PRIMARY> rs.add("mongod-1.mongodb-service:27017") { "ok" : 1, "$clusterTime" : { "clusterTime" : Timestamp(1603702008, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } },
同じく以下で3つ目のPodも追加できます。
(本コマンドはPrimary選出のみを行うARBITERとして追加していますがaddとすればSecondaryとして追加されます。)
rs.addArb("mongod-2.mongodb-service:27017")
これの状態で改めてレプリカセットの状態を確認するとPrimaryが一つとSecondaryが二つの構成であることが確認できます。
repltest:PRIMARY> rs.status() ... "members" : [ { "_id" : 0, "name" : "mongod-0.mongodb-service:27017", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", ... { "_id" : 1, "name" : "mongod-1.mongodb-service:27017", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", .... "_id" : 2, "name" : "mongod-2.mongodb-service:27017", "health" : 1, "state" : 7, "stateStr" : "ARBITER", ...
終わりに
MongoDBにてレプリケーションを行う上での初期設定について説明しました。
尚、よくあるミスとしてメンバーを追加する際にサーバ名の指定に失敗すると以下メッセージでエラーとなるのでご注意ください。
SocketException: Host not found (authoritative)", "code" : 74, "codeName" : "NodeNotFound",
以上、ご参考になれば幸いです。