MongoDB
Terraform

クラウドサーバー上でMongoDBクラスタを構築してみた

More than 1 year has passed since last update.


はじめに

オンプレミス環境では、システムを構築する前にサーバー調達から物理作業・OSインストールが完了しないと構築作業が進めないのですが、クラウド環境では、ボタンを押すだけでネットワークからサーバーまで短時間で準備できます。そして、最近の「Infrastructure as Code」で、ボタンも押す必要がなくなりました。設定ファイルを記述することでサーバーやネットワーク構成が自動的にプロビージョンニングされるようになり、コマンドを実行するだけで「インフラストラクチャー」ができあがってしまいます。

個人的にはこれを見てすごく興味深いので、MongoDBクラスタをコード実行で構築できるようにしたくやってみました。ちょうど@mosuke5さんのterraformレポジトリのサンプルがあったので、サンプルを見ながらやってみました。


構成

image.png

Mongodbのレプリケーション構成では、最低レプリカ3台が必要です。そして、可用性を担保するため、それぞれのレプリカが別のスイッチに刺さる必要があります。そのため、Alibabaクラウド上では、以下の図どおりのコンポネントを作ります

architecture_mongo_cluster.png


コンポーネント


  • VPCネットワーク。CIDR: 10.0.0.0/16

  • それぞれのレプリカのプライベートネットワーク


    • 10.0.0.0/19: プライマリレプリカ

    • 10.0.32.0/19: セカンダリレプリカ

    • 10.0.64.0/19: セカンダリレプリカ



  • mongoクラスタ用のECSインスタンス


    • テストのため、1CPU-1GBメモリを使います



  • mongoクラスタのECSはグローバルIPを持つと外からデータストアへアクセスができてしまうため、プライベートIPしか付与しません。ソフトウェア更新やmongoインストールするために、それぞれのゾーンにSNATゲートウェイを構築します。SNATのECSがmongoクラスタへ影響しないように、別のサブネットワークにおきます。


    • パブリックCIDR: 10.0.128.0/20




構築


Terraformによる自動構築

設計したコンポーネントに従ってalicloud providersを使用して実装します。

詳細のソースコードはmosuke5さんのレポジトリに参照すればよいですが、providersは以下のふうになります。


resource "alicloud_vpc" "vpc" {
name = "mongovpc"
cidr_block = "${var.vpc_cidr}"
}

# vswitchの作成。mongo-primary
resource "alicloud_vswitch" "mongo-primary-switch" {
name = "mongo-primary-switch"
vpc_id = "${alicloud_vpc.vpc.id}"
cidr_block = "${var.mongo_primary_cidr}"
availability_zone = "${var.zones[0]}"
}

# vswitchの作成。mongo-secondary0
resource "alicloud_vswitch" "mongo-secondary0-switch" {
name = "mongo-secondary0-switch"
vpc_id = "${alicloud_vpc.vpc.id}"
cidr_block = "${var.mongo_secondary0_cidr}"
availability_zone = "${var.zones[1]}"
}
...

上記のプログラムを terraform apply --var-file="terraform.tfvars" を実行することで、図の構成が作成されます。

VSwitch/VRouter

image.png

サーバー

image.png


レプリカ設定

terraform を実行した後では、mongodbクラスタ (サーバー、ミドルウェア)ができあがります。クラスタの設定は ansibleとかで自動化できます。ただ、今回は手動でやります。

まず、mongodbは全インターフェイスで通信できるように、bindIpを削除し、replication set名を設定します。設定語にmongodbを起動します。この作業をmongodbの3台をそれぞれ行います。

[mongoadmin@mongo-primary ~]$ sudo vim /etc/mongodb.conf

net:
port: 27017
# bindIp: 127.0.0.1 # Listen to local interface only, comment to listen on all interfaces.

replication:
replSetName: testrepl

# :wq
[mongoadmin@mongo-primary ~]$ sudo systemctl start mongod.service
[mongoadmin@mongo-primary ~]$ sudo systemctl status mongod.service
● mongod.service - High-performance, schema-free document-oriented database
Loaded: loaded (/usr/lib/systemd/system/mongod.service; enabled; vendor preset: disabled)
Active: active (running) since Mon 2017-06-05 10:02:25 CST; 3s ago
Docs: https://docs.mongodb.org/manual
Process: 9504 ExecStartPre=/usr/bin/chmod 0755 /var/run/mongodb (code=exited, status=0/SUCCESS)
Process: 9502 ExecStartPre=/usr/bin/chown mongod:mongod /var/run/mongodb (code=exited, status=0/SUCCESS)
Process: 9501 ExecStartPre=/usr/bin/mkdir -p /var/run/mongodb (code=exited, status=0/SUCCESS)
Main PID: 9509 (mongod)
CGroup: /system.slice/mongod.service
└─9509 /usr/bin/mongod --quiet -f /etc/mongod.conf run

Jun 05 10:02:25 mongo-primary systemd[1]: Starting High-performance, schema-free document-oriented database...
Jun 05 10:02:25 mongo-primary systemd[1]: Started High-performance, schema-free document-oriented database.
Jun 05 10:02:25 mongo-primary mongod[9506]: about to fork child process, waiting until server is ready for connections.
Jun 05 10:02:25 mongo-primary mongod[9506]: forked process: 9509

次には、mongoシェルでreplication設定を行います。

[mongoadmin@mongo-primary ~]$ mongo

MongoDB shell version v3.4.4
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.4.4
Welcome to the MongoDB shell.
...
>
> rs.initiate( {
... _id : "testrepl",
... members: [
... { _id : 0, host : "10.0.26.159:27017" },
... { _id : 1, host : "10.0.43.6:27017" },
... { _id : 2, host : "10.0.91.206:27017" }
... ]
... })
{ "ok" : 1 }
> rs.status()
..
{
"_id" : 0,
"name" : "10.0.26.159:27017",
"health" : 1,
...
},
{
"_id" : 1,
"name" : "10.0.43.6:27017",
"health" : 1,
...
},
{
"_id" : 2,
"name" : "10.0.91.206:27017",
"health" : 1,
...
}

それぞれの"health": 1となっていることを確認します。

secondaryで当インスタンスがslaveインスタンスなことを設定します。

testrepl:SECONDARY> db.getMongo().setSlaveOk()


動作確認

testCollectionmongo-primaryサーバーで作って、データがsecondaryへコピーされることを確認します

testrepl:PRIMARY> db.testCollection.insertOne({what: "Test mongodb", status: "ok"})

{
"acknowledged" : true,
"insertedId" : ObjectId("5934bf70cefc8e44e631908e")
}

secondarytestCollectionをクエリしてみます。

testrepl:SECONDARY> db.testCollection.find()

{ "_id" : ObjectId("5934bf70cefc8e44e631908e"), "what" : "Test mongodb", "status" : "ok" }


おわりに

terraformを使ってシンプルなmongoクラスタを作ってみました。terraformを使うことで、クラウドサーバーの購入・設定のような作業を自動化できます。