[Kubernetes] Kubernetes에서 EFS 연결하기: PVC 생성부터 파일 공유까지
쿠버네티스 실습에서 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들은 같은 파일을 볼 수 있다.
'Infra&DevOps > Kubernetes, K8s' 카테고리의 다른 글
| 쿠버네티스에 React 올리기(2) (0) | 2024.03.10 |
|---|---|
| 쿠버네티스에 React 올리기 (1) - M1 맥 환경 (1) | 2024.03.10 |