[k8s] K8s Storage with OpenEBS 본문
k8s Storage
컨테이너 환경에서는 별도 설정을 하지 않으면 데이터는 호스트 노드의 임시 디스크에 보관된다. 컨테이너를 삭제하면 임시 디스크에 있는 데이터는 저장되지 않고 컨테이너와 함께 삭제된다.
이러한 문제를 쿠버네티스에서는 Pod와 데이터를 분리해서 영구 볼륨이라는 별도의 추상화된 리소스로 해결한다.
쿠버네티스 볼륨을 구성하는 주요 리소스로 Persistent Volume (영구볼륨)
, PVC (Persistent VolumeClaim, 영구볼륨 요청자)
, Storage Class
가 있다.
클러스터 관리자와 사용자(개발자)의 역할에 따라 쿠버네티스 볼륨에 관련된 작업이 서로 다르다.
클러스터 관리자는 클라우드 서비스 제공업자, 상용 혹은 오픈소스 솔루션 중에서 원하는 성능과 기
능을 제공하는 스토리지를 선택하여 개발자에게 적절한 솔루션을 제공하는 역할을 한다.
게빌지는 애플리케이션에서 필요한 스토리지 용량과 특성(ReadWriteOnce/ReadWriteMany)을 고려해 애플리케이션에 연결하는 작업을 진행한다.
이번 예제에서는 오픈소스 OpenEBS 로컬 호스트패스를 이용해 스토리지 클래스를 만들고 스토리지 관련 설정을 YAML 파일로 작성하는 방법에 대해 알아보려고 한다.
PersistentVolume
PV (Persistent Volume) 영구볼륨
은 실제 데이터가 영속적으로 저장되는 스토리지의 일부다. 실제 데이터가 저장되는 리소스이며, 관리자는 정적으로 직접 영구볼륨을 생성할 수 있으나 운영 환경에서는 대부분 스토리지 클래스를 이용해 동적으로 영구볼륨을 할당한다.
PVC (Persistent Volume Claim) 영구볼륨 요청자
는 실제 데이터가 저장돠는 영구볼륨과 분리해서 영구볼륨의 스토리지 용량과 액세스 모드 등 영구볼륨과 관련된 설정만 별도로 분리한 쿠버네티스 리소스다.
관리자는 PV, 스토리지 클래스를 만들고 개발자는 영구볼륨의 상세한 설정 내역을 몰라도 PVC를 이용해 볼륨을 사용할 수 있다.
스토리지 클래스는 스토리지 솔루션 또는 클라우드 서비스 제공업체에서 제공하는 여러 가지 스토리지 중 동일한 속성 (IOPS, 레이턴시, 백업정책 등)을 가지는 스토리지의 집합 리소스다.
사용자는 원하는 스토리지 클래스를 지정해 PVC에서 요청하면 스토리지 클래스에서 해당 볼륨을 동적으로 할당한다.
이러한 쿠버네티스 볼륨을 할당하는 프로세스를 간략히 정리하면 관리자는 사전에 클러스터에 필요한 스토리지 유형을 정하고 이를 스토리지 클래스로 생성한다.
사용자는 PVC로 볼륨 할당을 요청하면 해당 스토리지 클래스에서 동적으로 PV가 할당된다.
OpenEBS 로컬 호스트패스 설치
쿠버네티스 자체에서는 스토리지 클래스를 제공하지 않고 별도의 솔루션을 설치해야 사용할 수 있다. 일반적으로 퍼블릭 클라우드 서비스 업체는 스토리지 클래스를 기본으로 제공하고 온프레미스 환경은 별도 스토리지 솔루션으로 구현한다.
현업에서 많이 사용하는 오픈소스 스토리지 솔루션으로 Ceph
와 GlusterFS
, OpenEBS
등이 있다. 이번 포스팅의 예제에서는 속도가 빠르고 설치 및 사용이 쉬운 OpenEBS 호스트패스
를 사용한다.
OpenEBS
는 Pod가 실행되는 호스트 노드의 특정 디렉터리(호스트패스)를 Pod의 볼륨으로 할당한다. OpenEBS
솔루션 없이 호스트 노드의 원하는 경로를 직접 Pod의 볼륨으로 할당할 수 있지만 스토리지 클래스를 이용하지 않으므로 필요할 때마다 영구볼륨을 생성하고 다시 수동으로 삭제해야 하는 정적인 구성으로 굉장히 번거롭다.
OpenEBS
를 사용하면 스토리지 클래스를 이용해 동적으로 볼륨을 생성하고 삭제할 수 있다. 또한 볼륨 관련 구성은 공통 속성을 사용하므로 기존에 사용하는 애플리케이션 YAML 파일을 수정하지 않고도 OpenEBS
환경에 그대로 사용할 수 있다는 장점이 있다.
외부 네트워크 지연과 분산 파일 시스템을 사용하지 않고 노드의 로컬 디스크에 직접 데이터를 읽고 쓰므로 다른 스토리지 솔루션에 비해 성능이 뛰어나다.
k create ns openbs
k ns openbs
k apply -f https://openebs.github.io/charts/openebs-operator-lite.yaml
k apply -f https://openebs.github.io/charts/openebs-lite-sc.yaml
k get sc
위의 명령어를 입력하면, openebs-device
와 openebs-hostpath
라는 2가지 스토리지 클래스가 생성된다.
openebs-device
는 노드에서 마운트하지 않은 별도의 디스크 디바이스에 Pod의 데이터를 저장하고 openebs-hostpath
는 호스트 노드의 특정 디렉터리에 데이터를 할당하는 방식이다.
호스트패스에서 사용하는 디렉터리 위치는 관리자가 변경할 수 있는데, 기본 설정은 /var/openebs/local
이다.
OpenEBS
에서 사용하는 볼륨이 호스트 노드의 파일시스템 용량에 영향을 끼치지 않도록 기본 디렉터리 경로가 아니라 별도의 마운트 포인트를 사용하는 것을 권장한다.
이제 새롭게 생성한 openebs-hostpath
스토리지 클래스를 이용해 PVC를 생성하고 Pod에 볼륨을 할당한다.
스토리지 클래스를 이용한 PVC 및 영구볼륨 사용
YAML 파일을 이용해 PVC를 생성하고 애플리케이션 내 영구 볼륨을 마운트하는 실습을 진행하려 한다. 개발자는 해당 작업만 가능하면 쿠버네티스 스토리지를 사용하는 데 별다른 문제가 없다.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: default-pvc
namespace: default
spec:
accessModes:
- ReadWriteOnce
volumeMode: FileSystem
resources:
requests:
storage: 1Gi
storageClassName: "openebs-hostpath"
kind: PersistentVolumeClaim
- 쿠버네티스는 영구볼륨을 요청하는 PersistentVolumeClaim을 별도의 리소스로 지정한다
namespace: default
- PVC는 네임스페이스 단위로 생성하고 구분된다
- 영구볼륨은 특정 네임스페이스가 아닌 전체 클러스터 단위로 할당된다
spec.accessModes: ReadWriteOnce
- 스토리지 클래스에서 지원하는 액세스 모드 중 한 가지를 지정한다
spec.volumeMode: Filesystem
- Filesystem과 Block의 두 가지 모드를 선택할 수 있다
spec.resources.requests.storage: 1Gi
- 영구볼륨이 사용하는 용량을 지정한다. Pod가 마운트한 볼륨은 해당 용량을 초과해서 사용할 수 없다
spec.storageClassName: "openebs-hostpath"
- 클러스터가 지원한느 스토리지 클래스 이름을 지정한다. 클러스터에서 사용 가능한 복수의 스토리지 클래스가 있으면 원하는 스토리지 클래스를 선택할 수 있다
개발자는 위와 같은 기본 템플릿 PVC 파일에서 용량과 스토리지 클래스 이름 등 몇 가지 변수만 변경해서 새로운 PVC를 반복 생성할 수 있다.
k ns default
k apply -f date-pvc.yaml
k get pvc
PVC를 생성하면 정상적으로 default-pvc
가 생성된다. PVC 또한 리소스이므로 k get 명령어로 PVC 목록을 확인할 수 있다. 하지만, 상태가 정상이지 않고 Pending
으로 표기되는 것을 확인할 수 있다.
k describe pvc default-pvc
명령어를 통해 확인해보면, 첫 번째 사용자(Pod)가 볼륨을 연결하기를 기다린다. 라는 의미의 메시지를 확인할 수 있다.
OpenEBS
스토리지 클래스의 특징으로 PVC는 해당 PVC를 사용하는 Pod가 먼저 생성되고 다음으로 볼륨이 연결된다. Pod가 생성되고 해당 PVC를 마운트하면 상태가 Pending
에서 Bound
로 변경된다.
이처럼 사용자는 먼저 Pod가 사용할 볼륨을 PVC로 생성한다. 이후 헤당 PVC를 Pod YAML 파일의 volumeMounts
와 volumes
에 추가해서 사용한다.
아래는 실제 애플리케이션에서 PVC를 사용하는 Deployment
YAML 파일의 예제다
apiVersion: apps/v1
kind: Deployment
metadata:
name: data-pod
namespace: default
labels:
app: date
spec:
replicas: 1
selector:
matchLabels:
app: date
template:
metadata:
labels:
app: date
spec:
containers:
- name: date-pod
image: busybox
command:
- "/bin/sh"
- "-c"
- "while true; do date >> /data/pod-out.txt; cd /data; sync; sync; sleep 30; done"
volumeMounts:
- name: date-vol
mountPath: /data
volumes:
- name: date-vol
persistentVolumeClaim:
claimName: default-pvc
spec.template.spec.containers.volumeMounts
- 컨테이너에서 사용할 볼륨의 정보를 지정한다. Pod는 볼륨을 사용하기 위해 volumeMounts와 volumes의 2가지를 사용한다
spec.template.spec.containers.volumeMounts.name
- 컨테이너 마운트 포인트에 사용할 볼륨의 이름을 지정한다
spec.template.spec.containers.volumeMounts.mountPath
- 컨테이너 내부의 마운트 포인트를 지정한다. 지정된 마운트 포인트로 볼륨이 할당된다
spec.template.spec.volumes.name
- 컨테이너 마운트 포인트 이름과 동일하게 매핑한다. YAML 파일 내에 볼륨 마운트가 여러 개 있으면 해당하는 볼륨 마운트 이름과 일치시킨다
spec.template.spec.volumes.persistentVolumeClaim.claimName
- 볼륨에 사용할 PVC 이름을 지정한다. PVC는 Pod와 동일한 네임스페이스에 있어야 한다
이전 Pod 예제와 동일하게 date 명령의 출력 결과를 파일에 저장하는 Deployment
YAML파일이다. 이전과 다르게 PVC를 사용해 데이터가 사라지지 않고 영구볼륨에 저장된다.
PVC 볼륨을 사용하는 Deployment
YAML 파일은 기존의 Deployment
YAML과 동일하지만 volumeMounts
와 volumes
부분만 기존 Deployment
YAML에 추가됐다.
위의 YAML 파일을 통해 Deployment
를 생성한다.
k apply -f date-pvc-deploy.yaml
k get pod -o wide
k get pvc
PV/PVC 삭제
영구볼륨은 Pod에서 볼륨으로 사용하고 있으므로 영구볼륨을 삭제하려면 먼저 볼륨을 사용하고 있는 Pod를 삭제해야 한다. Pod를 삭제하지 않으면, 영구볼륨이 삭제되지 않는다.
PVC를 삭제할 때는 영구볼륨의 삭제와 관련된 정책은 해당 스토리지 클래스의 정책을 따르며 k get pv
출력 결과에서 확인할 수 있다.
영구볼륨 삭제와 관련된 ReclaimPolicy(재요구정책)
에는 Delete
와 Retain
옵션이 있다. Delete
는 PVC를 삭제하면 영구볼륨도 함께 삭제되고, Retain
은 PVC는 삭제돼도 영구볼륨은 삭제되지 않고 유지하는 정책이다.
Retain
옵션을 사용하면 PVC를 삭제해도 PV는 삭제되지 않으므로 안전하지만, 삭제 작업은 수동으로 진행해야 한다. 만약 지워지지 않은 영구볼륨이 있다면 향후 해당 영구볼륨을 이용해 수동으로 새로운 PVC를 생성할 수 있다.
OpenEBS
스토리지 클래스의 기본 정책은 Delete
다.
사용자 스토리지 클래스를 지정해 헬름 차트 MySQL 설치하기
쿠버네티스 환경에서 애플리케이션을 설치하는 데는 주로 헬름을 이용한다. 헬름 차트는 템플릿 파일로 개별 상황에 맞게 설치 옵션을 지정할 수 있다. 스토리지 클래스도 템플릿 파일을 이용해 지정할 수 있다.
대부분의 헬름 파일에 스토리지 클래스만 지정하면 PVC가 자동으로 생성된다. 이번 예제에서는 OpenEBS
호스트패스를 스토리지 클래스로 지정해 헬름 차트로 MySQL 애플리케이션을 설치한다.
helm search repo mysql
helm pull bitnami/mysql
tar xvfz mysql-9.1.0.tgz
mv mysql mysql-9.1.0
cd mysql-9.1.0/
cp values.yaml my-values.yaml
이후 YAML 파일의 내용 중 아래 부분을 변경한다.
architecture: replication
- MySQL 애플리케이션 구조를 복제 구성으로 변경한다
persistence.storageClass
primary.persistence.storageClass
와secondary.persistence.storageClass
의 스토리지 클래스를openebs-hostpath
로 변경한다k create ns mysql k ns mysql helm install mysql -f my-values.yaml .
헬름 차트를 이용해 애플리케이션을 설치할 때 헬름의 스토리지 클래스를 새롭게 생성한 openebs-hostpath
로 지정하면 해당 스토리지 클래스를 이용해 자동으로 영구볼륨을 생성한다.
헬름 차트 삭제시, 데이터 보호를 위해 기본적으로 PVC는 삭제하지 않는다. 따라서 헬름 차트가 업그레이드되거나 변경돼도 데이터는 그대로 유지해서 기존 데이터의 변경 없이 그대로 사용할 수 있다.
PVC를 삭제하려면 다음과 같이 수동으로 삭제해야 한다.
k delete pvc --all
로컬 호스트패스 스토리지 클래스의 장점 및 제약 사항
OpenEBS
호스트패스는 이름에서 알 수 있듯이 로컬 호스트의 특정 디렉터리를 스토리지 클래스로 이용한다. 네트워크에 연결된 별도의 스토리지를 이용하지 않으므로 네트워크 전송에 따른 추가 지연 시간이 없다.
또한, 분산 파일 시스템을 사용하지 않고 로컬 노드의 디스크를 바로 사용하므로 다른 스토리지 솔루션에 비해 성능이 월등하다. 하지만 해당 노드에서만 Pod가 실행되므로 노드가 다운되면 Pod 역시 함께 사용하지 못한다는 제약 사항이 있다.
고가용성 측면에서의 제약 사항은 애플리케이션 단에서 다른 노드의 Pod와 데이터를 동기화하여 해결할 수 있다. 데이터베이스 자체에서 제공하는 동기화 기능을 사용하면 이러한 제약 사항이 없기 때문에 로컬 호스트패스를 실제 운영 환경의 데이터베이스 스토리지 클래스로 사용하는 경우도 있다.
스토리지 고가용성 구성 제약
로컬 호스트패스 스토리지 클래스는 Pod가 실행 중인 노드의 특정 디렉터리를 Pod의 볼륨으로 할당한다. 따라서 Pod의 데이터는 해당 노드에만 존재해서 다른 노드로 Pod를 이동하는 것이 불가능하다.
볼륨을 가지지 않는 일반 파드(Stateless POD)는 특정 노드에 장애가 발생해도 다른 노드로 이전이 가능하지만, 로컬 호스트패스를 스토리지 클래스로 가진 Pod는 다른 노드로 이동이 불가능하다.
PVC가 특정 노드만 실행 중인 Pod는 해당 노드에서만 실행 가능하다. 해당 노드의 문제가 발생하면 Pod가 실행되지 않아 서비스 장애가 발생한다.
호스트패스를 사용하는 Pod는 애플리케이션 단에서 서로 다른 노드의 Pod와 서로 데이터를 복제하도록 설정할 필요가 있다. 볼륨 복제를 지원하면 기존 PVC를 삭제했을 때 새로운 노드에서 기존 데이터를 처음부터 복제해서 Pod 실행이 가능하다.
다음 포스팅에서는 EKS 환경에서의 Storage 설정에 대해 작성해보고자 한다.
'Infra' 카테고리의 다른 글
[k8s] Kubernetes Network (0) | 2024.11.08 |
---|---|
[Traefik] K8s Traefik 설치, External-IP 설정 및 HTTPS 적용 방법 (5) | 2024.09.22 |
[Network] TCP 프로토콜에 대한 이해 (1) | 2024.07.23 |
[k8s] etcd & Raft Alogorithm (2) (0) | 2024.07.12 |
[k8s] etcd & Raft Algorithm (1) (0) | 2024.07.10 |