--- date: 2026-07-11 topic: outline-data 볼륨 Longhorn 스냅샷 250개 하드리밋 초과 areas: [infra/platform/longhorn] --- # 2026-07-11 / outline-data 볼륨 snapshot count 하드리밋(250) 초과 ## 배경 정기 k3s 상태 점검(kubectl events 확인) 중 발견: ``` Warning Failed snapshot/critical-b8830e5f-... longhorn-snapshot-controller proxyServer=10.42.2.83:8501 destination=10.42.2.83:11000: failed to snapshot volume: rpc error: code = Unknown desc = snapshot count total is already too big: 250 ``` `outline/outline-data` PVC → Longhorn volume `pvc-c4bb2746-79f4-41ea-85fc-765cfc473b15` (attach node incus-hp2). 이 볼륨에 대해 `critical-snapshot`(매시 정각, retain 24) / `critical-backup`(6시간마다, retain 28) recurring job이 신규 스냅샷을 못 만드는 상태. ## 확인된 사실 ### 1. outline-data만의 이상 급증 (다른 볼륨은 정상) 전체 25개 Longhorn 볼륨 스냅샷 개수 비교: | 볼륨 | 스냅샷 수 | |---|---| | **pvc-c4bb2746 (outline-data)** | **256** | | pvc-b3ae6d0d 외 8개 | 55 | | pvc-e5f7459d | 42 | | pvc-573db32c 외 2개 | 38 | | pvc-7fcc0e0a | 31 | | pvc-f248b2d1 외 8개 | 30 | | pvc-405c0355 | 25 | | pvc-f4b8b3b4, pvc-c702c67d | 8 | 동일한 recurring-job-group(`critical`, `default`) 라벨을 가진 다른 볼륨들은 모두 8~55개 범위에서 retain 정책이 정상 작동 중. outline-data만 250 하드캡을 넘김. 가장 오래된 잔존 스냅샷은 2026-06-01 (약 40일 전) — 정상 볼륨이면 retain 24~28에 의해 진작 정리됐어야 할 나이. ### 2. Backup(R2 업로드)은 정상 — 문제는 순수 snapshot만 `kubectl get backups.longhorn.io` 로 확인: outline-data의 Backup CR은 10개 전부 `Completed`, retain(28) 이내. 즉 R2로의 실제 백업/정리는 문제 없음. 하드캡을 넘긴 건 스냅샷(로컬 체인) 쪽만. ### 3. (정정) `status.ownerID=""` 는 outline-data만의 특징이 아님 최초 가설: 이 볼륨 스냅샷들의 `ownerID` 가 비어있어 [[2026-05-02-longhorn-snapshot-purge-cron|2026-05-02 v1.11.1 ownerID-loss 회귀]]와 동일 패턴이라 추정했으나, **클러스터 전체 25개 볼륨 전 스냅샷을 재확인한 결과 ownerID="" 는 모든 볼륨에 공통**이었음 (outline-data 256개, 나머지 볼륨들도 각자의 전체 스냅샷 100%가 동일). 즉 이 값은 정상/이상을 가르는 신호가 아니었고 위 가설은 근거 없음 — 재발 원인을 ownerID 회귀와 동일시하지 말 것. ### 4. 수동 kubectl delete 시도 → 실제 삭제 안 됨 (outline-data에서 재현, 타 볼륨 미검증) 하드캡 해소를 위해 가장 오래된 226개(최근 30개만 남기고) `kubectl delete snapshots.longhorn.io` 실행: - 즉시 삭제되지 않고 `metadata.deletionTimestamp` 만 설정, `finalizers: ["longhorn.io"]` 유지된 채 정지 - 수 분 경과 후에도 199개가 `deletionTimestamp` 있음 + `status.markRemoved=false` 그대로 — engine 단에서 삭제 요청이 전혀 처리되지 않음 - 전체 스냅샷 개수는 삭제 시도 전후 256개로 변화 없음 (실질적 정리 실패) - **볼륨 자체는 영향 없음**: `state=attached, robustness=healthy`, Outline pod/서비스 정상 (재시작 없음) - 이 "삭제해도 안 지워짐" 현상이 다른 정상 볼륨에서도 재현되는지는 검증 안 함 — outline-data만 시도했음 ### 5. Outline 파드 삭제 → 볼륨 detach/reattach 시도 → 효과 없음 (반증됨) 가설: 파드를 삭제해 볼륨을 완전히 detach 시켰다가 재attach 시키면 engine이 새로 뜨면서 stuck 상태(199개 deletionTimestamp-고착)가 풀릴 수도 있다. 실행: `kubectl delete pod outline-5d9fd7c56-62f6t -n outline` → ReplicaSet이 새 파드를 다른 노드(incus-hp2 → **incus-kr1**)에 스케줄 → 볼륨이 완전히 새 노드로 재attach (`state=attached, robustness=healthy, node=incus-kr1`), 새 engine 프로세스로 교체됨. 파드는 정상 Running 복귀, Outline 서비스 중단 없음(수 초 이내). **결과: 아무 변화 없음.** - 전체 스냅샷 개수: 재시도 전후 동일하게 256개 - `deletionTimestamp` 있는 stuck 항목: 200개 그대로 (재attach로 처리 진행 안 됨, markRemoved 여전히 false) - 새로 뜬 engine 하에서도 `ownerID`는 256개 전부 빈 값 그대로 **결론: "볼륨 detach/reattach(=파드 재배포)로 리셋된다"는 가설은 틀렸다.** 문제는 노드/engine/instance-manager 레벨이 아니라 **longhorn-manager 컨트롤 플레인 쪽 상태**에 있는 것으로 보임 (레플리카·engine을 갈아치워도 CR 상의 stuck 상태가 그대로 유지되는 것이 그 근거). 향후 같은 시도 반복 불필요. ### 6. 해결: `snapshotPurge` API 반복 호출로 256개 → 58개 정상화 `kubectl delete`(finalizer 무력화됨)와 파드/노드 재attach(효과 없음) 둘 다 실패한 뒤, [[2026-05-02-longhorn-snapshot-purge-cron|2026-05-02 도입 기록]]에 나온 Longhorn REST API `snapshotPurge` 액션을 직접 호출: ```bash kubectl port-forward -n longhorn-system svc/longhorn-frontend 19500:80 & curl -s -X POST -H "Content-Type: application/json" -d '{}' \ "http://127.0.0.1:19500/v1/volumes/pvc-c4bb2746-79f4-41ea-85fc-765cfc473b15?action=snapshotPurge" ``` - 1회 호출마다 응답은 HTTP 200 + 볼륨 리소스 echo (액션 자체 결과값은 없고 트리거만 됨 — 비동기) - 약 8~10초 간격으로 **반복 호출**하니 매번 카운트가 점진적으로 감소: 256 → 225 → 209 → 200 → 192 → 181 → 169 → 145 → 130 → 103 → 90 → 74 → 67 → 59 → **58** - 총 약 20회 트리거, 5분 정도 소요 - 최종 상태: 스냅샷 58개(다른 정상 볼륨과 같은 범위), `deletionTimestamp` 남은 것 3개(자연 정리 진행 중으로 추정), 볼륨 `state=attached/robustness=healthy`, Outline 파드 정상 Running, 서비스 중단 없음 **교훈**: 이 볼륨의 문제는 kubectl CR delete로는 못 풀리고(webhook이 finalizer 유지) engine 재시작(파드 재배포/재attach)으로도 안 풀렸다 — **오직 Longhorn 자체 `snapshotPurge` API를 반복 호출해야만 체인이 실제로 정리**됐다. 1회 호출은 충분하지 않고, 남은 개수가 줄어드는 걸 보면서 **여러 번 반복 호출**해야 완전히 정리됨(한 번에 전부 처리되는 게 아니라 매 호출마다 일부 chain만 병합·정리하는 것으로 보임). ### 7. 근본 원인 재구성: [[2026-06-01-longhorn-snapshot-retention-fix|2026-06-01 수정]]이 사실상 작동한 적이 없었음 이 사건 도중 기존 이력 [[2026-06-01-longhorn-snapshot-retention-fix|2026-06-01-longhorn-snapshot-retention-fix]]를 재확인. 그 문서의 핵심: 당시 전체 906개 스냅샷이 `recurring-job.longhorn.io/` 라벨 100% 누락 상태였고(각 RecurringJob의 `spec.labels`가 `{}`라서 retention이 자기 소속 스냅샷을 식별 못함), 4개 RecurringJob(`critical-snapshot`/`critical-backup`/`standard-snapshot`/`standard-backup`)에 `spec.labels`를 수동 patch해서 "다음 cron 실행부터 라벨 붙어 정상화될 것"이라 결론지었음. 단, 그 문서의 "검증" 섹션은 **"(예정)"으로 끝나 실제 확인이 안 된 채 방치**되어 있었음. 오늘(2026-07-11) 직접 재검증한 결과: ```bash kubectl get recurringjobs.longhorn.io -n longhorn-system critical-snapshot -o jsonpath='{.spec.labels}' # → {"recurring-job.longhorn.io/critical-snapshot":"enabled"} (patch는 그대로 살아있음, ArgoCD에 되돌려지지 않음) ``` 그런데 **가장 최근 생성된 스냅샷들(오늘 새벽 03시대, 다른 여러 볼륨)조차 `recurring-job.longhorn.io/*` 라벨이 전혀 붙어있지 않음** — `longhornvolume` 라벨만 존재. 즉 `spec.labels` 설정은 살아있는데 실제 라벨 부착 메커니즘이 **지금도 작동하지 않고 있음**. 2026-06-01의 "영구 수정"은 patch 자체는 유지됐지만 **한 번도 실제로 의도대로 동작한 적이 없었던 것**으로 재확인됨 (또는 이후 알 수 없는 이유로 재차 깨짐 — 어느 쪽이든 결과는 동일). **중요한 함의**: 라벨 기반 retention이 클러스터의 **모든 볼륨에서 지금도 동작 안 함**. outline-data(256)와 다른 볼륨들(8~55)의 극심한 개수 차이는 retention 여부 차이가 아니라 — **볼륨별 실제 쓰기 빈도 차이**로 보임 (Outline 위키는 상시 활발히 쓰기 발생 → 매 스케줄마다 실질적으로 새 스냅샷이 계속 쌓임 vs 조용한 볼륨은 변경 없으면 스냅샷 생성 자체가 적어 우연히 250 근처에 못 감). 즉 **outline-data는 "첫 번째로 한도에 도달한 사례일 뿐, 나머지 볼륨들도 시간 문제**"일 가능성이 높음. ### 8. 타 볼륨 점검 (같은 날 재검증) — 전부 안전하나 "버스트성 증가" 패턴 확인 outline-data 정리 직후 전체 25개 볼륨 스냅샷 개수 재점검: 최댓값 55개(outline-data 포함 10개 볼륨 동률), 250 하드캡까지 전부 여유 있음. 단, `n8n`(pvc-b3ae6d0d, 55개) 시계열 분석 결과 **하루 1개씩 30일 누적된 게 아니라, 2026-06-11~07-09는 하루 1개씩이다가 2026-07-10 하루에만 22개가 몰아서 생성**됨. 클러스터 전체로 확인한 결과 **같은 날(2026-07-10) 약 10개 볼륨(gitea 3종, openmemory 2종, apisix-etcd-2, teleport, portainer, vm-stack 등)에서 동시에 21~22개씩 버스트 발생**, 나머지 날짜는 모두 1개/일 수준. → hourly `critical-snapshot` 작업이 평소엔 사실상 거의 안 돌다가(라벨도 여전히 전부 미부착 확인됨 — `longhornvolume` 라벨만 존재), 특정 구간에만 몰아서 실행되는 불규칙한 패턴으로 보임. outline-data가 2026-06-05~07-06 한 달 가까이 이 "몰아서 실행" 상태가 계속돼 256까지 갔던 것과 같은 계열의 현상 — **다른 볼륨도 같은 버스트가 길게 지속되면 동일하게 250에 도달할 수 있음**. "지금 안전하다"가 "앞으로도 안전하다"를 보장하지 않음. ## 후속 필요 (근본 원인 재조사 필요 — 재발/타 볼륨 위험 있음) - **당장의 하드캡 문제는 해소됨** (58개, 여유 충분) - **진짜 근본 원인**: `spec.labels`는 올바르게 설정돼 있는데도 실제 스냅샷에 `recurring-job.longhorn.io/*` 라벨이 안 붙는 메커니즘 자체의 결함 — Longhorn v1.11.2의 알려지지 않은 버그이거나, RecurringJob 오브젝트를 patch가 아니라 재생성해야 반영되는 구조일 가능성. **미해결** - **위험 범위 재평가 필요**: 라벨/retention 결함이 전 볼륨 공통이므로, 쓰기 빈도가 높은 다른 볼륨(gitea, postgres 등)도 시간이 지나면 같은 250 하드캡에 부딪힐 수 있음 — outline-data 국한 문제가 아님 - 우선순위 제안: 1. **Longhorn `recurring-job.longhorn.io/*` 라벨이 왜 안 붙는지 직접 조사** (instance-manager/longhorn-manager 로그, RecurringJob 재생성 필요 여부 확인) — 이번 사건의 진짜 근본 수정 2. 원인 규명 전까지는 주기적으로(예: 주 1회) 전체 볼륨 스냅샷 개수 점검해 250 근접 볼륨 조기 발견 (`kubectl get snapshots.longhorn.io -A -o json | jq` 로 볼륨별 카운트) 3. 재발 시 이번에 검증된 `snapshotPurge` API 반복 호출로 즉시 완화 가능 (수 분 내 해결, 재현성 확인됨) 4. Longhorn upstream에 "`spec.labels` 설정에도 불구하고 스냅샷에 라벨 미부착" 으로 신규 이슈 등록 검토 ## 관련 문서 - [[../infra/platform/longhorn|longhorn]] — Longhorn 정본 문서 - [[2026-05-02-longhorn-snapshot-purge-cron|2026-05-02 snapshot-purge cron 도입]] / [[2026-05-09-longhorn-snapshot-purge-cron-removal|2026-05-09 회수]] — 유사하나 별개로 판명된 과거 사건 - [[../data/k3s-backup|k3s-backup]] — 백업/recurring job 구성