[Kubernetes] Kubernetes에서 EFS 연결하기: PVC 생성부터 파일 공유까지

728x90

쿠버네티스 실습에서 PVC를 만들고 컨테이너에 연결했지만, 처음에는 파일이 정확히 어디에 저장되는지 헷갈렸다.

이번 글에서는 이미 만들어진 AWS EFS를 사용한다는 가정으로, YAML 파일을 작성하고 두 Pod가 파일을 공유하는 과정까지 정리한다. 실습 이름은 모두 parkgyul을 사용한다.

1. 전체 구조

EFS는 여러 서버가 네트워크로 연결해 함께 사용할 수 있는 AWS의 파일 저장소다.

컨테이너 안에서 /data에 파일을 저장하더라도, 그 폴더에 EFS를 연결했다면 실제 파일은 EFS에 저장된다.

여기에 등장하는 용어는 다음과 같다.

EFS 실제 파일을 보관하는 네트워크 파일 시스템 공용 창고
StorageClass 저장 공간을 어떻게 준비할지 정의 창고 배정 규칙
PVC 사용할 저장 공간을 요청하는 쿠버네티스 리소스 창고 사용 신청서
PV 실제 저장소의 연결 정보를 가진 쿠버네티스 리소스 배정된 창고의 연결 정보
마운트 저장 공간을 컨테이너의 폴더에 연결 작업실에 창고 출입문 설치

 

 

PVC와 PV가 파일을 직접 보관하는 것은 아니다. 쿠버네티스가 실제 EFS 저장 공간을 찾아 컨테이너에 연결하도록 돕는 설정이다.

연결이 완료되면 컨테이너의 파일 읽기·쓰기는 마운트된 EFS를 통해 이루어진다.

2. 준비되어 있어야 하는 것

이 글은 다음 설정이 이미 준비된 환경을 기준으로 한다.

  • AWS EFS 파일 시스템
  • 노드에서 EFS로 접근할 수 있는 네트워크 설정
  • AWS EFS CSI Driver와 필요한 AWS 권한
  • EFS 동적 프로비저닝용 StorageClass인 efs-sc-shared
  • 실습 네임스페이스인 class

EFS CSI Driver는 쿠버네티스가 EFS를 볼륨으로 연결할 수 있도록 해주는 구성 요소다. 

맥 터미널에서 준비된 설정을 확인한다.

kubectl get namespace class
kubectl get storageclass efs-sc-shared -o yaml

StorageClass에는 일반적으로 다음과 같은 설정이 들어 있다.

provisioner: efs.csi.aws.com
parameters:
  provisioningMode: efs-ap
  fileSystemId: fs-...

fileSystemId는 미리 만들어진 EFS의 ID다. 이 설정을 통해 쿠버네티스는 어느 EFS를 사용할지 알게 된다.

EFS가 존재하는 것만으로 PVC가 자동 연결되지는 않는다. 드라이버, 권한, 네트워크, StorageClass까지 준비되어 있어야 한다.

3. PVC를 만드는 YAML 작성하기

맥 터미널에서 다음 명령을 실행한다. 현재 폴더에 pvc.yaml 파일이 만들어진다.

cat <<'EOF' > pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: parkgyul-efs-pvc
  namespace: class
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: efs-sc-shared
  resources:
    requests:
      storage: 100Mi
EOF

 

주요 설정의 의미는 다음과 같다.

kind: PersistentVolumeClaim PVC를 생성한다
name: parkgyul-efs-pvc PVC 이름을 지정한다
namespace: class PVC를 만들 네임스페이스다
ReadWriteMany 여러 노드에서 읽고 쓰는 공유 사용을 요청한다
storageClassName: efs-sc-shared 사용할 저장소 준비 방식을 지정한다
storage: 100Mi 요청 용량을 적는다

EFS에서는 100Mi가 실제 저장 공간의 상한을 설정하는 값은 아니다. 쿠버네티스 PVC에 필요한 요청 용량이며, EFS CSI Driver는 이 값을 디렉터리별 용량 제한으로 적용하지 않는다.

 

작성한 파일을 적용한다.

kubectl apply -f pvc.yaml

 

생성 상태를 확인한다.

kubectl get pvc parkgyul-efs-pvc -n class

 

다음은 출력 예시다.

NAME               STATUS   VOLUME        CAPACITY   ACCESS MODES   STORAGECLASS
parkgyul-efs-pvc    Bound    pvc-...       100Mi      RWX            efs-sc-shared

 

Bound는 PVC와 PV가 연결되었다는 뜻이다. 아직 컨테이너에 마운트한 단계는 아니다.

4. PVC를 만들었을 때 AWS에서 일어나는 일

이번에 사용하는 efs-ap 동적 프로비저닝 방식에서는 기존 EFS 안에 Access Point를 생성하고, 해당 저장 영역에 연결할 PV를 자동으로 준비한다. 

즉, PVC를 만들 때마다 EFS 파일 시스템 전체를 새로 만드는 것은 아니다. 이미 준비된 EFS 안에 사용할 접근 지점과 디렉터리 설정을 마련하는 방식이다.

5. Deployment에서 PVC 연결하기

PVC를 만들었으니, 이제 컨테이너의 /data에 연결한다.

이번에는 파일 공유를 확인하기 위해 동일한 PVC를 사용하는 Pod 두 개를 만든다.

cat <<'EOF' > deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: parkgyul-volume-test
  namespace: class
spec:
  replicas: 2
  selector:
    matchLabels:
      app: parkgyul-volume-test
  template:
    metadata:
      labels:
        app: parkgyul-volume-test
    spec:
      containers:
        - name: storage-test
          image: busybox:1.36
          command: ["/bin/sh", "-c"]
          args: ["sleep infinity"]
          volumeMounts:
            - name: shared-volume
              mountPath: /data
      volumes:
        - name: shared-volume
          persistentVolumeClaim:
            claimName: parkgyul-efs-pvc
EOF

여기서 중요한 부분은 세 가지다.

claimName: parkgyul-efs-pvc

사용할 PVC의 이름이다. kubectl get pvc 결과의 NAME 열에 나온 값을 넣는다. VOLUME 열의 pvc-... 값은 PV 이름이므로 이 자리에 넣지 않는다.

name: shared-volume

Pod 안에서 사용하는 볼륨 이름이다. volumes와 volumeMounts의 이름이 같아야 서로 연결된다.

mountPath: /data

컨테이너에서 저장 공간을 사용할 경로다. 이 설정 덕분에 /data에 저장한 파일이 EFS에 기록된다.

또한 PVC와 이를 사용하는 Pod는 같은 네임스페이스에 있어야 한다. 이번에는 모두 class다. 

배포하고 완료를 기다린다.

kubectl apply -f deploy.yaml

kubectl rollout status deployment/parkgyul-volume-test -n class

 

생성된 Pod를 확인한다.

kubectl get pod -n class -l app=parkgyul-volume-test

Pod 두 개가 모두 Running, READY 1/1 상태인지 확인한다.

6. 서로 다른 Pod에서 같은 파일 확인하기

Pod 이름 뒤에는 자동 생성된 문자열이 붙는다. 예제 이름을 복사하지 않고, 실제 Pod 이름을 변수에 담아 사용한다.

아래 명령은 모두 같은 맥 터미널에서 실행한다.

POD_A=$(kubectl get pod -n class \
  -l app=parkgyul-volume-test \
  -o jsonpath='{.items[0].metadata.name}')

POD_B=$(kubectl get pod -n class \
  -l app=parkgyul-volume-test \
  -o jsonpath='{.items[1].metadata.name}')

첫 번째 Pod에서 파일을 만든다.

kubectl exec -n class "$POD_A" -c storage-test -- \
  sh -c 'echo "Hello from parkgyul" > /data/hello.txt'

두 번째 Pod에서 읽는다.

kubectl exec -n class "$POD_B" -c storage-test -- \
  cat /data/hello.txt

 

예상 결과:

Hello from parkgyul

두 번째 Pod로 파일을 별도로 복사하지 않았는데도 내용이 보인다.

 

두 Pod의 /data가 같은 PVC를 통해 같은 EFS 저장 영역을 보고 있기 때문이다.

7. kubectl cp로 맥의 파일 넣기

앞에서는 컨테이너 안에서 파일을 만들었다. 이번에는 맥에 있는 파일을 공유 저장 공간으로 복사한다.

먼저 맥에서 파일을 만든다.

echo "맥에서 작성한 parkgyul의 파일" > from-parkgyul.txt

 

첫 번째 Pod의 /data로 복사한다.

kubectl cp ./from-parkgyul.txt \
  "class/$POD_A:/data/from-parkgyul.txt" \
  -c storage-test

 

이 명령의 의미는 다음과 같다.

내 맥의 from-parkgyul.txt
          ↓ kubectl cp
Pod A의 /data/from-parkgyul.txt
          ↓ /data에 EFS가 마운트되어 있음
EFS에 파일 저장

두 번째 Pod에서 확인한다.

kubectl exec -n class "$POD_B" -c storage-test -- \
  cat /data/from-parkgyul.txt

 

예상 결과:

맥에서 작성한 parkgyul의 파일

kubectl cp는 컨테이너 내부의 tar를 이용한다. 이 실습에서 사용하는 BusyBox에는 필요한 도구가 포함되어 있다. kubectl cp 공식 문서

8. 컨테이너에 직접 접속해서 확인하기

컨테이너 안을 직접 살펴보고 싶다면 다음을 실행한다.

kubectl exec -it -n class "$POD_A" -c storage-test -- /bin/sh

 

접속 후:

cd /data
ls
cat hello.txt
cat from-parkgyul.txt
exit

명령을 실행하는 위치도 구분해야 한다.

맥 터미널 kubectl apply, kubectl exec, kubectl cp
컨테이너 내부 cd, ls, cat, touch, exit

 

컨테이너 내부에서 kubectl: not found가 나오면, exit로 맥 터미널에 돌아온 뒤 실행하면 된다.

9. Pod가 새로 만들어져도 파일이 남을까?

이번 파일은 EFS에 저장되므로 Pod가 교체되어도 같은 PVC에 연결하면 다시 읽을 수 있다.

Deployment의 Pod를 새로 만들도록 요청한다.

kubectl rollout restart deployment/parkgyul-volume-test -n class

kubectl rollout status deployment/parkgyul-volume-test -n class

새 Pod에서 파일을 확인한다.

kubectl exec -n class deployment/parkgyul-volume-test \
  -c storage-test -- cat /data/from-parkgyul.txt

같은 내용이 출력되면 Pod의 수명과 저장된 데이터의 수명이 분리되어 있다는 것을 확인한 것이다.

Pod 삭제와 PVC 삭제는 다르다. PVC 삭제 후의 처리는 PV의 반환 정책과 드라이버 설정에 따라 달라지므로, 파일 유지 실험에서는 PVC를 그대로 둔다.

10. 가장 헷갈렸던 부분

폴더 이름이 같다고 같은 저장 공간은 아니다.

다음 상태에서는 두 Pod가 서로 다른 파일을 볼 수 있다.

Pod A의 /data → PVC A → 저장 영역 A
Pod B의 /data → PVC B → 저장 영역 B

같은 파일을 공유하려면 이번 실습처럼 연결해야 한다.

Pod A의 /data ─┐
              ├→ 같은 PVC → 같은 EFS 저장 영역
Pod B의 /data ─┘

또한 같은 StorageClass를 쓴다는 것만으로 파일이 공유되지는 않는다. StorageClass는 저장 공간을 준비하는 규칙이고, 별도로 만든 PVC는 서로 다른 Access Point와 디렉터리를 사용할 수 있다.

PVC로 저장 공간을 요청하고, Deployment에서 그 PVC를 /data에 연결한다. 같은 PVC를 연결한 Pod들은 같은 파일을 볼 수 있다.

728x90