kubernetes/udemy

[Udemy] AKS Storage - Azure Disks

bbiyak2da 2025. 2. 14. 10:50

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

 

[참고 문서]

https://github.com/stacksimplify/azure-aks-kubernetes-masterclass/tree/master/05-Azure-Disks-for-AKS-Storage