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

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

RBD 의 스냅숏과 복제 — 복사하지 않고 얼려 두기

TT Lab 에서 이어서 보기

한 줄 요약

RBD 의 스냅숏·복제는 데이터를 복사하지 않고 "부모를 가리키는 새 이미지" 를 만듭니다. 그래서 크기와 상관없이 빠르고, 대신 부모와 자식이 이어져 있다는 사실을 운영자가 알고 있어야 합니다.

왜 이게 필요했나

볼륨이 하나의 파일이라면 백업은 복사이고 시험 환경은 복사본입니다. 그런데 볼륨이 100GiB 라면 복사는 몇 분에서 몇십 분이 걸리고, 그동안 원본은 계속 바뀝니다. 복사 도중에 바뀐 블록이 섞이면 그 사본은 어느 순간의 상태도 아닙니다. 그래서 스토리지는 "한 순간을 얼려 두는" 기능을 따로 갖습니다. 그것이 스냅숏입니다.

쿠버네티스는 이 기능을 저장소마다 다르게 부르지 않게 하려고 VolumeSnapshot 이라는 공통 API 를 만들었습니다. 다만 이 API 는 쿠버네티스 본체가 아니라 별도 프로젝트(external-snapshotter)의 CRD 와 컨트롤러로 나옵니다. 저장소가 스냅숏을 지원하지 않는 클러스터도 많기 때문입니다. 그래서 스냅숏을 쓰려면 CRD·컨트롤러·스냅숏 클래스 셋을 먼저 깔아야 합니다.

어떻게 동작하나

층이 둘입니다. 쿠버네티스 쪽에서는 VolumeSnapshot(사용자가 만드는 요청) → VolumeSnapshotContent(실제 스냅숏을 가리키는 객체)로 PVC → PV 와 같은 짝을 이룹니다. snapshot-controller 가 이 짝을 맺고, CSI 드라이버 옆에 붙은 csi-snapshotter 사이드카가 드라이버를 불러 스토리지에 실제 스냅숏을 만듭니다. VolumeSnapshotClass 는 StorageClass 처럼 "어느 드라이버로, 지울 때 어떻게" 를 정합니다.

Ceph 쪽에서는. RBD 이미지는 고정 크기(기본 4MiB) 객체들의 묶음입니다. 스냅숏은 그 시점의 객체 목록을 얼려 두고, 이후 원본에 쓰기가 오면 바뀌는 객체만 새로 씁니다(copy-on-write). Ceph CSI 는 VolumeSnapshot 하나를 만들 때 원본 이미지의 스냅숏에서 복제한 별도 이미지를 만들어 두므로, rbd ls -l 에서 PARENT 칸이 채워진 이미지로 보입니다. 스냅숏에서 복원한 PVC 도, PVC 를 원본으로 한 복제도 같은 방식으로 "부모를 가리키는 이미지" 로 시작합니다. 처음에는 공간을 거의 쓰지 않고, 바뀐 만큼만 늘어납니다.

온라인 확장. PVC 의 요청 크기를 늘리면 CSI 컨트롤러가 RBD 이미지 크기를 늘리고(rbd resize), 볼륨이 붙어 있는 노드의 CSI 노드 플러그인이 파일시스템(ext4)을 늘립니다(resize2fs). ext4·xfs 는 마운트된 채로 늘릴 수 있어서 파드를 멈출 필요가 없습니다. 줄이는 것은 안 됩니다 — 파일시스템이 그 자리를 이미 쓰고 있을 수 있기 때문입니다.

스냅숏은 두 층이 모두 켜져야 합니다. 쿠버네티스 쪽의 CRD·컨트롤러가 있어도, CSI 드라이버의 컨트롤러 Deployment 안에 csi-snapshotter 사이드카가 없으면 VolumeSnapshot 은 만들어지기만 하고 영영 readyToUse 가 되지 않습니다. 이벤트도 거의 남지 않아서 "기다리면 되겠지" 로 시간을 씁니다. Rook v1.21 의 드라이버 차트는 CephFS 에는 스냅숏 사이드카를 기본으로 붙이지만 RBD 는 snapshotPolicy: none 이 기본값입니다(2026-10-29, 차트 1.1.0 에서 확인). 그래서 이 실습은 스냅숏 클래스를 만들기 전에 드라이버 차트의 그 값을 먼저 바꿉니다. 이것을 확인하는 가장 빠른 길은 컨트롤러 Deployment 의 컨테이너 이름 목록을 읽어 보는 것입니다.

현장에서 만나는 모습

스냅숏은 백업이 아닙니다. 스냅숏은 원본과 같은 Ceph 클러스터, 같은 디스크 위에 있습니다. 클러스터가 통째로 망가지면 스냅숏도 함께 사라집니다. 그래서 운영에서는 스냅숏으로 일관된 순간을 얻은 뒤, 그 스냅숏을 다른 곳(오브젝트 저장소 등)으로 내보내는 도구(Velero·Kasten 같은)를 씁니다.

데이터베이스의 스냅숏은 한 번 더 생각해야 합니다. 블록 스냅숏은 "전원을 갑자기 뽑은 순간" 과 같은 상태(crash-consistent)라서, 데이터베이스는 다시 열 때 WAL 로 복구합니다. 대부분 문제없지만, 확실하게 하려면 스냅숏 직전에 데이터베이스가 쓰기를 비우게(flush·freeze) 합니다.

복제는 시험 환경을 빠르게 만들지만 부모와 이어져 있습니다. 부모 이미지에 자식이 달려 있으면 부모를 바로 지울 수 없고, 자식이 많아지면 읽기가 부모까지 따라가야 해서 느려집니다. Ceph CSI 는 이어진 깊이가 정해진 값을 넘으면 자식을 부모에서 떼어 내는(flatten) 작업을 스스로 합니다.

지우는 순서도 기억해 둘 만합니다. VolumeSnapshotClass 의 deletionPolicy 가 Delete 이면 VolumeSnapshot 을 지울 때 Ceph 쪽 스냅숏도 지워지고, Retain 이면 쿠버네티스 객체만 사라지고 Ceph 에는 남습니다. 남은 스냅숏은 ceph df 의 사용량에는 잡히지만 쿠버네티스에서는 보이지 않아서, 몇 달 뒤 용량이 어디로 갔는지 찾게 만듭니다.

다음 실습에서 할 것

1실습의 values 로 Ceph 를 다시 세우고, 스냅숏 CRD 와 컨트롤러를 설치한 뒤 Helm 으로 VolumeSnapshotClass 를 켭니다. 200MiB 를 쓴 볼륨을 파드를 멈추지 않고 2Gi 로 늘리고, 스냅숏을 찍은 뒤 파일을 하나 더 씁니다. 스냅숏에서 복원한 볼륨에는 그 파일이 없고, 지금의 볼륨을 복제한 볼륨에는 있다는 것을 확인합니다.