MongoDB 4.0 + CentOS 7.5 を構築

こんにちは。grasys 清水です。

MongoDB の ver4.0 が6月(2018)に発表されましたね。

意外とネットにver4.0の構築ネタがなかったので今回はそちらをご紹介。

ver4.0からトランザクション機能が実装されたので、注目されている方もいるのではないでしょうか。

今回はCentOS 7にMongoDBのレプリカセットを構築していきます。

ver3.6以前と比べ、構築部分で少し変更点もあったのでそこにも触れます。

環境

CentOS Linux release 7.5 x 3台

ゴール

MongoDB 2台 + MongoDB Arbiter 1台 構成のレプリケーション

その前に。

レプリカセットを構築するのに最低 3台以上のノードが必要です。

でも全て同じスペックにするのは勿体無い、ということで、今回は3台のうち1台をArbitrにします。

Arbiterは「誰がPrimary(いわゆるマスター)になるのか」を投票する役割を持ったサーバ。

データセットを持たないのでArbiterを搭載するサーバは低スペックで構いません。

図解すると下の通り。

今回はわかりやすくdb01とdb02,そしてarb01というサーバを用意しました。

Primary/Secondary用のサーバとしてdb01/02を、Arbiter用のサーバとしてarb01を使います

何も指定しなければ、基本的にはPrimaryに対してwrite/readの処理を行います。

もし、db01がダウンした時、投票によってSecondaryだったdb02がPrimaryへと昇格します。

インストール

今回は手軽にyumで入れてみたいと思います。

まずはパッケージから。下をまるっとコピペしましょう。

cat << EOF > /etc/yum.repos.d/mongodb-org-4.0.repo
[mongodb-org-4.0]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/4.0/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-4.0.asc
EOF

そしてインストール

sudo yum install -y mongodb-org

できましたか?これをクラスタを構築する3台のサーバ全てにインストールします。

設定

3台ともインストールが完了したら、次はconfを編集していきます。

/etc/mongod.conf にデフォルトのファイルができてると思いますので、それを編集していきます。

Primary/Secodary用のmongoを二台作る

実際にデータを保持するDBを二台作成します。

$ vim /etc/mongod.conf

下記の設定を追加してください

storage:
  #dbPath: /var/lib/mongo
  dbPath: /var/lib/mongo/replica1/data # 実データが保存される場所。お好みの場所でどうぞ
  
~ (略) ~
net:
  port: 27017
  #bindIp: 127.0.0.1
  bindIp: 0.0.0.0
  
~ (略) ~
  replication: #コメントアウトを外す
   oplogSizeMB: 2048
   replSetName: replica1

もし、デフォルトと違うディレクトリを指定した場合は chownコマンドで所有者を変える必要があります。

mkdir -p /var/lib/mongo/replica1/data
chown mongod:mongod /var/lib/mongo/replica1/data

では起動してみましょう

systemctl start mongod

起動しているか確認

$ systemctl status mongod
● mongod.service - MongoDB Database Server
   Loaded: loaded (/usr/lib/systemd/system/mongod.service; enabled; vendor preset: disabled)
   Active: active (running) since Tue 2018-09-11 10:11:07 UTC; 2min 27s ago

起動しましたか?できたらmongoシェルを使ってみましょう

[root@db01]$ mongo
MongoDB shell version v4.0.2
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 4.0.2
Server has startup warnings:
>

もしかすると、いろんなWARNING が出ている方もいるかもしれません。「とりあえずすぐに使いたい!」という方は無視しても構いませんが、がっつり使いたい方は一つ一つ解消してあげるといいです。(ここでは取り上げません)

I CONTROL  [initandlisten] ** WARNING: Access control is not enabled for the database.
I CONTROL  [initandlisten] **          Read and write access to data and configuration is unrestricted.

ちょっと本当に動くのか rs.status() コマンドで確かめてみましょう。

> 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)
		}
	}
}

問題なさそうですね。

もちろんレプリケーションの設定はまだ完了してないので、

「レプリカセットの設定が完了してないよ〜」と怒られますが、今の所これが正解。

できたらもう一台も起動してみましょう。

Arbiterの起動

Arbiter用のmongoの構築をしていきます。

結果から言うと、ArbiterはPrimary/Secondaryと同じconf です。上記と同じ手順で 起動できます。

しかし、4.0から少し仕様が変わった部分があったので紹介します。

初めてmongoでレプリケーションを組む方は読み飛ばしてください。

storage:
  dbPath: /usr/local/var/mongodb/mongod/replica1/data
  journal:
    enabled: false

4.0以前は journal=false (ジャーナル=DBの書き込み実行前のオペレーションを一時保存する機能)設定がOFFにできました。(これのおかげでmongodの異常終了時、再起動と同時に保存したオペレーションを再実行することでリカバリできるのですが、Arbiterは投票ができればいいのでこの設定をOFFにすることがあります。)

どうやら ver4.0 からはデフォルトのストレージエンジンのWiredTigerでは上記の設定ができなくなったようです。

 (mongod.logに出力された内容から抜粋)
I STORAGE  [initandlisten] Running wiredTiger without journaling in a replica set is not supported. Make sure you are not using --nojournal and that storage.journal.enabled is not set to 'false'.   

ちなみにリリースノートにも書いてありました。 Release-Notes:journaling-and-replica-sets

なので、(今回はひとまず)Arbirterの設定はPrimary/Secondary用のmongoと同じconfで作成してます。

レプリケーションの設定

3台とも起動できましたか?

起動できたらレプリケーションの設定をしてみましょう。作業自体は超簡単です。

できたら、Primariにしたいサーバ(今回はdb01)で mongo をうってmongoシェルを起動します。

[root@db01]$ mongo
>

そしたら下記のコマンドを流します。

細かな設定をしたい場合は公式を参照してください。

conf = {
   _id : "replica1",
   members: [
      { _id: 0, host: "<db01のIP>:27017" },
      { _id: 1, host: "<db02のIP>:27017" },
      { _id: 2, host: "<arb01のIP>:27017", arbiterOnly: true },
   ]
}
rs.initiate(conf)

注目して欲しいのは、 arbiterOnly: true の部分。ここでちゃんと「 あなたはArbiterですよ」と指定してあげないと、データをコピーしたりPrimaryになれたりしてしまいます(つまり二つ目のSecondaryになります)。

ちなみに rs.addArb() でもArbiterを追加できます。

さて、こんな感じで OK : 1と出ましたか?

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

出たなら成功です。するとmongoシェルに変化が出てきます。

replica1:SECONDARY> <Enter>
replica1:SECONDARY> <Enter>
replica1:SECONDARY> <Enter>
replica1:PRIMARY>

シェルが replica1:SECONDARY> に変わりましたね。

ぽちぽちと時間を置きながらかEnterを押していると replica1:PRIMARY>に変わるかと思います。

これは設定が完了して、db01のmongoが Primary になったということです。

では実際にどんな設定になったのか見てみます。

replica1:PRIMARY> rs.conf()
{
	"_id" : "replica1",
	"version" : 1,
	"protocolVersion" : NumberLong(1),
	"writeConcernMajorityJournalDefault" : true,
	"members" : [
		{
			"_id" : 0,
			"host" : "<db01のIP>:27017",
			"arbiterOnly" : false,
			"buildIndexes" : true,
			"hidden" : false,
			"priority" : 1,
			"tags" : {

			},
			"slaveDelay" : NumberLong(0),
			"votes" : 1
		},
		{
			"_id" : 1,
			"host" : "<db02のIP>:27017",
			"arbiterOnly" : false,
			"buildIndexes" : true,
			"hidden" : false,
			"priority" : 1,
			"tags" : {

			},
			"slaveDelay" : NumberLong(0),
			"votes" : 1
		},
		{
			"_id" : 2,
			"host" : "<arb01のIP>:27017",
			"arbiterOnly" : true,
			"buildIndexes" : true,
			"hidden" : false,
			"priority" : 0,
			"tags" : {

			},
			"slaveDelay" : NumberLong(0),
			"votes" : 1
		}
	],
~ (略) ~
}

注目するのは "_id" : 2 の項目。ちゃんと arbiterOnly が true になってますね。

逆に他のmongoはarbiterが false になってることを確認してください。

はい、構築はこれで完了です。

ちょっとだけ操作

rs.stepDown()

db02をPrimaryにしたい時はdb01(Primaryの状態) のmongoシェルで rs.stepDown()コマンドを打ちます

replica1:PRIMARY> rs.stepDown()

すると Secondaryに変わります。

replica1:SECONDARY>

db02にでmongoシェルを起動してみてください。少し時間が経つと db02がPrimaryになっているはずです。

rs.status()

今、レプリケーションがどのような状態か知りたい時は rs.status() で状態を見れます。

先ほどはレプリケーション未設定だったので怒られましたが、今度は表示されるはずです。

終わりに

割とあっさり構築の方は終わったんじゃないでしょうか。

Arbiterの件以外にも気をつけなければいけない部分もありそうですが、

その他もろもろ試していきたいと思います。