K8S MySQL Operator 설치
apt install mariadb-client -y
mysql -h $MYSQLIP -uroot -psakila -e "SELECT @@hostname;SELECT @@max_connections;"
# service.yaml
---
apiVersion: v1
kind: Service
metadata:
labels:
application: kube-ops-view
component: frontend
name: kube-ops-view
spec:
selector:
application: kube-ops-view
component: frontend
type: NodePort
ports:
- port: 80
protocol: TCP
targetPort: 8080
# deployment.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
application: kube-ops-view
component: frontend
name: kube-ops-view
spec:
replicas: 1
selector:
matchLabels:
application: kube-ops-view
component: frontend
template:
metadata:
labels:
application: kube-ops-view
component: frontend
spec:
nodeSelector:
kubernetes.io/hostname: k8s-m
tolerations:
- effect: NoSchedule
key: node-role.kubernetes.io/master
operator: Exists
serviceAccountName: kube-ops-view
containers:
- name: service
# see https://github.com/hjacobs/kube-ops-view/releases
image: hjacobs/kube-ops-view:20.4.0
args:
# remove this option to use built-in memory store
- --redis-url=redis://kube-ops-view-redis:6379
# example to add external links for nodes and pods
# - --node-link-url-template=https://kube-web-view.example.org/clusters/{cluster}/nodes/{name}
# - --pod-link-url-template=https://kube-web-view.example.org/clusters/{cluster}/namespaces/{namespace}/pods/{name}
ports:
- containerPort: 8080
protocol: TCP
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
timeoutSeconds: 1
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 30
timeoutSeconds: 10
failureThreshold: 5
resources:
limits:
cpu: 200m
memory: 100Mi
requests:
cpu: 50m
memory: 50Mi
securityContext:
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 1000
설치
helm repo add mysql-operator https://mysql.github.io/mysql-operator/
helm install mysql-operator mysql-operator/mysql-operator --namespace mysql-operator --create-namespace
kubectl describe crd innodbclusters.mysql.oracle.com && kubectl get crd | grep -v calico
helm install mycluster mysql-operator/mysql-innodbcluster --set credentials.root.password='sakila' --set tls.useSelfSigned=true --namespace mysql-cluster --create-namespace
kubectl get configmap -n mysql-cluster mycluster-initconf -o yaml
kubectl describe cm -n mysql-cluster mycluster-initconf
# 접속 주소 변수 지정
MIC=mycluster.mysql-cluster.svc.cluster.local
MDB1=mycluster-0.mycluster-instances.mysql-cluster.svc.cluster.local
MDB2=mycluster-1.mycluster-instances.mysql-cluster.svc.cluster.local
MDB3=mycluster-2.mycluster-instances.mysql-cluster.svc.cluster.local
MYSQLIP=$(kubectl get svc -n mysql-cluster mycluster -o jsonpath={.spec.clusterIP})
접속
apt install mariadb-client -y
mysql -h $MYSQLIP -uroot -psakila -e "SELECT @@hostname;SELECT @@max_connections;"
MySQL 라우터를 통한 MySQL 파드 접속
kubectl exec -it -n mysql-operator deploy/mysql-operator -- mysqlsh mysqlx://root@mycluster.mysql-cluster.svc.cluster.local --password=sakila --sqlx --execute='show databases;'
샘플 데이터베이스 git clone 및 데이터 삽입
# 샘플 데이터베이스 git clone 및 IMPORT : 1분 10초 정도 소요
git clone https://github.com/datacharmer/test_db && cd test_db/
mysql -h $MYSQLIP -uroot -psakila -t < employees.sql && cd
mysql -h $MYSQLIP -uroot -psakila -e "SELECT * FROM employees.employees;"
mysql -h $MYSQLIP -uroot -psakila -e "SELECT * FROM employees.employees LIMIT 10;"
mysql router 설정 확인 및 메타데이터 캐시 정보 확인
# mysqlrouter 설정 확인
kubectl exec -it -n mysql-cluster deploy/mycluster-router -- cat /tmp/mysqlrouter/mysqlrouter.conf
# mysqlrouterd 에 메타데이터 캐시 정보 확인
kubectl exec -it -n mysql-cluster deploy/mycluster-router -- cat /tmp/mysqlrouter/data/state.json
클라이언트 파드를 통해 부하분산 확인
PODNAME=myclient1 envsubst < ~/DOIK/2/myclient.yaml | kubectl apply -f -
${PODNAME} 을 치환해준다.
추가로 2대 배포 / myclient[1,2,3]
for ((i=2; i<=3; i++)); do PODNAME=myclient$i envsubst < ~/DOIK/2/myclient.yaml | kubectl apply -f - ; done
# 클라이언트 파드
---
apiVersion: v1
kind: Pod
metadata:
name: ${PODNAME}
labels:
app: myclient
spec:
nodeName: k8s-m
containers:
- name: ${PODNAME}
image: mysql:8.0.29
command: ["tail"]
args: ["-f", "/dev/null"]
terminationGracePeriodSeconds: 0
파드들에서 mysql 라우터 서비스로 접속 확인
- 부하분산 되지 않음
for ((i=1; i<=3; i++)); do kubectl exec -it myclient$i -- mysql -h mycluster.mysql-cluster -uroot -psakila -e "SELECT @@HOSTNAME;USE employees;SELECT * FROM employees LIMIT $i;";echo; done
클라이언트 파드 myclient1에서 mysql 라우터 서비스로 접속 확인 : TCP 6446
- 부하분산 되지 않음
kubectl exec -it myclient1 -- mysql -h mycluster.mysql-cluster -uroot -psakila --port=6446 -e "SELECT @@HOSTNAME,@@SERVER_ID;"
클라이언트 파드 myclient1에서 mysql 라우터 서비스로 접속 확인 : TCP 6447
- secondary만 부하분산 됨
kubectl exec -it myclient1 -- mysql -h mycluster.mysql-cluster -uroot -psakila --port=6447 -e "SELECT @@HOSTNAME,@@SERVER_ID;"
for ((i=1; i<=3; i++)); do kubectl exec -it myclient$i -- mysql -h mycluster.mysql-cluster -uroot -psakila --port=6447 -e "SELECT @@HOSTNAME,host from information_schema.processlist WHERE ID=connection_id();";echo; done
설명
- Mysql 라우터 정책이 first-available 이라서 무조건 primary 첫번째로 전달
- 6447 port는 round-robin-with-fallback 정책에 의해서 2대에 라운드 로빈(부하분산) 접속 됨
데이터베이스에 Insert 및 MySQL 서버에 복제 확인
# 모니터링
watch -n 1 -d "kubectl exec -it myclient1 -- mysql -h mycluster-0.mycluster-instances.mysql-cluster.svc -uroot -psakila -e 'SELECT * FROM test.t1 ORDER BY c1 DESC LIMIT 5;'"
watch -n 1 -d "kubectl exec -it myclient2 -- mysql -h mycluster-1.mycluster-instances.mysql-cluster.svc -uroot -psakila -e 'SELECT * FROM test.t1 ORDER BY c1 DESC LIMIT 5;'"
watch -n 1 -d "kubectl exec -it myclient3 -- mysql -h mycluster-2.mycluster-instances.mysql-cluster.svc -uroot -psakila -e 'SELECT * FROM test.t1 ORDER BY c1 DESC LIMIT 5;'"
# 마스터노드 자체에서 test 데이터베이스에 97개의 데이터 INSERT
for ((i=3; i<=100; i++)); do mysql -h $MYSQLIP -uroot -psakila -e "SELECT @@HOSTNAME;INSERT INTO test.t1 VALUES ($i, 'Luis$i');";echo; done
mysql -h $MYSQLIP -uroot -psakila -e "SELECT * FROM test.t1;"
# 마스터노드 자체에서 test 데이터베이스에 원하는 갯수 만큼 데이터 INSERT, CTRL+C 로 취소
for ((i=101; i<=1000; i++)); do mysql -h $MYSQLIP -uroot -psakila -e "INSERT INTO test.t1 VALUES ($i, 'Luis$i');";echo; done
작업 전
작업 후
워드프레스 설치
# MySQL 에 wordpress 데이터베이스 생성
mysql -h $MYSQLIP -uroot -psakila -e "create database wordpress;"
# wordpress 설치 : MySQL 접속 주소(mycluster.mysql-cluster.svc), MySQL 데이터베이스 이름 지정(wordpress) , 장애 테스트를 위해서 2대의 파드 배포(2분~4분 정도 소요)
helm repo add bitnami https://charts.bitnami.com/bitnami
helm install my-wordpress \
--set replicaCount=2 \
--set wordpressUsername=admin \
--set wordpressPassword=password \
--set wordpressBlogName="DOIK Study" \
--set service.type=NodePort \
--set mariadb.enabled=false \
--set persistence.storageClass="nfs-client" \
--set persistence.accessMode=ReadWriteMany \
--set externalDatabase.host=mycluster.mysql-cluster.svc \
--set externalDatabase.user=root \
--set externalDatabase.password=sakila \
--set externalDatabase.database=wordpress \
bitnami/wordpress --version 14.3.1
helm get values my-wordpress
NFS 마운트 확인
duf -hide local,special
sshpass -p Pa55W0rd ssh -o StrictHostKeyChecking=no root@k8s-w1 duf -hide local,special
sshpass -p Pa55W0rd ssh -o StrictHostKeyChecking=no root@k8s-w2 duf -hide local,special
sshpass -p Pa55W0rd ssh -o StrictHostKeyChecking=no root@k8s-w3 duf -hide local,special
Wordpress 웹 접속
[장애1] MySQL 서버 파드(인스턴스) 1대 강제 삭제 및 동작 확인
- 데이터 4천개를 입력하는 동안 파드 삭제
# 데이터 4000개 입력
# 마스터노드 자체에서 test 데이터베이스에 원하는 갯수 만큼 데이터 INSERT, CTRL+C 로 취소, 대략 1분정도 기간내에 입력 완료됨
for ((i=1001; i<=5000; i++)); do mysql -h $MYSQLIP -uroot -psakila -e "SELECT NOW();INSERT INTO test.t1 VALUES ($i, 'Luis$i');";echo; done
# 파드 삭제 kubectl delete pod -n mysql-cluster <현재 프라이머리 MySQL 서버파드 이름> && kubectl get pod -n mysql-cluster -w
kubectl delete pod -n mysql-cluster mycluster-0 && kubectl get pod -n mysql-cluster -w
Primary pod 삭제
- 1초 미만으로 단절 발생
- secondary pod 삭제시 단절 발생하지 않음
# 반복 조회
while true; do mysql -h $MYSQLIP -uroot -psakila -e "SELECT MEMBER_HOST, MEMBER_ROLE FROM performance_schema.replication_group_members;"; date; sleep 1; done
+-----------------------------------------------------------------+-------------+
| MEMBER_HOST | MEMBER_ROLE |
+-----------------------------------------------------------------+-------------+
| mycluster-1.mycluster-instances.mysql-cluster.svc.cluster.local | SECONDARY |
| mycluster-0.mycluster-instances.mysql-cluster.svc.cluster.local | PRIMARY |
| mycluster-2.mycluster-instances.mysql-cluster.svc.cluster.local | SECONDARY |
+-----------------------------------------------------------------+-------------+
# MySQL 서버 파드(인스턴스) 1대 강제 삭제
kubectl delete pod -n mysql-cluster mycluster-0
# 반복 조회 : 프라이머리 멤버가 mycluster-1 로 변경됨
+-----------------------------------------------------------------+-------------+
| MEMBER_HOST | MEMBER_ROLE |
+-----------------------------------------------------------------+-------------+
| mycluster-1.mycluster-instances.mysql-cluster.svc.cluster.local | PRIMARY |
| mycluster-2.mycluster-instances.mysql-cluster.svc.cluster.local | SECONDARY |
+-----------------------------------------------------------------+-------------+
# 스테이트풀셋이므로 자동으로 MySQL 서버 파드 생성 시작!
kubectl get pod -n mysql-cluster -l app.kubernetes.io/component=database
NAME READY STATUS RESTARTS AGE
mycluster-0 2/2 Running 0 118s
mycluster-1 2/2 Running 0 150m
mycluster-2 2/2 Running 0 150m
+-----------------------------------------------------------------+-------------+
| MEMBER_HOST | MEMBER_ROLE |
+-----------------------------------------------------------------+-------------+
| mycluster-1.mycluster-instances.mysql-cluster.svc.cluster.local | PRIMARY |
| mycluster-0.mycluster-instances.mysql-cluster.svc.cluster.local | SECONDARY |
| mycluster-2.mycluster-instances.mysql-cluster.svc.cluster.local | SECONDARY |
+-----------------------------------------------------------------+-------------+
# Group Replication 이 관리하는 멤버 목록과 상태 정보(View ID) 확인 : 값 변경 확인!
mysql -h $MYSQLIP -uroot -psakila -e "SELECT VIEW_ID FROM performance_schema.replication_group_member_stats LIMIT 1;"
+---------------------+
| VIEW_ID |
+---------------------+
| 16524381853527486:5 |
+---------------------+
[장애2] MySQL 서버 파드(인스턴스) 가 배포된 노드 1대 drain 설정 및 동작 확인
# CoreDNS 미리 늘려놓기
kubectl scale deployment -n kube-system coredns --replicas=4
# 모니터링
watch -d 'kubectl get pod -o wide -n mysql-cluster;echo;kubectl get pod -o wide'
while true; do mysql -h $MYSQLIP -uroot -psakila -e 'SELECT VIEW_ID FROM performance_schema.replication_group_member_stats LIMIT 1;SELECT MEMBER_HOST, MEMBER_ROLE FROM performance_schema.replication_group_members;'; date;sleep 1; done
while true; do mysql -h $MYSQLIP -uroot -psakila --port=6447 -e 'select @@hostname;'; date;sleep 1; done
while true; do mysql -h $MYSQLIP -uroot -psakila --port=6447 -e 'SELECT * FROM test.t1 ORDER BY c1 DESC LIMIT 5'; date;sleep 1; done
# 마스터노드 자체에서 test 데이터베이스에 원하는 갯수 만큼 데이터 INSERT, CTRL+C 로 취소, 대략 1분정도 기간내에 입력 완료됨
for ((i=5001; i<=10000; i++)); do mysql -h $MYSQLIP -uroot -psakila -e "SELECT NOW();USE test;INSERT INTO t1 VALUES ($i, 'Luis$i');";echo; done
# EC2 노드 1대 drain(중지) 설정 : 세컨더리 노드 먼저 테스트 =>> 이후 프라이머리 노드 테스트 해보자! 결과 비교!
kubectl get pdb -n mysql-cluster # 왜 오퍼레이터는 PDB 를 자동으로 설정했을까요?
# kubectl drain <<노드>> --ignore-daemonsets --delete-emptydir-data
kubectl drain k8s-w2 --ignore-daemonsets --delete-emptydir-data
- 1대가 쫓겨나도 데이터 입력에는 이상이 없다.
추가로 1대 더 drain 테스트
kubectl drain k8s-w3 --ignore-daemonsets --delete-emptydir-data
... (아래 에러 메시지 반복 출력)
err or when evicting pods/"mycluster-1" -n "mysql-cluster" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.
evicting pod mysql-cluster/mycluster-1
error when evicting pods/"mycluster-1" -n "mysql-cluster" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.
evicting pod mysql-cluster/mycluster-1
...
PDB 정책에 의해서 mysql-cluster 가 쫓겨나지 않음
- 비정상 mysql 파드는 1개 이상이 될 수 없도록 설정 되어 있다.
# 현재 PDB 정책에 mysql 서버파드는 최대 1개까지만 UNAVAILABLE 비정상 상태로 될 수 있음
# 참고로 PDB 정책에 'MIN AVAILABLE' 과 'MAX AVAILABLE' 는 동시에 두 곳에 설정을 지정할 수 없음
kubectl get pdb -n mysql-cluster
NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE
mycluster-pdb N/A 1 0 49m
만약 PDB 정책을 삭제하게 된다면?
- 다시 시도 시 쫓겨나서 남은 MySQL 서버 파드가 1대만 존재한다...
kubectl delete pdb -n mysql-cluster mycluster-pdb
'스터디 > DOIK' 카테고리의 다른 글
Percona Operator for MongoDB - 옵션 변경 (0) | 2022.06.24 |
---|---|
Percona Operator for MongoDB - DOIK 스터디 4주차 (0) | 2022.06.22 |
기본 Object - Pod (0) | 2022.06.05 |
K8S Operator 패턴 - DOIK 스터디 2주차 (0) | 2022.06.01 |