쿠버네티스에서 MongoDB를 고가용성으로 운영하려면 레플리카셋으로 구성합니다. 파드마다 상태(데이터)가 다르므로 Deployment가 아니라 StatefulSet 을 씁니다.
왜 StatefulSet인가
Redis 클러스터처럼 하나의 PV를 공유하면, 각 파드가 같은 파일을 바라봐 문제가 생깁니다. MongoDB는 멤버마다 다른 데이터를 저장해야 하므로, volumeClaimTemplates 로 파드마다 별도의 PVC를 자동 생성하는 StatefulSet이 맞습니다. 여기에 동적 프로비저닝되는 NFS StorageClass를 물려주면 레플리카를 늘릴 때마다 저장소가 알아서 붙어요.
헤드리스 서비스
멤버 파드끼리 안정적인 도메인으로 통신하려면 헤드리스 서비스가 필요합니다. 서비스의 clusterIP 를 None 으로 두면 됩니다. 그러면 각 파드가 아래 형식의 도메인을 갖습니다.
파드명.서비스명.네임스페이스.svc.cluster.local
예) mongodb-0.mongo-in.myapp.svc.cluster.local
인증 키 공유
레플리카셋 멤버 간 내부 인증에 쓸 키 파일을 난수로 만들어 Secret으로 공유합니다.
openssl rand -base64 741 > ./keys.txt
kubectl create secret -n myapp generic mongodb-key \
--from-file=mongodb-auth-key=./keys.txt
레플리카셋 초기화
매니페스트를 배포하고 프라이머리로 쓸 파드에 접속합니다.
kubectl exec -it mongodb-0 -n myapp -- mongosh
rs.initiate({
_id: "rs0", version: 1,
members: [
{ _id: 0, host: "mongodb-0.mongo-in.myapp.svc.cluster.local:27017" },
{ _id: 1, host: "mongodb-1.mongo-in.myapp.svc.cluster.local:27017" },
{ _id: 2, host: "mongodb-2.mongo-in.myapp.svc.cluster.local:27017" }
]
})
여기서 _id: "rs0" 는 매니페스트의 replSet 값과 같아야 합니다. ok: 1 이 뜨면 성공이에요. 프라이머리 선출에 잠깐 시간이 걸리니 rs.status() 로 확인합니다.
이어서 인증용 관리자를 만듭니다.
use admin
db.createUser({ user: 'root', pwd: '<비밀번호>', roles: ['root'] })
애플리케이션 연결 시 주의
접속 URL은 replicaSet 을 지정하는 게 핵심입니다.
mongodb://root:<비밀번호>@mongo-in:27017/admin?authSource=admin&replicaSet=rs0
특히 Node.js 드라이버는 DNS 라운드로빈을 지원하지 않아, 위처럼 서비스명만 쓰면 세컨더리에 쓰기를 시도해 NotWritablePrimary 오류가 날 수 있습니다. 이럴 땐 멤버를 모두 명시하세요.
mongodb://mongodb-0.mongo-in,mongodb-1.mongo-in,mongodb-2.mongo-in:27017/admin?replicaSet=rs0&authSource=admin
이렇게 하면 드라이버가 프라이머리를 정확히 찾아 안정적으로 쓰기가 됩니다.