[Udemy] AKS Storage - Azure Disks
AKS Storage
Persistent Volume (PV)
- 클러스터 내에서 사용할 수 있는 스토리지
Persistent Volume Claim (PVC)
- 정의: PVC는 사용자가 필요한 스토리지의 요구 사항을 정의하는 객체입니다. 사용자는 PVC를 통해 필요한 스토리지의 크기와 접근 모드를 요청합니다.
- 용도: PVC는 SC를 통해 프로비저닝된 PV(Persistent Volume)를 요청하는 데 사용됩니다. 사용자는 PVC를 통해 스토리지를 요청하고, Kubernetes는 이를 충족하는 PV를 찾아 연결합니다.
- 특징
사용자가 직접 스토리지의 세부 사항을 지정할 수 있습니다.
PVC는 특정 SC에 의해 생성된 PV와 연결됩니다
Storage Class (SC)
- 정의: Storage Class는 Kubernetes에서 스토리지의 유형과 특성을 정의하는 객체입니다. 사용자가 요청한 스토리지의 속성을 설정할 수 있습니다.
- 용도: 다양한 스토리지 제공자에 대한 설정을 포함하여, 동적 프로비저닝을 가능하게 합니다. 예를 들어, 특정 스토리지 유형(SSD, HDD 등)을 지정할 수 있습니다.
- 특징
스토리지의 성능, 접근 모드, 재사용 정책 등을 정의합니다.
여러 스토리지 제공자와의 통합을 지원합니다.
차이점
- SC는 스토리지의 유형과 특성을 정의하는 반면, PVC는 사용자가 요청하는 스토리지의 요구 사항을 정의합니다.
- SC는 스토리지의 프로비저닝을 관리하고, PVC는 사용자가 필요한 스토리지를 요청하는 방법입니다.
사용 예시
1. PV 생성: 클러스터 관리자가 PV를 정의하여 스토리지를 프로비저닝합니다.
2. PVC 생성: 사용자가 PVC를 생성하여 필요한 스토리지를 요청합니다.
3. 바인딩: Kubernetes는 PVC의 요구 사항을 충족하는 PV를 찾아 바인딩합니다.
4. Pod에서 사용: 바인딩된 PVC를 Pod에서 사용하여 데이터를 저장하거나 읽을 수 있습니다.
Storage Class(SC) 생성
# Storage Class 확인
kubectl get sc
---
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
azurefile file.csi.azure.com Delete Immediate true 44h
azurefile-csi file.csi.azure.com Delete Immediate true 44h
azurefile-csi-premium file.csi.azure.com Delete Immediate true 44h
azurefile-premium file.csi.azure.com Delete Immediate true 44h
default (default) disk.csi.azure.com Delete WaitForFirstConsumer true 44h
managed disk.csi.azure.com Delete WaitForFirstConsumer true 44h
managed-csi disk.csi.azure.com Delete WaitForFirstConsumer true 44h
managed-csi-premium disk.csi.azure.com Delete WaitForFirstConsumer true 44h
managed-premium disk.csi.azure.com Delete WaitForFirstConsumer true 44h
이는 AKS 클러스터 생성 시, 자동으로 생성된 storage class이다.
# Storage-class.yml 파일 작성
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: managed-premium-retain-sc
provisioner: kubernetes.io/azure-disk
reclaimPolicy: Retain # Default is Delete, recommended is retain
volumeBindingMode: WaitForFirstConsumer # Default is Immediate, recommended is WaitForFirstConsumer
allowVolumeExpansion: true
parameters:
storageaccounttype: Premium_LRS # or we can use Standard_LRS
kind: managed # Default is shared (Other two are managed and dedicated)
# Storage Class 생성
kubectl apply -f 01-storage-class.yml
---
storageclass.storage.k8s.io/managed-premium-retain-sc created
# 확인
kubectl get sc
---
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
azurefile file.csi.azure.com Delete Immediate true 44h
azurefile-csi file.csi.azure.com Delete Immediate true 44h
azurefile-csi-premium file.csi.azure.com Delete Immediate true 44h
azurefile-premium file.csi.azure.com Delete Immediate true 44h
default (default) disk.csi.azure.com Delete WaitForFirstConsumer true 44h
managed disk.csi.azure.com Delete WaitForFirstConsumer true 44h
managed-csi disk.csi.azure.com Delete WaitForFirstConsumer true 44h
managed-csi-premium disk.csi.azure.com Delete WaitForFirstConsumer true 44h
managed-premium disk.csi.azure.com Delete WaitForFirstConsumer true 44h
managed-premium-retain-sc kubernetes.io/azure-disk Retain WaitForFirstConsumer true 3m19s
PVC(Persistent Volume Claim) 생성
# Persistent-volume-claim.yml 파일 작성
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: azure-managed-disk-pvc
spec:
accessModes:
- ReadWriteOnce
storageClassName: managed-premium-retain-sc
resources:
requests:
storage: 5Gi
# PVC 생성
kubectl apply -f 02-persistent-volume-claim.yml
# 확인
kubectl get pvc
---
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
azure-managed-disk-pvc Pending managed-premium-retain-sc <unset> 54s
현재 managed-premium-retain-sc가 WaitforFirstConsumer 상태이므로
azure-managed-disk-pvc도 pending 상태
ConfigMap 생성
ConfigMap
- 미리 ConfigMap에 구성정보를 정의해놓았다가, 컨테이너마다 해당 구성정보가 필요할 경우 사용
# UserManagement-ConfigMap.yml 파일 작성
apiVersion: v1
kind: ConfigMap
metadata:
name: usermanagement-dbcreation-script
data:
mysql_usermgmt.sql: |-
DROP DATABASE IF EXISTS webappdb;
CREATE DATABASE webappdb;
사용자 관리 DB 스크립트에 관한 ConfigMap이다.
# ConfigMap 생성
kubectl apply -f 03-UserManagement-ConfigMap.yml
Deployment 생성
# mysql-deployment.yml 생성
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql
spec:
replicas: 1
selector:
matchLabels:
app: mysql
strategy:
type: Recreate
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:5.6
env:
- name: MYSQL_ROOT_PASSWORD
value: dbpassword11
ports:
- containerPort: 3306
name: mysql
volumeMounts:
- name: mysql-persistent-storage
mountPath: /var/lib/mysql
- name: usermanagement-dbcreation-script
mountPath: /docker-entrypoint-initdb.d #https://hub.docker.com/_/mysql Refer Initializing a fresh instance
volumes:
- name: mysql-persistent-storage
persistentVolumeClaim:
claimName: azure-managed-disk-pvc
- name: usermanagement-dbcreation-script
configMap:
name: usermanagement-dbcreation-script
Mysql:5.6 이미지의 Mysql 컨테이너를 생성한다.
해당 컨테이너에는 mysql-persistent-storage와 usermanagement-dbcreation-script라는 Volume이 Mount 된다.
# Deployment 생성
kubectl apply -f 04-mysql-deployment.yml
ClusterIP 생성
# mysql-clusterip-service.yml 파일 생성
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
selector:
app: mysql
ports:
- port: 3306
clusterIP: None # This means we are going to use Pod IP
# ClusterIP 생성
kubectl apply -f 05-mysql-clusterip-service.yml
중간 확인
# pvc 확인
kubectl get pvc
---
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
azure-managed-disk-pvc Bound pvc-92e8ebe7-6a51-47a6-b469-2b761d61e123 5Gi RWO managed-premium-retain-sc <unset> 175m
pvc가 pending에서 bound 상태가 되었다.
현재 pod가 생성되었고, 그에 따라 volume이 mount 되었기 때문이다.
# pv 확인
kubectl get pv
---
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM
STORAGECLASS VOLUMEATTRIBUTESCLASS REASON AGE
pvc-92e8ebe7-6a51-47a6-b469-2b761d61e123 5Gi RWO Retain Bound default/azure-managed-disk-pvc managed-premium-retain-sc <unset> 8m54s
pv도 정상적으로 생성되었다.
해당 pv는 Azure Portal 내 Disk에서도 조회 가능하다. (하기 후술)
# pod 확인
kubectl get pods
---
NAME READY STATUS RESTARTS AGE
mysql-6868c58fbd-h9tk7 1/1 Running 0 4m3s
kubectl describe pod mysql-6868c58fbd-h9tk7
---
Name: mysql-6868c58fbd-h9tk7
Namespace: default
Priority: 0
Service Account: default
Node: aks-agentpool-29221675-vmss000004/10.224.0.199
Start Time: Fri, 14 Feb 2025 13:39:02 +0900
Labels: app=mysql
pod-template-hash=6868c58fbd
Annotations: <none>
Status: Running
IP: 10.224.0.20
IPs:
IP: 10.224.0.20
Controlled By: ReplicaSet/mysql-6868c58fbd
Containers:
mysql:
Container ID: containerd://aa0cd771c1fda8b5b1849778026c50a060366bbe15bd5dfb0b44d42c94267c5f
Image: mysql:5.6
Image ID: docker.io/library/mysql@sha256:20575ecebe6216036d25dab5903808211f1e9ba63dc7825ac20cb975e34cfcae
Port: 3306/TCP
Host Port: 0/TCP
State: Running
Started: Fri, 14 Feb 2025 13:39:28 +0900
Ready: True
Restart Count: 0
Environment:
MYSQL_ROOT_PASSWORD: dbpassword11
Mounts:
/docker-entrypoint-initdb.d from usermanagement-dbcreation-script (rw)
/var/lib/mysql from mysql-persistent-storage (rw)
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-8clwd (ro)
Conditions:
Type Status
PodReadyToStartContainers True
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
mysql-persistent-storage:
Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
ClaimName: azure-managed-disk-pvc
ReadOnly: false
usermanagement-dbcreation-script:
Type: ConfigMap (a volume populated by a ConfigMap)
Name: usermanagement-dbcreation-script
Optional: false
kube-api-access-8clwd:
Type: Projected (a volume that contains injected data from multiple sources)
TokenExpirationSeconds: 3607
ConfigMapName: kube-root-ca.crt
ConfigMapOptional: <nil>
DownwardAPI: true
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 4m18s default-scheduler Successfully assigned default/mysql-6868c58fbd-h9tk7 to aks-agentpool-29221675-vmss000004
Normal SuccessfulAttachVolume 4m6s attachdetach-controller AttachVolume.Attach succeeded for volume "pvc-92e8ebe7-6a51-47a6-b469-2b761d61e123"
Normal Pulling 4m3s kubelet Pulling image "mysql:5.6"
Normal Pulled 3m52s kubelet Successfully pulled image "mysql:5.6" in 11.373s (11.374s including waiting). Image size: 102984033 bytes.
Normal Created 3m52s kubelet Created container mysql
Normal Started 3m52s kubelet Started container mysql
mysql 컨테이너가 생성되었고,
mysql-persistent-storage와 usermanagement-dbcreation-script 두 개의 Volume이 Mount 되었다.
# Portal 내 Disk 확인
Portal에서도 Disk가 정상적으로 조회되는 것을 확인 가능하다.
MySQL Database에 연결
# MySQL DB에 연결
# Connect to MYSQL Database
kubectl run mysql-client --image=mysql:5.6 -it --rm --restart=Never -- mysql -h [MySQL 서버 호스트] -p[비밀번호]
kubectl run -it --rm --image=mysql:5.6 --restart=Never mysql-client -- mysql -h mysql -pdbpassword11
이 명령어는 MySQL 클라이언트를 실행하여 지정된 MySQL 서버에 연결할 수 있도록 합니다.
삭제
# 삭제
kubectl delete -f kube-manifests/
---
storageclass.storage.k8s.io "managed-premium-retain-sc" deleted
persistentvolumeclaim "azure-managed-disk-pvc" deleted
configmap "usermanagement-dbcreation-script" deleted
deployment.apps "mysql" deleted
service "mysql" deleted
# pvc 및 pv 확인
kubectl get pvc
---
No resources found in default namespace.
pvc는 삭제되었다.
kubectl get pv
---
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS VOLUMEATTRIBUTESCLASS REASON AGE
pvc-92e8ebe7-6a51-47a6-b469-2b761d61e123 5Gi RWO Retain Released default/azure-managed-disk-pvc managed-premium-retain-sc <unset> 23m
pv는 그대로 남아있다.
Portal > Disk에서도 그대로 남아있는 것을 확인 가능하다.
즉, PV 및 Disk는 그대로 사용가능하다.
# pv 삭제
kubectl delete pv pvc-92e8ebe7-6a51-47a6-b469-2b761d61e123
---
persistentvolume "pvc-92e8ebe7-6a51-47a6-b469-2b761d61e123" delete
pv는 이렇게 수동으로 지워줘야 삭제된다.
kubectl get pv
---
No resources found
그러나 Portal 내 Disk는 여전히 존재한다.
실수로 Pod를 삭제해도 Disk는 그대로 남아있고 상태만 Unattached가 될 뿐이다.
이게 PV(Persistent Volume)의 장점이다.
원하면 다시 붙여써도 되고, 필요 없으면 삭제하자
[참고 영상]
Udemy - Azure Kubernetes Service with Azure DevOps and Terraform
섹션 6 : AKS Storage - Azure Disks
44. Step-01: Azure Disks for AKS Storage Introduction
45. Step-02: Create Storage class Kubernetes Manifest
46. Step-03: Create Persistent Volume Claim Manifest, Deploy SC, PVC and Test
47. Step-04: Create ConfigMap Kubernetes Manifest
48. Step-05: Create MySQL Kubernetes Deployment Manifest
49. Step-06: Create MySQL Kubernetes Cluster IP Service, Deploy, Test and CleanUp
[참고 문서]