이번 포스팅에서는 Kubernetes 환경에서 NFS를 활용하여 PersistentVolume(PV)
와 PersistentVolumeClaim(PVC)
를 설정하는 방법과, ResourceQuota
를 통해 스토리지 사용량을 제한하는 방법에 대해 다룹니다. 특히, NFS
와 Kubernetes
를 연동하여 PV와 PVC를 설정하고, 여러 Pod에서 공유 스토리지를 사용하는 방법을 실습합니다.
Kubernetes 환경에서 컨테이너의 수명이 짧기 때문에 데이터를 안전하게 보존할 수 있는 스토리지 시스템이 필요합니다. NFS를 활용한 PV와 PVC 설정은 컨테이너 기반 환경에서 데이터 영속성(Persistence)을 보장하는 좋은 방법 중 하나입니다.
컨테이너는 기본적으로 일시적인 특성을 갖고 있어 Pod
가 삭제되거나 재시작되면 데이터도 함께 사라질 위험이 있습니다. 하지만 많은 애플리케이션은 데이터 영속성이 요구되며, 로그나 설정 파일, 사용자 데이터 등 중요한 정보를 안전하게 저장하고 여러 Pod
간에 공유하는 기능이 필요합니다. 이때 Persistent Storage
를 제공하는 PV와 PVC가 중요한 역할을 합니다.
NFS
NFS는
네트워크 파일 시스템(Network File System)
으로, 여러 클라이언트가 원격 파일 시스템에 접근할 수 있도록 해줍니다. Kubernetes에서 NFS를 활용해 스토리지를 제공하면, 여러 Pod가 동일한 데이터를 공유하며 사용할 수 있습니다. 이러한 스토리지 구조는 로그 저장, 공용 데이터 관리, 컨테이너 간 데이터 공유 등의 용도로 많이 사용됩니다.
NFS 서버는 Kubernetes 클러스터 외부에 위치하며, 스토리지로 사용할 디렉터리를 공유합니다. 여기서는 211.183.3.199
IP를 가진 Rocky8 서버를 NFS 서버로 설정했습니다.
NFS 패키지 설치 및 디렉터리 준비:
dnf -y install nfs-utils
mkdir /root/shared
touch /root/shared/from_nfs.txt
NFS 공유 설정:
/etc/exports
파일에 아래와 같은 설정을 추가하여 /root/shared
디렉터리를 네트워크 상에서 공유합니다.
/root/shared 211.183.3.0/24(rw,async,no_root_squash)
디렉터리 권한 설정 및 NFS 서버 활성화:
chmod 777 /root/shared -R
systemctl enable nfs-server --now
이제 NFS 서버가 설정되었으며, /root/shared
디렉터리가 네트워크에 공유되었습니다.
Kubernetes에서는 NFS 서버의 공유 디렉터리를 PersistentVolume(PV)
으로 설정할 수 있습니다. PV는 스토리지를 정의하며, PVC가 이를 요청하여 사용하게 됩니다.
apiVersion: v1
kind: PersistentVolume
metadata:
name: mypv
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
storageClassName: gildong
nfs:
path: /root/shared
server: 211.183.3.199
capacity
: PV의 용량을 1Gi로 설정했습니다.accessModes
: ReadWriteMany
로 설정하여 여러 Pod에서 읽고 쓸 수 있도록 했습니다.persistentVolumeReclaimPolicy
: Retain
으로 설정해 PV를 사용 중지해도 데이터가 삭제되지 않도록 했습니다.nfs
: NFS 서버와 경로를 지정합니다.적용 명령어:
kubectl apply -f mypv.yml
PVC는 Pod가 스토리지를 요청할 때 사용하는 리소스입니다. 앞서 생성한 mypv
와 연결하여 Pod에서 사용할 수 있도록 설정합니다.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mypvc
spec:
resources:
requests:
storage: 1Gi
accessModes:
- ReadWriteMany
storageClassName: gildong
requests.storage
: PVC가 요청하는 스토리지 용량을 1Gi로 설정했습니다.accessModes
: PV와 동일하게 ReadWriteMany
로 설정합니다.storageClassName
: gildong
으로 설정하여 해당 StorageClass에 맞는 PV가 바인딩됩니다.적용 명령어:
kubectl apply -f mypvc.yml
PVC를 사용하는 Pod를 생성하여 NFS 공유 디렉터리를 Pod 내 특정 경로에 마운트합니다.
apiVersion: v1
kind: Pod
metadata:
name: myapp
labels:
name: myapp
spec:
containers:
- name: myapp
image: nginx
resources:
limits:
memory: "128Mi"
cpu: "500m"
ports:
- containerPort: 80
volumeMounts:
- name: myvol
mountPath: /test
volumes:
- name: myvol
persistentVolumeClaim:
claimName: mypvc
volumeMounts
: 컨테이너 내 /test
경로에 mypvc
를 마운트합니다.volumes
: mypvc
를 참조하여 스토리지를 연결합니다.적용 명령어:
kubectl apply -f mypod.yml
Pod가 정상적으로 NFS 디렉터리를 마운트했는지 확인합니다.
kubectl exec myapp -- ls /test
from_nfs.txt
파일이 보이면 성공입니다. 또한, Pod 내부에서 새로운 파일을 생성하여 NFS 서버에 반영되는지 확인할 수 있습니다.
kubectl exec myapp -- touch /test/from_pod.txt
NFS 서버에서도 /root/shared/from_pod.txt
파일이 생성된 것을 확인할 수 있습니다.
NFS는 디렉터리와 디렉터리를 연결하는 bind 마운트 방식이므로, 지정한 PV 용량을 넘어서는 데이터 저장이 가능합니다. 이를 제한하기 위해 ResourceQuota
를 설정하여 네임스페이스 내 전체 PVC 사용량을 제한할 수 있습니다.
아래 설정을 통해 네임스페이스에서 최대 3Gi까지의 스토리지만 사용할 수 있도록 제한합니다.
apiVersion: v1
kind: ResourceQuota
metadata:
name: testquota
namespace: default
spec:
hard:
persistentvolumeclaims: "5"
requests.storage: "3Gi"
persistentvolumeclaims
: 네임스페이스 내에서 사용할 수 있는 PVC의 최대 개수를 5개로 제한합니다.requests.storage
: 네임스페이스 내에서 요청할 수 있는 스토리지 용량의 총합을 3Gi로 제한합니다.적용 명령어:
kubectl apply -f resource-quota.yml
아래와 같은 PVC 생성 명령어로 제한이 제대로 적용되는지 확인합니다.
1Gi 요청하는 PVC 생성
kubectl apply -f mypvc1.yml
2Gi 요청하는 PVC 생성
kubectl apply -f mypvc2.yml
2Gi 요청하는 PVC 추가 생성 (제한 초과)
kubectl apply -f mypvc3.yml
Error from server (Forbidden): error when creating "mypvc3.yml": persistentvolumeclaims "mypvc3" is forbidden: exceeded quota: testquota, requested: requests.storage=2Gi, used: requests.storage=3Gi, limited: requests.storage=3Gi
mypvc3
는 요청한 스토리지가 ResourceQuota
제한(3Gi)을 초과했으므로 생성되지 않고, exceeded quota
오류가 발생합니다.
kubectl get pvc
출력 예시는 아래와 같습니다.
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
mypvc Bound mypv 1Gi RWX gildong 1m
mypvc1 Bound mypv1 1Gi RWX gildong 1m
mypvc2 Pending <none> 2Gi RWX gildong 1m
mypvc2
는 PV가 아직 바인딩되지 않아 Pending
상태에 있습니다.mypvc3
는 ResourceQuota
초과로 생성되지 않았습니다.위의 설정에서는 정적 PV를 생성했지만, NFS를 동적 프로비저닝으로 사용하려면 Kubernetes에서 NFS External Provisioner를 설치해야 합니다. Helm을 사용해 설치할 수 있으며, 이를 통해 PVC가 생성될 때마다 NFS에서 자동으로 디렉터리를 생성하고 관리할 수 있습니다.
NFS와 Kubernetes의 PV/PVC 설정을 통해 스토리지의 영속성을 확보하면서도 여러 Pod에서 데이터에 접근할 수 있는 환경을 구축할 수 있습니다. 이 방식의 주요 장점은 데이터 공유와 안정성입니다.
다만, 다음과 같은 단점도 고려해야 합니다.
- 성능 : 네트워크 지연 및 대역폭 제한으로 인해 많은 Pod에서 데이터를 동시에 사용하는 경우 성능 저하가 발생할 수 있습니다.
- 용량 초과 문제 : NFS의 디렉터리 기반 마운트 특성상 PV 용량 제한을 엄격히 관리하기 어렵습니다. 이를 보완하기 위해서는 ResourceQuota 등을 활용해 네임스페이스 단위로 용량을 제한하고, 주기적으로 스토리지 사용량을 모니터링하는 것이 필요합니다.
향후 Kubernetes 환경에서 동적 프로비저닝(Dynamic Provisioning) 설정을 추가하여, NFS에서 자동으로 스토리지를 관리하고 운영을 효율화할 수 있습니다. 또한, 여러 서비스 간에 데이터 공유가 필요한 상황이나, 로그 및 설정 파일을 저장하는 데 유용하게 사용할 수 있습니다.