샤인의 IT (막 적는) 메모장

[DOIK 스터디] NoSQL와 MongoDB Operator 본문

Kubernetes 심화 주제

[DOIK 스터디] NoSQL와 MongoDB Operator

신샤인 2022. 6. 23. 22:45
반응형

 

 

나뭇잎 DB에 대해 알아보자!

 

NoSQL

  • Not only SQL
  • RDBMS처럼 고정된 스키마가 존재하지 않음

 

 

 

MongoDB

  • Document 지향 데이터베이스. 관계형 모델을 사용하지 않는 이유는 Scale-out을 용이하게 하기 위함
  • 고정된 스키마가 없기 때문에 쉽게 필드를 추가하거나 삭제할 수 있다.
  • CRUD 이외에 대부분의 DBMS 기능 제공
  • 몽고DB의 기본 단위는 다큐먼트이며 관계형 데이터베이스의 행과 유사
  • 컬렉션은 동적 스키마가 있는 테이블과 같음
  • 모든 다큐먼트 컬렉션 내에서 고유한 특수키인 “_id”를 가짐
  • Document
    • Key가 중복될 수 없음
    • .과 $ 문자는 몇 가지 특별한 속성을 가지며 보통 예약어로 취급됨
    • 데이터형과 대소문자를 구분함
  • Collection
    • 다큐먼트의 모음, RDB에서 테이블과 유사
    • 컬렉션은 동적 스키마를 가진다.
    • 데이터를 구분하여 같은 종류의 데이터를 하나의 컬렉션에 저장하여 사용함
  • Naming
    • Collection은 이름으로 식별된다.
    • 서브컬렉션의 네임스페이스에 .(마침표) 문자를 사용해 컬렉션을 체계화 한다.
  • MongoDB 기본 문법 정리
#DB 확인
db

#DB 유저 확인
db.getUsers()

#DB 사용자 생성
db.createUser({user: "user" , pwd: "user123" , roles: [ "userAdminAnyDatabase", "dbAdminAnyDatabase","readWriteAnyDatabase"]})

#DB 선택
use doik

#컬렉션 확인
show collections

#컬렉션 생성
db.createCollection("Test", {capped:true, size:10000})
show collections

#컬렉션 다큐먼트 조회
db.test.find()

#다큐먼트 추가
db.test.insertOne({ hello: 'world'})
db.test.find()

#콜렉션 통계정보 확인
db.test.stats()

#콜렉션 삭제
db.test.drop()

#DB 통계 확인
db.stats()

----
#Primary key를 위한 별도 컬럼을 만들 필요 없음. _id가 자동 생성됨

#콜렉션 생성
db.createCollection("users")

#다큐먼트 생성
**db.users.insertOne(**
 **{
  name: "shine",
  age: 30,
  status: "pending",
 }
)**
**db.users.find()**

# insertMany : 파이썬의 List [] 문법을 사용 >> RDBMS 처럼 컬럼(스키마)를 편하게 입력 가능
db.users.insertMany(
 [
  { subject: "abc1", author: "xyz1", views: 10 },
  { subject: "abc2", author: "xyz2", views: 20 },
  { subject: "abc3", author: "xyz3", views: 30 }
 ]
)

# 비교 문법 : equal , greater than , greater than equal , less than , less than or equal , not equal, nin
$eq     =    Matches values that are equal to a specified value.
$gt     >    Matches values that are greater than a specified value.
$gte    >=   Matches values that are greater than or equal to a specified value.
$in          Matches any of the values specified in an array.
$lt     <    Matches values that are less than a specified value.
$lte    <=   Matches values that are less than or equal to a specified value.
$ne     !=   Matches all values that are not equal to a specified value.
$nin         Matches none of the values specified in an array.

#Find 쿼리
db.employees.find({ age: { $gt: 25 } }) - age 값이 25 보다 큰 값을 찾음
db.employees.find( { status: "A" } ).sort( { user_id: 1 } ) - status 값이 A일 경우 오름차순 정리해서 찾음
db.employees.find().count() - 다큐먼트 수 확인

#update
$set: field 값 설정
$inc: field 값을 증가시키거나, 감소시킴
 예) $inc: { age: 2} - age 값을 본래의 값에서 2 증가

# 다음 Document 데이터 수정하기
age 가 30 보다 큰 Document 의 status 를 B 로 변환하기
**db.employees.updateMany( { age: {$gt: 30} }, { $set: {status: "B"} } )**

# 실습 결과 확인
**db.employees.find({}, {_id:0})

#delete
# 삭제1
db.employees.deleteMany( { status: "A" } ) - status 값이 A인 다큐먼트 삭제
# 실습 결과 확인
db.employees.find({}, {_id:0})

# 삭제2
db.employees.deleteMany({}) - SQL로 변환하면, DELETE FROM people
# 실습 결과 확인
db.employees.find({}, {_id:0})**

 

 

 

Percona Operator for MongoDB

  • Kubernetes용 MongoDB 오퍼레이터
    • 접속은 mongo+srv URL 주소로 접속
    • 사용 리소스 : 샤딩 미사용 시 2core 2G + 60G / 샤딩 사용 시 4core 6G
    • Operator는 PerconaServerMongoDB를 사용하며 적절한 Replicaset을 제공함

MongoDB Operator 구성

 

 

 

 

  • Pod 구성

MongoDB Operator 파드 구성

  • MongoDB Operator 설치
apiVersion: apps/v1
kind: Deployment
metadata:
  name: percona-server-mongodb-operator
spec:
  replicas: 1
  selector:
    matchLabels:
      name: percona-server-mongodb-operator
  template:
    metadata:
      labels:
        name: percona-server-mongodb-operator
    spec:
      serviceAccountName: percona-server-mongodb-operator
      containers:
        - name: percona-server-mongodb-operator
          image: percona/percona-server-mongodb-operator:1.12.0
          ports:
          - containerPort: 60000
            protocol: TCP
            name: metrics
          command:
          - percona-server-mongodb-operator
          imagePullPolicy: Always
          env:
            - name: WATCH_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
            - name: POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: OPERATOR_NAME
              value: percona-server-mongodb-operator
            - name: RESYNC_PERIOD
              value: 5s
            - name: LOG_VERBOSE
              value: "false"
      nodeSelector:
        kubernetes.io/hostname: k8s-m
      tolerations:
        - effect: NoSchedule
          key: node-role.kubernetes.io/master
          operator: Exists
---
#RBAC
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: percona-server-mongodb-operator
rules:
- apiGroups:
  - psmdb.percona.com
  resources:
  - perconaservermongodbs
  - perconaservermongodbs/status
  - perconaservermongodbbackups
  - perconaservermongodbbackups/status
  - perconaservermongodbrestores
  - perconaservermongodbrestores/status
  verbs:
  - get
  - list
  - watch
  - create
  - update
  - patch
  - delete
- apiGroups:
  - ""
  resources:
  - pods
  - pods/exec
  - services
  - persistentvolumeclaims
  - secrets
  - configmaps
  verbs:
  - get
  - list
  - watch
  - create
  - update
  - patch
  - delete
- apiGroups:
  - apps
  resources:
  - deployments
  - replicasets
  - statefulsets
  verbs:
  - get
  - list
  - watch
  - create
  - update
  - patch
  - delete
- apiGroups:
  - batch
  resources:
  - cronjobs
  verbs:
  - get
  - list
  - watch
  - create
  - update
  - patch
  - delete
- apiGroups:
  - policy
  resources:
  - poddisruptionbudgets
  verbs:
  - get
  - list
  - watch
  - create
  - update
  - patch
  - delete
- apiGroups:
  - coordination.k8s.io
  resources:
  - leases
  verbs:
  - get
  - list
  - watch
  - create
  - update
  - patch
  - delete
- apiGroups:
  - ""
  resources:
  - events
  verbs:
  - create
  - patch
- apiGroups:
  - certmanager.k8s.io
  - cert-manager.io
  resources:
  - issuers
  - certificates
  verbs:
  - get
  - list
  - watch
  - create
  - update
  - patch
  - delete
  - deletecollection
- apiGroups:
  - net.gke.io
  - multicluster.x-k8s.io
  resources:
  - serviceexports
  - serviceimports
  verbs:
  - get
  - list
  - watch
  - create
  - update
  - patch
  - delete
  - deletecollection
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: percona-server-mongodb-operator
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: service-account-percona-server-mongodb-operator
subjects:
- kind: ServiceAccount
  name: percona-server-mongodb-operator
roleRef:
  kind: Role
  name: percona-server-mongodb-operator
  apiGroup: rbac.authorization.k8s.io
---
#Secret
apiVersion: v1
kind: Secret
metadata:
  name: ${MYCLUSTERNAME}-secrets
type: Opaque
stringData:
  MONGODB_BACKUP_USER: backup
  MONGODB_BACKUP_PASSWORD: backup123456
  MONGODB_CLUSTER_ADMIN_USER: clusterAdmin
  MONGODB_CLUSTER_ADMIN_PASSWORD: clusterAdmin123456
  MONGODB_CLUSTER_MONITOR_USER: clusterMonitor
  MONGODB_CLUSTER_MONITOR_PASSWORD: clusterMonitor123456
  MONGODB_USER_ADMIN_USER: userAdmin
  MONGODB_USER_ADMIN_PASSWORD: userAdmin123456
  PMM_SERVER_USER: admin
  PMM_SERVER_PASSWORD: admin
# CRD 설치
kubectl apply -f --server-side -f crd.yaml

#Namespace 지정
kubectl create ns psmdb
kubeens psmdb

#RBAC 지정
kubectl apply -f rbac.yaml

#MongoDB Operator 설치
kubectl apply -f pomdb.yaml

#계정 정보 Secret 설정
MYCLUSTERNAME=$MYNICK envsubset < ~/secrets.yaml | kubectl apply -f -
kubectl get secret -A | grep -i $MYNICK

#클러스터 설치
MYCLUSTERNAME=$MYNICK envsubset < ~/mycluster.yaml | kubectl apply -f -

#클러스터 정보 확인
kubectl get po,sts,svc,endpoints,endpointslice

#MongoDB 확인
kubectl get perconaservermongodb $MYNICK-db -o jsonpath={.spec.image}

작업 확인

설치 확인
설치 이미지 확인

  • 서비스 확인
#DNS 조회용 파드 실행
kubectl run -it --rm netdebug --image=nicolaka/netshoot --restart=Never -- zsh

#DNS 질의
nslookup shine-db-rs0
nslookup -type=srv $MYNICK-db-rs0

 

작업 확인

서비스 확인을 위한 netshoot 설치
K8s DNS 확인 작업

 

  • MongoDB 클라이언트 배포
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
#MongoDB 클라이언트 3대 배포
#IMGVER 환경변수는 앞에서 설치한 MongoDB 이미지 버전을 지정하여 넣을 것!

IMGVER=x.xx
cat ~/DOIK/4/myclient.yaml
for ((i=1; i<=3; i++)); do PODNAME=myclient$i VERSION=$IMGVER envsubst < ~/myclient.yaml | kubectl apply -f - ; done


#MongoDB 접속
kubectl exec -it myclient1 -- mongo --quiet "mongodb+srv://userAdmin:userAdmin123456@$MYNICK-db-rs0.psmdb.svc.cluster.local/admin?replicaSet=rs0&ssl=false"

작업 확인

MongoDB 접속용 Client 파드 3대 배포

 

  • 접속주소 : mongodb+srv://<ID>:<PASSWORD>@<SVC>.<NS>.svc.cluster.local/admin?replicaset=rs0&ssl=false

Client 접속을 위한 계정 정보 확인

 

  • Replication 확인
#클러스터 접속
#user에 어드민, 클러스터, 생성 계정으로 접근
kubectl exec -it myclient1 -- mongo --quiet "mongodb+srv://userAdmin:userAdmin123456**@$MYNICK-db-rs0.psmdb.svc.cluster.local/**admin**?replicaSet=rs0&ssl=false"
# Ctrl + l 클릭 시 터미널 Clear

#Replica Set 상태 확인
rs.status
rs.status()['member']

#Replica Set 간단히 확인
db.isMaster()

#OP Log 확인 연산, 시간
rs.printReplicationInfo()

#Replica Set 동기화 정보 확인
rs.printSecondaryReplicationInfo()

#복제 설정 확인
rs.conf()

 실행 확인 (클러스터 어드민 계정으로 접속하여 확인)

Replica Set 정보 확인
Event Log 및 Replica 관련 설정 정보 확인

 

  • Primary 파드를 강제 삭제 후 재접속 하여 Primary가 변경되었는지 확인
    • 기존 Primary 파드가 1번으로 되어 있는데 파드를 삭제할 경우 변경되는 것을 확인할 수 있음

기본 rs0으로 Primary 설정되어 있음
어떡하죠ㅠㅠ DB 파드를 날렸어요 (인재)
오 두번째 DB 파드가 Primary로 변경된다!

 

 

  • 노드 Drain을 통한 장애 상황 시
    • 방금 전 2번째 DB 파드가 Primary로 변경되었음
    • 2번 Pod를 Drain(워커노드 2번) 하고 확인한 후 2번도 바로 Drain을 해보자
#Primary Pod 노드 drain
kubectl drain k8s-w2 --delete-emptydir-data --force --ignore-daemonsets 

#drain을 풀 경우
kubectl uncordon k8s-w1

 

Primary 2번 DB 파드 확인
유지보수 모드로 2번 DB 파드가 배포된 노드 Drain
2번 파드는 unhealthy 1번 파드가 다시 Primary로 변경됨!

  • 노드 Drain을 2대로 올릴 경우

엥?&nbsp; Evict가 안된다!
3번도 똑같다..

 

 

  • 두번째 노드 Drain 시 -> PodDisruptionBudget 제약을 받음
  • psmdb 네임스페이스 내에 replica 수가 보장되게끔 설정되어 있음
  • maxUnavailable 값이 1이기 때문에 desiredHealthy가 2가 되어야 함
#PDB 설정 확인
kubectl get pdb shine-db-mongod-rs0 -n psmdb -oyaml

podDisruptionBudget 설정 확인

 

 

마무리

운영자 관점에서 보면 DB도 어느정도 알아야 한다고 생각하는데 NoSQL은 또 코드로 관리하는 느낌이 살짝 들기도 하고..

설정값 확인을 함수를 호출해서 한다던가, 장애 상황 시 PRIMARY - SECONDARY 변경되는 것들을 실습해보면서 알아가다 보니 조금씩 DB랑 친해지는 것 같다😐

반응형
Comments