Probe 의 종류와 용도

Pod 의 상태를 주기적으로 파악하기 위한 기능을 Probe 라고 한다. Probe 설정의 파드 매니페스트의 spec.containers[] 하위에 startupProbe, readinessProbe, livenessProbe 를 지정한다. 각각의 Probe 는 아래의 의미를 가진다.

Probe명 용도 성공시 실패시
startupProbe app 기동 완료 여부 체크용.
Pod 가 (재)기동 시작할 때에만 수행된다.
startupProbe 호출을 중지하고 readinessProbe, livenessProbe 호출로 넘어간다. app 을 재기동한다.
readinessProbe app 이 트래픽을 받을 준비가 되었는지 체크용.
startupProbe 가 성공한 후에만 수행된다.
Service 에서 Pod 로 트래픽을 연결한다. Service 에서 Pod 로의 트래픽을 중단한다.
livenessProbe app 이 실행되고 있는지 체크용.
startupProbe 가 성공한 후에만 수행된다.
아무것도 안함 app 을 재기동한다.

 

readinessProbe 의 사용 의미

app 이 기동 완료(startupProbe success) 되었더라도 초기 데이터 로딩, 연동 시스템 체크, DB 데이터 유효성 검사 등 실제로 서비스가 정상적으로 수행되기 위한 사전 준비 작업이 필요할 수 있다. 이러한 사전 준비 작업이 완료되었는지 여부를 체크하기 위해 readinessProbe 를 사용하는 것이다.

 

readinessProbe 와 livenessProbe 사용시 주의할 점

이 두 Probe 는 app 이 서비스되는 동안 지속적으로 호출되기 때문에 무거운 검증을 실행시키면 안된다. 만약 피치 못하게 무거운 검증로직이 들어가야 한다면, 이전 검증 호출에 대한 응답을 받을 정도의 충분한 호출 주기를 설정해야 한다.

 

Probe 설정 세부항목

각각의 Probe 는 아래의 항목을 가진다. 일반적으로는 httpGet 으로 api 호출을 하겠지만, 필요에 따라서는 exec.command 를 사용하여 쉘스크립트를 실행하는 등의 프로그래밍적인 검증도 할 수 있다.(특정 경로에 파일이 생성되었는지 체크 등) 단,httpGet 과 exec 를 동시에 사용할 수는 없다.

항목명   내용 예시
httpGet path API path /startup
port Probe가 존재하는 컨테이너 port 8080
periodSeconds 호출주기 10
successThreshold 성공 간주 횟수 1
failureThreshold 실패 간주 횟수 10
exec command 실행할 명령어.
성공: 실행한 명령어의 종료 코드(Exit Code)가 0인 경우.
실패: 종료 코드가 0이 아닌 경우.
["cat", "/path/to/required/file.yaml"]
또는 yaml 문법을 준수하는
- cat
- /path/to/required/file.yaml
또는
- /bin/sh
- -c
- test -f /path/to/required/file.yaml

 

이를 정리하면 아래의 예시와 같다.

...
spec:
  containers:
    - name: api-server-123
      image: api-server:1.0.0
      ...
      # 3가지 Probe 설정
      startupProbe:
        httpGet:
          path: "/startup"
          port: 8080
        periodSeconds: 5
        failureThreshold: 20
      readinessProbe:
        httpGet:
          path: "/readiness"
          port: 8080
        periodSeconds: 10
        failureThreshold: 2
      livenessProbe:
        httpGet:
          path: "/liveness"
          port: 8080
        periodSeconds: 10
        failureThreshold: 3
      ...

 

블로그 이미지

망원동똑똑이

프로그래밍 지식을 자유롭게 모아두는 곳입니다.

,

쿠버네티스에서는 하나의 오브젝트가 다른 오브젝트를 선택하여 control 하거나 리소스를 사용하거나 연결하는데, 이때 선택하는 문법이 리소스마다 다르다. 매우 헷갈리는 부분이라 정리해둔다.

리소스명 피선택 리소스명 선택자 문법(항목)
Service Pod spec.selector
PersistentVolumeClaim PersistentVolume spec.selector.matchLabels
PersistentVolume Node spec.nodeAffinity.required.nodeSelectorTerms[].matchExpressions[]
Deployment ReplicaSet spec.selector.matchLabels
ReplicaSet Pod spec.selector.matchLabels
Pod Node spec.nodeSelector
Pod ConfigMap spec.containers[].envFrom[].configMapRef.name
Pod Secret spec.volumes[].secret.secretName
Pod PersistentVolumeClaim spec.volumes[].persistentVolumeClaim.claimName

 

블로그 이미지

망원동똑똑이

프로그래밍 지식을 자유롭게 모아두는 곳입니다.

,

1. 라벨링

쿠버네티스 오브젝트를 정의할 때 거의 필수로 정의하는 metadata.labels 항목이 있는데, 쿠버네티스에서 권고하는 규칙이 있다.

label 은 정보성으로만 사용하는 경우도 있고, 다른 오브젝트에서 선택하기 위한 기능성으로 사용하는 경우도 있다.

label명 라벨링 방법
part-of 애플리케이션의 이름
component 어플리케이션의 구성요소 이름
name 세부 구성요소 이름
instance 인스턴스 식별자. 동일한 앱이라도 목적에 따라 여러개를 설치할 수 있는데, 이때 각 앱을 식별하기 위해 사용됨. 보통 <name label>-<식별자> 형태로 사용한다.
version 파드에 실제로 올라가는 애플리케이션의 버전. 다른 label 들은 거의 고정이지만 version 은 버전 변경시마다 수정한다.
managed-by 생성주체

 

그 외 쿠버네티스 권고사항은 아니지만 사용자들이 자주 사용하는 라벨은 아래와 같다.

label명 라벨링 방법
owner 작성자
stage 배포환경(dev, stage, qa, prod)
release 배포 식별자
app-role 애플리케이션 역할

 

2. 네이밍

쿠버네티스에 권고하는 네이밍 규칙은 없으며, 사용자들이 권고하는 규칙이다.

object명 네이밍 방법
Namespace 애플리케이션의 기능을 설명할 수 있도록
StatefulSet instance label 과 동일
Service <Pod의 instance label>-<사용목적에 맞는 suffix>. 한개의 Pod 에 여러개가 붙을 수 있으므로 suffix 로 식별하도록 함. (internal, external 등)
ConfigMap <Pod의 instance label>-<사용목적에 맞는 suffix>. 한개의 Pod 에 여러개가 붙을 수 있으므로 suffix 로 식별하도록 함.(init-data, rules, properties 등)
HorizontalPodAutoscaler <Pod의 instance label>-<사용목적에 맞는 suffix>. 한개의 Pod 에 여러개가 붙을 수 있으므로 suffix 로 식별하도록 함.(특정 이벤트 기간에 사용하는 HPA 등)

 

블로그 이미지

망원동똑똑이

프로그래밍 지식을 자유롭게 모아두는 곳입니다.

,

쿠버네티스를 다루면서도  리소스, 오브젝트, 컨트롤러, 컴포넌트 용어의 정확한 의미를 이해하지 못하고 있었는데, 한번 정리하고자 한다.

용어 설명 역할 예시
리소스 API가 제공하는 추상적인 유형/자원 오브젝트를 생성하기 위한 HTTP Endpoint 또는 그 유형을 의미. 주로 API 관점에서 사용되는 용어. Namespace Level 리소스와 Cluster Lever 리소스로 나뉨. 'Pod'라는 리소스를 통해 특정 인프라 설정을 가진 'A-Pod'라는 오브젝트를 생성. 즉, 리소스를 기반으로 오브젝트나 컨트롤러를 생성함.
오브젝트 사용자가 생성한 구체적인 관리 대상 사용자가 원하는 상태(Desired State)를 기술한 영속적인 엔티티. "어떤 인프라 리소스를 어떻게 구동할 것인가"에 대한 정의서. YAML이나 JSON 형식으로 정의하는 클러스터 내의 인프라 상태.
즉, Pod, Service, ConfigMap, Secret, PersistentVolimeClaim 의 매니페스트.
컨트롤러 타 Controller 나 오브젝트를 제어하는 오브젝트 클러스터의 상태를 관찰하며, 현재 상태를 사용자가 원하는 바람직한 상태(Desired State)로 일치시키기 위해 끊임없이 루프를 도는 프로세스 HPA, Deployment, ReplicaSet 와 같이 인프라의 상태를 자동으로 제어하는 요소.
컴포넌트 클러스터를 구동하는 시스템 소프트웨어 쿠버네티스 클러스터 자체를 돌아가게 만드는 구성요소. 리소스를 동작시켜주는 요소. Control Plane의 kube-apiserver, etcd, kube-scheduler, kube-controller-manager, kube-proxy. 즉, 클러스터를 관리하는 부분.

 

블로그 이미지

망원동똑똑이

프로그래밍 지식을 자유롭게 모아두는 곳입니다.

,

파드에 지정하는 컨테이너의 volumeMounts[] 에는 name, mountPath 항목 외에도 몇가지 옵션 항목이 있다.

 

1. readOnly

파드 내 컨테이너에서 볼륨에 쓰기를 허용할지 여부를 지정하는 항목이다. 기본값은 false 라서 읽고 쓰기 모두 가능하다.(단, 당연히 Volume 자체가 readOnly 로 설정되어있다면 readOnly: false 로 지정하더라도 쓸 수 없다.) hostPath 볼륨 플러그인으로 사용하는 경우 파드가 노드의 파일 시스템에 직접 접근하므로 보안상 위험하여 권장되지 않는다. 이럴 때 최소한의 보안을 위해 readOnly 로 마운트하곤 한다.

아래와 같은 매니페스트로 파드를 생성해보자.

apiVersion: v1
kind: Pod
metadata:
  name: sample-readonly-volumemount
spec:
  containers:
    - image: nginx:1.27
      name: nginx-container
      volumeMounts:
        - name: hostpath-sample
          mountPath: /srv
          readOnly: true
  volumes:
    - name: hostpath-sample
      hostPath:
        path: /etc
        type: DirectoryOrCreate

생성한 파드 내 컨테이너에서 쓰기 작업을 실행시 아래와 같이 에러가 난다.

$ kubectl exec -it sample-readonly-volumemount -- touch /srv/motd
touch: cannot touch '/srv/motd': Read-only file system
command terminated with exit code 1

 

2. subPath

파드 내 컨테이너에서 볼륨의 어떤 디렉토리를 마운트할지 지정하는 항목이다. 만약 볼륨에 해당 디렉터리가 존재하지 않는다면 자동으로 생성되어 마운트된다. 이는 여러 컨테이너가 하나의 볼륨을 사용하면서도 서로 독립적인 디렉토리를 사용할 수 있게 한다. subPath 는 2계층 이상이어도 상관 없다.

아래와 같은 매니페스트로 3개의 컨테이너를 가진 멀티 컨테이너 파드를 띄워본다. 각각의 컨테이너는 마운트한 "/data/" 경로에 파일을 하나씩 생성하고 있다.

apiVersion: v1
kind: Pod
metadata:
  name: sample-subpath
spec:
  containers:
    - name: container-a
      image: alpine:3.7
      command: ["sh", "-c", "touch /data/a.txt; sleep 86400"]
      volumeMounts:
        - name: main-volume
          mountPath: /data
    - name: container-b
      image: alpine:3.7
      command: ["sh", "-c", "touch /data/b.txt; sleep 86400"]
      volumeMounts:
        - name: main-volume
          mountPath: /data
          subPath: path1 # 볼륨의 path1 디렉토리를 마운트
    - name: container-c
      image: alpine:3.7
      command: ["sh", "-c", "touch /data/c.txt; sleep 86400"]
      volumeMounts:
        - name: main-volume
          mountPath: /data
          subPath: path2 # 볼륨의 path2 디렉토리를 마운트
  volumes:
    - name: main-volume
      emptyDir: {}

아래와 같이 각각의 컨테이너의 mountPath 를 살펴보면, subPath 를 지정하지 않은 경우 "/"의 모든 파일이 조회되며, subPath 를 지정한 경우 지정한 subPath 내의 파일만 조회됨을 알 수 있다.

$ kubectl exec -it sample-subpath -c container-a -- find /data
/data
/data/path2
/data/path2/c.txt
/data/a.txt
/data/path1
/data/path1/b.txt

$ kubectl exec -it sample-subpath -c container-b -- find /data
/data
/data/b.txt

$ kubectl exec -it sample-subpath -c container-c -- find /data
/data
/data/c.txt
블로그 이미지

망원동똑똑이

프로그래밍 지식을 자유롭게 모아두는 곳입니다.

,

스테이트풀셋(StatefulSet)은 DB 등 영구 저장소를 위해 영구 볼륨을 사용하는 경우가 많다. 이를 편하게 사용하기 위해 spec.volumeClaimTemplate 항목을 지정할 수 있다. 이를 지정하면 영구 볼륨 클레임을 따로 정의하지 않아도 스테이트풀셋과 함께 생성할 수 있으며, 영구 볼륨 클레임을 사용하고자 하는 컨테이너 템플릿의 spec.containers[].volumeMounts 항목에 영구 볼륨 클레임 이름을 지정하기만 하면 된다.

 

아래와 같은 매니페스트로 스테이트풀셋을 생성해보자.(StorageClass 는 볼륨 스냅샷에서 생성한 것을 사용했다.)

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: sample-statefulset-with-pvc
spec:
  serviceName: stateful-with-pvc
  replicas: 2
  selector:
    matchLabels:
      app: sample-pvc
  template:
    metadata:
      labels:
        app: sample-pvc
    spec:
      containers:
        - name: sample-pvc
          image: nginx:1.27
          volumeMounts:
            - name: pvc-template-volume
              mountPath: /tmp
  volumeClaimTemplates:
    - metadata:
        name: pvc-template-volume
      spec:
        accessModes:
          - ReadWriteMany
        resources:
          requests:
            storage: 200Mi
        storageClassName: sample-nfs-csi-snapshot-source-storageclass

아래 커맨드로 조회해보면, volumeClaimTemplates 에 정의한대로 PVC 두개가 생성되고, 각각의 PV 도 생성되어 바인딩 된 것을 알 수 있다.

$ kubectl get pvc -l app=sample-pvc
NAME                                                STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS                                  VOLUMEATTRIBUTESCLASS   AGE
pvc-template-volume-sample-statefulset-with-pvc-0   Bound    pvc-1bc6a58d-3639-4037-b27f-6fab5dd3ba27   200Mi      RWX            sample-nfs-csi-snapshot-source-storageclass   <unset>                 5m52s
pvc-template-volume-sample-statefulset-with-pvc-1   Bound    pvc-3c338ba0-5726-424e-a8a5-bb4edf56bff1   200Mi      RWX            sample-nfs-csi-snapshot-source-storageclass   <unset>                 5m48s

# PVC 와 바인딩 된 PV 조회
$ kubectl get pvc -l app=sample-pvc | awk 'NR > 1 {printf "%s ", $3}' | xargs kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                                                       STORAGECLASS                                  VOLUMEATTRIBUTESCLASS   REASON   AGE
pvc-1bc6a58d-3639-4037-b27f-6fab5dd3ba27   200Mi      RWX            Delete           Bound    default/pvc-template-volume-sample-statefulset-with-pvc-0   sample-nfs-csi-snapshot-source-storageclass   <unset>                          22m
pvc-3c338ba0-5726-424e-a8a5-bb4edf56bff1   200Mi      RWX            Delete           Bound    default/pvc-template-volume-sample-statefulset-with-pvc-1   sample-nfs-csi-snapshot-source-storageclass   <unset>                          22m

PVC의 네이밍 규칙은 <template-name>-<statefulset-name>-<ordinal> 임을 알 수 있다.

블로그 이미지

망원동똑똑이

프로그래밍 지식을 자유롭게 모아두는 곳입니다.

,

 

스테이트풀한 애플리케이션을 운영하다보면 정기적인 백업이 필요하며, 백업된 데이터를 복구하는 작업도 필요하다. 이를 위해서는 볼륨 스냅샷이라는 기능을 사용해야 한다. 관련된 리소스는 VolumeSnapshot, VolumeSnapshotClass, VolumeSnapshotContent 가 있고 각각 아래와 같은 역할을 한다.

리소스명 설명 볼륨 관련 리소스와 비교
VolumeSnapshot(VS) 사용자가 스냅샷 생성을 요청하는 선언적 리소스 PersistentVolumeClaim 과 같은 역할
VolumeSnapshotClass(VSClass) 스냅샷을 생성할 때 사용할 드라이버(local.csi.openebs.io 와 같은)와 삭제 정책(deletionPolicy)을 정의한 리소스 StorageClass 와 같은 역할
VolumeSnapshotContent(VSC) 스냅샷의 실제 데이터 위치와 정보를 담고 있는 클러스터 단위의 리소스. 사용자가 직접 만들기보다는 CSI 컨트롤러에 의해 자동 생성됨 PersistentVolume 과 같은 역할

영구 볼륨을 보통 직접 생성하지 않고 PersistentVolumeClaim 이라는 "볼륨 요청 명세서"와 StorageClass 라는 "볼륨 프로비저닝 정책서"를 통해 자동 생성하듯이, 스냅샷도 VolumeSnapshot 이라는 "스냅샷 요청 명세서"와 VolumeSnapshotClass 라는 "스냅샷핸들링 정책서"를 통해 자동 생성한다.

생성된 스냅샷(VSC)을 볼륨(PV)으로 만드는 방법(즉, 복구하는 방법)은 PVC 의 매니페스트 spec.dataSource 항목에 스냅샷을 생성할 때 사용한 VolumeSnapshot 을 지정하여 생성하면 된다.

요약하면 스냅샷 저장/복구는 아래와 같다.

  • 저장: PVC 가 있는 상태(당연히 PV가 있음)에서 VS 을 생성하면 VSC 가 생성된다.
  • 복구: VS 가 있는 상태(당연히 VSC가 있음)에서 복구용 PVC를 생성하면 복구된 PV 가 생성된다.

앞서 동적 프로비저닝을 위해 Static NFS 타입의 스토리지를 구축해봤고, Block 장치를 영구 볼륨 사용하기 위해 OpenEBS LocalPV-LVM 방식의 스토리지를 구축해봤다. 하지만 스냅샷 기능을 파일시스템 기반 스토리지에서 실습하기 위해서는 CSI NFS 스토리지를 사용해야 하므로, 아래 실습을 따라하며 환경 설치부터 진행해야 한다.(앞서 구축한 Static NFS 는 스냅샷을 지원하지 않는 프로비저너를 사용했다.)

 

1. 사전 준비

1.1 헬름 설치

아래를 따라하며 Helm(쿠버네티스 패키지 관리 도구)을 설치한다.

# ARM64용 파일 다운로드(사용자 환경에 따라 다르게 지정)
$ curl -fsSL -o helm-v3.14.0-linux-arm64.tar.gz https://get.helm.sh/helm-v3.14.0-linux-arm64.tar.gz

# 압축 해제
$ tar -zxvf helm-v3.14.0-linux-arm64.tar.gz

# 파일 이동
$ mkdir -p $HOME/bin
$ cp linux-arm64/helm $HOME/bin/helm

# 설정 적용
$ echo 'export PATH=$PATH:$HOME/bin' >> ~/.bashrc
$ source ~/.bashrc

# 설치 확인
$ helm version
version.BuildInfo{Version:"v3.14.0", GitCommit:"3fc9f4b2638e76f26739cd77c7017139be81d0ea", GitTreeState:"clean", GoVersion:"go1.21.5"}

 

1.2 NFS CSI 드라이버 설치

아래를 따라하며 NFS CSI 드라이버를 설치한다.

# 저장소(Repository) 추가 및 업데이트
$ helm repo add csi-driver-nfs https://raw.githubusercontent.com/kubernetes-csi/csi-driver-nfs/master/charts
$ helm repo update

# 드라이버 설치
$ helm install csi-driver-nfs csi-driver-nfs/csi-driver-nfs --version v4.6.0

# 설치 상태 확인
$ kubectl --namespace=default get pods --selector="app.kubernetes.io/instance=csi-driver-nfs" --watch
NAME                                 READY   STATUS    RESTARTS   AGE
csi-nfs-controller-dc4b79d4c-25tzc   4/4     Running   0          42s
csi-nfs-node-dpn22                   3/3     Running   0          42s
csi-nfs-node-fx7nj                   3/3     Running   0          42s
csi-nfs-node-ldx9v                   3/3     Running   0          42s

 

2. Snapshot Controller 설치

# RBAC(Role-Based Access Control, 역할 기반 액세스 제어) 및 컨트롤러 배포
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/deploy/kubernetes/snapshot-controller/rbac-snapshot-controller.yaml
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/deploy/kubernetes/snapshot-controller/setup-snapshot-controller.yaml

아래 커맨드로 설치를 확인한다. Running 상태가 될 때까지 기다린다.

$ kubectl get pods -n kube-system | grep snapshot-controller
snapshot-controller-d4969fd45-749fk   1/1     Running   0              92s
snapshot-controller-d4969fd45-kkxfc   1/1     Running   0              92s

 

3. 스토리지 클래스 생성

아래와 같은 매니페스트로 스토리지 클래스를 생성한다.

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: sample-nfs-csi-snapshot-source-storageclass
provisioner: nfs.csi.k8s.io
parameters:
  server: 192.168.0.36 # 마스터 노드(NFS 서버) IP
  share: /srv/nfs/kubedata # NFS 공유 디렉토리 경로
reclaimPolicy: Delete
volumeBindingMode: Immediate

아래 커맨드로 생성된 스토리지 클래스를 확인한다.

$ kubectl get sc sample-nfs-csi-snapshot-source-storageclass
NAME                                          PROVISIONER                    RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
sample-nfs-csi-snapshot-source-storageclass   nfs.csi.k8s.io                 Delete          Immediate           false                  4s

 

4. PVC 생성

아래와 같은 매니페스트로 원본 볼륨을 요청할 PVC 를 생성한다. spec.storageClassName 에는 위에서 생성한 스토리지 클래스 이름을 지정한다.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: sample-nfs-csi-snapshot-source-pvc
spec:
  storageClassName: sample-nfs-csi-snapshot-source-storageclass
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 200Mi

아래 커맨드로 생성된 PVC와 동적 프로비저닝된 PV를 확인한다. 스토리지 클래스의 volumeBindingMode: Immediate 이기 때문에 바로 PV가 생성 및 바인딩 된다.

$ kubectl get pvc sample-nfs-csi-snapshot-source-pvc
NAME                                 STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS                                  VOLUMEATTRIBUTESCLASS   AGE
sample-nfs-csi-snapshot-source-pvc   Bound    pvc-ce7ee910-d765-4a39-a804-796bb9845309   200Mi      RWX            sample-nfs-csi-snapshot-source-storageclass   <unset>                 20s

$ kubectl get pv pvc-ce7ee910-d765-4a39-a804-796bb9845309
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                                        STORAGECLASS                                  VOLUMEATTRIBUTESCLASS   REASON   AGE
pvc-ce7ee910-d765-4a39-a804-796bb9845309   200Mi      RWX            Delete           Bound    default/sample-nfs-csi-snapshot-source-pvc   sample-nfs-csi-snapshot-source-storageclass   <unset>                          26s

 

5. Pod 생성

아래와 같은 매니페스트로 실제 PVC 를 사용할 Pod 를 생성한다. command 와 args 를 통해 컨테이너 구동시 컨테이너 내의 /data/time.txt 경로에 시간정보를 기록한다.

apiVersion: v1
kind: Pod
metadata:
  name: sample-nfs-csi-snapshot-source-pod
spec:
  containers:
    - name: tools-container
      image: busybox
      command: ["/bin/sh", "-c"]
      args: ["date > /data/time.txt && sleep infinity"]
      volumeMounts:
        - name: data-volume
          mountPath: /data
  volumes:
    - name: data-volume
      persistentVolumeClaim:
        claimName: sample-nfs-csi-snapshot-source-pvc
        readOnly: false

아래와 같은 커맨드로 실제 컨테이너 내에 생성된 시간정보 파일을 확인해본다. 나중에 스냅샷을 만든 후 다시 복구했을 때 이 파일이 그대로 복구되어야 한다.

$ kubectl exec -it sample-nfs-csi-snapshot-source-pod -- cat /data/time.txt
Mon Mar  2 08:54:02 UTC 2026

여기까지 확인되면, 동적 프로비저닝 방식으로 영구 볼륨 생성까지 진행한 것이다. 스냅샷을 지원하는 CSI NFS 를 드라이버를 사용한다는 점 이외에는 일반적인 동적 프로비저닝 방식과 차이가 없다.

다음 단계부터는 영구 볼륨을 스냅샷으로 백업하고 복구하는 방법이다.

 

6. VSClass 생성

아래와 같은 매니페스트로 VolumeSnapshotClass 를 생성한다. driver 에는 스냅샷을 지원하는 CSI 드라이버 명칭을 지정한다.

apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotClass
metadata:
  name: sample-nfs-csi-snapshot-volumesnapshotclass
driver: nfs.csi.k8s.io # CSI 드라이버 명칭
deletionPolicy: Delete

아래 커맨드로 생성된 VSClass 를 확인한다.

$ kubectl get vsclass sample-nfs-csi-snapshot-volumesnapshotclass
NAME                                          DRIVER           DELETIONPOLICY   AGE
sample-nfs-csi-snapshot-volumesnapshotclass   nfs.csi.k8s.io   Delete           7s

 

7. VS 생성(VSC 자동생성)

아래와 같은 매니페스트로 VolumeSnapshot 을 생성한다. spec.volumeSnapshotClassName 에는 사용할 VSClass 이름을, spec.source.persistentVolumeClaimName 에는 스냅샷으로 저장할 원본 볼륨에 대한 PVC 이름을 지정한다.

apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
  name: sample-nfs-csi-snapshot-volumesnapshot
spec:
  volumeSnapshotClassName: sample-nfs-csi-snapshot-volumesnapshotclass # 사용할 VSClass 이름
  source:
    persistentVolumeClaimName: sample-nfs-csi-snapshot-source-pvc # 원본 PVC 이름

아래 커맨드로 생성된 VS와 자동으로 생성된 VSC(VolumeSnapshotContent)를 확인한다. 둘 다 READYTOUSE 항목이 true 로 조회되어야 한다.

$ kubectl get vs sample-nfs-csi-snapshot-volumesnapshot
NAME                                     READYTOUSE   SOURCEPVC                            SOURCESNAPSHOTCONTENT   RESTORESIZE   SNAPSHOTCLASS                                 SNAPSHOTCONTENT                                    CREATIONTIME   AGE
sample-nfs-csi-snapshot-volumesnapshot   true         sample-nfs-csi-snapshot-source-pvc                           173           sample-nfs-csi-snapshot-volumesnapshotclass   snapcontent-b2b577a0-aeda-42b4-8f20-dafa81496496   6s             6s

$ kubectl get vsc snapcontent-b2b577a0-aeda-42b4-8f20-dafa81496496
NAME                                               READYTOUSE   RESTORESIZE   DELETIONPOLICY   DRIVER           VOLUMESNAPSHOTCLASS                           VOLUMESNAPSHOT                           VOLUMESNAPSHOTNAMESPACE   AGE
snapcontent-b2b577a0-aeda-42b4-8f20-dafa81496496   true         173           Delete           nfs.csi.k8s.io   sample-nfs-csi-snapshot-volumesnapshotclass   sample-nfs-csi-snapshot-volumesnapshot   default                   75s

 

 

8. 스냅샷 복구용 PVC 생성

아래와 같은 매니페스트로 스냅샷을 영구 볼륨으로 복구할 PVC 를 생성한다. spec.storageClassName 에는 원본 볼륨을 생성할 때 사용한 스토리지 클래스(SC) 이름을 지정하며, spec.dataSource 에는 복구할 스냅샷을 생성할 때 사용한 볼륨 스냅샷(VS) 이름을 지정한다. spec.resources.requests.storage 항목은 원본보다 크거나 같아야 한다.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: sample-nfs-csi-snapshot-restore-pvc
spec:
  storageClassName: sample-nfs-csi-snapshot-source-storageclass # 원본과 동일한 StorageClass
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 300Mi # 원본보다 크거나 같아야 함
  dataSource: # 핵심: 스냅샷을 원본으로 지정
    kind: VolumeSnapshot
    name: sample-nfs-csi-snapshot-volumesnapshot # 복구할 VS 이름
    apiGroup: snapshot.storage.k8s.io

아래 커맨드로 생성된 PVC를 확인한다.

$ kubectl get pvc sample-nfs-csi-snapshot-restore-pvc
NAME                                  STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS                                  VOLUMEATTRIBUTESCLASS   AGE
sample-nfs-csi-snapshot-restore-pvc   Bound    pvc-ef300ede-72ed-454f-afdb-25c4dc981df9   300Mi      RWX            sample-nfs-csi-snapshot-source-storageclass   <unset>                 30s

정상적으로 PVC가 생성되면, 자동으로 스냅샷을 복구한 PV가 생성된다.

 

9. 복구된 PV 조회

아래 커맨드로 스냅샷이 복구된 PV를 조화한다. 위에서 확인한 VOLUME 명칭으로 생성된다.

$ kubectl get pv pvc-ef300ede-72ed-454f-afdb-25c4dc981df9
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                                         STORAGECLASS                                  VOLUMEATTRIBUTESCLASS   REASON   AGE
pvc-ef300ede-72ed-454f-afdb-25c4dc981df9   300Mi      RWX            Delete           Bound    default/sample-nfs-csi-snapshot-restore-pvc   sample-nfs-csi-snapshot-source-storageclass   <unset>                          79s

 

10. 복구된 PV 를 사용하는 Pod 를 생성하여 실제 복구 데이터 확인

아래와 같은 매니페스트로 복구된 PV를 사용하는 파드를 띄운다. 컨테이너 기동시 파일 내용을 출력하는 커맨드가 담겨있다.

apiVersion: v1
kind: Pod
metadata:
  name: sample-nfs-csi-snapshot-restore-pod
spec:
  containers:
    - name: tools-container
      image: busybox
      command: ["/bin/sh", "-c"]
      args: ["cat /data/time.txt && sleep infinity"]
      volumeMounts:
        - name: data-volume
          mountPath: /data
  volumes:
    - name: data-volume
      persistentVolumeClaim:
        claimName: sample-nfs-csi-snapshot-restore-pvc
        readOnly: false

아래처럼 파드의 로그를 확인한다. 원본 볼륨에 저장되었던 내용이 그대로 복구되었음을 알 수 있다.

$ kubectl logs sample-nfs-csi-snapshot-restore-pod
Mon Mar  2 08:54:02 UTC 2026
블로그 이미지

망원동똑똑이

프로그래밍 지식을 자유롭게 모아두는 곳입니다.

,

동적 프로비저닝을 사용하면서 CSI 를 준수하는 벤더의 드라이버가 볼륨 resize 를 지원하는 경우에는 PVC 조정을 통해 볼륨 확장이 가능하다. 아래와 같이 실습을 진행해보자.

 

1. 스토리지 클래스 생성

다음과 같이 allowVolumeExpansion: true 를 지정하여 스토리지 클래스를 생성한다. 스토리지 클래스에 해당 항목을 지정하더라도, 실제 사용하는 볼륨 플러그인 드라이버 구현에서 지원해야 볼륨 확장이 가능한 점에 유의하자.

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: sample-block-storageclass-resize
provisioner: local.csi.openebs.io
parameters:
  storage: "lvm"
  volgroup: "lvmvg"
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true

 

2. PVC 생성

PVC 는 특별한 설정이 필요 없다. Static NFS 는 이미 존재하는 디렉토리를 스토리지로 사용하고, k8s 가 용량을 제어하지 않기 때문에 확장이 불가능하여 Block 스토리지로 사용하였다.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: sample-block-pvc-resize
spec:
  storageClassName: sample-block-storageclass-resize
  volumeMode: Block
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 500Mi

 

3. Pod 생성

위 PVC 를 사용하는 파드를 생성하여 동적 프로비저닝이 일어나도록 한다. 블록 장치 연결 위치는 /dev/sample-block 이다.

apiVersion: v1
kind: Pod
metadata:
  name: sample-block-pod-resize
spec:
  containers:
    - name: nginx-container
      image: nginx:1.27
      volumeDevices:
        - name: nginx-pvc
          devicePath: /dev/sample-block
  volumes:
    - name: nginx-pvc
      persistentVolumeClaim:
        claimName: sample-block-pvc-resize

 

4. 볼륨 크기 확인

동적 프로비저닝이 정상적으로 수행되었는지, 생성된 영구 볼륨의 크기는 몇인지, 실제 파드 연결된 볼륨의 크기는 몇인지 확인해본다.

$ kubectl get pvc sample-block-pvc-resize
NAME                      STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS                       VOLUMEATTRIBUTESCLASS   AGE
sample-block-pvc-resize   Bound    pvc-2d5bf77e-956e-4e38-9517-bb8f4da44ca4   500Mi      RWO            sample-block-storageclass-resize   <unset>                 115s

# PV 용량 확인
$ kubectl get pv pvc-2d5bf77e-956e-4e38-9517-bb8f4da44ca4
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                             STORAGECLASS                       VOLUMEATTRIBUTESCLASS   REASON   AGE
pvc-2d5bf77e-956e-4e38-9517-bb8f4da44ca4   500Mi      RWO            Delete           Bound    default/sample-block-pvc-resize   sample-block-storageclass-resize   <unset>                          9s

# 파드에 연결된 볼륨 용량 확인
$ kubectl exec -it sample-block-pod-resize -- blockdev --getsize64 /dev/sample-block
524288000

 

5. 볼륨 크기 확장

이제 아래처럼 PVC 매니페스트의 spec.resources.requests.storage 를 이전보다 더 크게 수정/적용한 후 볼륨 사이즈를 확인해본다.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: sample-block-pvc-resize
spec:
  storageClassName: sample-block-storageclass-resize
  volumeMode: Block
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 800Mi # 여기를 수정한 후, 다시 kubectl apply 한다.

apply 후 실제 적용은 최대 1분까지 소요된다.

$ kubectl apply -f sample-block-pvc-resize.yaml
persistentvolumeclaim/sample-block-pvc-resize configured

$ kubectl get pvc sample-block-pvc-resize
NAME                      STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS                       VOLUMEATTRIBUTESCLASS   AGE
sample-block-pvc-resize   Bound    pvc-2d5bf77e-956e-4e38-9517-bb8f4da44ca4   800Mi      RWO            sample-block-storageclass-resize   <unset>                 13m

$ kubectl get pv pvc-2d5bf77e-956e-4e38-9517-bb8f4da44ca4
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                             STORAGECLASS                       VOLUMEATTRIBUTESCLASS   REASON   AGE
pvc-2d5bf77e-956e-4e38-9517-bb8f4da44ca4   800Mi      RWO            Delete           Bound    default/sample-block-pvc-resize   sample-block-storageclass-resize   <unset>                          11m

$ kubectl exec -it sample-block-pod-resize -- blockdev --getsize64 /dev/sample-block
838860800

같은 디스크에서 용량만 800Mi 로 증가된 것을 확인할 수 있다.

 

단, 아래처럼 볼륨 사이즈 축소는 불가한 점에 유의하자.

# PVC 의 spec.resources.requests.storage 를 축소한 후 적용시
$ kubectl apply -f sample-block-pvc-resize.yaml
The PersistentVolumeClaim "sample-block-pvc-resize" is invalid: spec.resources.requests.storage: Forbidden: field can not be less than previous value

 

블로그 이미지

망원동똑똑이

프로그래밍 지식을 자유롭게 모아두는 곳입니다.

,

영구 볼륨을 일반적인 파일 시스템으로부터 어태치 하지 않고 블록 장치로부터 어태치할 수도 있다. PVC 의 spec.volumeMode: Block 으로 지정하고(기본값이 FileSystem 임), PVC 를 사용하는 Pod 에서는 컨테이너 템플릿의 volumeDevices 를 지정하면 된다.(파일시스템인 경우 volumeMounts 인 것과 대비됨)

 

단, 현재 로컬 머신에는 NFS 스토리지만 준비되어있기 때문에 블록 스토리지를 추가로 구성해줘야 한다. 블록 스토리지를 실습하기 위해서는 Longhorn을 사용하는 방법이 권장되지만, 맥북 리소스의 한계로 이전에 구축에 실패하였다. 따라서 이번에는 OpenEBS LocalPV-LVM/ZFS 방식으로 구축해본다. VM에 추가 가상 디스크를 구성하고, 각 노드에서 해당 디스크를 블록 장치로 사용하는 방식이다. 단, LocalPV 이기 때문에 클러스터 공유 스토리지가 아닌, 특정 노드의 로컬 디스크에 종속된 스토리지라서 노드 간에 데이터 공유가 안된다는 점이 유의하자.

 

1. 가상 머신에 블록 디스크 추가(모든 워커 노드)

각 워커 노드 머신의 전원을 종료(shutdown -h now)한 후, UTM 에서 디스크를 추가한다. 인터페이스는 VirtIO, 크기는 본인의 리소스를 고려하여 적절히 세팅한 후 저장한다.

이후 다시 워커 노드를 부팅 후, lsblk 명령어를 사용하여 추가된 디스크를 확인한다.

$ lsblk
NAME                      MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
...
vdb                       253:16   0    2G  0 disk

 

2. LVM(Logical Volume Manager)용 PV(Physical Volume) 생성(모든 워커 노드)

Logical Volume Manager 가 추가한 디스크를 사용할 수 있는 상태로 만드는 작업이다. 모든 워커 노드에서 아래 명령어를 입력한다.

# lvm2 도구 설치
$ sudo apt update && sudo apt install lvm2 -y

# 물리 볼륨 생성
$ sudo pvcreate /dev/vdb
  Physical volume "/dev/vdb" successfully created.

아래 명령어로 PV를 조회한다. 위에에서 생성한 /dev/vdb 가 조회되면 된다.

$ sudo pvs
  PV         VG        Fmt  Attr PSize   PFree
...
  /dev/vdb             lvm2 ---    2.00g  2.00g

 

3. VG(Volume Group) 생성(모든 워커 노드)

물리 볼륨(PV)들을 하나의 그룹으로 묶는다. VG 이름은 나중에 쿠버네티스 스토리지 클래스에서 그대로 사용하게 된다. 여기서는 lvmvg 이라고 지정했다. 모든 워커 노드에서 진행한다.

# /dev/vdb 물리 볼륨을 'lvmvg'라는 이름의 볼륨 그룹으로 생성한다.
$ sudo vgcreate lvmvg /dev/vdb
  Volume group "lvmvg" successfully created
  
# 조회
$ sudo vgs
  VG        #PV #LV #SN Attr   VSize   VFree
  lvmvg       1   0   0 wz--n-  <2.00g <2.00g

 

4. LVM-LocalPV CSI 드라이버 설치(마스터 노드)

OpenEBS 의 LVM 연동 도구를 설치한다. 마스터 노드에서 실행한다. openebs 네임스페이스가 아닌 kube-system 네임스페이스 설치가 기본값인 듯 하다.

# LVM-LocalPV 오퍼레이터(Operator)와 관련 구성 요소를 쿠버네티스 클러스터에 배포한다.
$ kubectl apply -f https://openebs.github.io/charts/lvm-operator.yaml

아래 커맨드를 실행하여 필요한 리소스들이 생성되었는지 확인한다.

$ kubectl -n kube-system get statefulsets -l openebs.io/component-name
NAME                     READY   AGE
openebs-lvm-controller   1/1     70m

$ kubectl -n kube-system get daemonsets -l openebs.io/component-name
NAME               DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
openebs-lvm-node   2         2         2       2            2           <none>          70m

# openebs-lvm-controller 는 statefulset 이 관리하고, openebs-lvm-node 는 daemonset 이 관리한다.
$ kubectl -n kube-system get pods -l openebs.io/component-name
NAME                       READY   STATUS    RESTARTS   AGE
openebs-lvm-controller-0   5/5     Running   0          72m
openebs-lvm-node-8fmwx     2/2     Running   0          72m
openebs-lvm-node-dgjbp     2/2     Running   0          72m

 

5. 스토리지 클래스 생성

아래 매니페스트를 이용하여 SC를 생성한다. 프로비저너로 위에서 설치한 OpenEBS 의 CSI  드라이버를 사용하기 때문에 동적 프로비저닝 기능이 이미 포함되어있다. volumeBindingMode: WaitForFirstConsumer 를 주어서 실제 파드가 노드에 스케쥴링된 후에야 동적으로 볼륨 바인딩이 일어날 수 있도록 한다. 이는 LocalPV 를 사용할 때 중요하다. 스토리지가 노드에 종속되어있기 때문에 실제로 파드가 노드에 배정되었을 때 그 노드의 lvmvg 에서 공간을 쪼개 할당할 수 있기 때문이다.

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: sample-block-storageclass
provisioner: local.csi.openebs.io # 중요
parameters:
  storage: "lvm"
  volgroup: "lvmvg" # 미리 생성해두 Volume Group 명을 지정한다.
volumeBindingMode: WaitForFirstConsumer # 중요
allowVolumeExpansion: true

 

 

6. PVC 생성

아래 매니페스트를 이용하여 PVC를 생성한다.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: sample-block-pvc
spec:
  storageClassName: sample-block-storageclass
  volumeMode: Block # 중요
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 500Mi

 

7. 파드 생성

실제로 블록 장치를 볼륨으로 사용할 파드를 배포한다.

apiVersion: v1
kind: Pod
metadata:
  name: sample-block-pod
spec:
  containers:
    - name: nginx-container
      image: nginx:1.27
      volumeDevices:
        - name: nginx-pvc
          devicePath: /dev/sample-block
  volumes:
    - name: nginx-pvc
      persistentVolumeClaim:
        claimName: sample-block-pvc

 

8. 동적 프로비저닝 확인

파드가 PVC 를 사용하는 시점에 동적으로 PV 가 생성되었는지 확인한다.

# PVC 가 BOUND 되었는지 확인
$ kubectl get pvc sample-block-pvc
NAME               STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS                VOLUMEATTRIBUTESCLASS   AGE
sample-block-pvc   Bound    pvc-560cb363-b43c-498c-b397-309cd893cc6c   500Mi      RWO            sample-block-storageclass   <unset>                 90m

# PV 가 생성되었는지 확인
$ kubectl get pv pvc-560cb363-b43c-498c-b397-309cd893cc6c
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                      STORAGECLASS                VOLUMEATTRIBUTESCLASS   REASON   AGE
pvc-560cb363-b43c-498c-b397-309cd893cc6c   500Mi      RWO            Delete           Bound    default/sample-block-pvc   sample-block-storageclass   <unset>                          60m

# Pod 가 Running 중인지 확인
$ kubectl get pods sample-block-pod -o wide
NAME               READY   STATUS    RESTARTS   AGE   IP            NODE       NOMINATED NODE   READINESS GATES
sample-block-pod   1/1     Running   0          90m   10.244.2.83   worker02   <none>           <none>

# Pod 내에 Block 장치가 연결되었는지 확인
$ kubectl exec -it sample-block-pod -- ls -l /dev/sample-block
brw------- 1 root root 252, 1 Feb 22 10:20 /dev/sample-block

 

블로그 이미지

망원동똑똑이

프로그래밍 지식을 자유롭게 모아두는 곳입니다.

,

동적 프로비저닝을 사용할 때 기본적으로 영구 볼륨 클레임 리소스를 생성하면 자동으로 영구 볼륨이 생성된다. 하지만, 실제 볼륨을 사용하고자 하는 파드에서 영구 볼륨 클레임을 지정하여 파드를 생성하기 전까지는 영구 볼륨이 생성된 채로 유지가 되어 낭비가 발생한다. 스토리지 클래스에는 이를 조정하는 volumeBindingMode 라는 항목이 있다. volumeBindingMode: WaitForFirstConsume 으로 지정하면 아래와 같이 동작한다.

  • 정적 프로비저닝시: PV는 Available(미리 생성하기 때문), PVC는 Pending 상태로 존재하다가, 파드에서 사용하는 시점에 바인딩됨
  • 동적 프로비저닝시: PV 는 없고, PVC는 Pending 상태로 존재하다가, 파드에서 사용하는 시점에 PV 생성 & 바인딩됨

즉, 동적 프로비저닝시 실제 파드에서 영구 볼륨을 사용하는 시점에 영구 볼륨을 생성할 수가 있는 것이다. 이 항목에 올 수 있는 값은 아래와 같다.

volumeBindingMode 설정값 설명
Immediate 기본값. 즉시 영구 볼륨이 생성됨
WaitForFirstConsumer 처음으로 파드에 의해 사용될 때 영구 볼륨이 생성됨

PVC 를 생성한 후, 실제 파드에서 사용할 때까지 PV가 어떻게 동작하는지 아래를 진행하며 살펴보자.

 

먼저 아래와 같은 매니페스트로 스토리지 클래스를 생성한다.

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-client
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
parameters:
  archiveOnDelete: "false"
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer

PVC 를 먼저 생성하고, 동적 프로비저닝이 일어나기까지 PV 가 어떻게 생성되는지 지켜보자

# PV, PVC, Pod 상태를 확인한다.
$ kubectl get pv
No resources found
$ kubectl get pvc
No resources found in default namespace.
$ kubectl get pods
NAME                                     READY   STATUS    RESTARTS   AGE
nfs-client-provisioner-cc5544bc4-v62cz   1/1     Running   0          2d3h

# PVC 만 생성한 후, PVC 의 상태가 Pending이고, PV 가 아직 생성되지 않았음을 확인한다.
$ kubectl apply -f sample-nfs-provisioning-pvc.yaml
persistentvolumeclaim/sample-nfs-provisioning-pvc created
$ kubectl get pvc
NAME                          STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
sample-nfs-provisioning-pvc   Pending                                      nfs-client     <unset>                 4s
$ kubectl get pv
No resources found

# 해당 PVC 를 사용하는 파드를 띄운 후 PV 가 자동으로 생성 및 바인딩 되었는지 확인한다.
$ kubectl apply -f sample-nfs-provisioning-pod.yaml
pod/sample-nfs-provisioning-pod created
$ kubectl get pvc
NAME                          STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
sample-nfs-provisioning-pvc   Bound    pvc-37ae35bc-517e-4c0c-a175-cc0aee0c6f44   200Mi      RWO            nfs-client     <unset>                 27s
$ kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                                 STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
pvc-37ae35bc-517e-4c0c-a175-cc0aee0c6f44   200Mi      RWO            Delete           Bound    default/sample-nfs-provisioning-pvc   nfs-client     <unset>                          7s

 

블로그 이미지

망원동똑똑이

프로그래밍 지식을 자유롭게 모아두는 곳입니다.

,