[DOIK2] 쿠버네티스 오퍼레이터 @MongoDB

2023. 11. 12. 01:55DOIK@CloudNet

- cloudnet에서 주관하는 쿠버네티스 데이터베이스 오퍼레이터 스터디 2기 내용입니다

- 목적: 다양한 db 오퍼레이터 실습으로 eks 환경에서 DB 배포 및 운영을 위한 다양한 DB 오퍼레이터 실습

이번주에는 Kubernates 환경에서 MongDB를 배포하고 관련 내용을 조금 정리해 보았다.

 

 

1. NoSQL이란?

MongoDB는 대표적인 NoSQL DB이다. 잠시 NoSQL에 대해 알아보고 마저 MongoDB 이야기를 이어가보자.

- NoSQL은 DBMS를 분류하는 기준으로, 가장 큰 특징은 고정된 schema 가 존재하지 않는 것이다.

- 대부분의 경우 SQL을 사용하지만, 케이스마다 특화된 NoSQL이 있어 고도화하기 좋다.

 

Document DB: MongoDB

- 데이터를 JSON 형태로 저장하므로 원하는 형태로 저장할 수 있다.

 

Key-Value DB: Cassandra

- 데이터를 저장하기 전에 액세스 방식을 구성해야 해서 러닝커브가 높지만 매우 빠르다

 

Graph DB

- document-column 방식이 아니라 노드간의 연결인 entity를 저장하는 방식으로, SNS에 유리하다.

 

 

2. MongoDB란?

- 데이터를 JSON format으로 저장하므로 비정형 데이터 관리에 용이하다.

- 고정 스키마가 없으므로 필요에 따라 필드 추가 및 제거가 용이하다.

- 그러나 반대로 고정 스키마가 없으므로 복잡한 JOIN 연산은 수행하기 어렵다.

- 분산 확장(scale-out) 이 용이하다(sharding)

- 별도 primary key가 필요하지 않다(collection내 _id 가 primary key 역할을 함)

- SQL의 table == MongoDB의 collection

 

3. Sharding

기본적인 아이디어: 테이블이 너무 커져서 CRUD가 느려진다

그러면 테이블을 쪼개서 병렬처리가 가능하게 하자!

(MongoDB는 이 shard 사이에서 데이터 일관성을 지키기 위해 설정 서버를 둠)

 

- 쪼갠 테이블을 shard라고 부르고 이 나누는 기준을 shard key라고 한다. 이때 shard key는 인덱스 필수.

- shard는 라우터를 통해서만 애플리케이션과 정보를 교환할 수 있음.

- sharding 수행 시 고려사항: 어떻게 테이블을 쪼개고 read 할지를 고려해서 적절한 방법론을 선택해야 한다.

 

 

4. MongoDB 오퍼레이터 실습

- 오퍼레이터로는 Percona 를 사용한다 (MongoDB 자체 커뮤니티 오퍼레이터는 sharding을 지원하지 않아서 percona 사용)

 

기본 설치

1. CRD 설치

- CRD(Custom Resource Definitions): 특정 애플리케이션 및 시스템 특화 리소스 정의 및 사용

- 스터디장님이 만들어주신 .yaml 파일 실행을 통해 설치한다

#CRD 설치
kubectl apply --server-side -f https://raw.githubusercontent.com/gasida/DOIK/main/psmdb/crd.yaml

#CRD 중 psmdb를 포함한 내용만 확인
kubectl get crd | grep psmdb

 

 

2. namespace 생성 및 변경

- namespace: 클러스터 내 리소스의 논리적 구분.

#namespace 생성
kubectl create ns psmdb

#실습 편의를 위한 namespace 변경(필수)
kubectl get pod
kubectl ns psmdb

namespace 를 변경하고 나면 N/A 에서 psmdb로 기본 설정이 바뀐 것을 확인할 수 있다(4번째 command부터)

 

 

 

3. RBAC, 오퍼레이터 설치

- RBAC(Role-Based Access Control): 권한구분을 통한 보안관리

- percona operator에 필요한 권한과 정보를 또 가시다님께서 .yaml로 배포해 주셨다.

# RBAC 설치
kubectl apply -f https://raw.githubusercontent.com/gasida/DOIK/main/psmdb/rbac.yaml
kubectl get-all -n psmdb

# 오퍼레이터 설치
curl -s -O https://raw.githubusercontent.com/gasida/DOIK/main/psmdb/operator.yaml
cat operator.yaml | yh
kubectl apply -f operator.yaml
kubectl get deploy,pod
kubectl get-all -n psmdb

 

- RBAC 설치

- 오퍼레이터 설치

오퍼레이터가 배포되어 Pod 1개에서 돌아가고 있는 모습을 볼 수 있다.

 

 

 

4. 닉네임 지정 및 secret 생성

- 이때 소문자만 가능한 것 같다(대문자를 포함했다가 오류가 발생함)

# /etc/profile 에 내 닉네임 저장(계속 사용됨)
MYNICK=hithere
echo "export MYNICK=hithere" >> /etc/profile

# secret 파일 가져오기
curl -s -O https://raw.githubusercontent.com/gasida/DOIK/main/psmdb/secrets.yaml

# 가져온 .yaml 에서 계정 정보(닉네임) 바꿔서 배포하기
cat secrets.yaml | sed -e "s/my-cluster-name/$MYNICK/" | kubectl apply -f -

# secret 정보 확인 
kubectl get secret $MYNICK-secrets -o json | jq .data

- cluster admin, user admin, database admin 3개의 역할이 생성된 것을 확인한다.

 

 

 

Replica Set 클러스터 구성

배포: 3개의 파드(복제세트) 를 가진 클러스터가 생성되는 것을 확인한다.

# 클러스터 파일 받기
curl -s -O https://raw.githubusercontent.com/gasida/DOIK/main/psmdb/cluster1.yaml

# 배포 (약 3분 소요)
cat cluster1.yaml | sed -e "s/my-cluster-name/$MYNICK/" | kubectl apply -f - && kubectl get psmdb -w

# 모니터링(다른 터미널)
watch kubectl get psmdb,sts,pod,svc,ep,pvc

cat 으로 cluster 를 확인할때 replset이 3개로 구성되어 있다.

배포가 잘 되었다. 와!

3개의 pod가 모두 statefulset으로 잘 배포되었고 pvc가 하나씩 붙어 동작하고 있음을 확인한다. 이때 primary pod는 rs0-0이다.

cluster IP가 none인 것으로 headless 임을 확인할 수 있고, headless 임으로 개별 ip/domain으로 접속할 수 있다.

affinity: replicaset pod 배포 시 antiAffinityTopologykey 를 kubernates의 hostname으로 설정했는데, 복제 pod들이 서로 떨어지라는 뜻이다.

 

 

# mongodb 이미지 버전 확인
kubectl get perconaservermongodbs $MYNICK -o jsonpath={.spec.image} ; echo
percona/percona-server-mongodb:6.0.9-7

# (옵션) 설치 리소스 확인
kubectl get-all --namespace=psmdb
# 10분 내의 동작만 확인
kubectl get-all --since 10m
# cluster 동작만 확인
kubectl get-all --only-scope=cluster

#삭제
cat cluster1.yaml | sed -e "s/my-cluster-name/$MYNICK/" | kubectl delete -f -

 

위 command들을 사용하면 cluster 동작 정보, MongoDB 버전 등을 확인할 수 있다.

--since, --only-scope 옵션이 매우 유용하다.

(너무 길어서 터미널 스샷 생략)

 

 

 

MongoDB 배포 및 접근

MongoDB 위한 클러스터 배포

# 가시다님의 yaml 파일 받아오기
curl -s -O https://raw.githubusercontent.com/gasida/DOIK/main/psmdb/myclient.yaml

# 내용 확인
cat myclient.yaml | yh

# 환경설정 변경 및 해당 변경사항 클러스터에 반영
VERSION=4.4.24-23 envsubst < myclient.yaml | kubectl apply -f -

# 변경된 pod 상태 확인
kubectl get pod -l name=mongodb -owide

 

환경설정 변경 내용을 해설하면

- VERSION=4.4.24-23: 말 그대로 버전을 이 범위 내에서 지정.

- envsubst: myclient.yaml 파일의 해당 내용(여기서는 버전) 을 변경해서 파일에 적용한다

- kubectl apply -f -: config의 변경 내용을 클러스터에 적용한다.

- CLUSTER_USER 로 접속해서 MongoDB config를 확인하고 클러스터에 접속한다

# secrets.yaml 에서 패스워드 확인
cat secrets.yaml | yh

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

 

admin user 접근 명령어를 해설하면

- exec ds/myclient --it demo set인 myclient로 shell실행을 실행하라 (--it: 컨테이너와 연결하고 상호작용을 활성화)

- --mongo --quiet : mongoDB on :실행상황 띄우지 말고 mongo를 실행하라

- "mongodb+srv://clusterAdmin:clusterAdmin123456@$MYNICK-rs0.psmdb.svc.cluster.local/admin?replicaSet=rs0&ssl=false" :

    - mongodb+srv://  SRV 라는 방식을 가지고 MongoDB와의 connection을 시작한다

    - clusterAdmin:clusterAdmin123456 : 자격증명(cluster_user_id:cluster_user_pw)

    - @$MYNICK-rs0.psmdb.svc.cluster.local/ : replicaset에 접근하기 위한 서비스명

    - admin?replicaSet=rs0&ssl=false : , 접근하는 테이블은 기본 생성되는 admin, ssl 인증 생략, 접근하는 replicaset: rs0

 

rs0에 primary 로 접근을 완료했다. 이제 터미널이 mongo terminal로 바뀐 것을 볼 수 있다.

MongoDB 사용

MongoDB는 진짜로(?!) json format을 사용한다

# user 생성
db.createUser({user:"doik", pwd:"qwe123", roles: ["userAdminAnyDatabase", "dbAdminAnyDatabase", "readWriteAnyDatabase"]})

# 복제 정보 확인
rs.status()

# cluster_user로 접속
kubectl exec ds/myclient -it -- mongo --quiet "mongodb+srv://clusterAdmin:clusterAdmin123456@$MYNICK-rs0.psmdb.svc.cluster.local/admin?replicaSet=rs0&ssl=false"

user_admin으로 접속했을 때: status 확인 실패
cluster_admin으로 접속했을때: 확인 가능

admin_user로 접속했을 때는 사용자를 추가할 수 있었지만 복제 정보는 확인할 수 없었다. 따라서 cluster user로 접속해서 rs.status() 정보를 확인하면 확인할 수 있다.

 

 

CRUD

위에서 생성한 user로 재접속한 후 CRUD action을 수행한다

#위에서 생성한 user로 접속
kubectl exec ds/myclient -it -- mongo --quiet "mongodb+srv://doik:qwe123@$MYNICK-rs0.psmdb.svc.cluster.local/admin?replicaSet=rs0&ssl=false"

#작업할 DB 선택
use doik

#콜렉션(테이블) 생성(사이즈 제한)
db.createCollection("test", {capped:true, size:10000}) 

#존재하는 테이블 확인
show collections

#생성한 test 테이블 내 데이터 확인
db.test.find()

#값 하나 삽입
db.test.insertOne({hello:"world"})

#통계정보 조회
db.test.stats()

# make a collection(table)
db.createCollection("users")

# drop a table
db.users.drop()

# CREATE
db.users.insertOne(
	{name: "hithere", status: "tired"}
)

db.users.insertMany([
	{name: "heyyou", status: "sleepy"},
    {name: "wassap", status: "drowsy"},
    {name: "whyme", status: "surprised"}
])

# READ (search)
db.users.find()
db.users.find({status:"tired"})

# UPDATE $set, $inc
db.users.updateMany({age: {$gt:30}}, {$set: {status:"B}}}) #if(age>30): status=B

#DELETE
de.employees.deleteMany({status:"A"})

 

 

 

하면서 든 생각

신기하다 NoSQL의 세상...!

확실히 json format을 사용할 수 있다는 점이 큰 장점으로 느껴졌고, 데이터에 자유도가 큰 만큼 MongoDB를 사용할 때 로직에서는 유효성검사를 더욱 철저히 해야겠다는 생각이 들었다. 또한 오늘 처음으로 멤버 경험발표를 들을 수 있어서 감사하다.

 

Reference

- https://www.youtube.com/watch?v=Q_9cFgzZr8Q

- https://www.youtube.com/watch?v=y42TXZKFfqQ

- https://aws.amazon.com/ko/what-is/database-sharding/