728x90
반응형
1. PostgreSQL이란?
- Global Development Group 에서 개발한 오픈소스 RDBMS
2. CloudNativePG(CNPG)란?
- CloudNativePG 는 EDB가 개발 후, Apache License 2.0 공개 및 ‘22.4 CNCF Sandbox 제출함, 오퍼레이터 Level V - Auto Pilot 지원 - 링크
- ‘23.10.29 CNPG 버전 : 1.21.x - 쿠버네티스 지원 버전(1.25 ~ 1.28), PostgreSQL 지원 버전(12 ~ 16) - 링크
2-1) 구조와 아키텍쳐
- 보통 복제 전략에는 스토리지 수준 복제 또는 애플리케이션 수준 복제가 존재
- PostgreSQL는 스토리지 수준 복제를 권장하지 않음 : https://youtu.be/99uSJXkKpeI?si=4Shn7hdxmCt4IDnO
- PostgreSQL 는 비동기 혹은 동기 스트리밍 복제를 지원, 복제서버는 Hot Standby 기능으로 읽기 처리가 가능
- CloudNativePG 는 비동기 혹은 동기 스트리밍 복제 구성의 클러스터를 지원
- 하나의 Primary 노드와, 다수의 standby replicas로 동작
- postgresql DB인스턴스는 3가지 역할이 존재
- rw: 쓰기를 위한 primary DB인스턴스 접근
- r: 읽기를 위한 아무 DB인스턴스 접근
- ro: 읽기를 위한 standby DB인스턴스 접근
- Read-Write workloads : -RW 요청을 프라이머리로 전달

- Read-Only : -RO 요청을 Standby 로 Round robin 방식으로 전달 , 참고로 -R 요청은 any 전달

- Multi-cluster deployments : 2개의 다른 쿠버네티스 클러스터에서, Replica Cluster 에 Designated Primary 는 Primary 클러스터의 Primary 의 복제

3. CloudNativePG(CNPG) 배포 테스트
- Operator Lifecycle Manager(OLM) 설치
- OLM은 k8s cluster 상에서 운영중인 Operator 운영의 Lifecycle을 자동으로 관리해주어 좀더 편하게 운영관리가 가능
curl -sL <https://github.com/operator-framework/operator-lifecycle-manager/releases/download/v0.25.0/install.sh> | bash -s v0.25.0
$ kubectl get all -n olm
NAME READY STATUS RESTARTS AGE
pod/catalog-operator-6db85b79dd-5p7z5 1/1 Running 0 93s
pod/olm-operator-b59c56b74-k7h8j 1/1 Running 0 93s
pod/operatorhubio-catalog-62t9f 1/1 Running 0 85s
pod/packageserver-655db5dc4c-7k2gd 1/1 Running 0 84s
pod/packageserver-655db5dc4c-zjr8w 1/1 Running 0 84s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/operatorhubio-catalog ClusterIP 172.20.192.106 <none> 50051/TCP 85s
service/packageserver-service ClusterIP 172.20.189.58 <none> 5443/TCP 84s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/catalog-operator 1/1 1 1 93s
deployment.apps/olm-operator 1/1 1 1 93s
deployment.apps/packageserver 2/2 2 2 84s
NAME DESIRED CURRENT READY AGE
replicaset.apps/catalog-operator-6db85b79dd 1 1 1 93s
replicaset.apps/olm-operator-b59c56b74 1 1 1 93s
replicaset.apps/packageserver-655db5dc4c 2 2 2 84s
- CloudNativePG Operator 설치
curl -s -O https://operatorhub.io/install/cloudnative-pg.yaml
cat cloudnative-pg.yaml | yh
kubectl create -f cloudnative-pg.yaml
- operator 네임스페이스 확인 및 CRD확인
$ kubectl get all -n operators
NAME READY STATUS RESTARTS AGE
pod/cnpg-controller-manager-55c4c6d8f6-p55qj 1/1 Running 0 24s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/cnpg-controller-manager-service ClusterIP 172.20.211.123 <none> 443/TCP 25s
service/cnpg-webhook-service ClusterIP 172.20.141.196 <none> 443/TCP 28s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/cnpg-controller-manager 1/1 1 1 25s
NAME DESIRED CURRENT READY AGE
replicaset.apps/cnpg-controller-manager-55c4c6d8f6 1 1 1 26s
$ kubectl get-all -n operators | grep -v packagemanifest
NAME NAMESPACE AGE
configmap/cnpg-default-monitoring operators 51s
configmap/kube-root-ca.crt operators 4m53s
endpoints/cnpg-controller-manager-service operators 48s
endpoints/cnpg-webhook-service operators 51s
pod/cnpg-controller-manager-55c4c6d8f6-p55qj operators 47s
secret/cnpg-controller-manager-service-cert operators 48s
serviceaccount/cnpg-manager operators 49s
serviceaccount/default operators 4m53s
service/cnpg-controller-manager-service operators 48s
service/cnpg-webhook-service operators 51s
deployment.apps/cnpg-controller-manager operators 48s
replicaset.apps/cnpg-controller-manager-55c4c6d8f6 operators 48s
lease.coordination.k8s.io/db9c8771.cnpg.io operators 33s
endpointslice.discovery.k8s.io/cnpg-controller-manager-service-c6vq5 operators 48s
endpointslice.discovery.k8s.io/cnpg-webhook-service-tgzgm operators 51s
clusterserviceversion.operators.coreos.com/cloudnative-pg.v1.21.1 operators 51s
installplan.operators.coreos.com/install-cnnls operators 52s
operatorcondition.operators.coreos.com/cloudnative-pg.v1.21.1 operators 51s
operatorgroup.operators.coreos.com/global-operators operators 4m53s
subscription.operators.coreos.com/my-cloudnative-pg operators 70s
rolebinding.rbac.authorization.k8s.io/cloudnative-pg.v1.21.1 operators 51s
rolebinding.rbac.authorization.k8s.io/cnpg-controller-manager-service-cert operators 48s
role.rbac.authorization.k8s.io/cloudnative-pg.v1.21.1 operators 51s
role.rbac.authorization.k8s.io/cnpg-controller-manager-service-cert operators 48s
$ kubectl get crd | grep cnpg
backups.postgresql.cnpg.io 2023-11-04T12:27:59Z
clusters.postgresql.cnpg.io 2023-11-04T12:28:00Z
poolers.postgresql.cnpg.io 2023-11-04T12:28:00Z
scheduledbackups.postgresql.cnpg.io 2023-11-04T12:27:59Z
- PostgreSQL Cluster 설치
- Cluster란 CR을 생성하면 Operator가 이를 Watch 한 뒤 그에 맞는 리소스를 생성 가능
$ cat <<EOT> mycluster1.yaml
# Example of PostgreSQL cluster
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: mycluster
spec:
imageName: ghcr.io/cloudnative-pg/postgresql:15.3
instances: 3
storage:
size: 3Gi
postgresql:
parameters:
max_worker_processes: "40"
timezone: "Asia/Seoul"
pg_hba:
- host all postgres all trust
primaryUpdateStrategy: unsupervised
enableSuperuserAccess: true
bootstrap:
initdb:
database: app
encoding: UTF8
localeCType: C
localeCollate: C
owner: app
monitoring:
enablePodMonitor: true
EOT
$ kubectl apply -f mycluster1.yaml
- PostgreSQL Cluster 설치 확인
- 해당 설치 과정은 1번 파드에서 Initializing(초기화)를 담당하는 Job이 뜬 뒤 종료되고 mycluster-1 파드가 생성되며, 이후 mycluster-2-join 이란 Job Pod가 생성되어 Join 작업을 수행한 뒤 mycluster-2 파드가 생성되는 식으로 진행
$ kubectl get pod,pvc,pv,svc
NAME READY STATUS RESTARTS AGE
pod/mycluster-1 2/2 Running 0 4m28s
pod/mycluster-2 2/2 Running 0 2m20s
pod/mycluster-3 2/2 Running 0 1m32s
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/mycluster-1 Bound pvc-c9382d6f-sdf9-832d-129f-23cfa34f09c3 2Gi RWO gp3 4m40s
persistentvolumeclaim/mycluster-2 Bound pvc-4924a34b-9cb0-8d0s-b102-a7fae4b97287 2Gi RWO gp3 2m52s
persistentvolumeclaim/mycluster-3 Bound pvc-734a0a91-0a27-01cc-befa-b74eb1cc2c19 2Gi RWO gp3 1m55s
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/pvc-c9382d6f-sdf9-832d-129f-23cfa34f09c3 3Gi RWO Delete Bound default/mycluster-1 gp3 4m30s
persistentvolume/pvc-4924a34b-9cb0-8d0s-b102-a7fae4b97287 3Gi RWO Delete Bound default/mycluster-2 gp3 2m43s
persistentvolume/pvc-734a0a91-0a27-01cc-befa-b74eb1cc2c19 3Gi RWO Delete Bound default/mycluster-3 gp3 1m30s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 172.20.0.1 <none> 443/TCP 26m
service/mycluster-r ClusterIP 172.20.37.238 <none> 5432/TCP 4m43s
service/mycluster-ro ClusterIP 172.20.160.200 <none> 5432/TCP 4m40s
service/mycluster-rw ClusterIP 172.20.93.78 <none> 5432/TCP 4m40s
3. 접속 테스트
3-1) secret 을 통해 Username, password 확인
$ kubectl get secret -l cnpg.io/cluster=mycluster
NAME TYPE DATA AGE
mycluster-app kubernetes.io/basic-auth 3 35m
mycluster-superuser kubernetes.io/basic-auth 3 35m
# superuser 계정명 확인
kubectl get secrets mycluster-superuser -o jsonpath={.data.username} | base64 -d ;echo
postgres
# superuser 계정 암호 확인
kubectl get secrets mycluster-superuser -o jsonpath={.data.password} | base64 -d ;echo
3-2) Client Pod 배포
# myclient 파드 3대 배포 : envsubst 활용
## PODNAME=myclient1 VERSION=15.3.0 envsubst < myclient.yaml | kubectl apply -f -
curl -s https://raw.githubusercontent.com/gasida/DOIK/main/5/myclient-new.yaml -o myclient.yaml
for ((i=1; i<=3; i++)); do PODNAME=myclient$i VERSION=15.3.0 envsubst < myclient.yaml | kubectl apply -f - ; done
3-3) superuser 계정으로 mycluster-rw 서비스 접속 및 DB 확인
$ kubectl exec -it myclient1 -- psql -U postgres -h mycluster-rw -p 5432 --variable=HISTFILE=/tmp/.psql_history
# 연결 정보 확인
$ postgres=# \conninfo
You are connected to database "postgres" as user "postgres" on host "mycluster-rw" (address "10.200.1.40") at port "5432".
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
# 데이터베이스 조회
$ postgres=# \l
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
-----------+----------+----------+---------+-------+-----------------------
app | app | UTF8 | C | C |
postgres | postgres | UTF8 | C | C |
template0 | postgres | UTF8 | C | C | =c/postgres +
| | | | | postgres=CTc/postgres
template1 | postgres | UTF8 | C | C | =c/postgres +
| | | | | postgres=CTc/postgres
4. 장애 테스트
4-1) 장애 테스트를 위해 test DB에 데이터 Insert
for ((i=3; i<=100; i++)); do kubectl exec -it myclient1 -- psql -U postgres -h mycluster-rw -p 5432 -d test -c "INSERT INTO t1 VALUES ($i, 'Luis$i');";echo; done
kubectl exec -it myclient1 -- psql -U postgres -h mycluster-ro -p 5432 -d test -c "SELECT COUNT(*) FROM t1"
4-2) 프라이머리 파드(인스턴스) 1대 강제 삭제 및 동작 확인
# 프라이머리 파드 정보 확인
kubectl cnpg status mycluster
# [터미널1] 모니터링
watch kubectl get pod -l cnpg.io/cluster=mycluster
# [터미널2] 모니터링
while true; do kubectl exec -it myclient2 -- psql -U postgres -h mycluster-ro -p 5432 -d test -c "SELECT COUNT(*) FROM t1"; date;sleep 1; done
# [터미널3] test 데이터베이스에 다량의 데이터 INSERT
for ((i=301; i<=10000; i++)); do kubectl exec -it myclient2 -- psql -U postgres -h mycluster-rw -p 5432 -d test -c "INSERT INTO t1 VALUES ($i, 'Luis$i');";echo; done
for ((i=10001; i<=20000; i++)); do kubectl exec -it myclient2 -- psql -U postgres -h mycluster-rw -p 5432 -d test -c "INSERT INTO t1 VALUES ($i, 'Luis$i');";echo; done
혹은
for ((i=301; i<=10000; i++)); do psql -U postgres -h psql.$MyDomain -p 5432 -d test -c "INSERT INTO t1 VALUES ($i, 'Luis$i');";echo; done
for ((i=10001; i<=20000; i++)); do psql -U postgres -h psql.$MyDomain -p 5432 -d test -c "INSERT INTO t1 VALUES ($i, 'Luis$i');";echo; done
# [터미널4] 파드 삭제 >> INSERT 가 중간에 끊어지나요?
kubectl get pod -l cnpg.io/cluster=mycluster -owide
kubectl delete pvc/mycluster-1 pod/mycluster-1
kubectl cnpg status mycluster
# 파드 정보 확인 : 파드의 이름과 배치 위치 비교 확인
kubectl get pod -l cnpg.io/cluster=mycluster -owide
kubectl get pod -l cnpg.io/cluster=mycluster
NAME READY STATUS RESTARTS AGE
mycluster-2 1/1 Running 0 125m
mycluster-3 1/1 Running 0 125m
mycluster-4 1/1 Running 0 2m18s
4-3) 프라이머리 파드(인스턴스) 가 배포된 노드 1대 drain 설정 및 동작 확인
# (옵션) 오퍼레이터 로그 확인
kubectl get pod -n operators -l app.kubernetes.io/name=cloudnative-pg
kubectl logs -n operators -l app.kubernetes.io/name=cloudnative-pg -f
# 워커노드 drain
# kubectl drain <<노드>> --ignore-daemonsets --delete-emptydir-data
kubectl get node
NODE=<각자 자신의 EC2 노드 이름 지정>
NODE=ip-192-168-3-231.ap-northeast-2.compute.internal
kubectl drain k8s-w1 --delete-emptydir-data --force --ignore-daemonsets && kubectl get node -w
혹은
kubectl drain $NODE --delete-emptydir-data --force --ignore-daemonsets && kubectl get node -w
# 클러스터 정보 확인 : 파드가 Pending 된 주 원인은 무엇일까요? >> 예를 들어 동일AZ에 정상 워커노드가 있었다면 어떻게 될까요?
kubectl get pod -owide
kubectl cnpg status mycluster
# 동작 확인 후 uncordon 설정
kubectl uncordon $NODE
ps) 4-2, 4-3 장애 테스트는 실컷 테스트 한후.. 해당 내용을 복사(캡쳐)하지않고 EKS 클러스터를 삭제하여.. 추후 업로드 예정....ㅠㅠ
728x90
반응형
'K8S Operator' 카테고리의 다른 글
[K8S Operator] Vault Secrets Operator(VSO) (1) | 2023.11.26 |
---|---|
[K8S Operator] Kafka & Strimzi Operator (1) | 2023.11.18 |
[K8S Operator] Percona Operator for MongoDB (1) | 2023.11.12 |
[K8S Operator] Operator& MySQL Operator (1) | 2023.10.29 |