https://www.mongodb.com/docs/manual/release-notes/6.0-compatibility/#legacy-mongo-shell-removed
PRIMARY:レプリカセット中に1台だけ存在する書き込み可能なサーバー。
SECONDARY:Primaryのデータ更新を行う読み取り専用のサーバー。
ARBITER:データは保持せず、Primaryへの昇格投票のみを行うサーバー。自身がPrimaryになることはなく、Arbiterは必須ではない。
(1). レプリケーション(レプリカセット)を構築するにあたり、ディレクトリ構成は以下になります。
mongo
├── docker-compose.yml
├── data ← MongoDBのデータの格納場所
│ ├── primary
│ └── secondary
└── etc
├── mongod-keyfile ← 認証キーファイル
└── init
└── init.js ← 初期化スクリプト
(2). 上記のディレクトリ構成に基づき必要なディレクトリを作成します。
$ sudo mkdir /usr/local/mongo
$ cd /usr/local/mongo
$ sudo mkdir data
$ sudo mkdir data/primary
$ sudo mkdir data/secondary
$ sudo mkdir etc
$ sudo mkdir etc/init
(3). docker-compose.ymlファイルを新規作成し、以下を記載して保存します。
$ cd /usr/local/mongo
$ sudo vi docker-compose.yml
version: '3.9'
services:
mongodb-primary:
image: mongo:6.0.5
container_name: mongodb-primary
hostname: mongodb-primary
command: mongod --replSet replset --auth --keyFile /etc/mongod-keyfile
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: password
volumes:
# データの永続化
- ./data/primary:/data/db
# 初期化スクリプトの配置
- ./etc/init/:/docker-entrypoint-initdb.d/:ro
# 認証鍵(キーファイル)配置
- ./etc/mongod-keyfile:/etc/mongod-keyfile:ro
expose:
- 27017
ports:
- 27011:27017
networks:
- replset
restart: always
mongodb-secondary:
image: mongo:6.0.5
container_name: mongodb-secondary
hostname: mongodb-secondary
command: mongod --replSet replset --auth --keyFile /etc/mongod-keyfile
volumes:
# データの永続化
- ./data/secondary:/data/db
# 認証鍵(キーファイル)配置
- ./etc/mongod-keyfile:/etc/mongod-keyfile:ro
expose:
- 27017
ports:
- 27012:27017
networks:
- replset
restart: always
mongodb-arbiter:
image: mongo:6.0.5
container_name: mongodb-arbiter
hostname: mongodb-arbiter
command: mongod --replSet replset --auth --keyFile /etc/mongod-keyfile
volumes:
# arbiterはデータを保持しないため、データの永続化は不要
# 認証鍵(キーファイル)配置
- ./etc/mongod-keyfile:/etc/mongod-keyfile:ro
expose:
- 27017
ports:
- 27013:27017
networks:
- replset
restart: always
networks:
replset:
ipam:
config:
- subnet: 192.168.1.0/24
※各サーバーの役割はそれぞれ以下になります。
mongodb-primary:PRIMARY
mongodb-secondary:SECONDARY
mongodb-arbiter:ARBITER
(4). 認証鍵(キーファイル)を作成します。
$ su - root
# cd /usr/local/mongo
# openssl rand -base64 756 > etc/mongod-keyfile
# chmod 600 etc/mongod-keyfile
# chown 999 etc/mongod-keyfile
# exit
(5). 初期化スクリプトを作成し、以下を記載して保存します。
$ cd /usr/local/mongo
$ sudo vi etc/init/init.js
rs.initiate({
_id: "replset",
members: [{
_id: 0,
host: "mongodb-primary:27017",
priority: 100
}, {
_id: 1,
host: "mongodb-secondary:27017",
priority: 10
}, {
_id: 2,
host: "mongodb-arbiter:27017",
arbiterOnly: true
}]
});
(6). コンテナを起動します。
$ cd /usr/local/mongo
$ docker-compose up -d
[+] Running 4/4
✔ Network mongo_replset Created
✔ Container mongodb-secondary Started
✔ Container mongodb-primary Started
✔ Container mongodb-arbiter Started
(7). コンテナが正しく起動しているか確認します。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
34a735f80f3e mongo:6.0.5 "docker-entrypoint.s…" 5 seconds ago Up 4 seconds 0.0.0.0:27012->27017/tcp, :::27012->27017/tcp mongodb-secondary
0bcfbf484fb5 mongo:6.0.5 "docker-entrypoint.s…" 5 seconds ago Up Less than a second 0.0.0.0:27011->27017/tcp, :::27011->27017/tcp mongodb-primary
a52856076f23 mongo:6.0.5 "docker-entrypoint.s…" 5 seconds ago Up 3 seconds 0.0.0.0:27013->27017/tcp, :::27013->27017/tcp mongodb-arbiter
(8). 初期化スクリプトを実行します。
docker-compose exec mongodb-primary mongosh admin -u root -p password /docker-entrypoint-initdb.d/init.js
mongodb-primary:PRIMARY
mongodb-secondary:SECONDARY
mongodb-arbiter:ARBITER
(1). mongodb-primaryへ接続します。
$ docker exec -it mongodb-primary bash
(2). MongoDBへログインします。
root@mongodb-primary:/# mongosh
replset:PRIMARY> use admin
replset:PRIMARY> db.auth("root","password")
(3). レプリケーション(レプリカセット)の状態を表示します。
replset:PRIMARY> rs.status()
(4). 正しくレプリケーション(レプリカセット)設定を行えていた場合は以下のようなステータス(一部抜粋)が表示されます。
"members" : [
{
"_id" : 0,
"name" : "mongodb-primary:27017",
"stateStr" : "PRIMARY"
},
{
"_id" : 1,
"name" : "mongodb-secondary:27017",
"stateStr" : "SECONDARY"
},
{
"_id" : 2,
"name" : "mongodb-arbiter:27017",
"stateStr" : "ARBITER"
}
]
※stateStrが各サーバーのレプリケーション(レプリカセット)における役割を示しています。上記のコマンド結果から現在各サーバーに以下の役割が設定されています。
mongodb-primary:PRIMARY
mongodb-secondary:SECONDARY
mongodb-arbiter:ARBITER
(1). mongodb-secondaryへ接続します。
$ docker exec -it mongodb-secondary bash
(2). MongoDBへログインします。
root@mongodb-secondary:/# mongosh
replset:SECONDARY> use admin
replset:SECONDARY> db.auth("root","password")
(3). mongodb-secondaryで読取操作を行うために以下のコマンドを入力し
ます。
replset:SECONDARY> db.getMongo().setReadPref("primaryPreferred")
※rs.slaveOk()とrs.secondaryOk()は非推奨になったため上記コマンドを使用しています。
(4). ドキュメントを検索します。
replset:SECONDARY> use test
replset:SECONDARY> db.user.find()
※この時点では検索結果は0件になります。
※(3)のコマンドを事前に実行していないと以下のエラーが表示されます。
MongoServerError: not primary and secondaryOk=false - consider using db.getMongo().setReadPref() or readPreference in the connection string
(5). mongodb-primaryでドキュメントを挿入します。
$ docker exec -it mongodb-primary bash
root@mongodb-primary:/# mongosh
replset:PRIMARY> use admin
replset:PRIMARY> db.auth("root","password")
replset:PRIMARY> use test
replset:PRIMARY> db.user.insertOne({name: 'test'})
replset:PRIMARY> db.user.find()
[ { _id: ObjectId("643baec213cf4070041c5fcc"), name: 'test' } ]
※ドキュメントを挿入したため検索結果は1件表示されます。
(6). mongodb-secondaryでドキュメントを検索します。
$ docker exec -it mongodb-secondary bash
root@mongodb-secondary:/# mongosh
replset:SECONDARY> use admin
replset:SECONDARY> db.auth("root","password")
replset:SECONDARY> db.getMongo().setReadPref("primaryPreferred")
replset:SECONDARY> use test
replset:SECONDARY> db.user.find()
[ { _id: ObjectId("643baec213cf4070041c5fcc"), name: 'test' } ]
※データが同期され検索結果は1件表示されます。
(1). mongodb-primaryを停止します。
$ docker stop mongodb-primary
(2). mongodb-primaryが表示されないことを確認します。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
34a735f80f3e mongo:6.0.5 "docker-entrypoint.s…" 22 minutes ago Up 22 minutes 0.0.0.0:27012->27017/tcp, :::27012->27017/tcp mongodb-secondary
a52856076f23 mongo:6.0.5 "docker-entrypoint.s…" 22 minutes ago Up 22 minutes 0.0.0.0:27013->27017/tcp, :::27013->27017/tcp mongodb-arbiter
(3). mongodb-secondaryへ接続します。
$ docker exec -it mongodb-secondary bash
(4). MongoDBへログインします。PRIMARYに昇格したため、replset:PRIMARYと表示されることを確認します。
root@mongodb-secondary:/# mongosh
replset:PRIMARY> use admin
replset:PRIMARY> db.auth("root","password")
(5). レプリケーション(レプリカセット)の状態を表示します。
replset:PRIMARY> rs.status()
(6). mongodb-secondaryがPRIMARYに昇格していることを確認します。
"members" : [
{
"_id" : 0,
"name" : "mongodb-primary:27017",
"health" : 0,
"stateStr" : "(not reachable/healthy)"
},
{
"_id" : 1,
"name" : "mongodb-secondary:27017",
"health" : 1,
"stateStr" : "PRIMARY"
},
{
"_id" : 2,
"name" : "mongodb-arbiter:27017",
"health" : 1,
"stateStr" : "ARBITER"
}
]
(1). mongodb-primaryを起動します。
$ docker start mongodb-primary
(2). mongodb-primaryが表示されていることを確認します。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
34a735f80f3e mongo:6.0.5 "docker-entrypoint.s…" 26 minutes ago Up 26 minutes 0.0.0.0:27012->27017/tcp, :::27012->27017/tcp mongodb-secondary
0bcfbf484fb5 mongo:6.0.5 "docker-entrypoint.s…" 26 minutes ago Up 2 seconds 0.0.0.0:27011->27017/tcp, :::27011->27017/tcp mongodb-primary
a52856076f23 mongo:6.0.5 "docker-entrypoint.s…" 26 minutes ago Up 26 minutes 0.0.0.0:27013->27017/tcp, :::27013->27017/tcp mongodb-arbiter
(3). mongodb-secondaryへ接続します。
$ docker exec -it mongodb-secondary bash
(4). MongoDBへログインします。SECONDARYに降格したため、replset:SECONDARYと表示されることを確認します。
root@mongodb-secondary:/# mongosh
replset:SECONDARY> use admin
replset:SECONDARY> db.auth("root","password")
(5). レプリケーション(レプリカセット)の状態を表示します。
replset:SECONDARY> rs.status()
(6). mongodb-primaryサーバーが復帰し、PRIMARYとして設定されていることを確認します。
"members" : [
{
"_id" : 0,
"name" : "mongodb-primary:27017",
"health" : 1,
"stateStr" : "PRIMARY",
},
{
"_id" : 1,
"name" : "mongodb-secondary:27017",
"health" : 1,
"stateStr" : "SECONDARY"
},
{
"_id" : 2,
"name" : "mongodb-arbiter:27017",
"health" : 1,
"stateStr" : "ARBITER"
}
]
※復帰したmongodb-primaryサーバーをPRIMARYとするかSECONDARYにするかはpriorityにより決定します。
本手順書ではmongodb-primaryサーバーのpriorityを100に設定し、mongodb-secondaryサーバーのpriorityを10に設定しているため、mongodb-primaryサーバーはPRIMARYとして復帰します。
以上で全ての手順は完了になります