---
title: "Ceph RBD 이미지가 '제거 중(Deleting)'에서 멈췄을 때 트러블슈팅"
description: "Ceph RBD 이미지가 삭제 중 멈출 때 발생하는 유령 엔트리를 rbd_header 존재 여부에 따라 구분하고, 헤더가 있으면 rbd trash rm --force로, 없으면 rmomapkey로 직접 제거하여 문제를 해결한다."
date: "2026-07-07T00:00:00.000Z"
last_modified: "2026-10-03T09:37:00.000Z"
type: "Post"
tags:
  - "ceph"
  - "openstack"
  - "storage"
  - "troubleshooting"
categories:
  - "🤖 Computer Science"
series:
  - "ceph"
authors:
  - "봉정근"
canonical_url: "https://pieroot.xyz/ceph-rbd-delete"
markdown_url: "https://pieroot.xyz/ceph-rbd-delete.md"
---

# Ceph RBD 이미지가 '제거 중(Deleting)'에서 멈췄을 때 트러블슈팅

Ceph RBD 이미지가 삭제 중 멈출 때 발생하는 유령 엔트리를 rbd\_header 존재 여부에 따라 구분하고, 헤더가 있으면 rbd trash rm --force로, 없으면 rmomapkey로 직접 제거하여 문제를 해결한다.

## 결론 요약

결론부터 말하면, 이번 이슈의 핵심은 **삭제가 중간에 멈추면서 ****`rbd_trash`**** omap에 쌓인 유령 엔트리**였다. Cinder에서 삭제에 실패한 볼륨 13개가 대시보드에 "제거 중" 상태로 계속 남아 있었고, `rbd_header` 존재 여부에 따라 `rbd trash rm --force`(11개)와 `rados rmomapkey`(2개)로 나눠 정리해 해소했다.

> **이 글에서 다루는 내용**
> 
> - "제거 중" 상태로 멈춘 RBD 이미지의 재현 가능한 증상
> 
> - `rbd_directory` / `rbd_trash` omap 구조와 유령 엔트리가 생기는 원리
> 
> - 원인 후보와 검증 순서 (카운트 대조 → 헤더 대조)
> 
> - 경로 A / 경로 B로 나눠 안전하게 정리하는 실제 조치
> 
> - Cinder DB 정합성과 OSD slow op까지 포함한 재발 방지 체크리스트

---

## 🚨 증상

OpenStack에서 Cinder의 백엔드로 Ceph을 사용 중이다. Cinder에서 볼륨을 삭제하다가 실패한 케이스들이 확인됐고, Ceph 쪽에서도 볼륨이 제거되다가 알 수 없는 이유로 멈춘 상태였다. 아래 중 하나라도 해당되면 이 절차를 따르면 된다.

- 대시보드 Images 탭에 볼륨 이름은 보이는데 **크기/사용량이 전부 0**이고 주황색 경고 삼각형이 붙어 있다.

- 경고 박스: `'제거 중' 상태인 RBD에 대한 정보를 표시할 수 없습니다.`

- 알림 반복 발생: `Failed to 업데이트 RBD ... [errno 2] RBD image not found`

- Cinder/대시보드에서 볼륨을 지웠는데 **목록에서 사라지지 않는다.**

- OpenStack 볼륨 목록에서 상태가 `error_deleting`으로 굳어 있다.

![image](https://pieroot.xyz/api/image-proxy?id=c09ec47a-0743-493b-a60f-0ecdf44c092e&kind=s3&pageId=396067c0-15d0-8083-bb29-faf58273aaa0&source=block&blockId=396067c0-15d0-80a8-92a8-e5c9f137adc1)

*OpenStack 볼륨 목록 — 삭제에 실패한 볼륨이 **`error_deleting`** 상태로 굳어 있다.*

![image](https://pieroot.xyz/api/image-proxy?id=03352b6e-699a-49b2-83d5-91690fac2ddf&kind=s3&pageId=396067c0-15d0-8083-bb29-faf58273aaa0&source=block&blockId=396067c0-15d0-8059-b198-d56cbba3ab69)

*Ceph 대시보드 Images 탭 — 크기·사용량·오브젝트가 전부 0으로 표시되고 '제거 중' 경고가 붙어 있다.*

대시보드에서는 원인을 알 수 없으니 CLI에서 확인해야 한다. ~~대시보드는 경고만 띄우고 이유는 안 알려준다~~

---

## 🧩 환경 정보

- **대상**: Ceph RBD (OpenStack Cinder 연동, pool: `volumes`)

- **실행 위치**: 모니터/관리 노드 (root 권한 필요)

- **위험도**: 중~높음 (omap 직접 조작 포함)

- **사례 발생일**: 2026-07-07, 유령 엔트리 13개

> **왜 목록에는 남는데 열리지 않는가?**
> 
> `rbd ls`가 세는 이름은 두 곳에서 나온다. 정상 이미지는 `rbd_directory` omap, 삭제 예약된 이미지는 `rbd_trash` omap이다.
> 
> 실체(`rbd_header.<id>`)가 없거나 trash 메타가 깨지면, 목록에는 남지만 열 수 없어 "제거 중"으로 보인다.

---

## 🔍 원인 후보와 검증 순서

가능한 원인은 크게 3가지로 나뉜다. P0과 P1은 같은 절차(헤더 대조)로 한 번에 판별되고, P2는 사후 점검에서 확인한다.

### P0. trash omap에만 남은 유령 엔트리 (헤더·데이터 완전 소멸)

- 판단 근거: `rbd info`가 실패하는데 `rbd trash ls`에도 안 보인다. 메타가 깨졌으면 정식 trash 목록에 나오지 않는 게 함정이다.

- 확인 방법: `rados -p volumes stat rbd_header.<id>`

- 기대 결과: `No such file or directory` → 매핑만 유령으로 남은 상태

### P1. 삭제가 중간에 멈춘 진짜 trash 이미지 (헤더 존재)

- 판단 근거: 삭제가 진행되다가 백그라운드에서 멈추면 헤더가 남는다.

- 확인 방법: 같은 `rados stat` 명령

- 기대 결과: `mtime ... size 0` → 헤더가 살아 있는 정상 trash 이미지

### P2. OSD slow op / 네트워크 저하로 백그라운드 purge 지연

- 판단 근거: trash purge가 데이터를 지우다 OSD 지연/장애로 멈추면 이런 엔트리가 누적된다.

- 확인 방법: `ceph health detail`에서 `BLUESTORE_SLOW_OP_ALERT`, `CephNodeNetworkPacketDrops` 여부 점검

- 기대 결과: slow op 경고가 있으면 근본 요인일 가능성이 높다.

---

## 🧪 진단 — 어디서 막혔는지 특정

추측하지 말고 순서대로 실제 상태를 점검한다.

### 1) 걸린 삭제 작업과 trash 확인

```bash
# 진행 중인 RBD 삭제 task (보통 비어 있음 → 백그라운드 task 없음)
ceph rbd task list

# 정식 trash 목록 — 메타가 깨졌으면 여기엔 안 보인다 (함정!)
rbd trash ls volumes

# 문제 이미지 실체가 열리는지
rbd status volumes/<image-name>
rbd info   volumes/<image-name>

# 상세 목록으로 열어보면 유령 이미지에서 에러가 쏟아진다
rbd -p volumes ls -l
```

![image](https://pieroot.xyz/api/image-proxy?id=9c50ec84-ca38-40de-8b34-def03bb74167&kind=s3&pageId=396067c0-15d0-8083-bb29-faf58273aaa0&source=block&blockId=396067c0-15d0-80cf-8320-d59fa62bb1c0)

***볼륨들 목록 확인***

![image](https://pieroot.xyz/api/image-proxy?id=e1f4bb40-a5fa-45c0-be5f-aac4fd412536&kind=s3&pageId=396067c0-15d0-8083-bb29-faf58273aaa0&source=block&blockId=396067c0-15d0-80eb-ab1e-cda148901ca9)

*`rbd ls -l`**로 상세 목록을 열면 유령 이미지들이 **`No such file or directory`**를 뱉으며 listing 자체가 실패한다.*

`rbd info`로 대조해 보면 정상 볼륨은 정보가 제대로 출력되는데, 문제 볼륨들만 같은 에러로 실패한다. 이번 사례에서 이런 볼륨이 13개가량이었다.

![image](https://pieroot.xyz/api/image-proxy?id=c287221d-9229-4bfc-aa17-229aa3037bec&kind=s3&pageId=396067c0-15d0-8083-bb29-faf58273aaa0&source=block&blockId=396067c0-15d0-800e-84e2-f2f7569b0bdd)

*`rbd info`** 대조 — 정상 볼륨은 상세 정보가 뜨지만 유령 볼륨은 열리지 않는다.*

### 2) 목록 카운트 불일치 확인 (가장 결정적)

```bash
# rbd_directory에 등록된 정상 이미지 수
rados -p volumes listomapkeys rbd_directory | grep -c '^name_'

# rbd ls가 보는 전체 이름 수
rbd ls volumes | wc -l
```

두 숫자의 차이가 곧 **유령(trash) 엔트리 수**다. 이번 사례에서는 `128` vs `141`로 13개가 trash에 묶여 있었다. ~~숫자는 거짓말을 하지 않는다~~

![image](https://pieroot.xyz/api/image-proxy?id=51baac37-95de-42de-a6c7-3ce37125c941&kind=s3&pageId=396067c0-15d0-8083-bb29-faf58273aaa0&source=block&blockId=396067c0-15d0-8049-aeba-e295e5255e08)

*실제 출력 — **`rbd_directory`**는 128개, **`rbd ls`**는 141개로 정확히 13개 차이가 난다.*

omap을 건드리기 전에 `rbd_directory`부터 백업해 둔다.

```bash
rados -p volumes listomapvals rbd_directory > /root/rbd_directory_backup_$(date +%F).txt
```

![image](https://pieroot.xyz/api/image-proxy?id=b3e309a0-baef-491b-bac2-973cc57bd2be&kind=s3&pageId=396067c0-15d0-8083-bb29-faf58273aaa0&source=block&blockId=396067c0-15d0-8029-975b-c685cc6b5265)

*백업 실행 후 **`rbd_directory_backup_2026-07-07.txt`** 파일이 생성된 것을 확인했다.*

### 3) trash omap과 실체 헤더 대조 (★ 가장 중요한 단계)

먼저 trash omap에 남은 id 목록을 조회한다.

```bash
rados -p volumes listomapkeys rbd_trash
```

![image](https://pieroot.xyz/api/image-proxy?id=f8bf5f1f-efd4-436f-95bd-90ba6e59ce6c&kind=s3&pageId=396067c0-15d0-8083-bb29-faf58273aaa0&source=block&blockId=396067c0-15d0-8091-9e06-da1ba2814697)

*`rbd_trash`** omap 키 조회 결과 — 13개의 id가 그대로 남아 있다.*

특정 id가 대시보드의 어떤 볼륨인지 확인하고 싶다면 trash omap 값을 덤프해서 볼륨 UUID로 grep하면 된다. omap 값 안에 원래 볼륨 이름이 들어 있다.

```bash
rados -p volumes listomapvals rbd_trash | grep -B3 -A3 4af7fdd5
```

![image](https://pieroot.xyz/api/image-proxy?id=36703fae-74aa-4fb5-9850-07c2f7641879&kind=s3&pageId=396067c0-15d0-8083-bb29-faf58273aaa0&source=block&blockId=396067c0-15d0-80dc-9854-dd574e76db87)

*omap 값 덤프 — **`id_b3922a36a46a5f`**가 대시보드에서 경고가 떴던 **`volume-4af7fdd5-...`** 볼륨에 매핑돼 있다.*

trash 쪽 omap도 반드시 백업한다.

```bash
rados -p volumes listomapvals rbd_trash > /root/rbd_trash_backup_$(date +%F).txt
rados -p volumes listomapkeys rbd_trash > /root/rbd_trash_keys_$(date +%F).txt
```

![image](https://pieroot.xyz/api/image-proxy?id=86a6b254-92e5-4772-a1ba-3dafcb4999a3&kind=s3&pageId=396067c0-15d0-8083-bb29-faf58273aaa0&source=block&blockId=396067c0-15d0-80e2-af32-cfc01dc69db5)

*`rbd_trash_backup`**, **`rbd_trash_keys`** 백업 파일이 생성된 것을 확인했다.*

각 id의 실제 헤더가 존재하는지 일괄 확인한다.

```bash
# 각 id의 실제 헤더가 존재하는지 일괄 확인
for id in <id1> <id2> ... ; do
  echo -n "rbd_header.$id : "
  rados -p volumes stat rbd_header.$id 2>&1
done
```

![image](https://pieroot.xyz/api/image-proxy?id=b65bbf95-f645-483f-b756-b5e3f2220b68&kind=s3&pageId=396067c0-15d0-8083-bb29-faf58273aaa0&source=block&blockId=396067c0-15d0-80f9-955f-f9ce97340d17)

*헤더 대조 결과 — 13개 중 11개는 **`mtime ... size 0`**으로 헤더가 살아 있고, **`07e48cd3132c6c`**와 **`eac2c688543f96`** 두 개만 헤더가 없다.*

stat 결과에 따라 처리 경로가 갈린다.

| stat 결과 | 의미 | 처리 경로 |
| --- | --- | --- |
| `No such file or directory` | 헤더·데이터 완전 소멸. trash 매핑만 유령으로 남음 | **경로 B** — omap 키 직접 제거 |
| `mtime ... size 0` | 헤더 존재 = 삭제가 중간에 멈춘 진짜 trash 이미지 | **경로 A** — 정식 `rbd trash rm --force` |

> **여기서 분기가 갈린다 — 절대 건너뛰지 말 것**
> 
> 헤더가 있는 id와 없는 id를 반드시 구분해야 한다. 둘을 똑같이 처리하면 데이터가 orphan(고아)이 되거나 삭제가 실패한다.
> 
> 또한 `size 0`은 헤더 오브젝트라 정상이다. 크기가 0이라고 "없는 것"으로 오해하지 말자.

---

## 🧭 결정 트리

![RBD '제거 중' 상태 진단 결정 트리](https://pieroot.xyz/api/image-proxy?id=909b6cd6-af68-442c-bc08-4cce885e22a7&kind=s3&pageId=396067c0-15d0-8083-bb29-faf58273aaa0&source=block&blockId=1a67160e-7cc9-4acd-af1f-0b6879484941)

위 그림은 `rbd status/info` → `rbd_trash` omap → `rbd_header` 존재 여부 순서로 분기해 경로 A/B를 결정하는 흐름을 정리한 개념도다.

---

## 🛠️ 조치

어느 경로든 **백업이 먼저다.** 위 진단 단계에서 만든 `rbd_directory`, `rbd_trash` 백업 파일이 있는지 확인하고 진행한다.

### 경로 A — 헤더 있는 id 일괄 정상 삭제 (11개)

```bash
for id in <헤더-있는-id들> ; do
  echo "=== removing $id ==="
  rbd trash rm volumes/$id --force
done
# 각 항목이 "Removing image: 100% complete...done." 이면 성공
```

`--force`는 지연(deferred) 삭제 보호기간이 남아 있어도 지우기 위해 필요하다. 이 방식은 헤더·데이터·omap을 한 번에 정리하므로 orphan이 생기지 않는 **1순위 방법**이다.

이번 사례에서는 먼저 한 건(`1de31faa83ffa5`)을 단건으로 제거해 정상 동작을 확인한 뒤, 나머지 10개를 for 루프로 일괄 제거했다.

![image](https://pieroot.xyz/api/image-proxy?id=94cbc693-e474-439a-884c-ee293405e5f4&kind=s3&pageId=396067c0-15d0-8083-bb29-faf58273aaa0&source=block&blockId=396067c0-15d0-8015-9ee3-e61589254fe6)

*단건 검증 — **`1de31faa83ffa5`** 제거가 **`100% complete...done.`**으로 끝난 것을 먼저 확인했다.*

![image](https://pieroot.xyz/api/image-proxy?id=6f38d9bc-03a6-4d17-b435-e45a5c8a13ac&kind=s3&pageId=396067c0-15d0-8083-bb29-faf58273aaa0&source=block&blockId=396067c0-15d0-80bc-b8e0-f99b4f743b02)

*나머지 10개 일괄 제거 — 모든 항목이 done으로 완료됐다.*

### 경로 B — 헤더 없는 id만 omap 직접 제거 (2개)

`rbd trash rm`이 `error getting image id from trash`로 실패하거나 헤더가 아예 없는 id는, 데이터 잔재가 없는지 재확인한 뒤 매핑만 직접 제거한다.

```bash
# 데이터 오브젝트 잔재가 정말 없는지 재확인
rados -p volumes ls | grep <id>

# 없으면 trash omap 키 제거
rados -p volumes rmomapkey rbd_trash id_07e48cd3132c6c
rados -p volumes rmomapkey rbd_trash id_eac2c688543f96
```

> **rmomapkey는 헤더가 실제로 없는 id에만 쓴다**
> 
> 헤더가 있는데 omap만 지우면 데이터 오브젝트가 참조 불가능한 orphan으로 남아 공간을 돌려받지 못한다.
> 
> 백업 없이 omap을 손대는 것도 금물이다.

---

## ✅ 검증

```bash
rados -p volumes listomapkeys rbd_trash   # 비어 있어야 함
rados -p volumes listomapkeys rbd_directory | grep -c '^name_' # 아래 volumes 수와 비교할 directory 수
rbd ls volumes | wc -l                    # directory 수와 일치해야 함
ceph health detail
```

성공 기준은 다음과 같다.

- trash omap이 비어 있다.

- `rbd ls` 카운트가 `rbd_directory` 카운트(사례 기준 128)와 일치한다.

- 대시보드 Images 탭 새로고침 시 경고와 유령 볼륨이 사라진다.

![image](https://pieroot.xyz/api/image-proxy?id=08d30d27-f504-41b8-99b4-e77c458497c0&kind=s3&pageId=396067c0-15d0-8083-bb29-faf58273aaa0&source=block&blockId=397067c0-15d0-8013-b3ae-ddc2f327ab97)

---

## 📋 실제 처리 사례 요약 (2026-07-07)

pool `volumes`, 유령 엔트리 13개 기준.

| 단계 | 발견 | 조치 | 결과 |
| --- | --- | --- | --- |
| 카운트 | `rbd ls` 141 vs directory 128 | 차이 13개 = trash 유령 | 범위 확정 |
| 헤더 대조 | 13개 중 11개 헤더 존재, 2개 없음 | 경로 A / B 분리 | — |
| 경로 A | 헤더 있는 11개 | `rbd trash rm --force` | 11/11 done |
| 경로 B | 헤더 없는 2개 (`07e48cd3132c6c`, `eac2c688543f96`) | `rmomapkey rbd_trash id_...` | 제거됨 |
| 검증 | trash omap 비고, 카운트 128 | 대시보드 새로고침 | 경고 해소 |

---

## 🔎 사후 점검 — 왜 멈췄고, 무엇을 더 봐야 하는가

### ① Cinder DB 정합성 (OpenStack 연동 시 필수)

`volume-<uuid>` 이름은 Cinder가 만든 볼륨이다. Ceph를 정리해도 Cinder DB에 `deleting` / `error_deleting` 레코드가 남아 있으면 반쪽짜리 조치다.

```bash
openstack volume list --all-projects | grep -E '<uuid1>|<uuid2>'
```

- `available` / `in-use`로 남아 있으면 → **실 데이터 유실**이므로 함부로 지우지 말고 복구·보고가 먼저다.

- `deleting` / `error_deleting` → 삭제 의도 확정. Ceph 정리 후 Cinder DB 레코드도 정리한다.

### ② 근본 요인 — 왜 삭제가 중간에 멈췄나

이번 사례에서 trash 이미지들의 `mtime`이 3~6월에 걸쳐 누적돼 있었고, 동시에 `BLUESTORE_SLOW_OP_ALERT`(OSD 8개 slow op) 경고가 있었다. RBD trash purge가 백그라운드로 데이터를 지우다 **OSD 지연/장애로 멈춘 것들이 쌓인 것**으로 보인다(가설). slow op를 방치하면 삭제 재시도도 또 걸린다.

```bash
ceph health detail
ceph daemon osd.<N> dump_historic_slow_ops   # 어떤 작업이 느린지
dmesg | grep -i error                        # 디스크 커널 에러
smartctl -a /dev/<dev>                       # 해당 OSD 디스크 상태
```

네트워크 드롭 경고(`CephNodeNetworkPacketDrops`)도 함께 떴다면 OSD 간 통신 저하가 삭제 지연에 기여했을 수 있으니 인터페이스(`enp11s0` 등)도 점검한다.

### ③ 함께 알아두면 좋은 것

- **`rbd trash restore`**: 헤더가 살아 있는 trash 이미지는 삭제 대신 복구도 가능하다. 실수로 지운 볼륨이 trash에 있다면 `rmomapkey`부터 치지 말고 복구를 먼저 검토하자.

- **trash 주기 정리**: `rbd trash purge <pool>`로 만료된 trash를 일괄 정리할 수 있고, 버전에 따라 `rbd trash purge schedule`로 주기 실행도 지원한다(버전·환경에 따라 다름, 공식 문서 확인 필요). trash가 오래 쌓이는 환경이라면 정기 purge와 함께 slow op 모니터링을 붙여두는 게 안전하다.

- **Cinder deferred deletion**: Cinder RBD 드라이버는 삭제를 trash 기반 비동기로 미루는 옵션을 제공한다. 이 기능이 켜져 있으면 "삭제했는데 trash에 남아 있는" 동작 자체는 정상일 수 있으니, 장애로 오인하기 전에 설정부터 확인하자. `cinder.conf`의 RBD 백엔드 섹션에서 확인한다.

| 옵션 | 기본값 | 설명 |
| --- | --- | --- |
| `enable_deferred_deletion` | `False` | 삭제 시 즉시 지우지 않고 태그만 남긴 뒤 비동기로 제거 |
| `deferred_deletion_delay` | `0` | 삭제 태그 후 영구 제거까지의 지연 시간(초) |
| `deferred_deletion_purge_interval` | `60` | 삭제 태그된 볼륨을 purge하는 주기 태스크 간격(초) |

---

> **재발 방지 체크리스트**
> 
> - [ ] omap 조작 전 `rbd_directory` / `rbd_trash` omap을 백업했는가?
> 
> - [ ] `rmomapkey` 전에 id별로 `rbd_header` 존재 여부를 확인했는가?
> 
> - [ ] 정리 후 `rbd ls` 카운트와 `rbd_directory` 카운트가 일치하는가?
> 
> - [ ] Cinder DB에 `deleting` / `error_deleting` 레코드가 남아 있지 않은가?
> 
> - [ ] `ceph health detail`의 slow op / 네트워크 드롭 경고를 해소했는가?

---

## 핵심 정리

- ✅ **유령 수 파악**: `rbd ls` vs `rbd_directory` 카운트 차이가 trash 유령 엔트리 수다.

- ✅ **분기 기준**: `rbd_trash` 각 id의 `rbd_header` 존재 여부로 경로가 갈린다.

- ✅ **조치 순서**: 헤더 있으면 `rbd trash rm --force`(안전, 1순위), 없으면 백업 후 `rmomapkey`.

- ✅ **마무리**: Cinder DB 정합성과 OSD slow op까지 점검해야 재발을 막는다.

> **하지 말 것**
> 
> 헤더 존재 여부 확인 없이 `rmomapkey`로 일괄 삭제하지 말 것. 헤더 있는 이미지의 omap만 지우면 데이터가 orphan으로 남는다. 백업 없이 omap을 손대지 말 것.

---

## 참고 자료

- [Ceph 공식 문서 — Basic Block Device Commands](https://docs.ceph.com/en/latest/rbd/rados-rbd-cmds/)

- [Ceph 공식 문서 — rbd manpage (trash 명령 포함)](https://docs.ceph.com/en/reef/man/8/rbd/)

- [Ceph 공식 문서 — Block Devices and OpenStack](https://docs.ceph.com/en/latest/rbd/rbd-openstack)

- [OpenStack Cinder — Ceph RADOS Block Device (RBD) 드라이버 옵션](https://docs.openstack.org/cinder/2026.1/configuration/block-storage/drivers/ceph-rbd-volume-driver.html)
