스터디/DOIK

Percona Operator for MongoDB - DOIK 스터디 4주차

시스템 엔지니어 2022. 6. 22. 23:40

MongoDB 소개

  • NoSQL
  • NoSQL 종류 : Key-Value Store(Redis), Wide Column Store(HBase, Cassandra), Document Store(mongoDB, CouchDB), Graph Store(Neo4j)

MongoDB 기본개념

  • 기본 단위는 도큐먼트이며, 관계형 데이터베이스의 행과 유사함
  • 컬렉션은 관계형 데이터베이스의 테이블과 같다
  • 모든 도큐먼트는 컬렉션 내에 고유한 특수키인 "_id"를 가진다
  • 복제 세트에는 프라이머리 Primary, 세컨더리 Secondary, 아비터 Arbiter 구성원이 있다.
    • 프라이머리 : 클라이언트와 읽기 및 쓰기 작업
    • 세컨더리 : 프라이머리 구성원의 정보를 동기화
    • 아비터 : 정보를 저장하지는 않고 복제 세트의 복구를 돕는다

Operator 설치

https://www.percona.com/doc/kubernetes-operator-for-psmongodb/kubernetes.html

 

Install Percona server for MongoDB on Kubernetes

Install Percona server for MongoDB on Kubernetes

www.percona.com

# CRD 설치
git clone -b v1.12.0 https://github.com/percona/percona-server-mongodb-operator
cd percona-server-mongodb-operator
kubectl apply --server-side -f deploy/crd.yaml
kubectl get crd

# 실습 편리를 위해서 네임스페이스 변경
kubens psmdb

# RBAC 생성
kubectl apply -f deploy/rbac.yaml

# 오퍼레이터 생성
kubectl apply -f deploy/operator.yaml

MYNICK=my-cluster-name

# 계정 정보를 위한 secret 생성 : base64 decode 로 값을 보자
kubectl apply -f deploy/operator.yaml
kubectl get secret $MYNICK-secrets
kubectl get secret $MYNICK-secrets -o json | jq

# 클러스터 생성 : 복제 세트(3개 파드)
MYCLUSTERNAME=$MYNICK envsubst < ~/DOIK/4/mycluster1.yaml | kubectl apply -f -

 

~/DOIK/4/mycluster1.yaml

기본만 배포

  • rs0 - 3개
  • nonvoting: false
  • arbiter: false
  • sharding: false
  • mongos: 3 이지만, sharding과 연결되어 사용하지 않음
  • backup: false
apiVersion: psmdb.percona.com/v1-12-0
kind: PerconaServerMongoDB
metadata:
  name: ${MYCLUSTERNAME}-db
  finalizers:
    - delete-psmdb-pods-in-order
spec:
  crVersion: 1.12.0
  image: percona/percona-server-mongodb:5.0.7-6
  imagePullPolicy: Always
  allowUnsafeConfigurations: false
  updateStrategy: SmartUpdate
  upgradeOptions:
    versionServiceEndpoint: https://check.percona.com
    apply: 5.0-recommended
    schedule: "0 2 * * *"
    setFCV: false
  secrets:
    users: ${MYCLUSTERNAME}-secrets
    encryptionKey: ${MYCLUSTERNAME}-mongodb-encryption-key
  pmm:
    enabled: false
    image: percona/pmm-client:2.27.0
    serverHost: monitoring-service
  replsets:
  - name: rs0
    size: 3
    affinity:
      antiAffinityTopologyKey: "kubernetes.io/hostname"
    podDisruptionBudget:
      maxUnavailable: 1
    expose:
      enabled: false
      exposeType: ClusterIP
    resources:
      limits:
        cpu: "300m"
        memory: "0.5G"
      requests:
        cpu: "300m"
        memory: "0.5G"
    volumeSpec:
      persistentVolumeClaim:
        resources:
          requests:
            storage: 5Gi
    nonvoting:
      enabled: false
      size: 3
      affinity:
        antiAffinityTopologyKey: "kubernetes.io/hostname"
      podDisruptionBudget:
        maxUnavailable: 1
      resources:
        limits:
          cpu: "300m"
          memory: "0.5G"
        requests:
          cpu: "300m"
          memory: "0.5G"
      volumeSpec:
        persistentVolumeClaim:
          resources:
            requests:
              storage: 5Gi
    arbiter:
      enabled: false
      size: 1
      affinity:
        antiAffinityTopologyKey: "kubernetes.io/hostname"
  sharding:
    enabled: false
    configsvrReplSet:
      size: 3
      affinity:
        antiAffinityTopologyKey: "kubernetes.io/hostname"
      podDisruptionBudget:
        maxUnavailable: 1
      expose:
        enabled: false
        exposeType: ClusterIP
      resources:
        limits:
          cpu: "300m"
          memory: "0.5G"
        requests:
          cpu: "300m"
          memory: "0.5G"
      volumeSpec:
        persistentVolumeClaim:
          resources:
            requests:
              storage: 5Gi
    mongos:
      size: 3
      affinity:
        antiAffinityTopologyKey: "kubernetes.io/hostname"
      podDisruptionBudget:
        maxUnavailable: 1
      resources:
        limits:
          cpu: "300m"
          memory: "0.5G"
        requests:
          cpu: "300m"
          memory: "0.5G"
      expose:
        exposeType: ClusterIP
  backup:
    enabled: false
    image: percona/percona-backup-mongodb:1.7.0
    serviceAccountName: percona-server-mongodb-operator
    pitr:
      enabled: false
      compressionType: gzip
      compressionLevel: 6

HeadLess 접속 정보 확인

https://www.percona.com/doc/kubernetes-operator-for-psmongodb/expose.html

kubectl get svc,ep

kubectl run -it --rm netdebug --image=nicolaka/netshoot --restart=Never -- zsh
nslookup $MYNICK-db-rs0
nslookup $MYNICK-db-rs0-0.nunu-db-rs0
nslookup $MYNICK-db-rs0-1.nunu-db-rs0
nslookup $MYNICK-db-rs0-2.nunu-db-rs0

복제 테스트

client 3개 생성

myclient.yaml

apiVersion: v1
kind: Pod
metadata:
  name: ${PODNAME}
  labels:
    app: myclient
spec:
  nodeName: k8s-m
  containers:
  - name: ${PODNAME}
    image: percona/percona-server-mongodb:${VERSION}
    command: ["tail"]
    args: ["-f", "/dev/null"]
  terminationGracePeriodSeconds: 0
MYNICK=
IMGVER=$(kubectl get perconaservermongodbs $MYNICK-db -o jsonpath={.spec.image} | cut -d ':' -f 2)
for ((i=1; i<=3; i++)); do PODNAME=myclient$i VERSION=$IMGVER envsubst < ~/DOIK/4/myclient.yaml | kubectl apply -f - ; done
# [터미널1] 프라이머리 파드 접속(doik)
kubectl exec -it myclient1 -- mongo --quiet "mongodb://doik:qwe123@$MYNICK-db-rs0-0.$MYNICK-db-rs0.psmdb.svc/admin?ssl=false"
rs0:PRIMARY> use doik
rs0:PRIMARY> db.test.insertOne({ reptest: 1 })
rs0:PRIMARY> db.test.find()
rs0:PRIMARY> db.test.count()

# [터미널2] 세컨더리 파드1 접속(doik)
kubectl exec -it myclient2 -- bash -il
--------------------------------------
# 변수 지정
MYNICK=<각자 자신의 닉네임>
MYNICK=gasida
echo $'rs.secondaryOk()\nuse doik\ndb.test.count()' | mongo --quiet "mongodb://doik:qwe123@$MYNICK-db-rs0-1.$MYNICK-db-rs0.psmdb.svc/admin?ssl=false"
while true; do echo $'rs.secondaryOk()\nuse doik\ndb.test.count()' | mongo --quiet "mongodb://doik:qwe123@$MYNICK-db-rs0-1.$MYNICK-db-rs0.psmdb.svc/admin?ssl=false" | grep -v Error; date; sleep 1; done
--------------------------------------

# [터미널3] 세컨더리 파드2 접속(doik)
kubectl exec -it myclient3 -- bash -il
--------------------------------------
# 변수 지정
MYNICK=<각자 자신의 닉네임>
MYNICK=gasida
echo $'rs.secondaryOk()\nuse doik\ndb.test.count()' | mongo --quiet "mongodb://doik:qwe123@$MYNICK-db-rs0-2.$MYNICK-db-rs0.psmdb.svc/admin?ssl=false"
while true; do echo $'rs.secondaryOk()\nuse doik\ndb.test.count()' | mongo --quiet "mongodb://doik:qwe123@$MYNICK-db-rs0-2.$MYNICK-db-rs0.psmdb.svc/admin?ssl=false" | grep -v Error; date; sleep 1; done
--------------------------------------

# [터미널1] 프라이머리 파드 접속(doik) : 대량의 도큐먼트 생성 및 복제 확인
rs0:PRIMARY> for (i=0; i<1000; i++) {db.test.insert({count: i, "created_at" : new Date()})}
rs0:PRIMARY> db.test.find({},{_id:0})

 

느낀점

  • Operator를 사용하면 쉽게 몽고 DB 클러스터를 구성할 수 있습니다.
  • 쉽게 구성되는 만큼 장애날 상황들에 대해 많은 테스트가 필요할 것 같습니다.