このラボでは、PersistentVolume(PV)とPersistentVolumeClaim(PVC)でデータを永続化し、StatefulSetでステートフルなアプリケーションを管理する方法を学びます。
まず利用可能なStorageClassを確認します。
# StorageClass一覧
kubectl get storageclasses
# デフォルトのStorageClassを確認
kubectl describe storageclass microk8s-hostpath
PVCを使ってストレージを要求します。
cat << 'EOF' > my-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
accessModes:
- ReadWriteOnce
storageClassName: microk8s-hostpath
resources:
requests:
storage: 1Gi
EOF
kubectl apply -f my-pvc.yaml
# PVCの状態を確認(STATUS が Bound になればOK)
kubectl get pvc
cat << 'EOF' > pvc-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: pvc-writer
spec:
containers:
- name: writer
image: nginx
volumeMounts:
- name: data
mountPath: /usr/share/nginx/html
volumes:
- name: data
persistentVolumeClaim:
claimName: my-pvc
EOF
kubectl apply -f pvc-pod.yaml
kubectl wait --for=condition=Ready pod/pvc-writer --timeout=60s
# Pod内にファイルを作成
kubectl exec pvc-writer -- sh -c 'echo "Hello from PV!" > /usr/share/nginx/html/index.html'
# ファイルの内容を確認
kubectl exec pvc-writer -- cat /usr/share/nginx/html/index.html
# Podを削除
kubectl delete pod pvc-writer
# 同じPVCを使う新しいPodを作成
kubectl apply -f pvc-pod.yaml
kubectl wait --for=condition=Ready pod/pvc-writer --timeout=60s
# データが残っていることを確認!
kubectl exec pvc-writer -- cat /usr/share/nginx/html/index.html
kubectl delete pod pvc-writer
kubectl delete pvc my-pvc
StatefulSetは各Podに固定の名前と専用のPVCを割り当てます。データベースなどステートフルなアプリケーションに使われます。
cat << 'EOF' > mysql-statefulset.yaml
apiVersion: v1
kind: Service
metadata:
name: mysql-headless
spec:
clusterIP: None
selector:
app: mysql
ports:
- port: 3306
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
serviceName: mysql-headless
replicas: 1
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:5.7
env:
- name: MYSQL_ROOT_PASSWORD
value: "rootpass"
- name: MYSQL_DATABASE
value: "testdb"
ports:
- containerPort: 3306
volumeMounts:
- name: mysql-data
mountPath: /var/lib/mysql
volumeClaimTemplates:
- metadata:
name: mysql-data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: microk8s-hostpath
resources:
requests:
storage: 2Gi
EOF
kubectl apply -f mysql-statefulset.yaml
# StatefulSetの状態確認
kubectl get statefulsets
# Pod名が連番であることを確認
kubectl get pods -l app=mysql
# 専用のPVCが作成されていることを確認
kubectl get pvc
# Pod起動を待つ
kubectl wait --for=condition=Ready pod/mysql-0 --timeout=120s
# MySQLに接続してデータを作成
kubectl exec -it mysql-0 -- mysql -uroot -prootpass -e "
USE testdb;
CREATE TABLE messages (id INT AUTO_INCREMENT PRIMARY KEY, text VARCHAR(255));
INSERT INTO messages (text) VALUES ('Hello from StatefulSet!');
SELECT * FROM messages;
"
# Podを削除(StatefulSetが自動で再作成する)
kubectl delete pod mysql-0
# 再起動を待つ
kubectl wait --for=condition=Ready pod/mysql-0 --timeout=120s
# データが残っていることを確認
kubectl exec -it mysql-0 -- mysql -uroot -prootpass -e "USE testdb; SELECT * FROM messages;"
# レプリカ数を2に増やす
kubectl scale statefulset mysql --replicas=2
# Podが順番に起動することを確認(mysql-1が追加される)
kubectl get pods -l app=mysql -w
# 各Podに個別のPVCが割り当てられている
kubectl get pvc
# StatefulSet削除
kubectl delete -f mysql-statefulset.yaml
# PVCは手動で削除(データごと削除される)
kubectl delete pvc mysql-data-mysql-0
kubectl delete pvc mysql-data-mysql-1
# すべてクリーンになったことを確認
kubectl get all
kubectl get pvc
# 1-2. PVCとPodの永続化確認
cat << 'EOF' | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: web-pvc
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: microk8s-hostpath
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: Pod
metadata:
name: web-writer
spec:
containers:
- name: nginx
image: nginx
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
volumes:
- name: html
persistentVolumeClaim:
claimName: web-pvc
EOF
kubectl wait --for=condition=Ready pod/web-writer --timeout=60s
kubectl exec web-writer -- sh -c 'echo "My persistent page" > /usr/share/nginx/html/index.html'
kubectl delete pod web-writer
# 再作成して確認
kubectl apply -f - << 'EOF'
apiVersion: v1
kind: Pod
metadata:
name: web-writer
spec:
containers:
- name: nginx
image: nginx
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
volumes:
- name: html
persistentVolumeClaim:
claimName: web-pvc
EOF
kubectl wait --for=condition=Ready pod/web-writer --timeout=60s
kubectl exec web-writer -- cat /usr/share/nginx/html/index.html
# 3. StatefulSet
cat << 'EOF' | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
name: web-headless
spec:
clusterIP: None
selector:
app: web-sts
ports:
- port: 80
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
serviceName: web-headless
replicas: 3
selector:
matchLabels:
app: web-sts
template:
metadata:
labels:
app: web-sts
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
EOF
kubectl get pods -l app=web-sts
# 4. クリーンアップ
kubectl delete statefulset web
kubectl delete service web-headless
kubectl delete pod web-writer
kubectl delete pvc web-pvc