LoginSignup
6
6

More than 5 years have passed since last update.

MongoDB のレプリケーションを Docker をつかって体験する

Last updated at Posted at 2018-03-06

はじめに

MongoDB をつかったことがなかったのですが、触ってみてレプリケーションに出会いました。
レプリケーションは 複数の mongo を動かす必要があるので、 Docker をつかってローカルで、レプリケーションの動きを体験 してみました。

3つのコンテナを用意して、以下のような役割を与えます。

  • Primary
  • Secondary
  • Arbiter

スクリーンショット 2018-03-06 11.25.31.png

これで、Primary の mongo を止めて、Secondary が Primary に昇格するのを眺めたいと思います。

対象読者

  • MongoDB つかったことない
  • MongoDB のレプリケーション知らない
  • レプリケーションの概念はなんとなくわかる
  • Docker は使ったことある

バージョン

  • centos6
  • mongo3.6

流れ

  • コンテナを 3 つ用意する
  • 各コンテナの間で通信できる IPAddress を確認
  • 各コンテナで mongo を起動する
  • Primary, Secondary, Arbiter の設定をする
  • 動作を確認する

Step1 コンテナを 3 つ用意する

Docker Hub にイメージを用意しましたので、それを使います。

ターミナルを 3 つ開きます。そしてそれぞれ以下を叩きます。
3つかきますが、それぞれコンテナ名が mongo1 mongo2 mongo3 としているだけです。

terminal_1
$ docker run -it --name mongo1 mochizukikotaro/centos6-mongo3.6:0.0.1 bash
terminal_2
$ docker run -it --name mongo2 mochizukikotaro/centos6-mongo3.6:0.0.1 bash
terminal_3
$ docker run -it --name mongo3 mochizukikotaro/centos6-mongo3.6:0.0.1 bash

image (mochizukikotaro/centos6-mongo3.6/) の説明

centos6 をベースにして、mongo3.6を入れたイメージになっています。 service mongod start とかが打てる状態になっています。
また、 /etc/mongod.conf/etc/yum.repos.d/mongodb-org-3.6.repo を置いてあります。

詳細はこちらをご覧ください。
https://hub.docker.com/r/mochizukikotaro/centos6-mongo3.6/

Step2 各コンテナの間で通信できる IPAddress を確認

// プロセスを確認
$ docker ps --format "{{.Image}}\t{{.Names}}"
mochizukikotaro/centos6-mongo3.6:0.0.1  mongo3
mochizukikotaro/centos6-mongo3.6:0.0.1  mongo2
mochizukikotaro/centos6-mongo3.6:0.0.1  mongo1

// IPAddress を確認
$ dk inspect -f '{{.NetworkSettings.IPAddress}}' mongo1
172.17.0.2

上記のように IPAddress を確認できます。結果は以下の通りです。これをあとでレプリカセットを設定するときに使います。

コンテナ名 IP
mongo1 172.17.0.2
mongo2 172.17.0.3
mongo3 172.17.0.4

Step3 各コンテナで mongo を起動する

各コンテナ内
# service mongod status <- 確認したければ
# service mongod start

ただ、start するだけですね。

Step3 Primary, Secondary, Arbiter の設定をする

ここが本題ですね。基本的に terminal_1 で作業をします。

まずは rs.status() でレプリカセットのステータスを見ます。

terminal_1
# mongo
> rs.status()
{
    "info" : "run rs.initiate(...) if not yet done for the set",
    "ok" : 0,
    "errmsg" : "no replset config has been received",
    "code" : 94,
    "codeName" : "NotYetInitialized"
}

まだセットしてないなら、 rs.initiate(...) するようにとあります。

なので、早速したいと思います。

まずは Primary をつくる

ちなみに、 /etc/mongod.conf には以下の設定をしています。

/etc/mongod.conf_抜粋
replication:
  replSetName: "testRepl"

ですので、mongo 内で以下を打ちます。

terminal_1
rs.initiate(
   {
      _id: "testRepl",
      members: [
         { _id: 0, host : "172.17.0.2:27017" },
      ]
   }
)

IPAddress は Step2 で取得した mongo1 コンテナの IPAddress です。
上をうつと下のように帰ってきて、無事成功しました。

terminal_1
{
    "ok" : 1,
    "operationTime" : Timestamp(1520298587, 1),
    "$clusterTime" : {
        "clusterTime" : Timestamp(1520298587, 1),
        "signature" : {
            "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
            "keyId" : NumberLong(0)
        }
    }
}

すると以下のように rs.status() が変わります。

terminal_1
testRepl:PRIMARY> rs.status()
{
    "set" : "testRepl",
    "date" : ISODate("2018-03-06T01:13:23.932Z"),
    "myState" : 1,
    "term" : NumberLong(1),
    "heartbeatIntervalMillis" : NumberLong(2000),
    "optimes" : {
        "lastCommittedOpTime" : {
            "ts" : Timestamp(1520298799, 1),
            "t" : NumberLong(1)
        },
        "readConcernMajorityOpTime" : {
            "ts" : Timestamp(1520298799, 1),
            "t" : NumberLong(1)
        },
        "appliedOpTime" : {
            "ts" : Timestamp(1520298799, 1),
            "t" : NumberLong(1)
        },
        "durableOpTime" : {
            "ts" : Timestamp(1520298799, 1),
            "t" : NumberLong(1)
        }
    },
    "members" : [
        {
            "_id" : 0,
            "name" : "172.17.0.2:27017",
            "health" : 1,
            "state" : 1,
            "stateStr" : "PRIMARY",
            "uptime" : 1643,
            "optime" : {
                "ts" : Timestamp(1520298799, 1),
                "t" : NumberLong(1)
            },
            "optimeDate" : ISODate("2018-03-06T01:13:19Z"),
            "electionTime" : Timestamp(1520298587, 2),
            "electionDate" : ISODate("2018-03-06T01:09:47Z"),
            "configVersion" : 1,
            "self" : true
        }
    ],
    "ok" : 1,
    "operationTime" : Timestamp(1520298799, 1),
    "$clusterTime" : {
        "clusterTime" : Timestamp(1520298799, 1),
        "signature" : {
            "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
            "keyId" : NumberLong(0)
        }
    }
}

これで、mongo1 が Primary になりました。

つづいて Secondary をつくる

mongo2 を Secondary にします。 rs.add() を使います。
mongo2 の IP が 172.17.0.3 なので、以下のようになります。

terminal_1
testRepl:PRIMARY> rs.add({_id: 1, host: "172.17.0.3:27017"})
{
    "ok" : 1,
    "operationTime" : Timestamp(1520298995, 1),
    "$clusterTime" : {
        "clusterTime" : Timestamp(1520298995, 1),
        "signature" : {
            "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
            "keyId" : NumberLong(0)
        }
    }
}

これで、 terminal_2 を確認しますと、以下のように Secandary として入力を待っている感じです。

terminal_2
testRepl:SECONDARY>

最後に Arbiter をつくる

mongo3 の IP は 172.17.0.4 なので以下のようにします。

terminal_1
testRepl:PRIMARY> rs.addArb("172.17.0.4:27017")
{
    "ok" : 1,
    "operationTime" : Timestamp(1520299760, 1),
    "$clusterTime" : {
        "clusterTime" : Timestamp(1520299760, 1),
        "signature" : {
            "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
            "keyId" : NumberLong(0)
        }
    }
}

mongo3 を確認すると、無事に Arbiter となっています。

terminal_3
testRepl:ARBITER>

動作を確認する

まずは Primary で適当にデータを入れます。

terminal_1
testRepl:PRIMARY> use study
switched to db study
testRepl:PRIMARY> db.user.insert({name: 'taro'})
WriteResult({ "nInserted" : 1 })
testRepl:PRIMARY> db.user.find()
{ "_id" : ObjectId("5a9def656b45e5c362a6bf4d"), "name" : "taro" }

それを Secondary で確認します。

terminal_2
testRepl:SECONDARY> rs.slaveOk()
testRepl:SECONDARY> use study
switched to db study
testRepl:SECONDARY> db.user.find()
{ "_id" : ObjectId("5a9def656b45e5c362a6bf4d"), "name" : "taro" }

つぎに、Primary である mongo1 を止めて見ます。以下のように切り替わることがわかりました。

mongo.gif

また、 Primary で rs.stepDown() を打つことで、自身を Secondary に落として、他方を Primary にあげることもできます。

以上です。

補足

いろいろなかったことにしたいとき

mongod.conf の replication をコメントアウト

show databases
use local
db.dropDatabase()

コメントインして、再起動。

rs.initiate() をなかったことにしたいとき

use local
db.system.replset.remove({})
6
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6