[Kubernetes] 볼륨(Volume)

컨테이너는 어떻게 외부 디스크 스토리지에 접근할까? 컨테이너 간 리소스 공유는 어떻게 할까?

파드 내부 각 컨테이너는 고유하게 분리된 파일시스템을 가지고 있다. 파일시스템은 컨테이너 이미지에서 제공되기 때문이다. 따라서 새로 시작된 컨테이너는 이전에 실행되었던 컨테이너가 작성한 파일시스템의 어떤 항목도 볼 수 없다.

스토리지 볼륨을 정의하면 컨테이너가 재시작되더라도 데이터를 보존할 수 있다. 혹은 여러 컨테이너가 데이터를 공유할 수도 있다.

볼륨 (Volume)

파드의 구성요소로 파드 스펙을 통해 정의할 수 있으며 파드 내의 모든 컨테이너에서 사용 가능하다. 각 컨테이너가 이 볼륨에 접근하려면 컨테이너에서 볼륨을 각각 마운트해야 한다.

참고로 리눅스에서는 파일시스템을 파일트리의 임의 경로에 마운트할 수 있다. 따라서 컨테이너에서 마운트하면 그 경로를 통해 파일시스템에 접근 가능하다.

즉 컨테이너 A와 B가 있을 때 동일한 볼륨을 A는 /var/log/app으로 B는 /var/log/src로 마운트한다면, 동일 볼륨을 각각 컨테이너에서 지정한 경로를 통해 접근할 수 있게 된다.

이런 볼륨을 이용하면 다음과 같이 사이드카 서비스를 구축하기 쉬울 것이다.

웹서버와 로그 포워더

웹 서버 컨테이너는 웹 서버로 동작하고 로그는 /var/log로 지정된 emptyDir 볼륨에 저장한다. 웹서버가 바로 로그를 Elastic Search 같은 중앙화된 로그 저장소로 보낼 수도 있지만 이는 좋은 방법이 아니다. 웹 서버에 부하를 주고 로깅 실패가 시스템의 장애로 연결될 수도 있기 때문이다.

이 경우, 사이드카 컨테이너를 하나 추가해 볼륨에 쌓이는 로그를 ES로 던져주는 역할을 하면 좋을 것이다.

볼륨 유형

볼륨에는 여러 유형이 있다.

  • emptyDir: 빈 디렉터리로 데이터를 저장하는 데 이용된다.
  • hostPath: 노드의 파일시스템을 마운트해 사용할 때 사용하며, 컨테이너간 데이터 공유 목적으로 사용하진 않는다.
  • nfs: NFS 공유를 파드에 마운트한다.
  • gitRepo: Git repository를 클론해 볼륨을 생성한 것이다.
  • 기타 클라우드 프로바이더의 전용 스토리지: GCE Persistent Disk, AWS Elastic Block Store
  • cinder, cephfs, iscsi, flocker, glusterfs, quobyte, rbd, flexVolume, vsphere Volume... : 다른 유형의 네트워크 스토리지 마운트에 사용
  • configMap, secret, downwardAPI: 쿠버네티스 리소스나 클러스터 정보를 파드에 노출하는 데 사용
  • persistentVolumeClaim: 사전에 구성되거나 동적으로 프로비저닝된 퍼시스턴트 스토리지 이용에 사용

참고로 gitRepo 볼륨의 경우 생성된 후에는 Repository와 동기화하지 않는다. 볼륨이 생성된 후 새로운 커밋이 푸시되더라도 반영되진 않는다는 얘기다. 다만, 레플리케이션컨트롤러가 파드를 관리하는 경우, 파드가 삭제되어 다시 생성되게 되면 최신 커밋을 포함하게 된다.

워커 노드 파일시스템의 파일 접근

hostPath 볼륨을 이용하면 노드의 파일시스템에 접근할 수 있다. 따라서 hostPath 볼륨은 gitRepo나 emptyDir 볼륨과는 다르게 파드가 종료되더라도 내부 데이터가 제거되지 않는다.

hostPath 볼륨은 로그조회, k8s 구성파일, CA 인증서 등을 접근하기 위해 사용하는 것이 보통이고, 데이터베이스를 위한 퍼시스턴스 스토어로 이용하는 것은 안티 패턴에 해당한다.

즉, 노드의 시스템 파일에 대한 READ/WRITE시에만 사용하고 여러 파드 간 데이터 공유 및 유지를 위해서는 사용하지 말아야 한다.

퍼시스턴트 스토리지(Persistent Storage)

파드는 생성되고 제거된다. 만약 데이터베이스를 K8S에서 관리한다면 데이터는 어디에 저장되어야 할까?

emptyDir은 파드 내 볼륨이므로 파드의 라이프사이클에 종속적이다. 파드가 제거되면 데이터도 제거된다.

hostPath는 노드의 시스템 파일을 관리할 때만 사용하는 것이므로 데이터를 저장하기엔 부적합하다.

데이터를 유지하고 여러 파드, 여러 컨테이너가 공유하기 위해서는 퍼시스턴트 스토리지를 이용해야 한다.

외부 스토리지 볼륨 이용

클라우드 프로바이더가 제공하는 스토리지나 NFS 같은 외장 스토리지를 볼륨에 마운트해 사용할 수 있다.

하지만 외부 스토리지를 직접 이용하는 것은 몇가지 단점이 있어 별로 좋은 방법이 아니다.

  1. 개발자가 실제 네트워크 스토리지 인프라에 대한 지식을 갖춰야 한다.
  2. 스토리지 기술과 쿠버네티스 클러스터가 강하게 바인딩 되어 동일한 파드 정의를 다른 클러스터에 사용하기 어렵다.
  3. 개발자가 선언적으로 요청하면 쿠버네티스가 필요한 리소스를 배분한다는 쿠버네티스의 기본 원칙에 반한다.

따라서, 가능은 하지만 더 나은 방법을 찾아야 하며, 보통 퍼시스턴트볼륨과 퍼시스턴트볼륨클레임을 사용하는 방법이 권장된다.

퍼시스턴트볼륨과 퍼시스턴트볼륨클레임 (PersistentVolume & PersistentVolumeClaim)

퍼시스턴트볼륨은 클러스터 관리자가 기반 스토리지를 설정하고 생성하는 리소스이고, 퍼시스턴트볼륨클레임은 개발자가 필요한 리소스를 쿠버네티스에 요청하기 위해 만드는 메니페스트다.

위 2개 개념을 활용하면 개발자는 실제 스토리지에 대해서는 고민할 필요가 없이 필요한 스토리지에 대해서 "묘사"만 하면 된다. 이 "묘사"가 퍼시스턴트볼륨클레임(PVC)이며, 쿠버네티스가 이 "묘사"에 매칭되는 퍼시스턴트볼륨을 찾아 바인딩한다.

쿠버네티스 관리자는 기반 스토리지를 설정하고 쿠버네티스 API 서버로 퍼시스턴트볼륨 리소스를 생성해 쿠버네티스에 등록한다. 생성 후에는 크기와 지원 가능한 접근 모드를 지정한다.

PVC에는 1) 볼륨의 최소 크기, 2) 필요한 접근 모드가 명시되어 있고, 이를 쿠버네티스 API에 게시하면 쿠버네티스는 적절한 볼륨을 클레임에 바인딩한다.

퍼시스턴트볼륨과 클러스터 노드는 파드나 퍼시스턴트볼륨클레임과 달리 특정 네임스페이스에 속하지 않는다.

퍼시스턴트볼륨은 클러스터 수준의 리소스로, 특정 네임스페이스에서 생성할 수 없고 동일한 네임스페이스의 파드에서만 사용 가능하다.

퍼시스턴트볼륨의 리클레임

persistentVolumeReclaimPolicy는 3가지가 있다.

  • Retain: 클레임과 파드를 삭제해도 볼륨의 데이터는 보존되며 볼륨을 수동으로 삭제하고 다시 생성하지 않으면 이용할 수 없다.
  • Recycle: 클레임과 파드가 삭제되면 볼륨의 콘텐츠를 삭제하고 다시 이용가능해 진다.
  • Delete: 클레임과 파드가 삭제되면 볼륨도 삭제된다.

동적 프로비저닝

앞서 설명하기로는 쿠버네티스관리자가 수동으로 퍼시스턴트볼륨을 생성해야만 이용이 가능했다. 하지만 동적 프로비저닝을 이용하면 이조차 불필요해 진다.

퍼시스턴트볼륨 프로비저너(PersistentVolume Provisioner)를 이용하면 선택할 수 있는 하나 이상의 볼륨 타입을 스토리지클래스(StorageClass) 오브젝트로 정의할 수 있고, 개발자는 PVC에 스토리지 클래스를 참조하면 된다. PVC 요청이 진행될 때 동적으로 스토리지클래스에 해당하는 퍼시스턴트볼륨이 생성된다.

즉, 관리자가 많은 퍼시스턴트볼륨을 미리 프로비저닝할 필요가 없다. 스토리지클래스를 정의해 놓으면, 온디맨드로 생성된다.

스토리지클래스를 지정하지 않은 동적 프로비저닝

더 간단히 이용하는 방법도 있다. 스토리지클래스 지정을 하지 않고 동적 프로비저닝을 이용하는 방법이다.

storageClassName속성 지정 없이 PVC를 생성하면 기본 스토리지 클래스로 동적 프로비저닝이 된다.

PVC를 미리 프로비저닝된 퍼시스턴트볼륨에 바인딩되도록 강제하기

storageClassName: "" 형식으로 빈 문자열을 지정하면 PVC가 새로운 퍼시스턴트볼륨을 동적으로 프로비저닝하는 대신 기존 PV에 바인딩된다.

요약

동적 프로비저닝은 퍼시스턴트 스토리지를 생성하고 사용하는 가장 바람직한 방법이다. storageClassName을 명시적으로 지정한 PVC와 파드만 생성함으로써 퍼시스턴트볼륨을 이용할 수 있다.