테크믈리에의 리뷰 공간

[k8s] OpenEBS를 통한 Local Device, Local HostPath 구축방법 본문

프로그래밍|소프트웨어/기타

[k8s] OpenEBS를 통한 Local Device, Local HostPath 구축방법

테크믈리에 2023. 12. 1. 17:45

OpenEBS?

https://openebs.io

 

OpenEBS - Kubernetes storage simplified.

OpenEBS makes it easy to attach Dynamic Local PV or Replicated Volumes to any Kubernetes application by abstracting all of the complex commands involved in creating robust multi-zone storage in a simple one-line command.

openebs.io

 

OpenEBS는 Rook Ceph, Longhorn 등과 함께 무료로 사용할 수 있는 k8s 저장소 관리 방법 중 하나로 Mayastor, cStor, Jiva, LocalPV 등의 다양한 옵션을 제공한다. 앞의 방법들도 강력하지만, 특히 뒤의 LocalPV 때문에 OpenEBS를 많이 쓰는데, 몇 안되는 Dynamic Local Provisioner이기 때문에 대체안이 없기 때문이다.

 

Rook Ceph 등의 분산 저장소는 데이터 안정성이 매우 높은 대신 특히 단일 읽기/쓰기 성능이 떨어지는 것이 문제인데 LocalPV를 사용하면 Pod가 돌아가는 노드의 물리적 저장장소를 바로 사용하기 때문에 원 저장 장치 성능을 큰 손해 없이 끌어다 쓸 수 있다는 것이 장점이다.

 

이러한 특성 때문에 ElasticSearch 등의 이미 분산 저장 기법이 적용된 DB를 운용할 때 특히 추천한다.

 

Local Device 사용을 위한 저장 장치 준비

 

이것저것 테스트 해본 결과, Local Device로 잘 인식되게 하기 위해서는 해당 저장 장치에 파티션을 1개 이상 생성 후, 사용하고자 하는 파티션을 ext4로 포맷하는 것이 좋았다.

 

Local Device 방식의 장점이라면 Block Storage 기반으로 동작한다는 것이고, 단점이라면 무조건 하나의 Persistent Volume 당 하나의 저장 장치가 온전하게 점유된다는 것이다.

가령 예를 들어, 저장 장치가 1TB의 용량을 갖고 있고 Persistent Volume Claim이 20GB라 해도 저장 장치의 나머지 용량에 다른 Persistent Volume을 선언할 수 없는 상태가 된다.

 

이 때문에, 이번 글의 예시에서는 1TB의 저장 용량을 2개의 파티션으로 나눠 하나는 Local Device에서, 나머지는 Local Host에서 쓰도록 해보겠다.

 

 

실험에 사용할 저장 장치는 /dev/sdb에 있는 1TB SSD로 하도록 하겠다.

sudo fdisk /dev/sdb

# fdisk 프로그램 내에서
# 우선 기존 파티션 전부 삭제 (다 삭제될 때까지 반복 실행)
d

# 새로운 파티션 생성
n
# 본인이 희망하는 대로 설정값을 적용하도록 하자 (본인은 파티션 2개 생성)

# 설정 반영
w

# fdisk 종료 후
sudo mkfs.ext4 /dev/sdb1
sudo mkfs.ext4 /dev/sdb2

 

 

그 결과 이렇게 2개의 파티션이 생성된 것을 확인할 수 있다.

Local Device로 사용할 /dev/sdb1은 이제 더 이상 건들이지 않아도 충분하다.

 

Local Hostpath 사용을 위한 저장 장치 준비

 

Local Hostpath로 사용하는 경우에는 OS의 파일 시스템을 그대로 사용하여 저장소를 관리하게 된다.

이 때문에 Hostpath 용도로 사용하고자 하는 저장 장치의 경우에는 반드시 마운트가 되어 있어야 하며 마운트 위치는 모든 노드에서 동일해야 한다.

 

이러한 특성 때문에 귀찮은 점은, 하나의 StorageClass 당 하나의 마운트 위치를 사용할 수 밖에 없으며 2개 이상의 저장 장치가 한 노드에 있는 경우에는 LVM으로 하나의 가상 저장 장치로 묶어서 사용하거나 2개 이상의 StorageClass를 사용하거나 Local Device로 사용하는 수밖에는 없다.

 

본 예시에서는 /mnt/openebs-local이라는 곳에 마운트 위치를 만들어 /dev/sdb2를 마운트하도록 하겠다.

sudo mkdir /mnt/openebs-local

# /dev/sdb2의 UUID 확인
sudo blkid | grep /dev/sdb2

# fstab 수정
sudo nano /etc/fstab
# 파일 최하단에 다음 내용 추가 후 저장
# UUID=</dev/sdb2의 UUID> /mnt/openebs-local ext4 defaults 0 0

sudo mount -a
# 아마 systemctl daemon-reload인가 하라고 나올텐데 해당 명령어 실행

sudo chmod -R 777 /mnt/openebs-local

 

OpenEBS LocalPV 설치

 

우선은 Rocky Linux OS를 기준으로 설명하도록 하겠다.

OpenEBS는 기본적으로 ISCSI 드라이버를 사용하기 때문에 ISCSI 드라이버를 설치해야하는데, Rocky Linux는 기본 설치가 된 상태이기 때문에 활성화만 해줘도 충분하다.

cat /etc/iscsi/initiatorname.iscsi

sudo systemctl status iscsid

sudo systemctl enable --now iscsid

 

그 다음에는 OpenEBS를 올리면 되는데, LocalPV 용도로만 사용할 경우에는 경량화된 버전을 따로 제공한다.

kubectl apply -f https://openebs.github.io/charts/openebs-operator-lite.yaml
kubectl apply -f https://openebs.github.io/charts/openebs-lite-sc.yaml

 

이렇게 올린 다음에는 OpenEBS가 인식한 장치를 openebs.io/BlockDevice에서 확인할 수 있다.

 

각각의 저장 장치를 자세하게 들여다보면 어떤 노드의 어떤 장치의 어떤 파티션인지 여부까지 다 나오는데, 여기서 OpenEBS가 관리하기 원치 않는 항목이 있다고 하면 미리 삭제를 해두도록 하자.

 

이번 예시에서는 일부러 파티션을 나눠서 몇몇 파티션은 Local Device 용도로, 몇몇 파티션은 Local Host 용도로 사용할 것이기 때문에 각각 방법을 설명하도록 하겠다.

 

더보기

Local Device로 사용하기 위한 장치의 경우, OpenEBS가 해당 장치를 포맷하고 블록 스토리지 기반으로 완전 점유하기 때문에 불시의 상황을 예방하기 위하여 미리 사용할 장치만 따로 걸러주는 것이 안전하다.

 

이를 위해서는 우선 장치 레이블링 작업이 필요하다.

kubectl label bd -n openebs <장치 이름> openebs.io/block-device-tag=<태그 이름>

 

장치를 레이블링 한 다음에는 해당 장치만 사용하는 새로운 StorageClass를 하나 만들어주도록 하자.

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: local-device
  annotations:
    openebs.io/cas-type: local
    cas.openebs.io/config: |
      - name: StorageType
        value: device
      - name: FSType
        value: ext4
      - name: BlockDeviceSelectors
        data:
          openebs.io/block-device-tag: <태그 이름>
provisioner: openebs.io/local
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer

 

성공적으로 Local Device 세팅이 되었으며 이를 사용해 Persistent Volume을 생성하였다면 아래와 같이 저장 장치가 Claimed된 상황을 확인할 수 있다.

 

더보기

Local Hostpath로 사용하기 위한 장치의 경우에는 단순하게 StorageClass 하나만 생성해주면 충분하다.

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: local-hostpath
  annotations:
    openebs.io/cas-type: local
    cas.openebs.io/config: |
      - name: StorageType
        value: hostpath
      - name: BasePath
        value: /mnt/openebs-local
provisioner: openebs.io/local
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer

 

만약에 저장 장소의 마운트 위치가 다르거나 OS가 설치된 것과 같은 저장 장소를 사용하고자 하는 경우 등에는 BasePath를 본인 환경에 맞게 변경하도록 하자.

 

만약, OpenEBS로 만든 StorageClass를 기본 저장 장소로 변경하고자 하는 경우에는 아래 명령어를 사용하도록 하자.

# 기존 기본 저장장소 해제
kubectl patch storageclass <이름> -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}'

# 새 기본 저장장소 지정
kubectl patch storageclass <이름> -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'

 

** OpenEBS 버그: 메모리 누수

OpenEBS + ElasticSearch를 운영하면서 가끔씩 ElasticSearch에 무거운 작업을 돌리면 서버가 설정된 Memory Request 및 Limit 범위를 벗어나 아예 멈춰버리는 현상이 발생하였다.

 

해당 현상 발생 시 서버의 Calico 등도 같이 나가버려서 서버 재부팅, 심하면 서버의 k0s를 재설치하고 해당 노드 내 모든 서비스를 재시작해야만 복구가 됐는데, 정작 ElasticSearch의 메모리 사용률에는 변화가 없다는 것을 확인할 수 있었다.

 

원인은 OpenEBS의 NDM Deployment 내 메모리 누수 현상으로 분명 평상시에 1GB 미만으로 메모리가 사용되어야 할 파드들이 메모리를 30GB 넘게도 먹는 것을 확인할 수 있었다.

 

해결방법은 상단의 OpenEBS 설치 코드를 바로 적용하지 말고 다운 받은 다음 resource 항목을 수정하여 적용해도 되고, 혹은 openebs-ndm DaemonSet 설정값에 접근하여 직접 변경하여도 된다. 설정값은 본인의 상황에 맞추어 수정하도록 하자.

 

 

 

Reference

https://openebs.io/docs/concepts/localpv

 

 

Comments