MongoDB 를 docker로 세팅해보자

몽고디비를 로컬환경에 설치를 해야하는데 라우트서버와 샤드서버 콘피그서버를 설치하려니까 이것저것 해야할 부분들이 너무많아서 docker 로 설치하는 방법이 제일 빠를거 같아 docker 를 올려보았다.

기본 세팅

#docker  설치
yum -y install docker

#docker compose 설치
sudo curl -L https://github.com/docker/compose/releases/download/1.22.0/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
docker-compose --version
docker-compose version 1.22.0, build 1719ceb

compose yaml 파일 생성

#디렉토리 생성
mkdir /home/mongodb

#파일생성
vim docker-compose.yaml

version: '2'
services:
  mongorsn1:
    container_name: mongors1n1
    image: mongo
    command: mongod --shardsvr --replSet mongors1 --dbpath /data/db --port 27017
    ports:
      - 27017:27017
    expose:
      - "27017"
    environment:
      TERM: xterm
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /mongo_cluster/data1:/data/db
  mongors1n2:
    container_name: mongors1n2
    image: mongo
    command: mongod --shardsvr --replSet mongors1 --dbpath /data/db --port 27017
    ports:
      - 27027:27017
    expose:
      - "27017"
    environment:
      TERM: xterm
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /mongo_cluster/data2:/data/db
  mongors1n3:
    container_name: mongors1n3
    image: mongo
    command: mongod --shardsvr --replSet mongors1 --dbpath /data/db --port 27017
    ports:
      - 27037:27017
    expose:
      - "27017"
    environment:
      TERM: xterm
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /mongo_cluster/data3:/data/db
  mongocfg1:
    container_name: mongocfg1
    image: mongo
    command: mongod --configsvr --replSet mongors1conf --dbpath /data/db --port 27017
    environment:
      TERM: xterm
    expose:
      - "27017"
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /mongo_cluster/config1:/data/db
  mongocfg2:
    container_name: mongocfg2
    image: mongo
    command: mongod --configsvr --replSet mongors1conf --dbpath /data/db --port 27017
    environment:
      TERM: xterm
    expose:
      - "27017"
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /mongo_cluster/config2:/data/db
  mongocfg3:
    container_name: mongocfg3
    image: mongo
    command: mongod --configsvr --replSet mongors1conf --dbpath /data/db --port 27017
    environment:
      TERM: xterm
    expose:
      - "27017"
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /mongo_cluster/config3:/data/db
  mongos1:
    container_name: mongos1
    image: mongo
    depends_on:
      - mongocfg1
      - mongocfg2
    command: mongos --configdb mongors1conf/mongocfg1:27017,mongocfg2:27017,mongocfg3:27017 --port 27017 --bind_ip_all
    ports:
      - 27019:27017
    expose:
      - "27017"
    volumes:
      - /etc/localtime:/etc/localtime:ro
  mongos2:
    container_name: mongos2
    image: mongo
    depends_on:
      - mongocfg1
      - mongocfg2
    command: mongos --configdb mongors1conf/mongocfg1:27017,mongocfg2:27017,mongocfg3:27017 --port 27017 --bind_ip_all
    ports:
      - 27020:27017
    expose:
      - "27017"
    volumes:
      - /etc/localtime:/etc/localtime:ro

실행

docker-compose up -d
`
docker ps -a
CONTAINER ID  IMAGE    COMMAND                  CREATED      STATUS       PORTS                      NAMES
051d3f0e87b0  mongo    "docker-entrypoint..."   2 hours ago  Up 2 hours   0.0.0.0:27020->27017/tcp   mongos2
e8e29446fa17  mongo    "docker-entrypoint..."   2 hours ago  Up 2 hours   0.0.0.0:27019->27017/tcp   mongos1
a031815d22a   mongo    "docker-entrypoint..."   4 hours ago  Up 3 hours   27017/tcp                  mongocfg2
e56c1111482   mongo    "docker-entrypoint..."   4 hours ago  Up 3 hours   27017/tcp                  mongocfg1
858dc7463fa   mongo    "docker-entrypoint..."   4 hours ago  Up 3 hours   27017/tcp                  mongocfg3
934b4fe8f8a8  mongo    "docker-entrypoint..."   4 hours ago  Up 3 hours   0.0.0.0:27037->27017/tcp   mongors1n3
0181076d2845  mongo    "docker-entrypoint..."   4 hours ago  Up 3 hours   0.0.0.0:27027->27017/tcp   mongors1n2
cfdea54a34c9  mongo    "docker-entrypoint..."   4 hours ago  Up 3 hours   0.0.0.0:27017->27017/tcp   mongors1n1
`

#콘피그 서버 replica set 구성
docker exec -it mongocfg1 bash -c "echo 'rs.initiate({_id: \"mongors1conf\",configsvr: true, members: [{ _id : 0, host : \"mongocfg1\" },{ _id : 1, host : \"mongocfg2\" }, { _id : 2, host : \"mongocfg3\" }]})' | mongo"
#콘피그서버 체크
docker exec -it mongocfg1 bash -c "echo 'rs.status()' | mongo"
#위와 같은명령어로 확인시 members 노드에 PRIMARY 1개와 SECONDARY 2개로 멤버가 구성되있는것을 확인할수있다.

#샤드 서버 replica set 구성
docker exec -it mongors1n1 bash -c "echo 'rs.initiate({_id : \"mongors1\", members: [{ _id : 0, host : \"mongors1n1\" },{ _id : 1, host : \"mongors1n2\" },{ _id : 2, host : \"mongors1n3\" }]})' | mongo"
#샤드서버 체크
docker exec -it mongors1n1 bash -c "echo 'rs.status()' | mongo"
#위와 같은 명령어로 확인시 members 노드에 PRIMARY 1개와 SECONDARY 2개로 멤버가 구성되있는것을 확인할수있다.

#라우트 서버에 샤드서버 추가
docker exec -it mongos1 bash -c "echo 'sh.addShard(\"mongors1/mongors1n1\")' | mongo "
 
#라우트 서버 확인
docker exec -it mongos1 bash -c "echo 'sh.status()' | mongo "
`
 shards:
        {  "_id" : "mongors1",  "host" : "mongors1/mongors1n1:27017,mongors1n2:27017,mongors1n3:27017",  "state" : 1 }
`
#테스트를 하던도중  세컨드리에서 검색을 하는 도중 다음과같은 오류가 발생하였다.
`
mongors1:SECONDARY> db.test.count()

2018-06-26T14:04:40.682+0900 E QUERY    [js] Error: count failed: {
        "operationTime" : Timestamp(1533099879, 1),
        "ok" : 0,
        "errmsg" : "not master and slaveOk=false",
        "code" : 13435,
        "codeName" : "NotMasterNoSlaveOk",
        "$gleStats" : {
                "lastOpTime" : Timestamp(0, 0),
                "electionId" : ObjectId("000000000000000000000000")
        },
        "lastCommittedOpTime" : Timestamp(1533099879, 1),
        "$configServerState" : {
                "opTime" : {
                        "ts" : Timestamp(1533099870, 2),
                        "t" : NumberLong(3)
                }
        },
        "$clusterTime" : {
                "clusterTime" : Timestamp(1533099879, 1),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        }

`
#rs.slaveOk()
#해당 명령어로 해결할수있다.
mongos 1,2 는 라우터서버다.
라우트서버에서는 모든 요청을 받는다.
php 에서  https://packagist.org/packages/mongodb/mongodb 해당 라이브러리를 사용한다면 다음과 같은 코드를 사용한다
해당 코드 순서의 위치와는 상관없이 랜덤하게 access 하며 27020 포트가 죽었을때는 27019 로 요청하는것을 확인하였다. 아래 ngrep sample 참조.

mongocfg 1,2,3 은 컨피그 서버다.
컨피그서버에서는 shard 에 어떻게 데이터가 분산되어있는지에 대한 메타정보를 가지고있는 서버이다. 메타정보가 있기때문에 라우터에서 컨피그서버에 요청후 샤드서버에서 데이터를 가져올수 있게된다.

mongors1n1,2,3 은 샤드서버다.
샤드서버는 데이터를 수직 혹은 수평으로 데이터를 분산처리하여 저장한다. 해당 서버늘리면 scale-out 이 가능해지고, chunk 라는 단위로 데이터가 파일이 쪼개진다.

<?php
use MongoDB\Client;
new Client('mongodb://127.0.0.1:27020,127.0.0.1:27019');

프라이머리 선출 테스트

docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                      NAMES
051d3f0e87b0        mongo               "docker-entrypoint..."   3 hours ago         Up 3 hours          0.0.0.0:27020->27017/tcp   mongos2
e8e29446fa17        mongo               "docker-entrypoint..."   3 hours ago         Up 3 hours          0.0.0.0:27019->27017/tcp   mongos1
a031815d22a9        mongo               "docker-entrypoint..."   5 hours ago         Up 4 hours          27017/tcp                  mongocfg2
e56c11114823        mongo               "docker-entrypoint..."   5 hours ago         Up 4 hours          27017/tcp                  mongocfg1
858dc7463f0a        mongo               "docker-entrypoint..."   5 hours ago         Up 4 hours          27017/tcp                  mongocfg3
934b4fe8f8a8        mongo               "docker-entrypoint..."   5 hours ago         Up 4 hours          0.0.0.0:27037->27017/tcp   mongors1n3
0181076d2845        mongo               "docker-entrypoint..."   5 hours ago         Up 4 hours          0.0.0.0:27027->27017/tcp   mongors1n2
cfdea54a34c9        mongo               "docker-entrypoint..."   5 hours ago         Up 4 hours          0.0.0.0:27017->27017/tcp   mongors1n1
3d6f0cc60b47        centos              "/bin/bash"              15 hours ago        Up 5 hours                                     forcommit

# mongors1n1  얘가 프라이머리 샤드
docker kill mongors1n1

docker ps -a
docker ps -a         
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                       PORTS                      NAMES
051d3f0e87b0        mongo               "docker-entrypoint..."   3 hours ago         Up 3 hours                   0.0.0.0:27020->27017/tcp   mongos2
e8e29446fa17        mongo               "docker-entrypoint..."   3 hours ago         Up 3 hours                   0.0.0.0:27019->27017/tcp   mongos1
a031815d22a9        mongo               "docker-entrypoint..."   5 hours ago         Up 4 hours                   27017/tcp                  mongocfg2
e56c11114823        mongo               "docker-entrypoint..."   5 hours ago         Up 4 hours                   27017/tcp                  mongocfg1
858dc7463f0a        mongo               "docker-entrypoint..."   5 hours ago         Up 4 hours                   27017/tcp                  mongocfg3
934b4fe8f8a8        mongo               "docker-entrypoint..."   5 hours ago         Up 4 hours                   0.0.0.0:27037->27017/tcp   mongors1n3
0181076d2845        mongo               "docker-entrypoint..."   5 hours ago         Up 4 hours                   0.0.0.0:27027->27017/tcp   mongors1n2
cfdea54a34c9        mongo               "docker-entrypoint..."   5 hours ago         Exited (137) 6 seconds ago                              mongors1n1
3d6f0cc60b47        centos              "/bin/bash"              15 hours ago        Up 5 hours                                              forcommit
 
 
#mongo --port 27027 (mongors1n2 접속)
2018-06-26T11:03:58.842+0900 I CONTROL  [initandlisten]
mongors1:PRIMARY

 
SECONDARY에서 PRIMARY로 바뀌어있는걸 확인할수있다.

라우터 테스트

use MongoDB\Client
 
 
$host = 'mongodb://xxxx:27020,xxxx:27019;
$this->client = new Client($host);
$this->collection = $this->client->selectCollection('testDB', 'testCollection');
 
 
for ($i = 0; $i <= 1000; $i++) {
    $this->collection->count();
}

다음은 ngrep 으로 서버로 요청오는 패킷을 잡아봤다.

yum install -y ngrep #미설치시
`
ngrep port 27019
 
interface: enp0s25 (xxx.xxx.xxx.xxx/255.255.255.255)
filter: ( port 27019 ) and ((ip || ip6) || (vlan && (ip || ip6)))
###
T xxx.xxx.xxx.xxx:58114 -> xxx.xxx.xxx.xxx:27019 [AP]
  O...................admin.$cmd.........(....isMaster......client......driver.C....name.....mongoc / ext-mongodb:PHP..version.....1.9.2 / 1.4.0...os.Y....type.....Windows
  ..name.....Windows..version.....10.0 (17134)..architecture.....x86...platform.@...cfg=0x402a0e9 CC=MSVC 1912 CFLAGS="" LDFLAGS="" / PHP 7.2.1-dev...compression.......  
##
T xxx.xxx.xxx.xxx:27019 -> xxx.xxx.xxx.xxx:58114 [AP]
  s...................................O....ismaster...msg.....isdbgrid..maxBsonObjectSize......maxMessageSizeBytes..l...maxWriteBatchSize......localTime.....d....logicalSe
  ssionTimeoutMinutes......maxWireVersion......minWireVersion......ok........?.operationTime.......b[.$clusterTime.X....clusterTime.......b[.signature.3....hash...........
  ................keyId............ 
.......생략
 
 
 
 
ngrep port 27020
 
interface: enp0s25 (xxx.xxx.xxx.xxx/255.255.255.255)
filter: ( port 27020 ) and ((ip || ip6) || (vlan && (ip || ip6)))
###
T xxx.xxx.xxx.xxx:58113 -> xxx.xxx.xxx.xxx:27020 [A]
  ......                                                                                                                                                                  
#
T xxx.xxx.xxx.xxx:58113 -> xxx.xxx.xxx.xxx:27020 [AP]
  O...................admin.$cmd.........(....isMaster......client......driver.C....name.....mongoc / ext-mongodb:PHP..version.....1.9.2 / 1.4.0...os.Y....type.....Windows
  ..name.....Windows..version.....10.0 (17134)..architecture.....x86...platform.@...cfg=0x402a0e9 CC=MSVC 1912 CFLAGS="" LDFLAGS="" / PHP 7.2.1-dev...compression.......  
##
.......생략
`

양쪽 라우터로 번갈아가면서 요청이 오는것을 확인할수있었다.

라우터를 강제로 죽여서 테스트를 진행해보았다.

docker kill mongos1
mongos1
docker ps -a      
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                       PORTS                      NAMES
051d3f0e87b0        mongo               "docker-entrypoint..."   4 hours ago        Up 4 hours                  0.0.0.0:27020->27017/tcp   mongos2
e8e29446fa17        mongo               "docker-entrypoint..."   4 hours ago        Exited (137) 3 seconds ago                              mongos1
a031815d22a9        mongo               "docker-entrypoint..."   4 hours ago        Up 4 hours                  27017/tcp                  mongocfg2
e56c11114823        mongo               "docker-entrypoint..."   4 hours ago        Up 4 hours                  27017/tcp                  mongocfg1
858dc7463f0a        mongo               "docker-entrypoint..."   4 hours ago        Up 4 hours                  27017/tcp                  mongocfg3
934b4fe8f8a8        mongo               "docker-entrypoint..."   4 hours ago        Up 4 hours                  0.0.0.0:27037->27017/tcp   mongors1n3
0181076d2845        mongo               "docker-entrypoint..."   4 hours ago        Up 4 hours                  0.0.0.0:27027->27017/tcp   mongors1n2
cfdea54a34c9        mongo               "docker-entrypoint..."   4 hours ago        Up 4 hours                  0.0.0.0:27017->27017/tcp   mongors1n1o


#ngrep
`
ngrep port 27020
 
 
interface: enp0s25 (xxx.xxx.xxx.xxx/255.255.255.255)
filter: ( port 27020 ) and ((ip || ip6) || (vlan && (ip || ip6)))
###
T xxx.xxx.xxx.xxx:60823 -> xxx.xxx.xxx.xxx:27020 [A]
  ......
#
T xxx.xxx.xxx.xxx:60823 -> xxx.xxx.xxx.xxx:27020 [AP]
  O...................admin.$cmd.........(....isMaster......client......driver.C....name.....mongoc / ext-mongodb:PHP..version.....1.9.2 / 1.4.0...os.Y....type.....Windows
  ..name.....Windows..version.....10.0 (17134)..architecture.....x86...platform.@...cfg=0x402a0e9 CC=MSVC 1912 CFLAGS="" LDFLAGS="" / PHP 7.2.1-dev...compression.......
##
T xxx.xxx.xxx.xxx:27020 -> xxx.xxx.xxx.xxx:60823 [AP]
  s...G...............................O....ismaster...msg.....isdbgrid..maxBsonObjectSize......maxMessageSizeBytes..l...maxWriteBatchSize......localTime.....d....logicalSe
  ssionTimeoutMinutes......maxWireVersion......minWireVersion......ok........?.operationTime.....C.b[.$clusterTime.X....clusterTime.....C.b[.signature.3....hash...........
  ................keyId............
 
 
 
 
ngrep port 27019
interface: enp0s25 (xxx.xxx.xxx.xxx/255.255.255.255)
filter: ( port 27019 ) and ((ip || ip6) || (vlan && (ip || ip6)))
####################################################################################
`
 
#위와같이 mongos1 라우터로는 접근을 시도하나 접속되지 않아 mongos2 라우터로 요청하는것을 확인할수있다.

비고

hash mark (#) 는 ngrep 에서 요청이 왔을때 표시해줌 ngrep (-q is be quiet (don’t print packet reception hash marks.)

참조링크