kakts-log

programming について調べたことを整理していきます

docker-composeでmongoDBのレプリカセット構築

概要

mongoDBのレプリカセットを構築する際に、docker-composeをつかって、複数のコンテナを立ち上げる方法をまとめます。

docker-composeを使うことで、複数のコンテナの設定の記述と、コンテナ起動、停止が楽にできるため、ローカル環境などで軽くmongoDBのレプリカセットを構築したいときは非常に便利です。

今回は下記構成で1セットのレプリカセットを作ります。 f:id:kakts:20170621001525p:plain

mongod primary secondary合わせて計3コンテナ用意し、それぞれに ホスト環境の30001, 30002, 30003ポートを割り当てます。
primayノードが死んだときに、次のprimaryノードを決定するために必要なarbiterノードを1コンテナ作り、30004ポートを割り当てます。

環境

今回のレプリカセット構築における環境は以下のとおりです。

macOS sierra 10.12.5
docker: 17.03.1-ce
docker-compose 1.11.2
mongoDB 3.4.5

docker-compose.ymlを記述する

さっそく、4つ分のコンテナの設定をdocker-compose.ymlに記述していきます。
ここでは、使用するmongoのdockerイメージはmongo公式のリポジトリのものを使います。
https://hub.docker.com/_/mongo/

docker-compose.yml

version: "3"
services:
  mongod001:
    container_name: mongors001
    image: mongo:3.4.5
    command: mongod --replSet rs1 --noprealloc --smallfiles
    ports:
      - "30001:27017"
  mongod002:
    container_name: mongors002
    image: mongo:3.4.5
    command: mongod --replSet rs1 --noprealloc --smallfiles
    ports:
      - "30002:27017"
  mongod003:
    container_name: mongors003
    image: mongo:3.4.5
    command: mongod --replSet rs1 --noprealloc --smallfiles
    ports:
      - "30003:27017"
  mongoa001:
    container_name: mongoa001
    image: mongo:3.4.5
    command: mongod --replSet rs1 --noprealloc --smallfiles
    ports:
      - "30004:27017"

こんな感じでservices配下に レプリカセット用のmongodノード3台、arbiterノード1台分の記述をしていきます。
imageは mongo:3.4.5と書くことで、前述した公式mongoリポジトリの3.4.5タグのイメージを取ってきます。

mongoのコンテナを立ち上げると、デフォルトでコンテナ内の27017ポートを利用する*1ため、各ノード毎に “{ホストのポート番号}:27017” と記述してホストのポートと各コンテナ内のポートを紐付けます。

各コンテナのcommandで、実際にコンテナ内で起動するコマンドを記述します。
本稿では、レプリカセットの名前をrs1とします。

docker-composeでコンテナを立ち上げる

docker-composeでコンテナを立ち上げる準備ができたので、実際に立ち上げてみます。

docker-compose upコマンドで、実行しているディレクトリにあるdocker-compose.ymlファイルを読み込み、コンテナを立ち上げていきます。

今回はバックグラウンドで立ち上げるため、docker-compose up の-dオプションを付けます

# バックグラウンドでコンテナ立ち上げ
$ docker-compose up -d
Starting mongors002
Starting mongoa001
Starting mongors001
Starting mongors003

立ち上げ自体はコレだけです。 念のため、正常に立ち上がったか、docker-compose psコマンドで確認してみます。

$ docker-compose ps
   Name                 Command               State            Ports           
------------------------------------------------------------------------------
mongoa001    docker-entrypoint.sh mongo ...   Up      0.0.0.0:30004->27017/tcp 
mongors001   docker-entrypoint.sh mongo ...   Up      0.0.0.0:30001->27017/tcp 
mongors002   docker-entrypoint.sh mongo ...   Up      0.0.0.0:30002->27017/tcp 
mongors003   docker-entrypoint.sh mongo ...   Up      0.0.0.0:30003->27017/tcp 

指定したとおり、4つのコンテナが正常に上がっているのを確認できました。
ここでStateがUpになっていない場合は、docker-compose logsでエラーを確認して対処します。

各コンテナに紐付けられているポートも30001〜30004まで紐付けられているので、続いてはレプリカセットの設定を進めていきます。

mongoのレプリカセットを初期化する。

早速、起動したmongoコンテナに接続してmongoのレプリカセットの設定を行っていきます。
mongors001 という名前のコンテナに接続するため、 ホストのmongoコマンドを叩いて30001ポートに接続します。

# ホスト(mac)で実行
$ mongo --port 30001


# レプリカセット初期化
> rs.initiate

# ステータス確認
> rs.status()
{
    "set" : "rs1",
    "date" : ISODate("2017-06-20T15:04:39.227Z"),
    "myState" : 1,
    "term" : NumberLong(17),
    "heartbeatIntervalMillis" : NumberLong(2000),
    "optimes" : {
        "lastCommittedOpTime" : {
            "ts" : Timestamp(1497971077, 1),
            "t" : NumberLong(17)
        },
        "appliedOpTime" : {
            "ts" : Timestamp(1497971077, 1),
            "t" : NumberLong(17)
        },
        "durableOpTime" : {
            "ts" : Timestamp(1497971077, 1),
            "t" : NumberLong(17)
        }
    },
    "members" : [
        {
            "_id" : 0,
            "name" : "mongors001:27017",
            "health" : 1,
            "state" : 1,
            "stateStr" : "PRIMARY",
            "uptime" : 24,
            "optime" : {
                "ts" : Timestamp(1497971077, 1),
                "t" : NumberLong(17)
            },
            "optimeDate" : ISODate("2017-06-20T15:04:37Z"),
            "infoMessage" : "could not find member to sync from",
            "electionTime" : Timestamp(1497971056, 1),
            "electionDate" : ISODate("2017-06-20T15:04:16Z"),
            "configVersion" : 7,
            "self" : true
        }
    ],
    "ok" : 1
}

レプリカセットメンバー追加
> rs.add("mongors002:27017")
> rs.add("mongors003:27017")

arbiterメンバ追加
> rs.addArb("mongoa001:27017")

これでレプリカセットの初期化と、secondaryノード、arbiterノードの追加ができました。 細かいところは省きますが、 最後にrs.status()を確認すると下記のようにmembersに各ノードが追加されているのを確認できます。

> rs.status()
{
    "set" : "rs1",
    "date" : ISODate("2017-06-20T15:07:46.407Z"),
    "myState" : 1,
    "term" : NumberLong(17),
    "heartbeatIntervalMillis" : NumberLong(2000),
    "optimes" : {
        "lastCommittedOpTime" : {
            "ts" : Timestamp(1497971258, 1),
            "t" : NumberLong(17)
        },
        "appliedOpTime" : {
            "ts" : Timestamp(1497971258, 1),
            "t" : NumberLong(17)
        },
        "durableOpTime" : {
            "ts" : Timestamp(1497971258, 1),
            "t" : NumberLong(17)
        }
    },
    "members" : [
        {
            "_id" : 0,
            "name" : "mongors001:27017",
            "health" : 1,
            "state" : 1,
            "stateStr" : "PRIMARY",
            "uptime" : 211,
            "optime" : {
                "ts" : Timestamp(1497971258, 1),
                "t" : NumberLong(17)
            },
            "optimeDate" : ISODate("2017-06-20T15:07:38Z"),
            "electionTime" : Timestamp(1497971056, 1),
            "electionDate" : ISODate("2017-06-20T15:04:16Z"),
            "configVersion" : 11,
            "self" : true
        },
        {
            "_id" : 1,
            "name" : "mongors002:27017",
            "health" : 1,
            "state" : 2,
            "stateStr" : "SECONDARY",
            "uptime" : 114,
            "optime" : {
                "ts" : Timestamp(1497971258, 1),
                "t" : NumberLong(17)
            },
            "optimeDurable" : {
                "ts" : Timestamp(1497971258, 1),
                "t" : NumberLong(17)
            },
            "optimeDate" : ISODate("2017-06-20T15:07:38Z"),
            "optimeDurableDate" : ISODate("2017-06-20T15:07:38Z"),
            "lastHeartbeat" : ISODate("2017-06-20T15:07:44.551Z"),
            "lastHeartbeatRecv" : ISODate("2017-06-20T15:07:43.562Z"),
            "pingMs" : NumberLong(0),
            "configVersion" : 11
        },
        {
            "_id" : 2,
            "name" : "30002:27017",
            "health" : 0,
            "state" : 8,
            "stateStr" : "(not reachable/healthy)",
            "uptime" : 0,
            "optime" : {
                "ts" : Timestamp(0, 0),
                "t" : NumberLong(-1)
            },
            "optimeDurable" : {
                "ts" : Timestamp(0, 0),
                "t" : NumberLong(-1)
            },
            "optimeDate" : ISODate("1970-01-01T00:00:00Z"),
            "optimeDurableDate" : ISODate("1970-01-01T00:00:00Z"),
            "lastHeartbeat" : ISODate("2017-06-20T15:07:44.553Z"),
            "lastHeartbeatRecv" : ISODate("1970-01-01T00:00:00Z"),
            "pingMs" : NumberLong(0),
            "lastHeartbeatMessage" : "Invalid argument",
            "configVersion" : -1
        },
        {
            "_id" : 3,
            "name" : "mongors003:27017",
            "health" : 1,
            "state" : 2,
            "stateStr" : "SECONDARY",
            "uptime" : 74,
            "optime" : {
                "ts" : Timestamp(1497971258, 1),
                "t" : NumberLong(17)
            },
            "optimeDurable" : {
                "ts" : Timestamp(1497971258, 1),
                "t" : NumberLong(17)
            },
            "optimeDate" : ISODate("2017-06-20T15:07:38Z"),
            "optimeDurableDate" : ISODate("2017-06-20T15:07:38Z"),
            "lastHeartbeat" : ISODate("2017-06-20T15:07:44.551Z"),
            "lastHeartbeatRecv" : ISODate("2017-06-20T15:07:43.568Z"),
            "pingMs" : NumberLong(0),
            "configVersion" : 11
        },
        {
            "_id" : 4,
            "name" : "mongoa001:27017",
            "health" : 1,
            "state" : 7,
            "stateStr" : "ARBITER",
            "uptime" : 7,
            "lastHeartbeat" : ISODate("2017-06-20T15:07:44.550Z"),
            "lastHeartbeatRecv" : ISODate("2017-06-20T15:07:43.720Z"),
            "pingMs" : NumberLong(1),
            "configVersion" : 11
        }
    ],
    "ok" : 1
}