クラウド上でMongoDBクラスタを構築する方法

オンプレミス環境では、サーバー調達から物理作業まで完成しないとミドルウェアの構築作業が進められません。その一方、クラウド環境では、ボタンを押すだけでネットワークからサーバーまで短時間で準備できるため、スケーラビリティのあるミドルウェアを簡単に構築できます。そして、「Infrastructure as Code」で、ボタンも押す必要がなくなりました。設定ファイルを記述することでサーバーやネットワーク構成が自動的に構成されるようになり、コマンドを実行するだけでミドルウェアが自動的にできてしまいます。

クラウド及び「Infrastructure as Code」のメリットを紹介したいため、Alibaba クラウド上でTerraformを用いてMongoDBを構築手順について書きます。

構成

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

コンポーネント

  • 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" を実行することで、図の構成が作成されます

terraform スクリプトを実行した後で作成されたVPCネットワーク
terraform が実行した後で作成されたMongoDB用のECSサーバー

レプリカ設定

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

おわりに

Alibabaクラウド上でMongoDBクラスタを構築する手順について聞きました。クラウドは低コストで短時間でシステムを構築できるメリットがあるため、気軽にいろいろなミドルウェアを試しに行きましょう。

この記事をシェアする