Kubernetes NFS StorageClass with MySQL
Kubernetes Persistent Volume (PV)
로 NFS
Stoarge를 활용해보겠습니다.
Container
의 생명 주기에 따라 내부 데이터는 사라지게 됩니다. 내부에 저장된 데이터를 유지하려면 Volume mount를 통해 데이터를 저장하게 됩니다.
Kubernetes cluster에 생성된 Pod들의 데이터를 유지하려면 실행된 Node의 host path에 저장하거나, NFS
Server 또는 분산 Storage인 Ceph
를 활용해 저장할 수 있습니다.
아래는 hostPath를 활용해 실행되는 Node에 저장하는 방법입니다. 단 nginx-app Pod가 동일한 노드에 스케줄링 되지 않는다면 같은 데이터를 바라볼 수 없게 됩니다.
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: nginx-app
spec:
replicas: 1
selector:
matchLabels:
app: nginx-app
template:
metadata:
labels:
app: nginx-app
spec:
containers:
- name: web-server
image: nginx:latest
volumeMounts:
- name: web-content
mountPath: /usr/share/nginx/html
ports:
- containerPort: 80
volumes:
- name: web-content
hostPath: <----
type: Directory
path: /data
이러한 문제를 해결하기 위해 NFS Storage Class를 생성해보겠습니다.
Master와 각 Worker node에 NFS 서버 패키지인 nfs-common
을 설치합니다.
apt install -y nfs-common
Kubernetes Cluster의 master
node 에 helm
을 설치하여 NFS를 배포해보겠습니다.
sudo snap install helm --classic
Data volume을 설정해야 합니다. 저는 4TB의 HDD가 마운트된 경로로 지정하겠습니다.
- data volume path: /data
nfs-server-provisioner
를 설치할 Namespace는 다음과 같습니다.
- namespace: kubernetes-nfs
Namespace 생성을 먼저 진행합니다.
kubectl create ns kubernetes-nfs
nfs-server-provisioner helm 배포를 진행하겠습니다.
helm repo add stable https://charts.helm.sh/stable --force-update
helm install kubernetes-nfs stable/nfs-server-provisioner --namespace kubernetes-nfs
배포된 helm을 확인해봅니다.
helm list -n kubernetes-nfs
배포된 Statefulset, Pod, Service를 확인해봅니다.
Statefulset을 수정합니다.
- 특정 Node에 배포하려면 nodeSelector를 활용해 지정할 수 있습니다.
kubectl edit statefulset -nkubernetes-nfs kubernetes-nfs-nfs-server-provisioner
----
volumes:
- hostPath:
path: /data
type: ""
name: data
배포된 Pod를 다시 재확인해보고 정상 기동되면 /data 볼륨을 확인해봅니다.
kubectl get pods -nkubernetes-nfs
ls /data
다음은 StorageClass를 확인해보겠습니다.
kubectl get storageclass -nkubernetes-nfs
StorageClass의 mount options 수정해보겠습니다.
PV가 lock이 걸리는 문제를 해결하기 위해 다음을 수정합니다.
- nolock
- rw
kubectl edit storageclass -nkubernetes-nfs nfs
---
mountOptions:
- nolock
- rw
...
NFS StorageClass 테스트를 MySQL
DB에 사용될 PVC를 생성해보겠습니다.
vi ~/k8s-yaml/mysql/pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: db
namespace: mysql
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 50Gi
storageClassName: nfs
volumeMode: Filesystem
status:
accessModes:
- ReadWriteMany
capacity:
storage: 50Gi
phase: Bound
kubectl apply -f ~/k8s-yaml/mysql/pvc.yaml
kubectl get pv -nmysql
kubectl get pvc -nmysql
MySQL을 배포해보겠습니다.
ConfigMap
을 먼저 배포해봅니다.
kubectl create configmap configmap-mysql -nmysql --from-literal MYSQL_USER=jckim --from-literal MYSQL_ROOT_HOST=%
다음은 DB 패스워드를 위한 Secret
을 배포하겠습니다.
kubectl create secret generic secret-mysql -nmysql --from-literal MYSQL_PASSWORD=test2024! --from-literal MYSQL_ROOT_PASSWORD=test2024!
다음은 Deployment를 생성해보겠습니다.
- PVC는 위에서 생성한
db
로 진행하겠습니다.
vi ~/k8s-yaml/mysql/deployment.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql
namespace: mysql
spec:
selector:
matchLabels:
app: mysql
strategy:
type: Recreate
template:
metadata:
labels:
app: mysql
spec:
containers:
- image: mysql/mysql-server:latest
name: mysql
env:
- name: MYSQL_USER
valueFrom:
configMapKeyRef:
name: configmap-mysql
key: MYSQL_USER
- name: MYSQL_PASSWORD
valueFrom:
secretKeyRef:
name: secret-mysql
key: MYSQL_PASSWORD
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: secret-mysql
key: MYSQL_ROOT_PASSWORD
- name: MYSQL_ROOT_HOST
valueFrom:
configMapKeyRef:
name: configmap-mysql
key: MYSQL_ROOT_HOST
ports:
- containerPort: 3306
name: mysql
volumeMounts:
- name: data
mountPath: /var/lib/mysql
volumes:
- name: data
persistentVolumeClaim:
claimName: db
kubectl apply -f ~/k8s-yaml/mysql/deployment.yaml
kubectl get pod -nmysql
kubectl logs -f -nmysql [POD_NAME]
해당 데이터 볼륨을 확인해보겠습니다.
data 내에 생성된 pvc로 생성된 디렉터리 내부에 MySQL Server에서 생성된 파일들을 확인해봅니다.
MySQL 에 접근하여 데이터 베이스를 생성해보겠습니다.
kubectl get pod -nmysql
kubectl exec -it -nmysql mysql-5c5d695d65-77dxx -- /bin/bash
mysql -u root -p
password : test2024!
CREATE DATABASE test_jckim;
Pod가 강제 종료되어도 해당 data 들을 mount되어 MySQL DB가 실행되어 DB Schema, Table, Data들이 재복구됩니다.
kubectl get pod -nmysql
kubectl delete pod -nmysql mysql-5c5d695d65-77dxx
kubectl logs -f -nmysql mysql-5c5d695d65-jjvd8
다시 MySQL DB에 접속해보겠습니다.
kubectl exec -it -nmysql mysql-5c5d695d65-jjvd8 -- /bin/bash
mysql -u root -p
> show databases;
> CREATE DATABASE test;
이를 통해 NFS Storage class를 활용해 Pod가 재기동되어도 Data가 복구되었음을 확인할 수 있습니다.
감사합니다.