Posted at

運用中のMongoDBのレプリカセットを行う in Docker

More than 1 year has passed since last update.

MongoDB4.0で遂にトランザクションに対応したので、先日アップデートを行った。

こちらの記事↓

MongoDBをバージョン4.0にアップグレード in Docker

ただ、Mongoを1台で起動しているため、今のままではトランザクションは使えないのだ。

トランザクションに対応するためには、レプリカセットしなければならない。

今まで面倒で行っていなかったレプリカセットを行おうと思う。


レプリカセットの構成

最小限の構成として、プライマリー1台、セカンダリー2台、アービター1台で作成します。

プライマリーとかアービターについてはこちら

https://qiita.com/hakozaki/items/c41a5e6e7f0fad557c43

また、Dockerを使っているので、コンテナ1台につき1DBにして、ネットワークでそれぞれを繋ぐ構成でいきます。


docker-compose.ymlを編集する

現在のコンテナの設定は、


docker-compose.yml

  mongo:

restart: always
image: mongo
volumes:
- /var/www/data/mongo:/data/db

いたってシンプルです。

3台共通のネットワークに繋げるために、dockerコマンドでmongo_linkというネットワークを作成します。

$ docker network create mongo_link

そして、docker-compose.ymlを編集


docker-compose.yml

  mongo:

restart: always
image: mongo
volumes:
- /var/www/data/mongo:/data/db
# 3行追加
networks:
- default
- mongo_link
networks:
mongo_link:
external: true

- default←これなんぞ?と思った方いると思いますが、docker-composeではコンテナを作成したときに、勝手にDIRECTORYNAME_defaultというネットワーク内にいることになります。

- defaultを書かなければ、他のコンテナからアクセスできなく恐れがあるので、docker-compose.yml内に別のコンテナを含んでいる場合は設定しておきましょう。

さらに、セカンダリーとアービター用のコンテナの追加とレプリカセット用の引数をセットします。

すると、docker-compose.ymlは最終的にこんな感じになります。


docker-compose.yml

  mongo:

restart: always
image: mongo
volumes:
- /var/www/data/mongo:/data/db
networks:
- default
- mongo_link
command: --replSet mongo-set

mongo-secondary:
restart: always
image: mongo
volumes:
- /var/www/data/mongo-secondary:/data/db
networks:
- default
- mongo_link
command: --replSet mongo-set

mongo-arbiter:
restart: always
image: mongo
networks:
- default
- mongo_link
command: --replSet mongo-set

networks:
mongo_link:
external: true


プライマリーは、--replSet mongo-setというのを追加してレプリカセットできるようにしています。

セカンダリーはほぼプライマリーと同じですが、DBのデータを保存する空のディレクトリmongo-secondary/を用意しておきます。

アービターは、データを保持しないので、volumesは不要となります。


レプリカセットをセット

コンテナを生成しましょう

$ docker-compose up -d

mongoが再起動するとアクセスできない時間ができます。運用中の場合は、速やかに下記の作業を行ってください

# mongoコンテナにアクセス

$ docker-compose exec mongo bash
# mongo起動
% mongo
> rs.initiate() # レプリカセットの初期化

一旦これで、mongo1台で稼働中となります。

(念ため、接続できているかアプリケーションの確認は行いましょう)

ここからセカンダリーとアービターをレプリカセットの中に追加していきます。

mongo-set:PRIMARY> rs.add({ host: 'mongo-secondary:27017' })

mongo-set:PRIMARY> rs.add({ host: 'mongo-arbiter:27017', arbiterOnly: true })

確認

membersの中に設定したセカンダリーとアービターがいれば成功です。

mongo-set:PRIMARY> rs.status()

{
"set" : "mongo-set",
"date" : ISODate("2018-08-17T10:02:29.297Z"),
"myState" : 1,
"term" : NumberLong(1),
"syncingTo" : "",
.
.
.
"members" : [
{
"_id" : 0,
"name" : "1b00277ff073:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 987,
"optime" : {
"ts" : Timestamp(1534500141, 2),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2018-08-17T10:02:21Z"),
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "",
"electionTime" : Timestamp(1534499609, 2),
"electionDate" : ISODate("2018-08-17T09:53:29Z"),
"configVersion" : 3,
"self" : true,
"lastHeartbeatMessage" : ""
},
{
"_id" : 1,
"name" : "mongo-secondary:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 18,
"optime" : {
"ts" : Timestamp(1534500141, 2),
"t" : NumberLong(1)
},
"optimeDurable" : {
"ts" : Timestamp(1534500141, 2),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2018-08-17T10:02:21Z"),
"optimeDurableDate" : ISODate("2018-08-17T10:02:21Z"),
"lastHeartbeat" : ISODate("2018-08-17T10:02:27.858Z"),
"lastHeartbeatRecv" : ISODate("2018-08-17T10:02:28.361Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "",
"syncingTo" : "1b00277ff073:27017",
"syncSourceHost" : "1b00277ff073:27017",
"syncSourceId" : 0,
"infoMessage" : "",
"configVersion" : 3
},
{
"_id" : 2,
"name" : "mongo-arbiter:27017",
"health" : 1,
"state" : 7,
"stateStr" : "ARBITER",
"uptime" : 7,
"lastHeartbeat" : ISODate("2018-08-17T10:02:27.859Z"),
"lastHeartbeatRecv" : ISODate("2018-08-17T10:02:27.887Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "",
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "",
"configVersion" : 3
}
],
"ok" : 1,
"operationTime" : Timestamp(1534500141, 2),
"$clusterTime" : {
"clusterTime" : Timestamp(1534500141, 2),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}

レプリカセットできていますね。


セカンダリーからも読み込みできるように設定する

レプリカセットは完了しましたが、このままでは、プライマリー以外からは、DBの中身を参照することができませんので、参照できるように設定します。

$ docker-compose exec mongo-secondary bash                                                                                                                                                                                  % mongo

mongo-set:SECONDARY> db.getMongo().setSlaveOk()

確認

> use DATABASE

> db.COL.count()
113

参照できました。

さらに、セカンダリーのデータを保存するために用意した、mongo-secondaryというディレクトリがあるとおもいますが、、、

$ ls mongo-secondary

WiredTiger collection-15--2012905472052276688.wt collection-34--2012905472052276688.wt index-17--2012905472052276688.wt index-3--2012905472052276688.wt index-5--2012905472052276688.wt
WiredTiger.lock collection-18--2012905472052276688.wt collection-37--2012905472052276688.wt index-19--2012905472052276688.wt index-30--2012905472052276688.wt index-7--2012905472052276688.wt
WiredTiger.turtle collection-2--2012905472052276688.wt collection-4--2012905472052276688.wt index-21--2012905472052276688.wt index-32--2012905472052276688.wt index-9--2012905472052276688.wt
WiredTiger.wt collection-20--2012905472052276688.wt collection-6--2012905472052276688.wt index-22--2012905472052276688.wt index-33--2012905472052276688.wt journal/
WiredTigerLAS.wt collection-23--2012905472052276688.wt collection-8--2012905472052276688.wt index-24--2012905472052276688.wt index-35--2012905472052276688.wt mongod.lock
_mdb_catalog.wt collection-25--2012905472052276688.wt diagnostic.data/ index-26--2012905472052276688.wt index-36--2012905472052276688.wt sizeStorer.wt
collection-0--2012905472052276688.wt collection-28--2012905472052276688.wt index-1--2012905472052276688.wt index-27--2012905472052276688.wt index-38--2012905472052276688.wt storage.bson
collection-14--2012905472052276688.wt collection-31--2012905472052276688.wt index-16--2012905472052276688.wt index-29--2012905472052276688.wt index-39--2012905472052276688.wt

こちらにもデータが保存されていることがわかりますね。

以上で、レプリカセットが完了となります。

お疲れ様でした。