MongoDB4.0で遂にトランザクションに対応したので、先日アップデートを行った。
こちらの記事↓
MongoDBをバージョン4.0にアップグレード in Docker
ただ、Mongoを1台で起動しているため、今のままではトランザクションは使えないのだ。
トランザクションに対応するためには、レプリカセットしなければならない。
今まで面倒で行っていなかったレプリカセットを行おうと思う。
レプリカセットの構成
最小限の構成として、プライマリー1台、セカンダリー2台、アービター1台で作成します。
プライマリーとかアービターについてはこちら
https://qiita.com/hakozaki/items/c41a5e6e7f0fad557c43
また、Dockerを使っているので、コンテナ1台につき1DBにして、ネットワークでそれぞれを繋ぐ構成でいきます。
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
を編集
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
は最終的にこんな感じになります。
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
こちらにもデータが保存されていることがわかりますね。
以上で、レプリカセットが完了となります。
お疲れ様でした。