> ## Documentation Index
> Fetch the complete documentation index at: https://docs.casebender.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 스토리지 마이그레이션 런북

> 데이터 손실 없이 제공자 스토리지를 복사, 검증, 전환, 롤백합니다

이 런북은 객체 키를 변경하지 않고 CaseBender 객체를 마이그레이션합니다.
복사 우선 의미를 사용합니다. 소스는 롤백 창이 만료될 때까지 권한
원본이며 온전합니다. `rclone` 원격을 통해 로컬 파일시스템, MinIO/S3
호환 스토리지, AWS S3, GCS에 적용됩니다.

## 전제 조건

* 두 제공자에 대한 스토리지 지원 정책과 릴리스 노트를 읽으세요.
* 릴리스가 제공자 중립의 내구성 삭제 outbox를 사용하는지 확인하세요.
  과거 MinIO 전용 삭제 공백은 수정되었습니다. 그 오래된 제한을
  새 설계에 가져오지 마세요.
* 대상 용량, 암호화, 버전 관리, 보존, 수명 주기, 객체 크기,
  메타데이터, 명명 동작을 확인하세요.
* 최소 권한 소스 읽기 및 대상 쓰기 마이그레이션 아이덴티티를
  만드세요.
* TLS 신뢰를 구성하고 `--no-check-certificate`를 사용하지 마세요.
* PostgreSQL과 소스 스토리지의 일관성 백업을 수행하고 테스트하세요.
* 객체 수, 총 바이트, 소스 버전/스냅샷, 구성을 기록하세요.
* 쓰기 정지와 롤백을 허용하는 변경 창을 설정하세요.

권한 있는 PostgreSQL 객체 인벤토리를 생성하고 보호하세요.

```sh theme={null}
pnpm storage:backup-verify inventory \
  --output '<protected-manifest.json>'
chmod 600 '<protected-manifest.json>'
```

마이그레이션되는 모든 항목은 정확한 소스 객체 버전/세대, 크기,
SHA-256을 식별해야 합니다. PostgreSQL과 해당 정확한 버전은 하나의
일관성 집합입니다. 버전이 기록되어 있을 때 유동적인 “latest” 객체를
마이그레이션하지 마세요.

아래 예는 `source:casebender`와 `destination:casebender`를 사용합니다.
rclone 구성과 로그는 리포지토리 밖에 두고 민감 정보로 보호하세요.

## 1. 인벤토리 및 드라이 런

```sh theme={null}
rclone version
rclone size source:casebender --json > source-size.before.json
rclone lsf source:casebender --recursive --files-only \
  > source-objects.before.txt
rclone copy source:casebender destination:casebender \
  --checksum --metadata --dry-run --log-level INFO \
  --log-file migration-dry-run.log
```

지원되지 않는 메타데이터 경고를 검토하세요. 제공자별 암호화, 보존,
법적 홀드, ACL, 버전 이력은 일반 객체 메타데이터로 복사되지 않을
수 있습니다. 대상에서 해당 제어를 구성하고 백업에 소스 버전을
보존하세요. 초기 복사에 `sync`를 사용하지 마세요. 대상 객체를
삭제할 수 있습니다.

## 2. 애플리케이션이 온라인인 동안 시드 복사

```sh theme={null}
rclone copy source:casebender destination:casebender \
  --checksum --metadata --fast-list --transfers 8 --checkers 16 \
  --log-level INFO --log-file migration-seed.log
```

동시성을 제공자 스로틀 한도 아래로 조정하세요. 실패한 객체를
재시도하고 전체 로그를 보관하세요. ETag로부터 무결성을 추론하지
마세요. 멀티파트 및 암호화된 객체는 MD5가 아닌 ETag를 가질 수
있습니다.

## 3. 쓰기를 정지하고 일관성 지점을 캡처

릴리스의 유지보수 절차를 사용하여 사용자 및 통합 쓰기를 차단하세요.
큐가 드레인되거나 내구성 있게 보존된 뒤에만 수집과 워커를
일시 중지하세요. 데이터베이스 타임스탬프/LSN, 소스 버킷
버전/스냅샷, 배포 레플리카를 기록하세요. 스토리지 쓰기가 발생하지
않는지 확인하세요.

최종 델타를 실행하세요.

```sh theme={null}
rclone copy source:casebender destination:casebender \
  --checksum --metadata --fast-list --transfers 8 --checkers 16 \
  --log-level INFO --log-file migration-final.log
```

소스를 삭제하거나 비활성화하지 마세요.

## 4. 전환 전 검증

```sh theme={null}
rclone check source:casebender destination:casebender \
  --download --one-way --combined migration-check.txt
rclone size source:casebender --json > source-size.final.json
rclone size destination:casebender --json > destination-size.final.json
```

`rclone check --download`는 다운로드한 콘텐츠를 해시하고 제공자
ETag 모호성을 피합니다. 누락, 변경, 읽을 수 없는 객체가 없어야
합니다. 제공자 마커 객체 또는 로컬 `.meta.json` sidecar로 인한
개수 차이를 조사하고, 기록된 설명 없이 차이를 면제하지 마세요.

애플리케이션 네트워크에서 대상 계약 테스트를 실행하세요.

```sh theme={null}
STORAGE_TEST_PROVIDER=s3 \
STORAGE_TEST_ENDPOINT=https://storage.example.com \
STORAGE_TEST_BUCKET=casebender \
AWS_REGION=us-east-1 \
./scripts/storage/validate-storage.sh
```

GCS 또는 로컬 예는 스크립트 사용법을 참고하세요. 고가치 증거,
대형 멀티파트 객체, Unicode 이름, 빈 파일, MIME 메타데이터,
보존된 객체도 샘플링하세요.

## 5. 전환

1. 암호화된 변경 기록에 이전 제공자 구성과 Secret 리소스 버전을
   저장하세요.
2. `StorageMigrationLedger` 항목이 `VERIFIED`인지 확인하세요.
   마이그레이션 프로세서는 먼저 복사하고, 다시 읽고, SHA-256을
   검증하고, 대상 제공자 버전을 기록한 뒤에만 `CUTOVER`로
   전환합니다.
3. 명시적 제공자 프로필과 자격 증명만 변경하세요. 버킷 내용과
   내구성 키는 보존하세요.
4. 웹 애플리케이션을 재시작하고 `/api/health/ready`를 기다리세요.
5. 애플리케이션 업로드/다운로드/list/copy/delete 테스트를 실행하고
   SHA-256을 검증하세요.
6. 여러 경과 시간과 크기에 걸쳐 기존 첨부 및 증거를 검증하세요.
7. 워커와 수집을 재개한 다음 사용자 쓰기를 재개하세요.
8. 롤백 창 동안 스토리지 오류, 실패한 삭제, 지연, 스로틀링,
   큐 깊이, 감사 이벤트를 지속적으로 모니터링하세요.

릴리스별 마이그레이션이 명시적으로 요구하지 않는 한 데이터베이스
키 재작성을 실행하지 마세요.

문서화된 호환성 창 동안 레거시 참조는 소스에서 읽고, 원장 기반
객체는 대상을 사용할 수 있습니다. 제한 없는 이중 쓰기를 구현하지
마세요. 조정으로 누락된 참조가 없고 롤백 승인이 허용한 뒤에만
레거시 읽기를 닫으세요.

## 6. 롤백

롤백은 이전 소스가 유지되고 새 쓰기를 조정할 수 있는 동안에만
안전합니다.

1. 유지보수 모드로 다시 들어가 쓰기를 정지하세요.
2. 전환 이후 대상에 기록된 모든 객체를 기록하세요.
3. 삭제 없이 역방향 델타를 소스에 복사하세요.

```sh theme={null}
rclone copy destination:casebender source:casebender \
  --checksum --metadata --fast-list \
  --log-level INFO --log-file rollback-copy.log
rclone check destination:casebender source:casebender \
  --download --one-way --combined rollback-check.txt
```

4. 깨끗한 검사를 요구한 다음, 이전 제공자 구성과 자격 증명
   버전을 복원하세요.
5. 재시작하고, 애플리케이션 수명 주기/무결성 테스트를 실행한 뒤
   트래픽을 재개하세요.
6. 인시던트/변경 검토가 완료될 때까지 두 스토어와 모든 증거를
   유지하세요.

소스 보존 또는 정책이 역방향 복사를 막으면 중단하고 기록된
일관성 백업을 복원하세요. 파괴적인 동기화를 즉흥적으로 하지
마세요.

## 7. 종료

* 최종 개수/바이트를 조정하고 해시, 로그, 도구 버전, 승인,
  구성 버전, 샘플링된 애플리케이션 결과를 아카이브하세요.
* 임시 마이그레이션 자격 증명을 로테이션하세요.
* 승인된 롤백 기간 동안 소스를 읽기 전용으로 유지하세요.
* 공식 서명과 법적/보존 검토 후, 제공자의 감사된 폐기 프로세스로
  소스 데이터를 제거하세요.
* 지원 기록을 제공자 제품/버전, TLS/CA 세부 정보, 계약 결과,
  성능 결과, 백업 결과, 롤백 연습으로 업데이트하세요.

소스 폐기 전에 격리된 복원 검증을 실행하세요.

```sh theme={null}
pnpm storage:backup-verify verify-restore \
  --manifest '<protected-manifest.json>' \
  --target-profile '<isolated-restore-profile>' \
  --isolated-prefix 'tenants/<test-tenant>/restore-verification/<exercise-id>' \
  --evidence-output '<sanitized-restore-evidence.json>'
```

실제 복구 지점과 복구 시간을 기록하세요. 측정된 복원과 롤백
연습이 없는 RPO/RTO 목표는 증거가 아닙니다.

## 제공자별 주의 사항

* **S3/Ceph RGW:** 버전 ID와 delete marker를 보존하세요. 일반
  복사는 Object Lock/법적 홀드 상태를 유지하지 않을 수 있습니다.
  정확한 제품 버전과 프라이빗 CA를 재자격 검증하세요.
* **GCS:** 숫자 세대를 보존하세요. 버킷 보존, 객체 보존, 이벤트
  기반 홀드, CMEK 정책은 별도의 대상 증명이 필요합니다.
* **Azure:** blob 버전 ID를 보존하세요. 불변성과 법적 홀드는
  대상별이며, 복사된 blob은 새 버전 ID를 받습니다.
* **레거시 MinIO:** 원본 볼륨 스냅샷과 S3 API 내보내기를 모두
  유지하세요. MinIO의 내부 파일시스템 레이아웃을 다른 제공자로
  가져오지 마세요.

[백업 및 복원](/ko/deployment/storage-backup-restore)과
[MinIO 수명 주기](/ko/deployment/storage-minio-lifecycle)를
참고하세요.
