Database & NoSQL/NoSQL

반응형

docker-compose with Redis Container 환경 구성

들어가며,
회사에서 업무로 Redis를 Global Cache 용도로 사용 하고 있습니다. Cache 전략은 다양한 패턴이 있는데, 그 중 현재는 Cache Aside 전략으로 DB 조회 전 Cache에 동일한 Key에 해당하는 데이터가 있는지 조회 후 결과를 리턴해주는 용도로 사용 중입니다. 가장 일반적인 Cache 용도라고 보실 수 있습니다. Cache 전략에 관한 자세한 내용은 다음에 한번 다뤄 보도록 하고, 오늘은 docker-compose를 활용하여 로컬 환경에 Redis Container를 구성하는 방법에 대한 실습 과정을 공유해보겠습니다.

docker-compose file 구성

Redis docker image 6.2.8
Redis Cluster 구성
redis.conf 설정

Container properties를 먼저 보겠습니다.

  • 각 클러스터와의 연결을 위해 ports 추가,
  • Redis 환경 구성을 위해 설정한 redis.conf 파일 경로를 volumes에 추가.
  • 컨테이너 기동시 설정된 conf 파일을 로드하기 위한 Command 명령어 추가.

redis.conf 파일은 redis.io 사이트에서 설치하시는 image 버전에 맞게 다운로드 받으실 수 있습니다.
다운 받은 conf 파일에 기본적으로 port 설정과 보안, 클러스터 그리고 백업 정책 등을 아래와 같이 변경하였습니다. 이 부분에서 삽질을 많이 했네요ㅜㅜ
보안 설정의 경우 추후 Spring Boot application과 연동을 위해서는 반드시 적절한 정책으로 설정을 하셔야 합니다. Default로 설정할 경우 Redis Container는 정상적으로 생성되고 redis-cli Command를 사용하여 Redis command 테스트는 가능하지만 실제 Spring Boot application과 연동하여 개발 용도로는 사용할 수 없기 때문입니다.. 주저리주저리..했네요

redis-master:
      image: redis:6.2.8
      container_name: redis-6379
      restart: always
      ports:
        - 6379:6379
        - 6380:6380
        - 6381:6381
      volumes:
        - ./data/redis/6379:/data
        - ./data/redis.conf:/usr/local/etc/redis/redis.conf
      command: redis-server /usr/local/etc/redis/redis.conf

Redis Container 구성을 위해 yml 파일에 설정한 properties 입니다.
아래 설정한 내용은 Github에 프로젝트로 생성하였으니 Clone 하셔서 활용하셔도 좋을 거 같습니다.

version: '3'

services:
    redis-master:
      image: redis:6.2.8
      container_name: redis-6379
      restart: always
      ports:
        - 6379:6379
        - 6380:6380
        - 6381:6381
      volumes:
        - ./data/redis/6379:/data
        - ./data/redis.conf:/usr/local/etc/redis/redis.conf
      command: redis-server /usr/local/etc/redis/redis.conf

    redis-slave1:
      image: redis:6.2.8
      container_name: redis-6380
      network_mode: "service:redis-master"
      restart: always
      volumes:
        - ./data/redis/6380:/data
        - ./data/redis6380.conf:/usr/local/etc/redis/redis.conf
      command: redis-server /usr/local/etc/redis/redis.conf

    redis-slave2:
      image: redis:6.2.8
      container_name: redis-6381
      network_mode: "service:redis-master"
      restart: always
      volumes:
        - ./data/redis/6381:/data
        - ./data/redis6381.conf:/usr/local/etc/redis/redis.conf
      command: redis-server /usr/local/etc/redis/redis.conf

    redis-cluster-entry:
      image: redis:6.2.8
      container_name: redis-cluster-entry
      network_mode: "service:redis-master"
      command: redis-cli --cluster create 127.0.0.1:6379 127.0.0.1:6380 127.0.0.1:6381 --cluster-yes
      depends_on:
        - redis-master
        - redis-slave1
        - redis-slave2

update 중....

반응형
반응형
MongoDB 로컬 환경 구성 (with. docker-compose)

docker-compose를 이용하여 MongoDB를 설치해 보려고 합니다.
먼저 docker-compose를 활용하여 MongoDB 컨테이너를 구성하기 위해서는 사전 작업으로 docker-desktop 설치를 우선적으로 해야 합니다.
설치가 안되신 분은 (Mac에서 Docker 설치하기)를 참고하셔서 docker-desktop 환경을 구성하시면 됩니다.

docker-compose.yml container image 추가 하기

ersion은 각 실습 환경에 맞는 docker 버전을 고려하여 작성하시면 됩니다. yml작성은 idl 등을 이용하시면 작성하시는데 도움이 됩니다.

version: '3'

services:
  mongo1:
      image: mongo:4.4.5
      container_name: mongo1
      expose:
        - 27017
      ports:
        - 27017:27017      
      entrypoint: [ "/usr/bin/mongod", "--bind_ip_all", "--replSet", "r0" ]

docker-compose 명령어

  • docker-compose up //실행
  • docker-compose down //종료
  • docker ps //container 프로세스 확인

docker-compose up 명령어를 사용하여 컨테이너를 실행합니다.

> docker-compose up

Docker Compose is now in the Docker CLI, try `docker compose up`

Creating network "docker_default" with the default driver
Creating mongo1       ... done

mongo1       | {"t":{"$date":"2022-06-30T03:40:07.225+00:00"},"s":"I",  "c":"CONTROL",  "id":23285,   "ctx":"main","msg":"Automatically disabling TLS 1.0, to force-enable TLS 1.0 specify --sslDisabledProtocols 'none'"}
mongo1       | {"t":{"$date":"2022-06-30T03:40:07.228+00:00"},"s":"W",  "c":"ASIO",     "id":22601,   "ctx":"main","msg":"No TransportLayer configured during NetworkInterface startup"}
mongo1       | {"t":{"$date":"2022-06-30T03:40:07.228+00:00"},"s":"I",  "c":"NETWORK",  "id":4648601, "ctx":"main","msg":"Implicit TCP FastOpen unavailable. If TCP FastOpen is required, set tcpFastOpenServer, tcpFastOpenClient, and tcpFastOpenQueueSize."}

error log 없이 컨테이너가 올라왔다면 docker ps 명령어를 사용하여 생성된 컨테이너의 상태를 확인해 봅니다.

> docker ps

CONTAINER ID   IMAGE         COMMAND                  CREATED       STATUS       PORTS                                 NAMES
dc0c851d73a7   mongo:4.4.5   "/usr/bin/mongod --b…"   1 hours ago   Up 1 hours   0.0.0.0:27017->27017/tcp              mongo1

mongodb container 접속 하기

먼저 docker container terminal로 접속 후, 아래와 같이 정상적으로 mongo shell로 이동해 보겠습니다.

> docker exec -it mongo1 bash

root@dc0c851d73a7:/# mongo 
MongoDB shell version v4.4.5
connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("74aea9a1-e1b8-4367-ab9e-02b0d96cce37") }
MongoDB server version: 4.4.5
---
The server generated these startup warnings when booting:
        2022-06-30T03:40:07.230+00:00: Using the XFS filesystem is strongly recommended with the WiredTiger storage engine. See http://dochub.mongodb.org/core/prodnotes-filesystem
        2022-06-30T03:40:07.727+00:00: Access control is not enabled for the database. Read and write access to data and configuration is unrestricted
        2022-06-30T03:40:07.727+00:00: You are running this process as the root user, which is not recommended
---
---
        Enable MongoDB's free cloud-based monitoring service, which will then receive and display
        metrics about your deployment (disk utilization, CPU, operation statistics, etc).

        The monitoring data will be available on a MongoDB website with a unique URL accessible to you
        and anyone you share the URL with. MongoDB may use this information to make product
        improvements and to suggest MongoDB products and deployment options to you.

        To enable free monitoring, run the following command: db.enableFreeMonitoring()
        To permanently disable this reminder, run the following command: db.disableFreeMonitoring()
---

MongoDB compass tool로 접속 하기

다양한 GUI Tool 중 compass를 이용하여 MongoDB에 접속해 보겠습니다. compass tool은 해당 링크에서 다운로드 가능합니다.
아래와 같이 정상적으로 접속이 되면 개발을 위한 MongoDB 환경 구성은 성공적으로 마무리 되었습니다.

오늘은 docker-compose를 활용한 로컬 환경 구성에 대하여 실습해 봤습니다.

반응형
반응형

MongoDB admin user 생성 하기

실습 전에 docker, docker-compose, 그리고 MongoDB 컨테이너가 구성된 yml 파일이 필요한데, 이전 블로그를 참고해도 좋습니다.
[MongoDB docker-compose로 구성 하기]

MongoDB 컨테이너가 설치되었다는 가정하에 먼저 docker ps 명령어로 컨테이너 정보를 조회 합니다.

$docker ps
CONTAINER ID   IMAGE         COMMAND                  CREATED       STATUS       PORTS                                 NAMES
dc0c851d73a7   mongo:4.4.5   "/usr/bin/mongod --b…"   2 hours ago   Up 2 hours   0.0.0.0:27017->27017/tcp              mongo1

MongoDB admin user 생성을 위해 docker 컨테이너 터미널로 접속해 보겠습니다.

$docker exec -it mongo1 bash  //container terminal 접속

root@dc0c851d73a7:/# mongo
MongoDB shell version v4.4.5
connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("7de3fbdb-078a-476c-8003-fcd12c1dd105") }
MongoDB server version: 4.4.5
---
The server generated these startup warnings when booting:
        2022-06-30T03:40:07.230+00:00: Using the XFS filesystem is strongly recommended with the WiredTiger storage engine. See http://dochub.mongodb.org/core/prodnotes-filesystem
        2022-06-30T03:40:07.727+00:00: Access control is not enabled for the database. Read and write access to data and configuration is unrestricted
        2022-06-30T03:40:07.727+00:00: You are running this process as the root user, which is not recommended
---
---
        Enable MongoDB's free cloud-based monitoring service, which will then receive and display
        metrics about your deployment (disk utilization, CPU, operation statistics, etc).

        The monitoring data will be available on a MongoDB website with a unique URL accessible to you
        and anyone you share the URL with. MongoDB may use this information to make product
        improvements and to suggest MongoDB products and deployment options to you.

        To enable free monitoring, run the following command: db.enableFreeMonitoring()
        To permanently disable this reminder, run the following command: db.disableFreeMonitoring()
---

이제 admin db로 이동하여 순서대로 진행해 봅니다. 그 전에 replica 설정이 안되어 있을 경우 user 계정 생성이 불가할 수 있습니다.
admin db 이동 후 rs.status() 명령어로 replica set 상태를 확인해 봅니다.

> use admin       //admin db 이동
switched to db amdin

> rs.status()
{
    "ok" : 0,
    "errmsg" : "no replset config has been received",
    "code" : 94,
    "codeName" : "NotYetInitialized"
}

> db.createUser(
...   {
...      user: "admin",
...      pwd: passwordPrompt(), // or cleartext password
...      roles: [ { role: "root", db: "admin" } ]
...   }
... )  //replica 설정이 없어서 아래 오류 발생함.
Enter password:
uncaught exception: Error: couldn't add user: not master :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
DB.prototype.createUser@src/mongo/shell/db.js:1386:11
@(shell):1:1

이제 다시 rs.initiate() 명령어로 default replica 정보를 설정합니다. 아래와 같이 변경된 커맨드로 전환되면 됩니다.
그리고 rs.status() 명령어로 설정을 재확인 합니다.

> rs.initiate()   //replica default 설정
r0:SECONDARY>


r0:PRIMARY> rs.status() 
{
    "set" : "r0",
    "date" : ISODate("2022-06-30T04:12:32.988Z"),
    "myState" : 1,
    "term" : NumberLong(1),
    "syncSourceHost" : "",
    "syncSourceId" : -1,
    "heartbeatIntervalMillis" : NumberLong(2000),
    "majorityVoteCount" : 1,
    "writeMajorityCount" : 1,
    "votingMembersCount" : 1,
    "writableVotingMembersCount" : 1,
    "optimes" : {
        "lastCommittedOpTime" : {
            "ts" : Timestamp(1656562345, 1),
            "t" : NumberLong(1)
        },
        "lastCommittedWallTime" : ISODate("2022-06-30T04:12:25.854Z"),
        "readConcernMajorityOpTime" : {
            "ts" : Timestamp(1656562345, 1),
            "t" : NumberLong(1)
        },
        "readConcernMajorityWallTime" : ISODate("2022-06-30T04:12:25.854Z"),
        "appliedOpTime" : {
            "ts" : Timestamp(1656562345, 1),
            "t" : NumberLong(1)
        },
        "durableOpTime" : {
            "ts" : Timestamp(1656562345, 1),
            "t" : NumberLong(1)
        },
        "lastAppliedWallTime" : ISODate("2022-06-30T04:12:25.854Z"),
        "lastDurableWallTime" : ISODate("2022-06-30T04:12:25.854Z")
    },
    "lastStableRecoveryTimestamp" : Timestamp(1656562335, 1),
    "electionCandidateMetrics" : {
        "lastElectionReason" : "electionTimeout",
        "lastElectionDate" : ISODate("2022-06-30T04:03:15.746Z"),
        "electionTerm" : NumberLong(1),
        "lastCommittedOpTimeAtElection" : {
            "ts" : Timestamp(0, 0),
            "t" : NumberLong(-1)
        },
        "lastSeenOpTimeAtElection" : {
            "ts" : Timestamp(1656561795, 1),
            "t" : NumberLong(-1)
        },
        "numVotesNeeded" : 1,
        "priorityAtElection" : 1,
        "electionTimeoutMillis" : NumberLong(10000),
        "newTermStartDate" : ISODate("2022-06-30T04:03:15.778Z"),
        "wMajorityWriteAvailabilityDate" : ISODate("2022-06-30T04:03:15.853Z")
    },
    "members" : [
        {
            "_id" : 0,
            "name" : "dc0c851d73a7:27017",
            "health" : 1,
            "state" : 1,
            "stateStr" : "PRIMARY",
            "uptime" : 1945,
            "optime" : {
                "ts" : Timestamp(1656562345, 1),
                "t" : NumberLong(1)
            },
            "optimeDate" : ISODate("2022-06-30T04:12:25Z"),
            "syncSourceHost" : "",
            "syncSourceId" : -1,
            "infoMessage" : "",
            "electionTime" : Timestamp(1656561795, 2),
            "electionDate" : ISODate("2022-06-30T04:03:15Z"),
            "configVersion" : 1,
            "configTerm" : 1,
            "self" : true,
            "lastHeartbeatMessage" : ""
        }
    ],
    "ok" : 1,
    "$clusterTime" : {
        "clusterTime" : Timestamp(1656562345, 1),
        "signature" : {
            "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
            "keyId" : NumberLong(0)
        }
    },
    "operationTime" : Timestamp(1656562345, 1)
}

다시 db.createUser() 명령어를 실행하여 admin user 생성을 시도하면 아래 처럼 successfully 메세지와 생성된 계정 정보를 확인할 수 있습니다.
이때 password는 Prompt or cleartext 형태로 진행할 수 있습니다.

//role type: root, readWrite, dbOwner
r0:PRIMARY> db.createUser(
...   {
...      user: "admin",
...      pwd: passwordPrompt(), // or cleartext password
...      roles: [{ role: "root", db: "admin" }]
...   }
... )
Enter password:
Successfully added user: {
    "user" : "admin",
    "roles" : [
        {
            "role" : "root",
            "db" : "admin"
        }
    ]
}
r0:PRIMARY>

이제 생성된 계정으로 MongoDB 명령어를 사용해 봅니다.

r0:PRIMARY> show dbs
admin   0.000GB
config  0.000GB
local   0.000GB

오늘은 MongoDB에서 admin user 생성하는 방법에 대하여 정리해 봤습니다.

반응형
반응형

MongoDB Replica Config 설정

docker container names 확인

$docker ps
CONTAINER ID   IMAGE         COMMAND                  CREATED       STATUS       PORTS                                 NAMES
346c91282c62   mongo:4.4.5   "/usr/bin/mongod --b…"   2 hours ago   Up 2 hours   27019/tcp, 0.0.0.0:27019->27017/tcp   mongo3
dc0c851d73a7   mongo:4.4.5   "/usr/bin/mongod --b…"   2 hours ago   Up 2 hours   0.0.0.0:27017->27017/tcp              mongo1
97c22ce1192c   mongo:4.4.5   "/usr/bin/mongod --b…"   2 hours ago   Up 2 hours   27018/tcp, 0.0.0.0:27018->27017/tcp   mongo2

docker container 터미널 및 mongo shell 접속

$docker exec -it mongo1 bash  //container terminal 접속

root@dc0c851d73a7:/# mongo    //mongo shell 접속
MongoDB shell version v4.4.5
connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("07312a4b-c4d4-4aef-96c7-f733eccdc611") }
MongoDB server version: 4.4.5

> use admin   //admin db 이동
switched to db admin

replica set config 설정

rs.status() 명령어로 설정 정보를 확인하면 아래와 같이 no repliset 정보가 노출된다.

> rs.status()
{
    "ok" : 0,
    "errmsg" : "no replset config has been received",
    "code" : 94,
    "codeName" : "NotYetInitialized"
}

초기화만 진행할 경우는 rs.initate() 명령어로 rsconf 설정 정보 없이 진행해도 되고, 명령어 수행 후 아래와 같이 커맨드가 변경된다.

> rs.initiate()
rs0:PRIMARY>

P-S-S 환경으로 구축했다면 아래와 같이 replica rsconf 정보를 기동한 Container host 및 ip에 맞춰 등록해준다.

> rsconf = {  "_id" : "rs0",  "members" : [ { "_id" : 0, "host" : "mongo1:27017", "priority" : 1 }, {"_id" : 1, "host" : "mongo2:27017", "priority": 2 }, {"_id": 2,  "host": "mongo3:27017", "priority": 3 } ]}
{
	"_id" : "rs0",
	"members" : [
		{
			"_id" : 0,
			"host" : "mongo1:27017",
			"priority" : 1
		},
		{
			"_id" : 1,
			"host" : "mongo2:27017",
			"priority" : 2
		},
		{
			"_id" : 2,
			"host" : "mongo3:27017",
			"priority" : 3
		}
	]
}
> rs.initiate(rsconf)
{ "ok" : 1 }
rs0:SECONDARY>

아래와 같이 변경된 커맨드를 확인할 수 있고, rs.status()로 rs 상태를 점검해 본다.

r0:PRIMARY>

rs0:PRIMARY> rs.status()
{
    "set" : "rs0",
    "date" : ISODate("2024-04-12T01:39:28.051Z"),
    "myState" : 1,
    "term" : NumberLong(9),
    "syncSourceHost" : "",
    "syncSourceId" : -1,
    "heartbeatIntervalMillis" : NumberLong(2000),
    "majorityVoteCount" : 2,
    "writeMajorityCount" : 2,
    "votingMembersCount" : 3,
    "writableVotingMembersCount" : 3,
    "optimes" : {
        "lastCommittedOpTime" : {
            "ts" : Timestamp(1712885964, 1),
            "t" : NumberLong(9)
        },
        "lastCommittedWallTime" : ISODate("2024-04-12T01:39:24.677Z"),
        "readConcernMajorityOpTime" : {
            "ts" : Timestamp(1712885964, 1),
            "t" : NumberLong(9)
        },
        "appliedOpTime" : {
            "ts" : Timestamp(1712885964, 1),
            "t" : NumberLong(9)
        },
        "durableOpTime" : {
            "ts" : Timestamp(1712885964, 1),
            "t" : NumberLong(9)
        },
        "lastAppliedWallTime" : ISODate("2024-04-12T01:39:24.677Z"),
        "lastDurableWallTime" : ISODate("2024-04-12T01:39:24.677Z")
    },
    "lastStableRecoveryTimestamp" : Timestamp(1712885924, 1),
    "electionCandidateMetrics" : {
        "lastElectionReason" : "priorityTakeover",
        "lastElectionDate" : ISODate("2024-04-12T00:19:54.539Z"),
        "electionTerm" : NumberLong(9),
        "lastCommittedOpTimeAtElection" : {
            "ts" : Timestamp(1712881186, 1),
            "t" : NumberLong(8)
        },
        "lastSeenOpTimeAtElection" : {
            "ts" : Timestamp(1712881186, 1),
            "t" : NumberLong(8)
        },
        "numVotesNeeded" : 2,
        "priorityAtElection" : 2,
        "electionTimeoutMillis" : NumberLong(10000),
        "priorPrimaryMemberId" : 0,
        "numCatchUpOps" : NumberLong(0),
        "newTermStartDate" : ISODate("2024-04-12T00:19:54.547Z"),
        "wMajorityWriteAvailabilityDate" : ISODate("2024-04-12T00:19:55.547Z")
    },
    "members" : [
        {
            "_id" : 0,
            "name" : "mongo1:27017",
            "health" : 1,
            "state" : 2,
            "stateStr" : "PRIMARY",
            "uptime" : 4783,
            "optime" : {
                "ts" : Timestamp(1712885964, 1),
                "t" : NumberLong(9)
            },
            "optimeDurable" : {
                "ts" : Timestamp(1712885964, 1),
                "t" : NumberLong(9)
            },
            "optimeDate" : ISODate("2024-04-12T01:39:24Z"),
            "optimeDurableDate" : ISODate("2024-04-12T01:39:24Z"),
            "lastHeartbeat" : ISODate("2024-04-12T01:39:26.957Z"),
            "lastHeartbeatRecv" : ISODate("2024-04-12T01:39:26.961Z"),
            "pingMs" : NumberLong(0),
            "lastHeartbeatMessage" : "",
            "syncSourceHost" : "mongo2:27017",
            "syncSourceId" : 3,
            "infoMessage" : "",
            "configVersion" : 13,
            "configTerm" : 9
        },
        {
            "_id" : 1,
            "name" : "mongo2:27017",
            "health" : 1,
            "state" : 1,
            "stateStr" : "SECONDARY",
            "uptime" : 4787,
            "optime" : {
                "ts" : Timestamp(1712885964, 1),
                "t" : NumberLong(9)
            },
            "optimeDate" : ISODate("2024-04-12T01:39:24Z"),
            "syncSourceHost" : "",
            "syncSourceId" : -1,
            "infoMessage" : "",
            "electionTime" : Timestamp(1712881194, 1),
            "electionDate" : ISODate("2024-04-12T00:19:54Z"),
            "configVersion" : 13,
            "configTerm" : 9,
            "self" : true,
            "lastHeartbeatMessage" : ""
        },
        {
            "_id" : 2,
            "name" : "mongo3:27017",
            "health" : 1,
            "state" : 2,
            "stateStr" : "SECONDARY",
            "uptime" : 4783,
            "optime" : {
                "ts" : Timestamp(1712885964, 1),
                "t" : NumberLong(9)
            },
            "optimeDurable" : {
                "ts" : Timestamp(1712885964, 1),
                "t" : NumberLong(9)
            },
            "optimeDate" : ISODate("2024-04-12T01:39:24Z"),
            "optimeDurableDate" : ISODate("2024-04-12T01:39:24Z"),
            "lastHeartbeat" : ISODate("2024-04-12T01:39:26.958Z"),
            "lastHeartbeatRecv" : ISODate("2024-04-12T01:39:26.962Z"),
            "pingMs" : NumberLong(0),
            "lastHeartbeatMessage" : "",
            "syncSourceHost" : "mongo1:27017",
            "syncSourceId" : 0,
            "infoMessage" : "",
            "configVersion" : 13,
            "configTerm" : 9
        }
    ],
    "ok" : 1,
    "$clusterTime" : {
        "clusterTime" : Timestamp(1712885964, 1),
        "signature" : {
            "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
            "keyId" : NumberLong(0)
        }
    },
    "operationTime" : Timestamp(1712885964, 1)
}

설정된 replica conf 정보 확인해보자

members 속성 중 priority 높은 순서에 따라 primary가 shutdown될 경우 높은 secondary가 primary로 전환된다.

rs0:PRIMARY> rs.conf()
{
    "_id" : "rs0",
    "version" : 12,
    "term" : 9,
    "members" : [
        {
            "_id" : 0,
            "host" : "mongo1:27017",
            "arbiterOnly" : false,
            "buildIndexes" : true,
            "hidden" : false,
            "priority" : 1,
            "tags" : {

            },
            "secondaryDelaySecs" : NumberLong(0),
            "votes" : 1
        },
        {
            "_id" : 1,
            "host" : "mongo2:27017",
            "arbiterOnly" : false,
            "buildIndexes" : true,
            "hidden" : false,
            "priority" : 3,
            "tags" : {

            },
            "secondaryDelaySecs" : NumberLong(0),
            "votes" : 1
        },
        {
            "_id" : 2,
            "host" : "mongo3:27017",
            "arbiterOnly" : false,
            "buildIndexes" : true,
            "hidden" : false,
            "priority" : 1,
            "tags" : {

            },
            "secondaryDelaySecs" : NumberLong(0),
            "votes" : 1
        }
    ],
    "protocolVersion" : NumberLong(1),
    "writeConcernMajorityJournalDefault" : true,
    "settings" : {
        "chainingAllowed" : true,
        "heartbeatIntervalMillis" : 2000,
        "heartbeatTimeoutSecs" : 10,
        "electionTimeoutMillis" : 10000,
        "catchUpTimeoutMillis" : -1,
        "catchUpTakeoverDelayMillis" : 30000,
        "getLastErrorModes" : {

        },
        "getLastErrorDefaults" : {
            "w" : 1,
            "wtimeout" : 0
        },
        "replicaSetId" : ObjectId("6617491a03de995df431b70d")
    }
}

replica members add/remove 하자

remove 전 삭제하고자하는 인스턴스를 먼저 종료 하자.
rs0:SECONDARY> db.shutdownServer()

primary node로 접속 하자.
rs0:PRIMARY> cfg = rs.conf()
rs0:PRIMARY> cfg.memebrs.splice(2,1) // 2번째 로우부터 1개 삭제
rs0:PRIMARY> rs.reconfig(cfg)

rs0:PRIMARY> cfg = rs.conf()  //cfg에 현재 conf 정보를 저장하고
{
    "_id" : "rs0",
    "version" : 13,
    "term" : 11,
    "members" : [
        {
            "_id" : 0,
            "host" : "mongo1:27017",
            "arbiterOnly" : false,
            "buildIndexes" : true,
            "hidden" : false,
            "priority" : 2,
            "tags" : {

            },
            "secondaryDelaySecs" : NumberLong(0),
            "votes" : 1
        },
        {
            "_id" : 3,
            "host" : "mongo2:27017",
            "arbiterOnly" : false,
            "buildIndexes" : true,
            "hidden" : false,
            "priority" : 3,
            "tags" : {

            },
            "secondaryDelaySecs" : NumberLong(0),
            "votes" : 1
        },
        {
            "_id" : 4,
            "host" : "mongo3:27017",
            "arbiterOnly" : false,
            "buildIndexes" : true,
            "hidden" : false,
            "priority" : 1,
            "tags" : {

            },
            "secondaryDelaySecs" : NumberLong(0),
            "votes" : 1
        }
    ],
    "protocolVersion" : NumberLong(1),
    "writeConcernMajorityJournalDefault" : true,
    "settings" : {
        "chainingAllowed" : true,
        "heartbeatIntervalMillis" : 2000,
        "heartbeatTimeoutSecs" : 10,
        "electionTimeoutMillis" : 10000,
        "catchUpTimeoutMillis" : -1,
        "catchUpTakeoverDelayMillis" : 30000,
        "getLastErrorModes" : {

        },
        "getLastErrorDefaults" : {
            "w" : 1,
            "wtimeout" : 0
        },
        "replicaSetId" : ObjectId("6617491a03de995df431b70d")
    }
}
rs0:PRIMARY> cfg.members[1].priority = 1   // members 2번째 node의 priority 순서를 변경한 후
1
rs0:PRIMARY> rs.reconfig(cfg)       // 설정을 다시해준다.
{
    "ok" : 1,
    "$clusterTime" : {
        "clusterTime" : Timestamp(1712886887, 1),
        "signature" : {
            "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
            "keyId" : NumberLong(0)
        }
    },
    "operationTime" : Timestamp(1712886887, 1)
}
rs0:PRIMARY> rs.conf()    // 변경 내역 확인
{
    "_id" : "rs0",
    "version" : 14,
    "term" : 11,
    "members" : [
        {
            "_id" : 0,
            "host" : "mongo1:27017",
            "arbiterOnly" : false,
            "buildIndexes" : true,
            "hidden" : false,
            "priority" : 2,
            "tags" : {

            },
            "secondaryDelaySecs" : NumberLong(0),
            "votes" : 1
        },
        {
            "_id" : 3,
            "host" : "mongo2:27017",
            "arbiterOnly" : false,
            "buildIndexes" : true,
            "hidden" : false,
            "priority" : 1,
            "tags" : {

            },
            "secondaryDelaySecs" : NumberLong(0),
            "votes" : 1
        },
        {
            "_id" : 4,
            "host" : "mongo3:27017",
            "arbiterOnly" : false,
            "buildIndexes" : true,
            "hidden" : false,
            "priority" : 1,
            "tags" : {

            },
            "secondaryDelaySecs" : NumberLong(0),
            "votes" : 1
        }
    ],
    "protocolVersion" : NumberLong(1),
    "writeConcernMajorityJournalDefault" : true,
    "settings" : {
        "chainingAllowed" : true,
        "heartbeatIntervalMillis" : 2000,
        "heartbeatTimeoutSecs" : 10,
        "electionTimeoutMillis" : 10000,
        "catchUpTimeoutMillis" : -1,
        "catchUpTakeoverDelayMillis" : 30000,
        "getLastErrorModes" : {

        },
        "getLastErrorDefaults" : {
            "w" : 1,
            "wtimeout" : 0
        },
        "replicaSetId" : ObjectId("6617491a03de995df431b70d")
    }
}

다음에는 실제 구성된 레플리카 환경에서 Spring Boot MongoDB 어플리케이션을 연동하여 테스트 하고자 한다.

반응형
반응형

uncaught exception: Error: couldn't add user

MongoDB 설치 후 Create User 생성을 시도하다보면 아래와 같은 메세지를 맞이하게 됩니다.(docker 컨테이너 생성시 entry point로 default rs 정보를 추가할 경우는 발생 안함)

최초 설치 후 default replica set 설정을 하지 않은 경우 발생하는데, 이럴 경우 rs.initiate() 명령어로 replica 초기화를 수행하면 정상적으로 mongodb admin 생성이 가능하게 됩니다.

> db.createUser(
...   {
...      user: "admin",
...      pwd: passwordPrompt(), // or cleartext password
...      roles: [ { role: "userAdminAnyDatabase", db: "admin" }, "readWriteAnyDatabase" ]
...   }
... )
Enter password:
uncaught exception: Error: couldn't add user: not master :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
DB.prototype.createUser@src/mongo/shell/db.js:1386:11
@(shell):1:1

> rs.status()    //replica set 상태 확인
{
    "ok" : 0,
    "errmsg" : "no replset config has been received",
    "code" : 94,
    "codeName" : "NotYetInitialized"
}

> rs.initiate()   //replica default 설정

r0:PRIMARY>    //prompt PRIMARY 변경 확인

r0:PRIMARY> rs.status()  //replica set 상태 재확인
{
    "set" : "r0",
    "date" : ISODate("2022-06-30T04:12:32.988Z"),
    "myState" : 1,
    "term" : NumberLong(1),
    "syncSourceHost" : "",
    "syncSourceId" : -1,
    "heartbeatIntervalMillis" : NumberLong(2000),
    "majorityVoteCount" : 1,
    "writeMajorityCount" : 1,
    "votingMembersCount" : 1,
    "writableVotingMembersCount" : 1,
    "optimes" : {
        "lastCommittedOpTime" : {
            "ts" : Timestamp(1656562345, 1),
            "t" : NumberLong(1)
        },
        "lastCommittedWallTime" : ISODate("2022-06-30T04:12:25.854Z"),
        "readConcernMajorityOpTime" : {
            "ts" : Timestamp(1656562345, 1),
            "t" : NumberLong(1)
        },
        "readConcernMajorityWallTime" : ISODate("2022-06-30T04:12:25.854Z"),
        "appliedOpTime" : {
            "ts" : Timestamp(1656562345, 1),
            "t" : NumberLong(1)
        },
        "durableOpTime" : {
            "ts" : Timestamp(1656562345, 1),
            "t" : NumberLong(1)
        },
        "lastAppliedWallTime" : ISODate("2022-06-30T04:12:25.854Z"),
        "lastDurableWallTime" : ISODate("2022-06-30T04:12:25.854Z")
    },
    "lastStableRecoveryTimestamp" : Timestamp(1656562335, 1),
    "electionCandidateMetrics" : {
        "lastElectionReason" : "electionTimeout",
        "lastElectionDate" : ISODate("2022-06-30T04:03:15.746Z"),
        "electionTerm" : NumberLong(1),
        "lastCommittedOpTimeAtElection" : {
            "ts" : Timestamp(0, 0),
            "t" : NumberLong(-1)
        },
        "lastSeenOpTimeAtElection" : {
            "ts" : Timestamp(1656561795, 1),
            "t" : NumberLong(-1)
        },
        "numVotesNeeded" : 1,
        "priorityAtElection" : 1,
        "electionTimeoutMillis" : NumberLong(10000),
        "newTermStartDate" : ISODate("2022-06-30T04:03:15.778Z"),
        "wMajorityWriteAvailabilityDate" : ISODate("2022-06-30T04:03:15.853Z")
    },
    "members" : [
        {
            "_id" : 0,
            "name" : "dc0c851d73a7:27017",
            "health" : 1,
            "state" : 1,
            "stateStr" : "PRIMARY",
            "uptime" : 1945,
            "optime" : {
                "ts" : Timestamp(1656562345, 1),
                "t" : NumberLong(1)
            },
            "optimeDate" : ISODate("2022-06-30T04:12:25Z"),
            "syncSourceHost" : "",
            "syncSourceId" : -1,
            "infoMessage" : "",
            "electionTime" : Timestamp(1656561795, 2),
            "electionDate" : ISODate("2022-06-30T04:03:15Z"),
            "configVersion" : 1,
            "configTerm" : 1,
            "self" : true,
            "lastHeartbeatMessage" : ""
        }
    ],
    "ok" : 1,
    "$clusterTime" : {
        "clusterTime" : Timestamp(1656562345, 1),
        "signature" : {
            "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
            "keyId" : NumberLong(0)
        }
    },
    "operationTime" : Timestamp(1656562345, 1)
}

 

오늘은 MongoDB admin user 생성시 발생할 수 있는 오류를 처리하는 방법에 대하여 정리해 보았습니다.

반응형

+ Recent posts

반응형