본문 바로가기

Container/Kubernetes

[K8S] PV & PVC

  • 기본 스토리지 운영환경을 분리시켜서 사용할 수 있다.
    • 관리자: 스토리지 구성 (PV)
    • 개발자: 필요한 만큼 요구 (PVC)
  • 일반적으로 Pod가 재시작되면 데이터가 사라지는데( emptyDir 라는 일시적인 공간에 저장), PV & PVC를 사용하면 데이터를 유지할 수 있다.
  • Pod가 PVC를 마운트하여 스토리지를 사용하며, PVC가 삭제되면 PV는 설정된 정책에 따라 처리된다.

실습] /log의 데이터가 /var/log/webapp에 저장될 수 있도록 volume configure

controlplane ~ ➜  kubectl edit pod webapp
  volumeMounts:
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: kube-api-access-xhjhq
      readOnly: true
    - mountPath: /log
      name: log-volume
...
  volumes:
  - name: log-volume
    hostPath:
      path: /var/log/webapp
      
controlplane ~ ✖ kubectl replace --force -f /tmp/kubectl-edit-2279183393.yaml
pod "webapp" deleted
pod/webapp replaced

controlplane /var/log/webapp ➜  ls
app.log # Mount 된 것 확인

# PersistentVolumes (PV) 

  • PV는 클러스터 내에서 독립적으로 관리되는 스토리지 리소스이다. ( 쉽게 말해 애플리케이션이 쓰는 Disk를 모아놓은 Pool이 PV이다.)
  • Access Modes
    • RWO - ReadWriteOnce: 하나의 노드에서 읽기/쓰기 가능 (대부분의 블록 스토리지)
    • ROX - ReadOnlyMany
    • RWX - ReadWriteMany: 여러 노드에서 읽기/쓰기 가능 (NFS, CephFS 등)
    • RWOP - ReadWriteOncePod: 하나의 Pod에서만 읽기/쓰기 가능 
controlplane ➜  vi pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-log
spec:
  capacity:
    storage: 100Mi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  hostPath:
    path: /pv/log
    
controlplane  ➜ kubectl create -f pv.yaml 
persistentvolume/pv-log created

controlplane  ➜  kubectl get pv
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
pv-log   100Mi      RWX            Retain           Available                          <unset>                          6s

 

 

# 실습 : NFS 기반의 PV

[master ~/Getting-Start-Kubernetes/14]$kubectl get pv
No resources found

[master ~/Getting-Start-Kubernetes/14]$cat pv.yaml 
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv1
spec:
  capacity:
    storage: 2Gi
  volumeMode: Filesystem
  accessModes:
  - ReadWriteMany
  storageClassName: manual
  persistentVolumeReclaimPolicy: Delete
  nfs:
    server: 127.27.20.50
    path: /sharedir/k8s
    
[master ~/Getting-Start-Kubernetes/14]$kubectl get pv
No resources found
[master ~/Getting-Start-Kubernetes/14]$kubectl apply -f pv.yaml 
persistentvolume/pv1 created
[master ~/Getting-Start-Kubernetes/14]$kubectl get pv
NAME   CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
pv1    20Gi       RWX            Delete           Available           manual                  3s

# PersistentVolumesClaims

  • Pod가 PV를 직접 사용할 수 없기 때문에, PVC를 통해 스토리지를 요청하는 방식이다.
    • 즉, PersistentVolumesClaims (PVC)은 사용자의 스토리지에 대한 요청이다. 
  • 쿠버네티스는 해당 PVC에 맞는 PV를 찾아서 자동으로 연결해준다.
controlplane ~ ➜  vi pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: claim-log-1
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 50Mi
      
controlplane ~ ➜  kubectl create -f pvc.yaml 
persistentvolumeclaim/claim-log-1 created

controlplane ~ ➜  kubectl get pvc
NAME          STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
claim-log-1   Pending                                                     <unset>                 5s
#  ACCESS MODES 불일치가 되면 이렇게 Pending상태가 된다.
# PVC를 ReadWriteMany 모드로 바꿔준다.

controlplane ~ ➜  vi pvc.yaml 

controlplane ~ ➜  kubectl replace --force -f pvc.yaml 
persistentvolumeclaim "claim-log-1" deleted
persistentvolumeclaim/claim-log-1 replaced

controlplane ~ ➜  kubectl get pvc
NAME          STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
claim-log-1   Bound    pv-log   100Mi      RWX                           <unset>                 11s
# 100Mi로 바뀌었다.
  • 새롭게 만든 PVC를 Pod에 업데이트하기
    • volume으로 Claim하기
      •  Claim을 volume 으로 사용해서 파드가 스토리지에 접근
      •  Claim 은  Claim 을 사용하는 파드와 동일한 네임스페이스에 있어야 한다.
      • 클러스터는 파드의 네임스페이스에서 클레임을 찾고 이를 사용하여 클레임과 관련된 PV을 얻는다. 그런 다음 볼륨이 호스트와 파드에 마운트된다.
 controlplane ~ ➜  kubectl edit pod webapp 
  volumes:
  - persistentVolumeClaim:
      claimName: claim-log-1
    name: log-volume

https://kubernetes.io/docs/concepts/storage/persistent-volumes/#claims-as-volumes

 

 

PV 삭제 정책(persistentVolumeReclaimPolicy)

PV가 더 이상 사용되지 않을 때, 어떻게 처리할지 결정하는 옵션이다.

Retain: PV를 유지 (데이터 삭제 X)
Recycle: PV를 삭제하고 초기화 후 다시 사용 (현재는 deprecated)
Delete: PVC가 삭제되면 PV도 함께 삭제됨 (AWS EBS, GCE PD 등에서 사용)

 

controlplane ~ ➜  kubectl get pv
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                 STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
pv-log   100Mi      RWX            Retain           Bound    default/claim-log-1                  <unset>                          17m
# Retain 정책 사용

controlplane ~ ➜  kubectl get pvc
NAME          STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
claim-log-1   Bound    pv-log   100Mi      RWX                           <unset>                 10m

controlplane ~ ➜  kubectl delete pvc claim-log-1 
persistentvolumeclaim "claim-log-1" deleted


controlplane ~ ➜  kubectl get pvc
NAME          STATUS        VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
claim-log-1   Terminating   pv-log   100Mi      RWX                           <unset>                 11m

controlplane ~ ➜  kubectl describe pvc claim-log-1 
Name:          claim-log-1
Namespace:     default
StorageClass:  
Status:        Terminating (lasts 2m5s)   # Terminating에서 멈춰있다.( pv-log pod에서 사용중이기 때문에)
Volume:        pv-log
Labels:        <none>
Annotations:   pv.kubernetes.io/bind-completed: yes
               pv.kubernetes.io/bound-by-controller: yes
Finalizers:    [kubernetes.io/pvc-protection]
Capacity:      100Mi
Access Modes:  RWX
VolumeMode:    Filesystem
Used By:       webapp
Events:        <none>

# 파드를 삭제한다면
controlplane ~ ➜  kubectl delete pod webapp 
pod "webapp" deleted

controlplane ~ ➜  kubectl get pvc
No resources found in default namespace.
# 삭제됐다.

controlplane ~ ➜  kubectl get pv
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS     CLAIM                 STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
pv-log   100Mi      RWX            Retain           Released   default/claim-log-1                  <unset>                          24m
# PV는 Released 상태가 된다.

 

 

# PVC 실습

[master ~/Getting-Start-Kubernetes/14]$cat pvc-pod-web.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: web
spec:
  containers:
  - image: nginx:1.14
    name: nginx
    volumeMounts:
    - name: html
      mountPath: /usr/share/nginx/html
  volumes:
  - name: html  # pvc의 이름 선언
    persistentVolumeClaim:
      claimName: pvc-web # pvc 이름
      
[master ~/Getting-Start-Kubernetes/14]$kubectl apply -f pvc-pod-web.yaml 
pod/web created

[master ~/Getting-Start-Kubernetes/14]$kubectl get pods
NAME   READY   STATUS    RESTARTS   AGE
web    1/1     Running   0          19s

[master ~/Getting-Start-Kubernetes/14]$kubectl describe pod web
Name:             web
Namespace:        default
Priority:         0
Service Account:  default
Node:             gke-cluster-1-default-pool-697aeef7-xlub/10.128.0.16
...
Volumes:
  html:
    Type:       PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
    ClaimName:  pvc-web
    ReadOnly:   false
    
[master ~/Getting-Start-Kubernetes/14]$ kubectl get pods -o wide
NAME   READY   STATUS              RESTARTS   AGE     IP       NODE                                       NOMINATED NODE   READINESS GATES
web    0/1     ContainerCreating   0          2m28s   10.32.0.2   gke-cluster-1-default-pool-697aeef7-xlub   <none>           <none>

 

StorageClass

일반적으로 Pod가 스토리지를 직접 사용하지 않고, PVC를 통해 요청해야 접근할 수 있다.  스토리지 클래스 (StorageClass)를 사용하면 동적으로 PV를 생성할 수도 있다.

StorageClass를 사용하면 스토리지가 자동으로 생성되기 때문에 PV를 정의하지 않아도 된다.

PVC Definition에 StorageClass 이름을 지정한다.

  • 스토리지 클래스는 특정 프로비저너를 사용하여 동적으로 영구 볼륨을 생성한다.
    • PROVISIONER란 특정 스토리지 클래스를 사용하여 영구 볼륨(Persistent Volume, PV)을 생성하는 데 사용되는 프로비저닝(provisioning) 플러그인
# 스토리지 조회하기
controlplane ~ ➜  kubectl get sc
NAME                        PROVISIONER                     RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
local-path (default)        rancher.io/local-path           Delete          WaitForFirstConsumer   false                  6m53s
local-storage               kubernetes.io/no-provisioner    Delete          WaitForFirstConsumer   false                  9s
portworx-io-priority-high   kubernetes.io/portworx-volume   Delete          Immediate              false                  9s
# local-path는 로컬 경로 기반의 스토리지를 제공하는 프로비저너
# no-provisioner: 수동으로 영구 볼륨을 프로비저닝해야 함

# local-stroage 사용하는 pvc만들기

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: local-pvc
spec:
  accessModes:
    - ReadWriteOnce
  volumeMode: Filesystem
  resources:
    requests:
      storage: 500Mi
  storageClassName: local-storage
  
controlplane ~ ➜  kubectl get pvc
NAME        STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS    VOLUMEATTRIBUTESCLASS   AGE
local-pvc   Pending                                      local-storage   <unset>                 4s

PVC가 PV를  사용하지 않으면 waiting for first consumer to be created before binding이유로 Pending이 된다.

controlplane ~ ➜  kubectl describe pvc local-pvc 
Name:          local-pvc
Namespace:     default
StorageClass:  local-storage
Status:        Pending
Volume:        
Labels:        <none>
Annotations:   <none>
Finalizers:    [kubernetes.io/pvc-protection]
Capacity:      
Access Modes:  
VolumeMode:    Filesystem
Used By:       <none>
Events:
  Type    Reason                Age                   From                         Message
  ----    ------                ----                  ----                         -------
  Normal  WaitForFirstConsumer  10s (x12 over 2m51s)  persistentvolume-controller  waiting for first consumer to be created before binding
  
# Pod 생성
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: nginx
  name: nginx
spec:
  containers:
  - image: nginx:alpine
    name: nginx
    resources: {}
    volumeMounts:  # 컨테이너 내의 디렉토리에 연결
    - mountPath: "/var/www/html"
      name: local-pvc-volume
  dnsPolicy: ClusterFirst
  restartPolicy: Always
  volumes: # PVC 참조
  - name: local-pvc-volume
    persistentVolumeClaim:
      claimName: local-pvc
# local-pvc로 요청된 스토리지를 /var/www/html에 마운트한다.     
controlplane ~ ➜  kubectl create -f nginx.yaml 
pod/nginx created


controlplane ~ ➜  kubectl get pods
NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0          9s
controlplane ~ ➜  kubectl create -f delayed-volume-sc.yaml 
storageclass.storage.k8s.io/delayed-volume-sc created

controlplane ~ ➜  kubectl get sc
NAME                        PROVISIONER                     RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
delayed-volume-sc           kubernetes.io/no-provisioner    Delete          WaitForFirstConsumer   false                  42s
local-path (default)        rancher.io/local-path           Delete          WaitForFirstConsumer   false                  60m
local-storage               kubernetes.io/no-provisioner    Delete          WaitForFirstConsumer   false                  54m
portworx-io-priority-high   kubernetes.io/portworx-volume   Delete          Immediate              false                  54m
  •  VOLUMEBINDINGMODE: Persistent Volume (PV)이 Persistent Volume Claim (PVC)와 바인딩되는 시점을 제어한다.
    • Immediate (기본값) : PVC가 생성되면 즉시 PV와 바인딩
      • 스토리지 리소스가 클러스터의 어떤 노드에 있든지 상관없이 PVC가 요청하는 즉시 바인딩이 이루어짐을 의미한다.
    • WaitForFirstConsumer: PVC가 생성되더라도, 해당 PVC가 사용될 Pod가 실제로 스케줄링되기 전까지 PV와 바인딩되지 않는다.
반응형

'Container > Kubernetes' 카테고리의 다른 글

[K8S] ETCD Backup 및 Restore  (0) 2024.04.21
[K8S] Kubernetes DNS  (0) 2024.04.21
CKA 시험준비  (0) 2024.04.16
[K8S] cordon & drain  (0) 2024.04.13
[K8S] Taint & Toleration  (0) 2024.04.12