Pod 에서 Ephemeral 및 Persistent 볼륨 사용하기

KubernetesBeginner
지금 연습하기

소개

컨테이너는 쓰기 가능한 파일 시스템을 가지고 있지만, 해당 스토리지는 컨테이너에 종속되어 있습니다. Kubernetes 볼륨은 Pod 가 파일을 더 효율적으로 관리할 수 있는 방법을 제공합니다. 일부 볼륨은 ephemeral(일시적) 하며 단일 Pod 내의 임시 데이터를 위해 설계되었습니다. 반면, persistent(영구적) 볼륨은 Pod 가 삭제되고 재생성되어도 데이터를 유지할 수 있습니다.

이번 실습에서는 Pod 로컬 임시 데이터를 위해 emptyDir 볼륨을 사용해 보고, PersistentVolumeClaim 을 생성하여 두 개의 서로 다른 Pod 에 마운트함으로써 Pod 가 교체되어도 데이터가 유지됨을 확인합니다.

볼륨 실습을 위한 네임스페이스 준비

이 단계에서는 실습을 위한 깨끗한 네임스페이스를 준비하고, 클러스터에 필요한 스토리지 구성 요소가 준비되었는지 확인합니다.

/home/labex/project 디렉토리에서 시작합니다. 이 디렉토리에 Pod 및 PVC 매니페스트를 작성하게 됩니다.

mkdir -p /home/labex/project
cd /home/labex/project

Kubernetes API 서버에 접근 가능한지 확인합니다. VM 이 막 시작되어 노드가 아직 준비되지 않았다면, 잠시 기다린 후 명령어를 다시 실행하세요.

kubectl get nodes --request-timeout=5s

예상 출력:

NAME         STATUS   ROLES           AGE   VERSION
labex-v135   Ready    control-plane   ...   v1.35...

클러스터 네트워킹 Pod 가 준비 (Ready) 상태가 될 때까지 기다립니다:

kubectl wait --namespace kube-system --for=condition=Ready pod -l k8s-app=calico-node --timeout=120s

예상 출력:

pod/calico-node-... condition met

이 실습에서는 나중에 PersistentVolumeClaim 을 사용합니다. 기본 standard StorageClass 가 존재하는지 확인한 후, minikube 스토리지 프로비저너 Pod 가 준비될 때까지 기다립니다.

kubectl get storageclass standard
kubectl wait --namespace kube-system --for=condition=Ready pod/storage-provisioner --timeout=120s

예상 출력:

NAME                 PROVISIONER                RECLAIMPOLICY   VOLUMEBINDINGMODE   ...
standard (default)   k8s.io/minikube-hostpath   Delete          Immediate           ...
pod/storage-provisioner condition met

ckad-prep-volumes라는 이름의 네임스페이스를 생성합니다:

kubectl create namespace ckad-prep-volumes

이 네임스페이스를 현재 컨텍스트 네임스페이스로 설정합니다:

kubectl config set-context --current --namespace=ckad-prep-volumes

현재 네임스페이스를 확인합니다:

kubectl config view --minify --output 'jsonpath={..namespace}'; echo

예상 출력:

ckad-prep-volumes

Pod 로컬 임시 데이터를 위한 emptyDir 사용

이 단계에서는 emptyDir 볼륨을 사용하는 Pod 를 생성합니다.

emptyDir 볼륨은 Pod 가 생성될 때 비어 있는 상태로 시작됩니다. 동일한 Pod 내의 컨테이너들은 이를 공유 스크래치 공간, 캐시 공간 또는 임시 작업 디렉토리로 사용할 수 있습니다. 이는 Pod 가 제거된 후 데이터를 보존하기 위한 용도가 아닙니다.

emptydir-pod.yaml 파일을 생성합니다:

cat > emptydir-pod.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
  name: scratch-worker
  labels:
    app: scratch-worker
spec:
  terminationGracePeriodSeconds: 0
  volumes:
  - name: scratch-space
    emptyDir: {}
  containers:
  - name: worker
    image: busybox:1.36
    command:
    - /bin/sh
    - -c
    - 'echo scratch-ready > /scratch/status.txt; sleep 3600'
    volumeMounts:
    - name: scratch-space
      mountPath: /scratch
EOF

매니페스트를 적용합니다:

kubectl apply -f emptydir-pod.yaml

예상 출력:

pod/scratch-worker created

Pod 가 준비될 때까지 기다립니다:

kubectl wait --for=condition=Ready pod/scratch-worker --timeout=120s

예상 출력:

pod/scratch-worker condition met

마운트된 emptyDir 볼륨에서 파일을 읽어옵니다:

kubectl exec scratch-worker -c worker -- cat /scratch/status.txt

예상 출력:

scratch-ready

Pod 의 볼륨 타입을 확인합니다. jsonpath 표현식은 볼륨 이름을 출력하고 이것이 emptyDir임을 확인해 줍니다.

kubectl get pod scratch-worker -o 'jsonpath={.spec.volumes[0].name}{" emptyDir\n"}'

예상 출력:

scratch-space emptyDir

PersistentVolumeClaim 에 데이터 쓰기

이 단계에서는 PersistentVolumeClaim(PVC) 을 생성하고 이를 작성자 (writer) Pod 에 마운트합니다.

PersistentVolumeClaim(PVC) 은 애플리케이션의 스토리지 요청입니다. 이 실습에서 standard StorageClass 는 해당 요청에 대해 동적으로 스토리지를 제공합니다. Pod 는 이 클레임을 /data 경로에 마운트하고 파일을 작성합니다.

notes-pvc.yaml 파일을 생성합니다:

cat > notes-pvc.yaml <<'EOF'
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: notes-pvc
spec:
  accessModes:
  - ReadWriteOnce
  storageClassName: standard
  resources:
    requests:
      storage: 1Mi
EOF

PVC 를 적용합니다:

kubectl apply -f notes-pvc.yaml

예상 출력:

persistentvolumeclaim/notes-pvc created

PVC 가 Bound 상태가 될 때까지 기다립니다:

kubectl wait --for=jsonpath='{.status.phase}'=Bound pvc/notes-pvc --timeout=120s

예상 출력:

persistentvolumeclaim/notes-pvc condition met

PVC 를 마운트하는 작성자 Pod 를 생성합니다:

cat > pvc-writer-pod.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
  name: pvc-writer
  labels:
    app: pvc-writer
spec:
  terminationGracePeriodSeconds: 0
  volumes:
  - name: notes-storage
    persistentVolumeClaim:
      claimName: notes-pvc
  containers:
  - name: writer
    image: busybox:1.36
    command:
    - /bin/sh
    - -c
    - 'echo persistent-note > /data/note.txt; sleep 3600'
    volumeMounts:
    - name: notes-storage
      mountPath: /data
EOF

작성자 Pod 를 적용하고 준비될 때까지 기다립니다:

kubectl apply -f pvc-writer-pod.yaml
kubectl wait --for=condition=Ready pod/pvc-writer --timeout=120s

예상 출력:

pod/pvc-writer created
pod/pvc-writer condition met

PVC 마운트에서 파일을 읽어옵니다:

kubectl exec pvc-writer -c writer -- cat /data/note.txt

예상 출력:

persistent-note

새 Pod 에서 PVC 재사용하기

이 단계에서는 작성자 Pod 를 삭제하고, 동일한 PVC 를 마운트하는 새로운 읽기 (reader) Pod 를 생성하여 파일이 그대로 남아 있는지 확인합니다.

이것이 Pod 로컬 임시 데이터와 영구 스토리지의 실질적인 차이점입니다. 작성자 Pod 는 제거될 수 있지만, PVC 는 그대로 유지됩니다. 새로운 Pod 는 동일한 클레임을 마운트하여 데이터를 읽을 수 있습니다.

작성자 Pod 를 삭제합니다:

kubectl delete pod pvc-writer

예상 출력:

pod "pvc-writer" deleted

동일한 PVC 를 마운트하는 읽기 Pod 를 생성합니다:

cat > pvc-reader-pod.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
  name: pvc-reader
  labels:
    app: pvc-reader
spec:
  terminationGracePeriodSeconds: 0
  volumes:
  - name: notes-storage
    persistentVolumeClaim:
      claimName: notes-pvc
  containers:
  - name: reader
    image: busybox:1.36
    command:
    - /bin/sh
    - -c
    - 'cat /data/note.txt; sleep 3600'
    volumeMounts:
    - name: notes-storage
      mountPath: /data
EOF

읽기 Pod 를 적용하고 준비될 때까지 기다립니다:

kubectl apply -f pvc-reader-pod.yaml
kubectl wait --for=condition=Ready pod/pvc-reader --timeout=120s

예상 출력:

pod/pvc-reader created
pod/pvc-reader condition met

새로운 Pod 에서 파일을 읽어옵니다:

kubectl exec pvc-reader -c reader -- cat /data/note.txt

예상 출력:

persistent-note

PVC 를 확인합니다. 원래의 작성자 Pod 가 사라졌음에도 불구하고 여전히 Bound 상태여야 합니다.

kubectl get pvc notes-pvc

예상 출력:

NAME        STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
notes-pvc   Bound    ...      1Mi        RWO            standard       <unset>                 ...

요약

Pod 로컬 임시 데이터를 위해 emptyDir 볼륨을 사용하고, 영구 스토리지를 위해 PVC 를 생성했습니다. 한 Pod 를 통해 데이터를 작성하고 해당 Pod 를 삭제한 뒤, 동일한 클레임을 마운트한 새로운 Pod 에서 데이터를 읽어보았습니다. 이제 임시 Pod 데이터를 위해 언제 ephemeral 스토리지를 사용해야 하는지, 그리고 Pod 교체 후에도 유지되어야 하는 데이터를 위해 언제 영구 스토리지를 요청해야 하는지 이해하게 되었습니다.