Backend/Database

Kubernetes 클러스터에 MongoDB 구성하기

findmypiece 2022. 8. 31. 02:50
728x90

kubernetes 에 MongoDB 를 replica set 으로 구성해서 사용해본다. MongoExpress 도 함께 설치할 예정인데 MongoExpress는 MongoDB 관리를 위한 GUI 웹어드민 툴이다.

우선 replica set 구성을 위해서는 각 노드가 통신할 수 있는 인증 key 가 필요하고 kubernetes 환경에서는 특정 key 파일을 secret 로 만들어서 각 노드에서 활용한다. 즉, 아래와 같다.

openssl rand -base64 741 > ./replica-sets-key.txt
kubectl create secret generic shared-bootstrap-data --from-file=internal-auth-mongodb-keyfile=./replica-sets-key.txt

이렇게 생성한 secret 는 mongo pod 구성시 볼륨으로 참조한다.

MongoDB 구성에 사용한 yaml 파일은 아래와 같다.

apiVersion: v1
kind: ConfigMap
metadata:
  name: tcp-services
  namespace: ingress-nginx
data:
  27017: "default/mongo-svc:27017"
---
kind: Service
apiVersion: v1
metadata:
  name: mongo-svc-vip # 서비스 명에 맞게 변경
  namespace: ingress-nginx
spec:
  externalTrafficPolicy: Local
  type: LoadBalancer
  ports: # 서비스에 맞게 변경
    - name: mongo-svc
      port: 27017
      targetPort: 27017
      protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
  name: mongo
  labels:
    name: mongo
spec:
  ports:
  - port: 27017
    targetPort: 27017
  clusterIP: None
  selector:
    role: mongo
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mongo
spec:
  serviceName: mongo-svc
  replicas: 3
  selector:
    matchLabels:
      role: mongo
  template:
    metadata:
      labels:
        role: mongo
        environment: test
    spec:
      terminationGracePeriodSeconds: 10
      containers:
        - name: mongo
          image: ...mongo-5.0.11
          command:
            - "numactl"
            - "--interleave=all"
            - "mongod"
            - "--bind_ip"
            - "0.0.0.0"
            - "--replSet"
            - "MainRepSet"
            - "--auth"
            - "--clusterAuthMode"
            - "keyFile"
            - "--keyFile"
            - "/etc/secrets-volume/internal-auth-mongodb-keyfile"
            - "--setParameter"
            - "authenticationMechanisms=SCRAM-SHA-1"
          resources:
            requests:
              cpu: 0.2
              memory: 200Mi
          ports:
            - containerPort: 27017
          volumeMounts:
            - name: secrets-volume
              readOnly: true
              mountPath: /etc/secrets-volume
            - name: mongo-persistent-storage
              mountPath: /data/db
        - name: mongo-sidecar
          image: ...cvallance-mongo-k8s-sidecar-20220824
      volumes:
        - name: secrets-volume
          secret:
            secretName: shared-bootstrap-data
            defaultMode: 256
  volumeClaimTemplates:
    - metadata:
        name: mongo-persistent-storage
      spec:
        accessModes: [ "ReadWriteOnce" ]
        resources:
          requests:
            storage: 10Gi

여기에서는 클러스터 외부에서 접근하기 위해 LoadBalancer 서비스를 사용했고 TCP 통신을 위해 ingress 컨트롤러가 참조할 tcp-services 라는 ConfigMap 을 정의했다. 위 yaml 이 정상적으로 동작하기 위해서는 클러스터에 LoadBalancer 와 ingress 컨트롤러가 구성되어 있어야 한다.

추가로 mongo-svc 에 해당하는 Service 를 Headless 서비스로 만들었는데 replica set 을 구성했기 때문에 굳이 이렇게 만들지 않아도 된다.

MongoDB 를 실행시키는 커맨드 명령어인 mongod 의 옵션들은 추후 조사할 예정이다. 사이드카 pod는 k8s 환경에 MongoDB를 구성할 때 필요한 유틸성 pod 인거 같다.

volumeClaimTemplates 에 StorageClass 지정이 필요할 수도 있다. 일부 포스팅을 보면 아래와 같이 annotations 에 StorageClass 를 지정하는 예가 많은데 해당 annotations은 아직까지는 사용할 수 있지만 향후 쿠버네티스 릴리스에서 완전히 사용 중단(deprecated)이 될 예정이다.

...
  volumeClaimTemplates:
  - metadata:
       name: mongo-persistent-storage
       annotations:
         volume.beta.kubernetes.io/storage-class: "cinder-csi"
...


이에 StroageClass 지정이 필요하다면 아래와 같이 하도록 한다.

...
  volumeClaimTemplates:
  - metadata:
      name: mongo-persistent-storage
    spec:
      storageClassName: "cinder-csi"
...


물론 굳이 지정하지 않아도 아래 명령으로 확인되는 StorageClass 중 default 로 지정된 것이 있다면 그게 사용되긴 한다.

kubectl get storageclass


내가 사용하는 환경에서는 아래와 같이 cinder-csi 가 Default StroageClass 로 지정되어 있었다.


정상적으로 구성되었다면 이제부터 replica set 을 구성해줘야 한다. 아래 명령어로 특정 mongo-0 pod 에 접속한다.

kubectl exec -ti mongo-0 -- /bin/bash


아래 명령어로 MongoDB 터미널에 접속한다.

mongo


아래 명령어로 replica set 을 구성한다. 각 pod 의 내부 도메인들은 CoreDns 를 사용하는 기준으로 작성한 것임에 유의하자.

rs.initiate({_id: "MainRepSet", version: 1, members: [
  { _id: 0, host : "mongo-0.mongo-svc.default.svc.cluster.local:27017" },
  { _id: 1, host : "mongo-1.mongo-svc.default.svc.cluster.local:27017" },
  { _id: 2, host : "mongo-2.mongo-svc.default.svc.cluster.local:27017" }
]
});


만약 지정한 내부 도메인이 유효하지 않다면 아래와 같은 에러 메시지가 출력될 수 있는데 이 때는 busybox 를 통해 nslookup 으로 도메인을 체크해보자.

{
        "ok" : 0,
        "errmsg" : "No host described in new configuration with {version: 1, term: 0} for replica set MainRepSet maps to this node",
        "code" : 93,
        "codeName" : "InvalidReplicaSetConfig"
}


아래 명령어로 구성된 replica set 을 확인할 수 있을텐데 mongo-0 이 Primary 노드가 되었을 것이고 그 외 두 개의 pod 이 Secondary노드가 되어 있을 것이다.

rs.status()


이제 database 와 user 를 만들어야 한다. 그 전에 RDBMS에 해당하는 MySql 과 같은 와 NoSql 에 해당하는 MongoDB의 용어를 비교하면 아래와 같다.

Mongo RDBMS
database database
collection table
document row 혹은 record
field column


database 와 user 는 아래와 같이 생성한다.

use admin #생성과 동시에 해당 database로 스위칭 된다.
db.createUser({user:"admin",pwd:passwordPrompt(),roles:[{role:"root",db:"admin"}]})

기본적으로 user 가 없이도 database 에 접속은 가능하다. 인증없이 접근이 가능하다는 말인데 아무런 인증을 받지 않았기 때문에 권한도 없다. 즉, 때문에 뭔가 유의미한 작업을 하려면 적절한 role 의 user 를 생성하고 이를 통해 database 에 접근해야 한다.

database 이 인증을 포함해서 접근하는 방법은 세 가지 방법이 있다.

1. mongo 터미널 접속과 동시에 인증 획득

mongo --port 27017 -u "admin" -p "1234" --authenticationDatabase "admin"


2. 인증 없이 mongo 터미널 접속 후 database 스위칭->인증획득

mongo
use admin
db.auth('admin', passwordPrompt())


3. database 스위칭 없이 특정 database 접근

db.getSiblingDB('admin').auth("admin", passwordPrompt())


마지막으로 DataGrip 로 위에서 구성한 MongoDB에 접속해 보자. 외부 노출 아이피는 아래 명령어의 결과 중 EXTERNAL-IP 를 사용하면 된다.

kubectl get svc mongo-svc-vip -n ingress-nginx



DataGrip 커넥션은 아래와 같이 작성하면 된다.

 

https://linux.systemv.pe.kr/statefulset-에서-로컬-디스크-사용/
https://kubernetes.io/ko/docs/concepts/storage/persistent-volumes/
https://www.cloudskillsboost.google/focuses/640?locale=ko&parent=catalog
https://toma0912.tistory.com/85
https://support.skdt.co.kr/ko/support/solutions/articles/42000055916-pvc-persistentvolumeclaim-를-생성하고-pod-에-마운트하기
https://hyeo-noo.tistory.com/m/364
http://daplus.net/mongodb-mongodb-복제-및-오류-err-not-master-and-slaveok-false-code-13435/
https://dba.stackexchange.com/questions/211605/node-is-not-in-primary-or-recovering-state
https://maruftuhin.com/blog/mongodb-replica-set-on-kubernetes/
https://blog.1day1.org/599
https://knight76.tistory.com/entry/mongodb-replica-set-만들기
https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=humongousdb&logNo=220090678711
https://emong.tistory.com/237
https://www.shellhacks.com/mongodb-create-user-database-admin-root/
https://kubernetes.github.io/ingress-nginx/user-guide/exposing-tcp-udp-services/

 

728x90