docker-compose로 MongoDB ReplicaSet 환경 구축하기

Key Kim
7 min readDec 2, 2021

--

https://docs.mongodb.com/manual/replication/

docker-compose로 3개의 node를 가지는 mongodb replicaset (P-S-S)환경을 구축해봅니다.

마지막에는 노드를 죽여보면서 HA 설정을 테스트해보겠습니다.

모든 소스코드는 아래에 있습니다.

docker-compose.yaml

service.demo-mongo-keys 에서 KeyFile을 만드는 이유는 mongo replica set 멤버끼리 keyFile 을 사용하여 인증하도록 하기 위함입니다.

자세한 내용은 아래 문서를 참고해주세요.

scripts/init.js

replicaset을 초기화하기 위한 명령어 모음입니다.

rs.initiate 에서 선언한 정보는 노드들의 주소입니다.

10.0.0.17 은 docker-compose에서 networks.demo-replica-set의 gateway IP입니다.

docker-compose에 명시한대로, 27020 ~ 27023포트로 향하는 모든 요청을 10.0.0.17 로 보내주고, 이를 포트포워딩하여 각 포트에 맞는 mongoDB에 연결해주게 됩니다.

참고로 현재 구조에선 기본 도커 브릿지인 172.17.0.1 , localhost인 127.0.0.1 에서도 27020 ~ 27022 포트로 mongoDB에 접근 가능합니다.

만약 10.0.0.17 에서만 접근하게 하려면 docker-compose의 ports를

27020:27017 에서 10.0.0.17:27020:27017 (27020 ~ 27022 도 마찬가지)

로 수정해주시면 됩니다.

priority의 경우, 숫자가 클수록 높은 priority를 가진다는 의미이며, 가장 높은 priority 는 primary 노드가 됩니다.

여기서는 10.0.0.17:27020 이 primary 노드가 될 예정입니다.

priority가 primary 노드 선정시 모든걸 결정하지는 않습니다.

다수의 노드들이 인정한(majority) 경우에만 primary 노드로 선출이 가능하며, 상황에 따라 arbiter 노드를 추가하는게 안정적인 primary 노드 선거를 보장해줄 수 있을 것 같습니다. 아래 글에서 자세히 다루고 있으니 참고해주세요 :)

scripts/init.sh

init.js 를 mongo 프로세스에 실행시킵니다.

sleep 3 은 모든 노드가 정상적으로 동작할 때를 기다리기 위한 대기시간입니다.

이제 실행시켜봅시다.

docker-compose up

잠시 기다리면 초기화가 완료됩니다.

그 후 아래 명령을 실행해봅니다.

docker-compose exec -it demo-mongo-test bashmongo "mongodb://root:1q2w3e4r@10.0.0.17:27020,10.0.0.17:27021,10.0.0.17:27022/admin?replicaSet=demo-replica-set">>> rs.status()
...
"members" : [
{
"_id" : 0,
"name" : "10.0.0.17:27020",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 59,
"optime" : {
"ts" : Timestamp(1638336167, 1),
"t" : NumberLong(1)
},
....
},
{
"_id" : 1,
"name" : "10.0.0.17:27021",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 57,
...
},
{
"_id" : 2,
"name" : "10.0.0.17:27022",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 57,
"optime" : {
"ts" : Timestamp(1638336167, 1),
"t" : NumberLong(1)
},
"optimeDurable" : {
"ts" : Ti
....

우선순위를 가장 높은 숫자로 준 노드 10.0.0.17:27020가 primary node가 된것을 볼 수 있습니다.

이제 primary node를 죽여봅시다

docker stop demo-mongo-primarydocker-compose exec -it demo-mongo-test bashmongo "mongodb://root:1q2w3e4r@10.0.0.17:27020,10.0.0.17:27021,10.0.0.17:27022,10.0.0.17:27023/admin?replicaSet=demo-replica-set">>> rs.status()
....
"members" : [
{
"_id" : 0,
"name" : "10.0.0.17:27020",
"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)
},
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "Error connecting to 10.0.0.17:27020 :: caused by :: Connection refused",
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "",
"configVersion" : 2,
"configTerm" : 3
},
{
"_id" : 1,
"name" : "10.0.0.17:27021",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 1131,
"optime" : {
"ts" : Timestamp(1638333007, 1),
"t" : NumberLong(4)
},
...
},
{
"_id" : 2,
"name" : "10.0.0.17:27022",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
.............

위에서 지정한 노드 중 우선순위가 3으로 가장 높은 10.0.0.17:27021이 primary 노드가 된 것을 볼 수 있습니다.

감사합니다.

--

--