Post

[K8s] Kubernetes에서 NFS 스토리지 연동하기

Kubernetes에서 NFS 서버를 연동해 동적 Persistent Volume을 구성하고 Pod와 연동 해보자.

[K8s] Kubernetes에서 NFS 스토리지 연동하기

안녕하세요. Kubernetes 환경에서 NFS(Network File System)를 스토리지로 연동하는 방법을 정리해 보았습니다.

Kubernetes에서 NFS를 사용할 때는 크게 두 가지 방식(정적 PV, 동적 PVC)이 있습니다. 두 방식의 개념과 차이점을 모두 설명하지만, 실습 예제는 동적 PVC 기반으로 진행합니다. 실무에서 가장 많이 쓰이는 자동화 방식이며, Helm Chart와 연계해 쉽게 배포할 수 있기 때문입니다.

구성 아키텍처

이번 실습에서 진행할 전체 흐름입니다.

nfs아키텍처

  1. NFS 서버(192.168.0.116)에 공유 디렉토리(/srv/nfs/kubedata) 생성
  2. Kubernetes 클러스터 내에서 Helm으로 NFS Provisioner(nfs-subdir-external-provisioner) 설치
  3. NFS를 사용하는 PVC를 생성하여 Pod에 마운트
  4. BusyBox Pod에서 access log를 기록하고, NFS 서버에 파일이 실제로 적재되는지 확인
    (예: /srv/nfs/kubedata/default-busybox-test-pvc-<uid>/access.log)

실습은 동적 PVC 기반으로 진행하며, 자동으로 NFS 경로가 생성되고 Pod에서 파일을 쓸 수 있는지 검증합니다.


NFS란?

NFS(Network File System)는 네트워크를 통해 여러 서버와 클라이언트가 파일을 공유할 수 있게 해주는 표준 프로토콜입니다. NAS(Network Attached Storage)처럼 여러 시스템에서 동시에 파일을 읽고 쓸 수 있어, Kubernetes의 여러 Pod가 데이터를 공유하는 데 적합합니다.

TIP: NFS는 여러 Pod가 동시에 파일을 읽고 쓸 수 있는 ReadWriteMany(RWX) 접근 모드를 지원합니다. DB, 로그, 공유 데이터 등 다양한 워크로드에 활용됩니다.


NFS 서버 설치 방법

NFS 서버는 외부 또는 내부 VM에 설치할 수 있으며, Ubuntu 기준 아래 명령어로 설치합니다. (사전에 보안 설정, 방화벽, 네트워크 접근 제어도 반드시 확인)

1
2
sudo apt update
sudo apt install -y nfs-kernel-server

NFS 공유 디렉토리 생성:

1
2
3
sudo mkdir -p /srv/nfs/kubedata
sudo chown nobody:nogroup /srv/nfs/kubedata
sudo chmod 777 /srv/nfs/kubedata

/etc/exports 설정:

1
2
3
echo "/srv/nfs/kubedata *(rw,sync,no_subtree_check,no_root_squash)" | sudo tee -a /etc/exports
sudo exportfs -rav
sudo systemctl restart nfs-kernel-server

참고: 실무에서는 * 대신 특정 클러스터 노드 IP만 허용하는 것이 안전합니다. 예: 192.168.0.0/24(rw,sync,no_subtree_check,no_root_squash)


PV란?

storage

PV(Persistent Volume)는 Kubernetes 클러스터에서 관리자가 직접 생성하거나, 동적 프로비저너에 의해 자동으로 생성되는 영구 저장소 리소스입니다. PV는 실제 스토리지(NFS, Ceph, AWS EBS 등)와 연결되어 있으며, Pod가 데이터를 안전하게 저장·공유할 수 있도록 합니다.

  • PV는 클러스터 내에서 독립적으로 존재하며, 여러 PVC가 바인딩될 수 있습니다.
  • 접근 모드(ReadWriteOnce, ReadWriteMany 등), 용량, 스토리지 타입(NFS, 블록 등)을 명시할 수 있습니다.
  • PVC가 PV를 요청하면, Kubernetes가 자동으로 바인딩하여 Pod에 마운트합니다.

TIP: PV는 스토리지의 실제 경로, 서버 정보, 권한 등을 직접 지정할 수 있어, 외부 시스템 연동이나 고정 경로가 필요한 경우에 유용합니다.


StorageClass란?

StorageClass는 Kubernetes에서 동적 볼륨(PV)을 생성할 때 사용하는 스토리지 유형, 프로비저닝 방식, 파라미터 등을 정의하는 리소스입니다. 즉, 어떤 스토리지(예: NFS, Ceph, AWS EBS 등)를 어떤 방식으로, 어떤 옵션으로 사용할지 미리 지정해두는 역할입니다.

  • StorageClass를 지정하면 PVC 생성 시 자동으로 해당 스토리지 타입의 PV가 만들어집니다.
  • provisioner 필드로 동적 프로비저너(예: nfs-subdir-external-provisioner)를 지정할 수 있습니다.
  • parameters를 통해 NFS 서버 주소, 경로, 파일 시스템 타입 등 세부 옵션을 설정할 수 있습니다.
  • 여러 StorageClass를 만들어 환경별(테스트/운영), 스토리지별(NFS/블록)로 분리 관리할 수 있습니다.

TIP: StorageClass를 활용하면 스토리지 자동화, 환경별 분리, 다양한 스토리지 타입을 유연하게 관리할 수 있습니다. PVC에서 storageClassName을 명시하지 않으면 기본 StorageClass가 사용됩니다.


PVC란?

PVC(PersistentVolumeClaim)는 Kubernetes에서 Pod가 영구 저장소(Persistent Volume)를 요청할 때 사용하는 리소스입니다. 사용자는 원하는 용량, 접근 방식(ReadWriteOnce/ReadWriteMany 등), StorageClass 등을 명시해 PVC를 생성하면, Kubernetes가 자동으로 적합한 PV를 연결해줍니다. PVC를 통해 Pod가 외부 스토리지(NFS 등)를 안전하게 사용할 수 있습니다.

주의: PVC의 storageClassName을 지정하지 않으면 기본 StorageClass가 사용됩니다. NFS 기반 동적 PVC를 원한다면 반드시 NFS StorageClass를 명시하세요.


StorageClass 구성

nfs-subdir-external-provisioner를 Helm으로 설치하면, PVC 생성 시 자동으로 NFS 경로를 만들어주는 동적 프로비저닝이 가능해집니다. (NFS 서버와 Kubernetes 노드 간 네트워크가 반드시 열려 있어야 합니다)

Helm 설치

1
2
3
4
5
6
7
8
helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner
helm repo update

helm install nfs-storage nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \
  --set nfs.server=192.168.0.116 \
  --set nfs.path=/srv/nfs/kubedata \
  --set storageClass.name=nfs-storage \
  --set storageClass.defaultClass=true

3. 동적 PVC 구성 방식 (자동 프로비저닝)

동적 PVC는 StorageClass를 기반으로 PVC만 생성하면, PV와 NFS 경로가 자동 생성됩니다. 즉, 사용자는 StorageClass와 PVC만 정의하면 되고, 실제 NFS 디렉토리 생성·PV 바인딩은 프로비저너가 알아서 처리합니다.

동적 PVC 구성 흐름

  1. NFS 서버 준비 및 공유 디렉토리 생성 (예: /srv/nfs/kubedata)
  2. nfs-subdir-external-provisioner Helm Chart로 설치 (자동 프로비저닝)
  3. StorageClass 생성 (예: nfs-storage)
  4. PVC 생성 시 storageClassName: nfs-storage 지정
  5. Pod에서 PVC를 마운트하면, NFS 서버에 자동으로 디렉토리가 생성되고 데이터가 저장됨

동적 PVC 배포

1
2
3
4
5
6
7
8
9
10
11
12
# busybox-test-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: busybox-test
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
  storageClassName: nfs-storage
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# nfs-test-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nfs-test-pod
spec:
  containers:
    - name: busybox
      image: busybox
      command: ["/bin/sh", "-c"]
      args:
        - |
          mkdir -p /mnt/logs;
          while true; do
            echo $(date) >> /mnt/logs/access.log;
            sleep 5;
          done
      volumeMounts:
        - name: nfs-volume
          mountPath: /mnt
  volumes:
    - name: nfs-volume
      persistentVolumeClaim:
        claimName: busybox-test

Pod가 실행되면 NFS 서버에는 /srv/nfs/kubedata/default-busybox-test-pvc-<uid> 경로가 자동 생성되고 로그가 저장됩니다.

참고: Pod가 삭제되어도 PVC가 남아 있으면 NFS 경로와 데이터는 유지됩니다. PVC까지 삭제해야 완전히 정리됩니다.


4. 배포 및 NFS 서버 확인

1) 리소스 배포

1
2
kubectl apply -f busybox-test-pvc.yaml
kubectl apply -f nfs-test-pod.yaml

2) Pod 정상 동작 확인

1
2
kubectl get pod nfs-test-pod
kubectl logs nfs-test-pod
  • 로그에 access.log 파일에 기록되는 내용이 출력되는지 확인

3) NFS 서버에서 파일 적재 확인

NFS 서버에 접속하여 아래 경로에 access.log 파일이 생성되고, 내용이 계속 추가되는지 확인합니다.

1
2
ls /srv/nfs/kubedata/default-busybox-test-pvc-<uid>/
tail -f /srv/nfs/kubedata/default-busybox-test-pvc-<uid>/logs/access.log

예시 결과:

1
2
3
4
Wed Aug 6 08:31:26 UTC 2025
Wed Aug 6 08:31:31 UTC 2025
Wed Aug 6 08:31:36 UTC 2025
...
  • 여러 Pod에서 동시에 파일을 쓸 수 있는지, 로그가 정상적으로 쌓이는지 확인

실무 TIP: PVC와 Pod를 삭제하면 NFS 경로와 파일이 어떻게 처리되는지도 함께 테스트해보세요.


4. 정적 PV / PVC 구성 방식 (수동 프로비저닝)

정적 PV는 관리자가 직접 NFS 서버에 디렉토리를 만들고, PV 리소스에 해당 경로를 명시적으로 지정합니다. PVC는 특정 PV를 바인딩하도록 volumeName을 지정합니다. 이 방식은 외부 시스템 연동, 고정 경로, 권한 제어가 필요한 경우에 적합합니다.

정적 PV/PVC 구성 흐름

  1. NFS 서버에 수동으로 디렉토리 생성 (예: /srv/nfs/manualdata/myapp)
  2. PV 리소스에 해당 경로와 서버 정보 명시
  3. PVC에서 volumeName으로 PV를 직접 지정
  4. Pod에서 PVC를 마운트하면, 지정한 NFS 경로에 데이터가 저장됨

정적 PV/PVC 예시

1
2
3
4
5
6
7
8
9
10
11
12
13
apiVersion: v1
kind: PersistentVolume
metadata:
  name: myapp-pv
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  nfs:
    server: 192.168.0.116
    path: /srv/nfs/manualdata/myapp
1
2
3
4
5
6
7
8
9
10
11
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: myapp-pvc
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
  volumeName: myapp-pv

정적 vs 동적 비교

항목동적 PVC정적 PV/PVC
디렉토리 생성❌ 자동 생성 (프로비저너가 생성)✅ 수동 생성 (관리자가 직접 생성)
디렉토리 이름 제어❌ 불가 (자동 생성, 규칙 기반)✅ 가능 (원하는 경로 지정)
Helm/CI/CD 적합✅ 매우 적합 (자동화, 반복 배포)❌ 번거로움 (수동 관리 필요)
권한·보안 제어❌ 어렵다 (자동 생성 경로, 권한 제어 제한)✅ 유리 (경로별 권한, 외부 연동)
운영 자동화✅ 쉬움 (PVC만 만들면 됨)❌ 수동 개입 필요 (디렉토리·PV 직접 관리)
실무 활용도자동화, 확장성, 공유 데이터외부 연동, 고정 경로, 특수 권한
삭제 시 데이터PVC 삭제 시 NFS 경로 자동 삭제 가능PV/PVC 삭제 시 직접 정리 필요
대표 활용앱 로그, 임시 데이터, CI/CD외부 시스템 연동, DB, 고정 경로

마무리

  • Kubernetes에서 NFS를 스토리지로 사용하는 방식은 매우 유연하며, 동적 PVC 덕분에 자동화와 확장성에 유리합니다.
  • 특수한 경우(예: 외부 시스템 연동, 정해진 경로 필요)에는 정적 PV 방식도 병행할 수 있습니다.
  • nfs-subdir-external-provisioner는 간단하게 Helm으로 설치 가능하고, 실무에서도 널리 사용됩니다.

참고

This post is licensed under CC BY 4.0 by the author.