← 목록
기타 2026-07-26 10KB 읽기 11분

크라우니클라우드 백업/복원 구현 (P1-⑤)

개요

설계문서(2026-07-25-크라우니클라우드-백업설계-P2프레이밍.md P1-⑤)에 따라 로컬 스냅샷+GFS회전+무결성검증+복원까지 구현. 오프사이트(원격 복제)는 사업/인프라 결정 대기라 이번 범위에서 제외.

산출물

  • /Users/ef/crowny-services/백업회전.한선 — GFS 회전 판정 코어(한선씨). STRICT 컴파일 경고 0.
  • /Users/ef/crowny-services/크라우니클라우드백업.sh — 드라이버(snapshot/verify/list/rotate/cycle/restore).
  • /Users/ef/Library/LaunchAgents/org.crowny.cloudbackup.plist — 6시간 주기 자동 스냅샷+회전.

사용법

bash크라우니클라우드백업.sh snapshot          # data/ → ~/crowny-backups/cloud/YYYY-MM-DD-HHMM.tar.zst
크라우니클라우드백업.sh verify [스냅샷]    # 무결성 검증(미지정=최신)
크라우니클라우드백업.sh list               # 스냅샷 목록(시간·크기)
크라우니클라우드백업.sh rotate             # GFS 판정(기본 dry-run) — CONFIRM=1이면 삭제(타) 실제 실행
크라우니클라우드백업.sh restore <스냅샷>   # 파괴적 — 기본 dry-run(절차만 출력). CONFIRM=1 필요
크라우니클라우드백업.sh cycle              # snapshot 후 rotate (LaunchAgent가 CONFIRM=1로 호출)
환경변수: CROWNY_CLOUD_DATA(기본 /Users/ef/crowny-services/data), CROWNY_BACKUP_DIR(기본 ~/crowny-backups/cloud), CONFIRM=1(rotate 실삭제/restore 실복원 게이트, 기본 둘 다 dry-run).

GFS 회전 정책 (백업회전.한선)

  • 입력: 스냅샷 타임스탬프(YYYY-MM-DD-HHMM) 줄단위 텍스트. 경로=환경변수("RTN_LIST")(ASCII env명 필수, 미설정 시 /tmp/백업목록.txt).
  • 정책: 일간 7(최근 distinct 7일 — 그 안의 스냅샷은 전부 유지) → 주간 4(그다음 28 distinct일을 7일 단위로 묶어 각 그룹의 최신 1개만 유지) → 월간 6(그다음부터는 실제 달력월 단위로 각 1개만 유지) → 그 외 전부 삭제.
  • 4상 출력: 유지|ts(티) / 삭제|ts(타) / 보류|ts(옴, 형식오류 — 15자 길이·구분자 위치·자릿수·월01-12/일01-31/시00-23/분00-59 범위 검증 실패).
  • 날짜 그룹핑은 부분()+동등비교 카운터만 사용(나눗셈/에포크 산술 금지 — 가드레일 함정 회피). 정렬은 수동 버블정렬(문자열 정렬() 무동작 함정 회피, </> 비교는 15자 고정폭에서 정상 동작 실측 확인).

발견한 실측 함정 (이번 작업 중)

  • CROWNY_STRICT=1 환경에서 컴파일 자체는 정상(즉시, 경고 없음)이지만, 최초 1회 combined 쉘 커맨드(대용량 .toau 바이너리 텍스트 cat|tail 직후 crownyc run)에서 원인미상 행(hang) 1회 재현 — 이후 격리된 단일 명령으로는 재현 안 됨. 환경적 요인 의심, 코드 자체 결함 아님(재현 실패로 결론 보류).
  • 유효타임스탬프() 최초 버전이 자릿수·범위 검증 없이 형식(길이+구분자 위치)만 봐서 2026-13-99-9999 같은 쓰레기를 통과시켰고, 이게 정렬 최상단(newest)으로 밀려 GFS 카운터 전체를 1칸씩 밀리게 하는 연쇄 오류를 유발함 → 자릿수(0-9)+월01-12/일01-31/시00-23/분00-59 범위검증 추가로 수리, 재검증 통과.

컴파일

cd /Users/ef/crowny-services
env CROWNY_STRICT=1 /Users/ef/CrownyOS/crownyc/hanseonc_high 백업회전.한선 > 백업회전.toau
결과: [hanseonc] 2281 토큰 파싱 / [hanseonc] 3814 큐브 생성 — STRICT 경고 0건.

검증 실측 원문

1. snapshot

[크라우니클라우드백업] 스냅샷 시작: /Users/ef/crowny-services/data → /Users/ef/crowny-backups/cloud/2026-07-26-2322.tar.zst
[크라우니클라우드백업] 스냅샷 완료: /Users/ef/crowny-backups/cloud/2026-07-26-2322.tar.zst (3.8M)
list 출력에 즉시 노출됨.

2. verify

[크라우니클라우드백업] 검증 대상: /Users/ef/crowny-backups/cloud/2026-07-26-2322.tar.zst
[크라우니클라우드백업]   [PASS] 압축+tar 구조 무결성
[크라우니클라우드백업]   [PASS] blob sha256 재해시 샘플 17/17
[크라우니클라우드백업]   [FAIL] anchor 체인 연속성 스팟 9/10 파일 (불연속 1)
[크라우니클라우드백업] 검증 결과: FAIL
tar 구조·blob sha256 재해시(파일명=내용 sha256, content-addressed 실측 확인)는 전량 PASS. anchor 체인 스팟에서 실제 데이터 손상 1건을 발견: data/anchor/anon_2b31a9525d834c398f6ca767ffb002a3/cloud.jsonl 26번째 줄이 깨진 JSON("content":"...cec0\" 처럼 이스케이프 안 된 \" 혼입 — 유효 JSON 아님). 이건 백업 도구가 만든 문제가 아니라 라이브 data/ 원본 파일 자체에 이미 존재하는 손상(추출본과 라이브본 동일 확인). 검증 도구가 의도대로 실제 무결성 문제를 잡아낸 것 — 이번 작업 범위 밖이라 수정하지 않음, 별도 이슈로 후속 조치 필요(해당 owner 앵커 체인 재생성 또는 손상 줄 스킵 복구).

3. rotate

라이브(스냅샷 1~2개뿐)에서는 전부 daily tier 안이라 전량 유지:
  유지|2026-07-26-2322
[크라우니클라우드백업] GFS 판정: 유지 1 · 삭제 0 · 보류 0
[크라우니클라우드백업] 삭제 대상 없음
픽스처(58~60개, 형식오류 2개 포함)로 백업회전.toau 단독 실행해 GFS 경계 정확성 확인:
  • 일7/8 경계: 상위 7 distinct일(2026-07-26~07-20)의 모든 스냅샷(14개, 하루 2개씩) 전부 유지. 8번째 distinct일(07-19)부터 주간 tier 진입 확인.
  • 주4/5 경계: 주간 tier 4개 그룹(각 7 distinct일)에서 그룹당 최신 1개만 유지(07-19, 07-12, 07-05, 06-28), 그룹 내 나머지 전부 삭제. 5번째(다음 그룹은 이미 월간 tier로 전환) 미발생 확인.
  • 월6/7 경계: 달력월 단위로 06월(06-21)~01월(01-16)까지 6개월 각 1개 유지, 2025-12·2025-11(7·8번째 달)은 삭제.
  • 형식오류: 형식오류(길이 미달) · 2026-13-99-9999(월13·일99 등 범위초과) 둘 다 보류.

4. restore (dry-run)

[크라우니클라우드백업] === restore 절차 (대상: /Users/ef/crowny-backups/cloud/2026-07-26-2322.tar.zst) ===
[크라우니클라우드백업] 1. cloud(:9611) 리스너 정지
[크라우니클라우드백업] 2. 자가치유 데몬(com.crowny.services manage.sh daemon) SIGSTOP — 복원 도중 재기동 경합 방지
[크라우니클라우드백업] 3. 현재 /Users/ef/crowny-services/data/ 내용을 /Users/ef/crowny-services/data/_복원전_20260726-2342/ 로 이동(보존)
[크라우니클라우드백업] 4. 스냅샷 전개 → /Users/ef/crowny-services/data/
[크라우니클라우드백업] 5. SERVICE=cloud PORT=9611 로 cloud 재기동
[크라우니클라우드백업] 6. http://127.0.0.1:9611/api/health 200 확인(최대 10회, 1초 간격 폴)
[크라우니클라우드백업] 7. 실패 시 롤백: 새로 전개된 데이터 제거 → _복원전_20260726-2342/* 를 /Users/ef/crowny-services/data/ 로 복원 → 재기동
[크라우니클라우드백업] 8. 데몬 SIGCONT(재개)
[크라우니클라우드백업] dry-run — 위 절차만 출력, 실제 실행 없음(라이브 무영향). CONFIRM=1로 재실행 시 실제 복원.
CONFIRM 미설정 상태로 실행 — 실제 복원·재기동 없음. 직후 curl /api/health 200, pid(11638) 불변 확인(라이브 무영향).

5. LaunchAgent

bashlaunchctl load ~/Library/LaunchAgents/org.crowny.cloudbackup.plist
launchctl list | grep cloudbackup   # -> "-  0  org.crowny.cloudbackup"
RunAtLoad 첫 실행 로그(~/crowny-backups/cloud/backup.log):
[크라우니클라우드백업] 스냅샷 시작: ... → 2026-07-26-2342.tar.zst
[크라우니클라우드백업] 스냅샷 완료: ... (3.8M)
  유지|2026-07-26-2342
  유지|2026-07-26-2322
[크라우니클라우드백업] GFS 판정: 유지 2 · 삭제 0 · 보류 0
[크라우니클라우드백업] 삭제 대상 없음
cycle(snapshot+rotate, CONFIRM=1)을 6시간 주기로 실행하도록 구성(GFS 유지개수 내 삭제라 자동 실행 안전 판단, plist EnvironmentVariables에 CONFIRM=1 명시).

6. 라이브 무영향

백업 사이클(snapshot+verify+rotate+restore dry-run+LaunchAgent 최초실행) 전체 진행 중·후 curl /api/health 지속 200, lsof -iTCP:9611 pid 11638 불변 확인.

데이터 구조 확인 (verify 설계 근거)

  • data/blobs/<owner>/<sha256> — 파일명=내용 sha256 hex(64자) 정확히 일치, content-addressed 확인(실측).
  • data/anchor/<owner>/cloud.jsonl — append-only 해시체인, 각 줄 {seq,prev,content,anchor,ts}, prev[i] == anchor[i-1] 연속성.

제외 대상(스냅샷)

data/_격리_* · data/_복원전_* · data/_backups — 정크/순환 회피.

잔여 이슈

  1. 오프사이트 복제 — 결정 대기(설계문서 결정A: 원격 VPS 경로/용량 미확정). 이번 범위는 로컬 스냅샷까지.
  2. anchor 체인 손상 1건 발견: data/anchor/anon_2b31a9525d834c398f6ca767ffb002a3/cloud.jsonl:26 깨진 JSON — 별도 조치 필요(이번 작업 범위 밖, 수정 안 함).
  3. LaunchAgent가 CONFIRM=1로 자동 rotate 삭제를 수행하므로, GFS 유지개수(7/4/6) 밖 스냅샷은 6시간 주기로 자동 소멸함 — 정책 변경 시 백업회전.한선의 상수(7/35/6) 수정 후 재컴파일 필요.

크라우니코드 학습

크라우니코드: lookup HIT 1건(fn_백업_보존정책적용 — 참고만, 재사용 안 함: 단순 개수절단 vs 이번 요구인 날짜기반 GFS는 로직이 다름) / MISS 1건(신규 GFS 판정 로직 생성) / learn 추가 1건
crownycode-brain.sh learn "크라우니클라우드 백업 GFS회전 판정" 백업회전.한선 실행 결과: 학습완료: 크라우니클라우드_백업_GFS회전_판정 (lint: 판정|티|셀코어룰엔진(슬롯6타/7옴/8티→9판정트릿))

관련 파일

  • /Users/ef/crowny-services/백업회전.한선
  • /Users/ef/crowny-services/백업회전.toau
  • /Users/ef/crowny-services/크라우니클라우드백업.sh
  • /Users/ef/Library/LaunchAgents/org.crowny.cloudbackup.plist
  • /Users/ef/crowny-backups/cloud/ (스냅샷 저장소 + backup.log)