๐ฌ Day 12 - MySQL InnoDB Cluster ๊ตฌ์ถ ๊ฐ์ด๋ (Operator ๋ฐฉ์)
MySQL Operator for Kubernetes๋ฅผ ์ฌ์ฉํ ์๋ํ๋ InnoDB Cluster ๊ตฌ์ถ
๋ชฉ์ฐจโ
- ๐ ๊ฐ์
- ๐๏ธ ์ํคํ ์ฒ
- ๐ ๊ตฌ์ถ ๊ฐ์ด๋
- โ ๊ฒ์ฆ
- ๐ง ํธ๋ฌ๋ธ์ํ
- ๐ ํ์ผ ๊ตฌ์กฐ
- ๐ ์ฐธ๊ณ ์๋ฃ
๐ ๊ฐ์โ
MySQL Operator for Kubernetes๋ฅผ ์ฌ์ฉํ์ฌ InnoDB Cluster๋ฅผ ์๋์ผ๋ก ๊ตฌ์ถํฉ๋๋ค.
์ Operator์ธ๊ฐ?โ
| ๊ตฌ๋ถ | StatefulSet (์๋) | MySQL Operator (์๋) |
|---|---|---|
| ํด๋ฌ์คํฐ ์์ฑ | MySQL Shell ์๋ | โ ์๋ |
| Failover | ์๋ ๋ณต๊ตฌ | โ ์๋ |
| MySQL Router | ๋ณ๋ ๋ฐฐํฌ | โ ์๋ ํฌํจ |
| ๋ฐฑ์ /๋ณต์ | ์คํฌ๋ฆฝํธ ์์ฑ | โ CRD ์ ๊ณต |
| ์ค์ผ์ผ๋ง | ์๋ | โ replicas ๋ณ๊ฒฝ๋ง |
์์ธ ๋น๊ต: ๊ธฐ์กด Docker MySQL + NFS vs InnoDB Cluster + Operatorโ
| ๊ตฌ๋ถ | ๊ธฐ์กด Docker MySQL + NFS | InnoDB Cluster + Operator |
|---|---|---|
| MySQL ์คํ ๋ฐฉ์ | ๋จ์ผ/์๋ Replication | ํด๋ฌ์คํฐ ๊ธฐ๋ฐ |
| Primary ์ ์ | ์ฌ๋์ด ์ง์ ์ง์ | ์๋ ์ ์ถ (์ฟผ๋ผ) |
| ์ฅ์ ๋์ | ์๋ | ์๋ Failover |
| ์ ํ๋ฆฌ์ผ์ด์ ์ฐ๊ฒฐ | Primary ์ง์ ์ฐ๊ฒฐ | MySQL Router ๋จ์ผ ์๋ํฌ์ธํธ |
| Primary ์ฅ์ ์ | ์๋น์ค ์ค๋จ | ๋ฌด์ค๋จ ๋๋ ์ต์ ์ค๋จ |
| ๋ฐ์ดํฐ ๋ณต์ | binlog ๋น๋๊ธฐ | Group Replication (๋๊ธฐ/ํฉ์) |
| Split-brain ๋ฐฉ์ง | ์์ | ์์ |
| ์คํ ๋ฆฌ์ง | NFS (๊ณต์ , SPOF) | Block Storage (๊ฐ๋ณ PV) |
| Kubernetes ์นํ์ฑ | ๋ฎ์ | ๋งค์ฐ ๋์ |
| ์ด์ ๋์ด๋ | ๋ฎ์ ๋ณด์ด๋ ์ํ | ์ด๊ธฐ ๋์, ์ด์ ์์ |
| ํ๋ก๋์ ์ ํฉ์ฑ | โ | โ |
๐๏ธ ์ํคํ ์ฒโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Kubernetes Cluster โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ MySQL Operator (Controller) โ โ
โ โ ์๋: ํด๋ฌ์คํฐ ์์ฑ, Failover, Router ๊ด๋ฆฌ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ โ
โ โผ โ
โ โโโโโโโโโโโโโโโโโโโโ ๊ฐ์/๊ด๋ฆฌ โ
โ โ MySQL Router โ โ ์ฝ๊ธฐ/์ฐ๊ธฐ ๋ผ์ฐํ
โ
โ โ (2 replicas) โ :6446 (R/W), :6447 (R/O) โ
โ โโโโโโโโโโฌโโโโโโโโโโ โ
โ โ โ
โ โโโโโโโโโโดโโโโโโโโโฌโโโโโโโโโโโโโโโโโ โ
โ โผ โผ โผ โ
โ โโโโโโโโ โโโโโโโโ โโโโโโโโ โ
โ โmysql โ โmysql โ โmysql โ โ
โ โ -0 โ โโโโโ โ -1 โ โโโโโโ โ -2 โ Group Replication โ
โ โ(R/W) โ โ(R/O) โ โ(R/O) โ โ
โ โโโโโโโโ โโโโโโโโ โโโโโโโโ โ
โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Persistent Volumes (๊ฐ ๋
ธ๋๋ณ) โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
ํฌํธ ๊ตฌ์ฑโ
| ํฌํธ | ์ฉ๋ |
|---|---|
| 3306 | MySQL ํด๋ผ์ด์ธํธ (์ง์ ์ฐ๊ฒฐ) |
| 6446 | MySQL Router (R/W) |
| 6447 | MySQL Router (R/O) |
| 6448 | MySQL Router (R/W X Protocol) |
| 6449 | MySQL Router (R/O X Protocol) |
| 33061 | Group Replication ํต์ |
๐ ๊ตฌ์ถ ๊ฐ์ด๋โ
Step 0: ๊ธฐ์กด MySQL ๋ฆฌ์์ค ์ญ์ (๋ง์ด๊ทธ๋ ์ด์ ์)โ
โ ๏ธ ์ฃผ์: ๊ธฐ์กด Master-Slave ๊ตฌ์ฑ์์ ๋ง์ด๊ทธ๋ ์ด์ ํ๋ ๊ฒฝ์ฐ์๋ง ์ํ
# ๊ธฐ์กด ๋ฆฌ์์ค ์ญ์
kubectl delete statefulset mysql-slave -n gition
kubectl delete svc mysql-read mysql-master -n gition
kubectl delete configmap mysql-slave-config -n gition
kubectl delete pvc -l app=mysql -n gition
Step 1: MySQL Operator ์ค์นโ
Helm ์ฌ์ฉ (๊ถ์ฅ)โ
# Helm ์ ์ฅ์ ์ถ๊ฐ
helm repo add mysql-operator https://mysql.github.io/mysql-operator/
helm repo update
# Operator ์ค์น
helm install mysql-operator mysql-operator/mysql-operator \
--namespace mysql-operator \
--create-namespace
์ค์น ํ์ธโ
kubectl get pods -n mysql-operator
# NAME READY STATUS RESTARTS AGE
# mysql-operator-xxxxxxxxxx-xxxxx 1/1 Running 0 1m
Step 2: Secret ์์ฑโ
# Namespace ์์ฑ
# ์์ ๊ฒฝ์ฐ
kubectl create namespace gition
# Secret ์์ฑ (โ ๏ธ ๋น๋ฐ๋ฒํธ ๋ณ๊ฒฝ!)
kubectl create secret generic mysql-cluster-secret -n gition \
--from-literal=rootUser=root \
--from-literal=rootHost=% \
--from-literal=rootPassword='<STRONG_PASSWORD>'
๋๋ YAML ํ์ผ ์ฌ์ฉ:
kubectl apply -f k8s/mysql-cluster/02-mysql-secret.yaml
Step 3: Local PV ์์ฑโ
๊ฐ K8s Worker ๋ ธ๋์์ ๋๋ ํ ๋ฆฌ ์์ฑ (k8s-m์์ ์คํ):
for node in k8s-n1 k8s-n2 k8s-n3; do
ssh $node "sudo mkdir -p /mnt/mysql-data && sudo chmod 777 /mnt/mysql-data"
done
StorageClass ๋ฐ PV ์์ฑ:
kubectl apply -f k8s/mysql-cluster/03-local-storage.yaml
PV ์ํ ํ์ธ:
kubectl get pv -l app=mysql-cluster
# NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS VOLUMEATTRIBUTESCLASS REASON AGE
# mysql-pv-0 5Gi RWO Retain Available local-storage <unset> 3m34s
# mysql-pv-1 5Gi RWO Retain Available local-storage <unset> 3m34s
# mysql-pv-2 5Gi RWO Retain Available local-storage <unset> 3m34s
---
### Step 4: InnoDB Cluster ์์ฑ
```bash
kubectl apply -f k8s/mysql-cluster/04-innodb-cluster.yaml
ํด๋ฌ์คํฐ ์ํ ํ์ธโ
## InnoDBCluster ๋ฆฌ์์ค ํ์ธ
kubectl get innodbcluster -n gition
## Pod ์ํ ํ์ธ (3๊ฐ MySQL + 2๊ฐ Router)
kubectl get pods -n gition -l mysql.oracle.com/cluster=mysql-cluster
## NAME READY STATUS RESTARTS AGE
## mysql-cluster-0 2/2 Running 0 3m
## mysql-cluster-1 2/2 Running 0 3m
## mysql-cluster-2 0/2 Init:0/3 0 3m
## ์์ธ ์ํ
kubectl describe innodbcluster mysql-cluster -n gition
โณ ํด๋ฌ์คํฐ๊ฐ ์์ ํ ์ค๋น๋๋ ๋ฐ ์ฝ 5-10๋ถ ์์
Step 5: DB ์คํค๋ง ์ด๊ธฐํโ
ํด๋ฌ์คํฐ๊ฐ ONLINE ์ํ๊ฐ ๋๋ฉด:
kubectl apply -f k8s/mysql-cluster/05-app-user.yaml
Job ์ํ ํ์ธ:
kubectl get jobs -n gition
kubectl logs job/mysql-init-schema -n gition
Step 6: ์๋ ๋ฐฑ์ ์ค์ (์ ํ)โ
NFS์ ๋งค์ผ 02:00 mysqldump ๋ฐฑ์ :
kubectl apply -f k8s/mysql-cluster/06-mysql-backup.yaml
CronJob ํ์ธ:
kubectl get cronjob -n gition
## NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
## mysql-backup 0 17 * * * False 0 <none> 1m
Step 7: Backend ๋ฐฐํฌโ
โ ๏ธ ์ฃผ์: ๊ธฐ์กด
fastapi-deployment.yaml์ญ์ ํ์
## ๊ธฐ์กด ๋ฐฐํฌ ์ญ์
kubectl delete -f k8s/fastapi-deployment.yaml -n gition 2>/dev/null || true
## ์ Backend ๋ฐฐํฌ (MySQL Cluster ์ฐ๋)
kubectl apply -f k8s/mysql-cluster/07-backend-deployment.yaml
Backend ์ํ ํ์ธ:
kubectl get pods -n gition -l app=api
kubectl logs -n gition -l app=api --tail=20
Step 8: ์ ํ๋ฆฌ์ผ์ด์ ์ฐ๊ฒฐ ์ค์ โ
์ฐ๊ฒฐ ์ ๋ณดโ
| ์ฉ๋ | ํธ์คํธ | ํฌํธ |
|---|---|---|
| R/W (์ฐ๊ธฐ) | mysql-cluster | 6446 |
| R/O (์ฝ๊ธฐ) | mysql-cluster | 6447 |
FastAPI ํ๊ฒฝ๋ณ์ ์์โ
env:
- name: MYSQL_WRITE_HOST
value: "mysql-cluster"
- name: MYSQL_WRITE_PORT
value: "6446"
- name: MYSQL_READ_HOST
value: "mysql-cluster"
- name: MYSQL_READ_PORT
value: "6447"
โ ๊ฒ์ฆโ
ํด๋ฌ์คํฐ ์ํ ํ์ธโ
## InnoDBCluster ์ํ
kubectl get innodbcluster -n gition -o wide
## ์ถ๋ ฅ ์์:
## NAME STATUS ONLINE INSTANCES ROUTERS AGE
## mysql-cluster ONLINE 3 3 2 10m
Primary ๋ ธ๋ ํ์ธโ
## Router๋ฅผ ํตํด Primary ํ์ธ (6446 = R/W = Primary)
kubectl exec -it mysql-cluster-0 -n gition -c mysql -- \
mysql -h mysql-cluster -P 6446 -uroot -p -e "SELECT @@hostname"
## ๋ชจ๋ ๋ฉค๋ฒ ์ญํ ํ์ธ
kubectl exec -it mysql-cluster-0 -n gition -c mysql -- \
mysql -uroot -p -e "SELECT member_host, member_role FROM performance_schema.replication_group_members"
## ์ถ๋ ฅ ์์:
## +-----------------------------------------------+-------------+
## | member_host | member_role |
## +-----------------------------------------------+-------------+
## | mysql-cluster-0.mysql-cluster.gition.svc... | PRIMARY |
## | mysql-cluster-1.mysql-cluster.gition.svc... | SECONDARY |
## | mysql-cluster-2.mysql-cluster.gition.svc... | SECONDARY |
## +-----------------------------------------------+-------------+
MySQL ์ฐ๊ฒฐ ํ ์คํธโ
## R/W ์ฐ๊ฒฐ (Primary)
kubectl exec -it mysql-cluster-0 -n gition -c mysql -- \
mysql -h mysql-cluster -P 6446 -uroot -p -e "SELECT @@hostname, @@read_only"
## R/O ์ฐ๊ฒฐ (Secondary)
kubectl exec -it mysql-cluster-0 -n gition -c mysql -- \
mysql -h mysql-cluster -P 6447 -uroot -p -e "SELECT @@hostname, @@read_only"
์๋ Failover ํ ์คํธโ
1. ํ์ฌ Primary ํ์ธโ
ํ์ฌ ์ด๋ค ๋ ธ๋๊ฐ Primary์ธ์ง ํ์ธํฉ๋๋ค.
kubectl exec -it mysql-cluster-0 -n gition -c mysql -- \
mysql -uroot -p -e "SELECT member_host, member_role FROM performance_schema.replication_group_members"
2. Primary Pod ์ญ์ โ
Primary ๋ ธ๋๋ฅผ ๊ฐ์ ์ญ์ ํ์ฌ ์ฅ์ ์ํฉ์ ์๋ฎฌ๋ ์ด์ ํฉ๋๋ค.
## Primary๊ฐ mysql-cluster-2์ด๋ผ๊ณ ๊ฐ์
kubectl delete pod mysql-cluster-2 -n gition
3. Failover ๋ชจ๋ํฐ๋ง (์ฝ 30์ด~1๋ถ)โ
MySQL Operator๊ฐ ์๋์ผ๋ก ์ Primary๋ฅผ ์ ์ถํ๋ ๊ณผ์ ์ ์ค์๊ฐ์ผ๋ก ํ์ธํฉ๋๋ค.
## Pod ์ํ ์ค์๊ฐ ํ์ธ
kubectl get pods -n gition -l mysql.oracle.com/cluster=mysql-cluster -w
## ํด๋ฌ์คํฐ ์ํ ํ์ธ
kubectl get innodbcluster -n gition
4. ์ Primary ํ์ธโ
Failover ์๋ฃ ํ ์๋ก์ด Primary๊ฐ ์ ์ถ๋์๋์ง ํ์ธํฉ๋๋ค.
## mysql-cluster-1์์ ํ์ธ (0์ด ์ฌ์์ ์ค์ด๋ฏ๋ก)
kubectl exec -it mysql-cluster-1 -n gition -c mysql -- \
mysql -uroot -p -e "SELECT member_host, member_role FROM performance_schema.replication_group_members"
์์ ๊ฒฐ๊ณผโ
Before:
mysql-cluster-0 โ PRIMARY
mysql-cluster-1 โ SECONDARY
mysql-cluster-2 โ SECONDARY
After (mysql-cluster-0 ์ญ์ ํ):
mysql-cluster-1 โ PRIMARY โ ์๋ ์น๊ฒฉ!
mysql-cluster-2 โ SECONDARY
mysql-cluster-0 โ (์ฌ์์ ํ) SECONDARY
โ ์๋ Failover ์ฑ๊ณต ์ ์ ํ๋ฆฌ์ผ์ด์ ์ MySQL Router๋ฅผ ํตํด ๋ฌด์ค๋จ์ผ๋ก ์ Primary์ ์ฐ๊ฒฐ๋ฉ๋๋ค.
๐ง ํธ๋ฌ๋ธ์ํ โ
Operator๊ฐ ์ค์น๋์ง ์์โ
## CRD ํ์ธ
kubectl get crd innodbclusters.mysql.oracle.com
## ์์ผ๋ฉด ์ฌ์ค์น
kubectl apply -f https://raw.githubusercontent.com/mysql/mysql-operator/trunk/deploy/deploy-crds.yaml
ํด๋ฌ์คํฐ๊ฐ PENDING ์ํโ
## ์ด๋ฒคํธ ํ์ธ
kubectl describe innodbcluster mysql-cluster -n gition
## Pod ๋ก๊ทธ ํ์ธ
kubectl logs mysql-cluster-0 -n gition -c mysql
kubectl logs mysql-cluster-0 -n gition -c sidecar
StorageClass ๋ฌธ์ โ
## StorageClass ํ์ธ
kubectl get sc
## PVC ์ํ ํ์ธ
kubectl get pvc -n gition
Router ์ฐ๊ฒฐ ์คํจโ
## Router Pod ํ์ธ
kubectl get pods -n gition -l component=router
## Router ๋ก๊ทธ
kubectl logs -l component=router -n gition
๐ ํ์ผ ๊ตฌ์กฐโ
day12-0108/
โโโ README.md # ์ด ๋ฌธ์
โโโ k8s/
โโโ mysql-cluster/
โโโ 01-mysql-operator.yaml # [Step 1] Operator ์ค์น ๊ฐ์ด๋
โโโ 02-mysql-secret.yaml # [Step 2] Secret (๋น๋ฐ๋ฒํธ)
โโโ 03-local-storage.yaml # [Step 3] Local PV StorageClass
โโโ 04-innodb-cluster.yaml # [Step 4] InnoDBCluster CR
โโโ 05-app-user.yaml # [Step 5] ์คํค๋ง ์ด๊ธฐํ Job
โโโ 06-mysql-backup.yaml # [Step 6] ์๋ ๋ฐฑ์
CronJob (NFS)
โโโ 07-backend-deployment.yaml # [Step 7] Backend API Deployment
๋ฐฐํฌ ์์โ
## 1. Operator ์ค์น (ํ ๋ฒ๋ง)
helm install mysql-operator mysql-operator/mysql-operator -n mysql-operator --create-namespace
## 2. Secret
kubectl apply -f k8s/mysql-cluster/02-mysql-secret.yaml
## 3. Local PV
kubectl apply -f k8s/mysql-cluster/03-local-storage.yaml
## 4. InnoDB Cluster
kubectl apply -f k8s/mysql-cluster/04-innodb-cluster.yaml
## 5. ์คํค๋ง ์ด๊ธฐํ (ํด๋ฌ์คํฐ ONLINE ํ)
kubectl apply -f k8s/mysql-cluster/05-app-user.yaml
## 6. ๋ฐฑ์
CronJob (์ ํ)
kubectl apply -f k8s/mysql-cluster/06-mysql-backup.yaml
## 7. Backend ๋ฐฐํฌ (๊ธฐ์กด fastapi-deployment.yaml ์ญ์ ํ์)
kubectl apply -f k8s/mysql-cluster/07-backend-deployment.yaml