รัน MySQL-MariaDB Cluster บน Kubernetes ด้วย StatefulSet
การเรียกใช้ MySQL-MariaDB Cluster บน Kubernetes โดยใช้ StatefulSet เป็นวิธีที่มีประสิทธิภาพในการจัดการฐานข้อมูลขนาดใหญ่ที่ต้องการความพร้อมใช้งานสูง (High Availability) และการ Replication ที่เสถียร StatefulSet ให้คุณสามารถจัดการ database replication, persistent storage, และ stable network identity สำหรับแต่ละ Pod ได้อย่างสมบูรณ์
ทำไมต้องใช้ MySQL-MariaDB บน Kubernetes
- Replication Support: StatefulSet จัดการ Master-Slave Replication และ Galera Cluster ได้อย่างมีประสิทธิภาพ
- Persistent Storage: PersistentVolume เก็บข้อมูลฐานข้อมูลแบบถาวร ไม่สูญหายเมื่อ Pod ถูกลบ
- Network Stability: StatefulSet ให้ stable hostname สำหรับแต่ละ Pod ทำให้การเชื่อมต่อระหว่าง Pod เสถียรขึ้น
- Ordered Deployment: Pods ถูกสร้างและลบตามลำดับ 0, 1, 2, …, n ป้องกัน data inconsistency
- Scalability: ง่ายต่อการเพิ่มหรือลดจำนวน Replicas ตามความต้องการ
1. Master-Slave Replication
เป็นรูปแบบที่ใช้มากที่สุด โดย Master Pod รับการเขียนข้อมูล (write) และ Slave Pods รับการอ่านข้อมูล (read) โดยการทำ replicate จาก Master ทำให้สามารถแยกโหลดการอ่านและการเขียนได้
2. Galera Cluster
Galera Cluster เป็นรูปแบบ Multi-Master Replication ที่ให้ทุก Node สามารถรับการเขียนข้อมูลได้ด้วยกัน มีการ synchronous replication ทำให้ข้อมูลสอดคล้องกันตลอดเวลา
ขั้นตอนที่ 1: สร้าง Namespace
kubectl create namespace mysql-cluster
kubectl config set-context --current --namespace=mysql-cluster
ขั้นตอนที่ 2: สร้าง Secret สำหรับ MySQL Passwords
สร้าง Kubernetes Secret เพื่อเก็บรหัสผ่าน MySQL อย่างปลอดภัยแทนการเขียน hard-coded ลงในไฟล์ YAML:
kubectl create secret generic mysql-secret \
--from-literal=MYSQL_ROOT_PASSWORD=secure-root-password \
--from-literal=MYSQL_REPLICATION_USER=repl \
--from-literal=MYSQL_REPLICATION_PASSWORD=repl-password \
-n mysql-cluster
ขั้นตอนที่ 3: สร้าง MySQL ConfigMap
สร้าง ConfigMap ที่เก็บไฟล์การตั้งค่า MySQL (my.cnf) สำหรับ replication:
cat > mysql-config.yaml << 'EOF'
apiVersion: v1
kind: ConfigMap
metadata:
name: mysql-config
namespace: mysql-cluster
data:
my.cnf: |
[mysqld]
log-bin=mysql-bin
binlog-format=ROW
server-id=0
relay-log=relay-bin
relay-log-index=relay-bin.index
master-info-repository=TABLE
relay-log-info-repository=TABLE
skip-slave-start
read-only=off
EOF
kubectl apply -f mysql-config.yaml
ขั้นตอนที่ 4: สร้าง MySQL StatefulSet
สร้าง StatefulSet สำหรับจัดการ MySQL Pods โดยมี Persistent Storage และ Health Checks:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
namespace: mysql-cluster
spec:
serviceName: mysql
replicas: 3
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0-debian
ports:
- containerPort: 3306
name: mysql
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: MYSQL_ROOT_PASSWORD
- name: MYSQL_REPLICATION_USER
valueFrom:
secretKeyRef:
name: mysql-secret
key: MYSQL_REPLICATION_USER
- name: MYSQL_REPLICATION_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: MYSQL_REPLICATION_PASSWORD
volumeMounts:
- name: mysql-data
mountPath: /var/lib/mysql
- name: mysql-config
mountPath: /etc/mysql/conf.d
livenessProbe:
exec:
command:
- /bin/sh
- -c
- "mysqladmin ping -h127.0.0.1 -uroot -p${MYSQL_ROOT_PASSWORD}"
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
exec:
command:
- /bin/sh
- -c
- "mysql -h127.0.0.1 -uroot -p${MYSQL_ROOT_PASSWORD} -e 'SELECT 1'"
initialDelaySeconds: 5
periodSeconds: 5
volumes:
- name: mysql-config
configMap:
name: mysql-config
volumeClaimTemplates:
- metadata:
name: mysql-data
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 30Gi
ขั้นตอนที่ 5: สร้าง MySQL Service
สร้าง Kubernetes Service สองแบบ: Headless Service สำหรับ StatefulSet และ ClusterIP Service สำหรับการเชื่อมต่อแบบ load-balanced:
apiVersion: v1
kind: Service
metadata:
name: mysql
namespace: mysql-cluster
spec:
clusterIP: None
selector:
app: mysql
ports:
- port: 3306
targetPort: 3306
---
apiVersion: v1
kind: Service
metadata:
name: mysql-read
namespace: mysql-cluster
spec:
type: ClusterIP
selector:
app: mysql
ports:
- port: 3306
targetPort: 3306
ขั้นตอนที่ 6: ตั้งค่า Replication
สร้าง Job เพื่อตั้งค่า Replication จากอปลายน์ Master (mysql-0) ไปยัง Slave Pods:
apiVersion: batch/v1
kind: Job
metadata:
name: mysql-replication-init
namespace: mysql-cluster
spec:
template:
spec:
containers:
- name: mysql-init
image: mysql:8.0-debian
command: ["/bin/bash"]
args:
- -c
- |
for i in {1..2}; do
mysql -h mysql-$i.mysql -u root -p${MYSQL_ROOT_PASSWORD} -e \
"CHANGE MASTER TO MASTER_HOST='mysql-0.mysql', \
MASTER_USER='repl', MASTER_PASSWORD='${MYSQL_REPLICATION_PASSWORD}', \
MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=154; \
START SLAVE;"
done
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: MYSQL_ROOT_PASSWORD
- name: MYSQL_REPLICATION_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: MYSQL_REPLICATION_PASSWORD
restartPolicy: Never
การตรวจสอบ Cluster Status
# ตรวจสอบสถานะของ Pods
kubectl get pods -n mysql-cluster
# เข้าไป Master Pod และดูสถานะ Master
kubectl exec -it mysql-0 -n mysql-cluster -- \
mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e "SHOW MASTER STATUS\G"
# ตรวจสอบสถานะ Slave Replication
kubectl exec -it mysql-1 -n mysql-cluster -- \
mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e "SHOW SLAVE STATUS\G"
# ดูรายชื่อกระบวนการที่กำลังทำงาน
kubectl exec -it mysql-0 -n mysql-cluster -- \
mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e "SELECT * FROM information_schema.processlist\G"
Full Backup จาก Master Pod
kubectl exec -it mysql-0 -n mysql-cluster -- \
mysqldump -uroot -p${MYSQL_ROOT_PASSWORD} \
--all-databases --single-transaction > mysql-full-backup.sql
Incremental Backup โดยใช้ Binary Logs
kubectl exec -it mysql-0 -n mysql-cluster -- \
mysqlbinlog mysql-bin.000001 > binlog-000001.sql
การขยายขนาด (Scaling) MySQL Cluster
เพื่อเพิ่ม Replicas สำหรับการรับน้ำหนักการอ่าน (read load) หรือสำหรับความพร้อมใช้งานที่สูงขึ้น:
# เพิ่มจาก 3 เป็น 5 replicas
kubectl patch statefulset mysql -n mysql-cluster -p '{"spec":{"replicas":5}}'
Best Practices สำหรับ MySQL on Kubernetes
- ใช้ Kubernetes Secret เพื่อเก็บ Passwords แทนการ hard-code ในไฟล์ YAML
- เลือก PersistentVolume storage class ที่เหมาะกับ infrastructure ของคุณ (SSD, NAS, Cloud Storage)
- ตั้งค่า Liveness Probe และ Readiness Probe เพื่อตรวจสอบสุขภาพ Cluster
- จัดการ Backup strategy อย่างเหมาะสมและทดสอบ Recovery process เป็นประจำ
- ใช้ Binary Logs สำหรับ Incremental Backup และ Point-in-time Recovery
- ตั้งค่า Monitoring และ Alerting สำหรับ Replication lag และการลบต่าง ๆ
- ปิด skip-slave-start เพื่อให้ Slave Replication เริ่มต้นใหม่โดยอัตโนมัติหลังจาก Pod restart
- ใช้ row-based binary logging (binlog-format=ROW) สำหรับความปลอดภัยของ Replication
บทสรุป
การ Deploy MySQL-MariaDB Cluster บน Kubernetes ด้วย StatefulSet ต้องการความเข้าใจลึก ๆ เกี่ยวกับ Kubernetes primitives และ database replication concepts StatefulSet ให้ข้อมูลเหล่านี้: stable network identity, ordered deployment, persistent storage, ทำให้เป็นตัวเลือกที่ดีสำหรับ database workloads ด้วยการตั้งค่าที่ถูกต้องและ monitoring ที่เพียงพอ คุณสามารถสร้าง MySQL Cluster ที่มีความพร้อมใช้งานสูงและ scalable ได้
