TT Lab
블로그 시작하기
배우기 러닝패스 코스

Helm 으로 Rook-Ceph 세우기 — 블록·파일·오브젝트와 장애

CephFS 와 RGW — 함께 쓰는 파일, S3 버킷, 이레이저 코딩

TT Lab 에서 이어서 보기

한 줄 요약

Ceph 는 한 저장소 위에서 블록·파일·오브젝트를 함께 냅니다. 파일은 MDS 가 이름과 잠금을, 오브젝트는 RGW 가 S3 API 를 맡고, 데이터는 셋 다 같은 OSD 에 풀로 나뉘어 들어갑니다.

왜 이게 필요했나

블록 볼륨(RBD)은 디스크 한 장입니다. 디스크 한 장을 두 서버가 동시에 마운트하면 각자 자기 캐시를 믿고 쓰다가 파일시스템이 깨집니다. 그래서 ReadWriteOnce 입니다. 그런데 웹 서버 여러 대가 같은 업로드 디렉터리를 보거나, 학습 파드 여럿이 같은 데이터셋을 읽어야 할 때가 있습니다. 이것을 풀려면 "누가 지금 이 파일을 쓰고 있나" 를 조정하는 주체가 있어야 하고, 그것이 CephFS 의 MDS(메타데이터 서버)입니다.

한편 요즘 애플리케이션은 파일시스템보다 S3 API 를 더 많이 씁니다. 디렉터리·잠금·부분 덮어쓰기가 없는 대신 HTTP 로 어디서나 쓰고, 객체 단위로 끝까지 늘어납니다. Ceph 의 RGW 는 Ceph 위에 S3 호환 API 를 얹은 게이트웨이입니다.

어떻게 동작하나

CephFS. 파일의 내용은 데이터 풀의 객체로, 디렉터리 구조와 권한 같은 메타데이터는 메타데이터 풀에 저장됩니다. 클라이언트(노드의 커널 ceph 모듈)는 열 때 MDS 에게 권한(capability)을 받고, 데이터는 OSD 와 직접 주고받습니다. MDS 가 데이터 길목에 서지 않으므로 처리량은 OSD 가 정합니다. activeStandby: true 는 대기 MDS 하나를 따뜻하게 띄워 두어 활성이 죽으면 몇 초 안에 넘겨받게 합니다. MDS 는 메타데이터를 캐시에 들고 있어서 메모리를 먹고, Rook 은 컨테이너 한도를 보고 그 캐시 크기를 정합니다.

RGW 와 OBC. RGW 는 HTTP 요청을 받아 버킷 색인과 객체를 RADOS 풀에 나눠 씁니다. ObjectBucketClaim 은 PVC 처럼 동작합니다 — 앱이 OBC 를 만들면 Rook 이 RGW 에 사용자와 버킷을 만들고, 같은 이름의 ConfigMap(버킷 이름·주소)과 Secret(키)을 내 줍니다. 앱은 이 둘을 환경 변수로 받아 씁니다. 키를 사람이 옮겨 적지 않아도 되고, OBC 를 지우면 버킷과 사용자가 함께 정리됩니다.

이레이저 코딩. 복제 3벌은 같은 데이터를 세 번 씁니다 — 가용 용량은 원시의 1/3 이고 노드 둘을 잃어도 읽습니다. 이레이저 코딩 k+m 은 데이터를 k 조각으로 나누고 패리티 m 조각을 더해 k+m 곳에 둡니다. 2+1 이면 원시의 2/3 를 쓰고 노드 하나까지 잃어도 됩니다. 대신 쓰기마다 패리티를 계산하고, 작은 객체도 k+m 조각으로 쪼개며, 일부만 덮어쓰려면 조각 전체를 다시 계산합니다. 그래서 크고 한 번 쓰는 RGW 데이터에 어울리고, 작은 덮어쓰기가 많은 볼륨에는 잘 쓰지 않습니다.

작은 노드에서 켤 때의 값. 차트 기본값은 MDS 요청·한도가 각각 4Gi, RGW 요청 1Gi·한도 2Gi 입니다. 이 실습의 스토리지 노드는 4GiB 라서 그대로 켜면 MDS 하나가 노드를 다 차지합니다. MDS 는 메타데이터를 캐시에 들고 있는 데몬이라 한도를 낮추면 캐시가 작아지고, 파일 수가 많을 때 MDS 가 클라이언트에게 캐시를 돌려 달라고 자주 요청하게 됩니다. RGW 는 요청을 처리하는 동안만 메모리를 쓰므로 작은 한도에서도 잘 버팁니다. 그리고 MDS·RGW 는 CephCluster 의 placement 를 따르지 않으므로, controlplane 에 앉지 않게 하려면 각자의 placement 에 같은 조건을 다시 적어야 합니다.

현장에서 만나는 모습

values 의 목록을 upgrade 할 때가 가장 위험합니다. Helm 은 이번에 준 values 를 전부로 봅니다. 파일시스템을 켤 때 쓴 values 파일을 다음 upgrade 에서 빠뜨리면 Helm 은 CephFilesystem 을 지우는 것으로 계산합니다. 운영에서는 values 를 파일로 저장소에 두고 항상 같은 파일 묶음으로 upgrade 하며, 먼저 helm diff(플러그인)나 helm template 으로 무엇이 바뀌는지 봅니다.

이레이저 코딩을 처음 고를 때 흔한 실수는 노드 수보다 큰 k+m 입니다. failureDomain 이 host 인데 노드가 셋이면 4+2 의 여섯 조각을 놓을 곳이 없어 PG 가 영영 만들어지지 않습니다. 그리고 2+1 로 노드 셋을 다 쓰면, 노드 하나를 잃었을 때 다시 2+1 로 맞출 자리가 없어 그 노드가 돌아올 때까지 패리티 없이 버팁니다.

OBC 를 지우는 것도 PVC 처럼 정책을 따릅니다. StorageClass 의 reclaimPolicy 가 Delete 이면 OBC 를 지울 때 버킷과 그 안의 객체, RGW 사용자가 함께 사라집니다. 운영 데이터가 든 버킷이라면 Retain 으로 두고, 지우는 일은 사람이 따로 하게 합니다.

다음 실습에서 할 것

1실습의 values 로 Ceph 를 다시 세우고, helm upgrade 로 CephFS 를 켭니다. 두 노드의 파드가 한 볼륨에 각자 쓰고 서로의 파일을 읽습니다. 이어서 이레이저 코딩 2+1 데이터 풀을 가진 오브젝트 저장소를 켜고, ObjectBucketClaim 으로 버킷을 받아 S3 클라이언트로 올리고 내려받습니다. 마지막으로 복제 3벌과 2+1 의 가용 용량을 ceph df 로 견줍니다.