'15단계로 배우는 도커와 쿠버네티스' 기반으로 내용 정리하였습니다.
K8s에 배포한 애플리케이션이 데이터를 보존하기 위해서는 내부 혹은 외부의 스토리지 시스템과 연결하여 '퍼시스턴트 볼륨(Persistent Volume)'을 이용해야 한다.
여기서 말하는 데이터의 보존이란 데이터 분실, 파손, 잘못된 변경 등을 막는 것을 말한다.
데이터 분실은 조작 실수, 해킹, 디스크 고장, 프로그램의 예외나 에러, 비정상 종료, 데드락 등에 의해 발생한다.
외부 스토리지 시스템을 사용하면 여러 개의 물리적인 장비를 묶어 단일 장애점을 극복하고 가용성을 높여 데이터 자산의 분실을 방지할 수 있다.
외부 스토리지 시스템을 사용하는 방법으로는
이 있다.
'퍼시스턴트'란 컨테이너나 파드가 종료되어도 데이터는 분실하지 않는 것을 의미한다.
그리고 '볼륨'은 외부 스토리지의 논리적인 볼륨을 컨테이너에 마운트하는 것을 의미한다.
쿠버네티스는 다양한 환경에서 일괄된 인터페이스로 운영할 수 있도록 디자인되었기 때문에 퍼시스턴트 볼륨도 외부 스토리지 시스템의 종류와 차이가 은폐되는 구조로 구현되어 있다. (추상화)
PV (PersistentVolume) 와 PVC (PersistentVolumeClaim) 개념
쿠버네티스 사상
쿠버네티스는 service account나 namespace 등의 object에서 알 수 있듯이 여러 사용자가 동시에 클러스터를 사용하는 것을 전제로 하고 있다.
쿠버네티스는 인프라에 대한 복잡성을 추상화를 통해서 간단하게 하고, 개발자들이 손쉽게 필요한 인프라 (컨테이너,디스크, 네트워크)를 설정할 수 있도록 하는 개념을 가지고 있다.
스웜 모드와 같은 간단한 컨테이너 오케스트레이션 툴과 대조되는 특징 중 하나이다.
PV (PersistentVolume) 란?
시스템 관리자가 실제 물리 디스크를 생성한 후에, 이 디스크를 PersistentVolume이라는 이름으로 쿠버네티스에 등록한다.
시스템 관리자가 생성한 물리 디스크를 쿠버네티스 클러스터에 표현한것이 PV 이다.
PVC (PersistentVolumeClaim) 란?
개발자는 Pod를 생성할때, 볼륨을 정의하고 이 볼륨 정의 부분에 물리적 디스크에 대한 특성을 정의하는 것이 아니라 PVC를 지정하여, 관리자가 생성한 PV와 연결한다.
여기서 Pod의 볼륨과 이 PV를 연결하는 관계가 PVC가 된다.
PV와 PVC의 상관관계는?
쿠버네티스는 PV와 PVC라는 개념을 통해 Persistent 볼륨을 Pod에 제공한다.
PV와 PVC는 인프라 관리자와 사용자의 입장을 고려해 설계된 볼륨 제공 방법이다.
시스템 관리자가 PV를 구성하면 사용자는 PVC를 생성(또는 관리자에게 요청: Claim) 함으로써 PV를 CPU나 메모리처럼 소모 가능한 자원으로서 사용한다.
사용자(개발자) 입장에서는 PVC라는 일종의 요청(Claim)을 통해 Persistent 볼륨을 제공받을 수 있기 때문에 실제 PV를 신경쓰지 않고도 볼륨을 사용할수 있게 된다.
PVC는 Namespaced Object이기 때문에 Namespace에 종속되어 사용된다. 그러나 PV는 Cluster Role과 비슷하게 클러스터에서 공용으로 사용될 수 있는 객체이다.
pv와 pvc는 1:1 상관관계이다.
PVC의 조건을 만족하는 PV가 없을 경우 PV를 자동으로 프로비저닝해주는 Dynamic Provisioning이 있다.
사용자가 요청한 PVC의 요구 사항이 인프라 관리자가 미리 생성해 둔 PV 중 어떠한 PV와도 일치하지 않을 시 쿠버네티스는 Dynamic Provisioning을 시도한다.
즉, Dynamic Provisioning을 사용하려면 관리자가 사전에 Storage Class의 정의 및 기능을 활성해 놓아야 한다는 뜻이 된다.
이 때 쓰이는 일종의 Specification Template인 StorageClass 라는 이름의 Object 또한 존재한다.
스토리지의 종류와 클러스터 구성
쿠버네티스와 외부 스토리지 시스템을 연동하면 데이터를 보다 안정적으로 보존하는 것이 가능하다.
한편, 클러스터 내부에서 빠르게 읽고 쓸 수 있는 볼륨을 사용하는 것도 가능하다.
먼저 내부적으로 사용할 수 있는 볼륨의 종류와 그 한계를 살펴보자.
노드 내부에서 간단하게 사용할 수 있는 볼륨으로는 emptyDir과 hostPath 가 있다.
emptyDir : 노드의 디스크를 파드가 일시적으로 사용하는 방법이다.
같은 파드의 컨테이너 간에는 볼륨을 공유할 수 있으나 다른 파드에서는 접근할 수 없다.
그리고 파드가 종료하면 emptyDir은 삭제된다. 이러한 특성에 의해 emptyDir은 데이터를 일시적으로 기록하는 용도로 사용된다.
hostPath : 동일하게 노드의 디스크를 사용하지만, 같은 노드에 배포된 서로 다른 파드에서 볼륨을 공유할 수 있다. hostPath는 파드와 함께 지워지지 않으나 각 노드의 디스크를 사용하기 때문에 다른 노드에 배포된 파드 간에 데이터를 공유할 수 없다. 그리고 노드가 정지하면 데이터에 접근할 수 없게 되므로 hostPath는 외부 스토리지가 아직 준비 중인 상황에서 간단하게 사용하는 용도 수준으로 바라봐야 한다.
외부 스토리지 시스템 : 모든 노드에서 외부 스토리지 시스템에 접근할 수 있어야 한다.
그러면 노드가 정지되어도 파드가 다른 노드에 이동하여 애플리케이션을 문제 없이 수행할 수 있다.
한 가지 주의할 것은 외부 스토리지 시스템을 사용한다고 해서 반드시 여러 노드에서 볼륨을 공유할 수 있는 건 아니라는 점이다. 이는 스토리지 시스템의 동작 방식에 따라 다르다. 즉, 서버와 스토리지를 연결하는 프로토콜 (NFS나 iSCSI등), 소프트웨어 , 그리고 클라우드의 스토리지 서비스에 따라 다르다. 예를 들어 NFS 처럼 파일 시스템을 공유하는 시스템의 경우, 여러 노드에서 볼륨을 공유할 수 있으나 iSCI처럼 블록 스토리지를 기반으로 하는 경우에는 한 개의 노드에서만 접근할 수 있다.
스토리지 시스템의 방식
퍼시스턴트 볼륨을 제공하는 주체를 의미한다. OSS (오픈 소스 소프트웨어)는 별도로 시스템을 구성해야 하는데,
온프레미스 환경과 클라우드 환경 모두에서 사용할 수 있다.
또한, ReadWrite 열의 Once는 ReadWrite 모드로 마운트 할 수 있는 노드의 수가 하나임을 의미한다.
한편, Many의 경우는 여러 노드상의 컨테이너에서 마운트하여 쓸 수 있음을 의미한다.
클라우드의 퍼시스턴트 볼륨의 경우는 구현과 스펙에 따라 동작에 차이가 있을 수 있다.
그 결과, 같은 노드의 파드 간 공유가 불가능하거나 매니페스트를 배포할 때 에러가 발생하기도 하므로 미리 확인해 보는 것이 좋다.
쿠버네티스는 인프라의 복잡성을 감추고, 통일된 인터페이스로 이용할 수 있도록 설계되었다.
스토리지의 추상화와 자동화
'추상화를 위한 K8s 오브젝트'는 퍼시스턴트 볼륨 요구 (Persistent Volume Claim,PVC) 와 퍼시스턴트 볼륨 (Persistent Volume,PV) 이 중심이 된다.
미리 PVC를 작성해 놓고 파드의 매니페스트에 PVC의 이름을 기술하면 컨테이너가 퍼시스턴트 볼륨을 마운트한다.
쿠버네티스가 외부 스토리지 시스템의 API를 사용하여 볼륨을 자동으로 준비해주는 방법에 해당한다.
프로비저닝(provisioning)은 사용자의 요구에 맞게 시스템 자원을 할당, 배치, 배포해 두었다가 필요 시 시스템을 즉시 사용할 수 있는 상태로 미리 준비해 두는 것을 말한다.
즉, 매니페스트에 PVC를 기술 → 컨테이너가 PV마운트
외부 스토리지 시스템의 설정을 직접 진행하는 방법에 해당한다.
프로비저너나 스토리지 클래스가 없어서, PVC의 매니페스트에 직접 PV명을 지정하고 있다.
그리고 PV 작성과 스토리지 설정을 직접한다.
예를 들어,기존에 사용해 오던 NFS 서버의 IP 주소나 export path 등 NFS 에 접속하기 위한 설정을 기술해야 한다. 그리고 NFS 서버에서는 K8s 클러스터 노드에서 접속할 수 있도록 설정해야 한다.
퍼시스턴트 볼륨 이용
PVC를 작성하면 PV가 자동으로 프로비저닝된다.
퍼시스턴트클레임 생성을 통한 퍼시스턴트볼륨 요청
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
# persistentVolumeClaim 의 이름으로 나중에 파드의 볼륨을 요청할 때 사용합니다
name: mongodb-pvc
spec:
resources:
# 1GiB의 스토리지를 요청합니다
requests:
storage: 1Gi
# 단일 클라이언트를 지원하는 스토리지로 읽기/쓰기를 모두 수행합니다
accessModes:
- ReadWriteOnce
storageClassName: standard
위 디스크립터를 API 서버에 게시하면 PVC가 생성되자마자 쿠버네티스는 적잘한 PV를 찾고 클레임에 바인딩한다. PV의 용량은 PVC의 요청을 수용할 만큼 커야 하며 접근 모드는 PVC에서 요청한 접근 모드를 모두 포함하고 있어야 한다. 위의 경우 PVC가 요청한 1GiB 용량과 ReadWriteOnce 접근 모드를 PV가 모두 만족하므로 PV는 PVC에 바인딩된다.
PVC 또한 kubectl get pvc 명령으로 조회할 수 있다.
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
mongodb-pvc Bound mongodb-pv 1Gi RWO,ROX 7s
[ 퍼시스턴트 볼륨 요구 API ]
[ ObjectMeta v1 meta ]
[ 퍼시스턴트 볼륨 요구 사양 ]
[ 자원 요구 사항 ]
파드에서 퍼시스턴트볼륨클레임 사용하기
이제 PV를 사용중에 있으며 볼륨을 해제할 때 까지 다른 개발자는 동일한 볼륨에 클레임을 할 수 없다.
파드 내부에서 볼륨을 사용하기 위해 다음과 같이 파드 볼륨에서 이름으로 PVC를 참조할 수 있다.
apiVersion: v1
kind: Pod
metadata:
name: mongodb
spec:
containers:
- image: mongo
name: mongodb
volumeMounts:
- name: mongodb-data
mountPath: /data/db
ports:
- containerPort: 27017
protocol: TCP
volumes:
- name: mongodb-data
# 파드 볼륨에서 이름으로 PVC를 참조합니다
persistentVolumeClaim:
claimName: mongodb-pvc
위 파드 디스크립터를 게시하여 PVC를 참조하는 볼륨을 컨테이너에 마운트하는 파드를 생성하면, 이전에 파드 디스크립터에 gcePersistentDisk 를 직접 기술해서 생성했던 것과 동일하게 동작한다. 그러나 PV와 PVC가 연결되는 구조가 생겼단 점에서 차이가 있다.
[ 볼륨 설정 ]
[ 컨테이너 내의 마운트 경로 지정 ]
NFS 서버 사용
NFS 서버란?
공유된 원격 호스트의 파일을 로컬에서 사용할 수 있도록 개발된 파일 시스템을 네트워크 파일 시스템(NFS)이라고 한다.
전통적인 유닉스 환경에서는 오랫동안 네트워크에서 자료를 공유하는 방법으로 NFS를 사용했다.
NFS 서버가 파일을 공유하면 NFS 클라이언트가 공유한 디렉터리를 마운트해서 원격 호스트(NFS 서버)의 파일을 사용한다.
NFS 서버는 간단한 설정으로 쉽게 쿠버네티스에서 활용할 수 있다. NFS 서버에서 파드에 공개할 영역을 설정한 후, PV 를 작성하면 된다. 단, 이 설정은 직접 해야 한다.
pvc에 의해 자동으로 pv를 프로비저닝해주기 때문에 운영 면에서도 부담이 적다.
동일 노드 상의 복수의 파드로부터 같은 블록 스토리지를 마운트 할 수 없다.
동일 파드 상의 컨테이너는 블록 스토리지를 각각 마운트하여 사용할 수 없다.
(설정 방법은 생략..)
클라우드에서의 동적 프로비저닝
퍼블릭 클라우드에서 퍼시스턴트 볼륨 요구(PVC)를 만들고 컨테이너에서 마운트하는 과정을 살펴보자.
(1) IKS(IBM) 그리고 GKE(Google)의 블록 스토리지
IKS나 GKE의 블록 스토리지는 iSCSI를 사용한다.
SCSI는 한 대의 컴퓨터에 여러 개의 하드디스크 드라이브를 연결하기 위한 기술이다.
SCSI 케이블로 호스트 어댑터에 하드디스크 드라이브를 연결한다.
한편, iSCI는 물리적인 케이블 대신에 IP 프로토콜을 사용한다.
이 방식은 NFS랑 비교했을 때 고속으도 동작한다는 특징을 가져, 블록 단위로 스토리지를 읽고 쓰는 관계형 데이터 베이스 관리 시스템의 성능을 높일 수 있다.
그러나 SCSI는 복수의 호스트 어댑터에서 하드디스크 드라이브를 공유할 수 없다.
그래서 iSCI를 이용한 블록 스토리지도 복수의 노드에서 읽고 쓸 수 있는 모드로 마운트 할 수 없다.
즉,ReadWriteOnce 로만 마운트 가능하다.
(2) IKS 파일 스토리지
이 파일의 스토리지의 특징은 여러 개의 파드에서 동시에 마운트해서 사용할 수 있다는 점이다.
이는 기반이 되는 프로토콜이 NFS이기 때문에 그렇다. 그리고 NFS에서 수동으로 작업했던 것과 달리,
클라우드에서는 PVC에 의해 자동으로 PV를 프로비저닝 해주기 때문에 운영 면에서도 부담이 적다.
SDS 연동에 의한 동적 프로비저닝
퍼블릭 클라우드에서는 PVC를 만들면 자동으로 PV가 만들어져 컨테이너로 부터 이용할 수 있다.
한편, 자사 데이터 센터 내에 K8s 클러스트를 구축한 경우, 일일이 수작업으로 NFS 서버와 연동하는 것은 큰 부담이 된다. 가능하면 온프레미스 환경에서도 퍼블릭 클라우드에서 처럼, 볼륨의 프로비저닝을 자동화 하는 것이 좋을 것 이다.
이 문제는 쿠버네티스와 SDS를 연동하면 해결된다. PV의 다이내믹 프로비저닝을 실현할 수 있는 것이다.
(이번 클라우드 작업에서는 스토리지를 따로 정의안했는데.. 스토리지 구성 안하는 건가? 그래서 nas 장비를 사용하는 서버는 대상이 아니였던 거 같은데??!)