Files
obsidian/infra/data/k3s-backup.md
kaffa 75cdcc0aa6 OpenMemory(Mem0) 서비스 전면 폐기
kappa 세션의 MCP 호출 실패를 계기로 K3s 공용 OpenMemory 서비스를
완전히 폐기(ArgoCD Application + namespace 삭제, chart 소스 제거,
MCP 클라이언트 등록 해제). heimdall/syn도 사용 중이었으나 대체 없이 중단.
IronDesk 전용 별도 인스턴스(irondesk-openmemory, RUNNING 확인)는
범위에서 제외.
2026-07-27 12:35:22 +09:00

8.5 KiB
Raw Blame History

title, updated, tags
title updated tags
K3s 백업 파이프라인 2026-04-15 Longhorn 라벨 키 오타 수정 (recurring-job-group, 대시 포함). 자세히는 history/2026-04-15-longhorn-backup-label-typo.md 참조
infra
backup
k3s
r2
longhorn
synology

아키텍처 (2026-04-14 이후)

두 레이어 병행:

앱 레벨:  K3s Pod(dump/rsync) → NAS (/volume1/k3s-backup/) → R2(k3s-backup)
                                                      ↓
                                             Synology systemd timer

Longhorn: Longhorn Volume → Snapshot → Backup → R2(longhorn-backup)
                                         ↓
                                    RecurringJob (cluster-native)
레이어 용도 정합성 복원 단위
앱 레벨 (pg_dump, gitea dump, rsync) 1순위 복구 경로 application-consistent 특정 테이블·파일
Longhorn Volume backup 2순위 안전망, 볼륨 통째 롤백 crash-consistent (block-level) 볼륨 전체

DB는 반드시 앱 레벨 dump 병행. Longhorn 백업 단독은 crash-consistent에 불과해 트랜잭션 중간 상태가 캡처될 수 있음.

K3s → NAS (NFS)

NFS PV/PVC

네임스페이스 PVC 이름 NFS 경로 비고
gitea gitea-backup-nfs /volume1/k3s-backup/gitea gitea dump
  • NFS 서버: 192.168.9.100 (Synology NAS)
  • PV reclaim policy: Retain

CronJob

네임스페이스 CronJob 스케줄 내용
gitea gitea-backup 0 3 * * * (UTC) gitea dump → NFS

NAS → R2 (Synology systemd timer)

Synology 구성

  • rclone 설정: /volume1/docker/rclone/rclone.conf
  • rclone 실행: Docker 컨테이너 (rclone/rclone:latest)
  • systemd service: r2-backup.service
  • systemd timer: r2-backup.timer — 매일 05:00 KST (±5분 jitter)

R2 버킷

  • 버킷명: k3s-backup
  • 엔드포인트: https://d8e5997eb4040f8b489f09095c0f623c.r2.cloudflarestorage.com
  • 크레덴셜: vault secret/cloud/cloudflare/r2

관리 명령 (Synology SSH)

# 수동 sync
sudo systemctl start r2-backup.service

# 상태 확인
sudo systemctl status r2-backup.timer
sudo systemctl list-timers r2-backup.timer

# 로그
sudo journalctl -u r2-backup.service

# R2 내용 확인
sudo /usr/local/bin/docker run --rm \
  -v /volume1/docker/rclone:/config:ro \
  rclone/rclone:latest \
  --config /config/rclone.conf \
  ls r2:k3s-backup/

보존 정책

  • NAS: 수동 관리 (디스크 여유에 따라)
  • R2: lifecycle rule 설정 필요 (Cloudflare 대시보드에서 30일 만료 설정)

Longhorn 볼륨 백업 (2026-04-14 구축)

Backup Target

항목
종류 Cloudflare R2 (S3 호환)
버킷 longhorn-backup (APAC 리전)
BackupTarget CR longhorn-system/defaults3://longhorn-backup@auto/
크레덴셜 K8s Secret longhorn-system/longhorn-backup-r2 (Vault secret/cloud/cloudflare/r2 기반)
Secret 키 AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_ENDPOINTS
상태 확인 kubectl -n longhorn-system get backuptarget default — AVAILABLE=true 여야 함

RecurringJob (4개)

이름 그룹 Task Cron 보존 Concurrency
critical-snapshot critical snapshot 0 * * * * UTC (매시간) 24 (1일치) 2
critical-backup critical backup 0 */6 * * * UTC (6h 간격, KST 03/09/15/21시 포함) 28 (7일치) 1
standard-snapshot standard snapshot 0 18 * * * UTC (= KST 03:00) 7 (7일치) 2
standard-backup standard backup 0 19 * * * UTC (= KST 04:00) 7 (7일치) 1

cron 은 UTC 기준. standard 그룹은 KST 새벽 트래픽 저점에 실행되도록 설정 (2026-04-15 조정).

[!info] 보존 정책 통일 (2026-04-14) 백업 보존을 일관적으로 7일 기준으로 통일. snapshot은 CoW 체인이라 개수보다 보존 기간이 중요 — critical은 1일치 시간 단위, standard는 7일치 일단위로 유지.

볼륨 분류 (2026-04-14 기준, 라벨 recurring-job-group.longhorn.io/<group>=enabled)

[!warning] 라벨 키 주의 (2026-04-15 정정) 정확한 키는 recurring-job-group.longhorn.io/<group> (대시 포함). 2026-04-14 초기 구축 시 recurringjob-group.longhorn.io/<group> (대시 없음) 오타로 18볼륨 백업이 전부 noop 동작했음. RecurringJob 컨트롤러는 셀렉터 매칭 실패 시 에러 없이 "Found 0 volumes"로 조용히 종료하므로 라벨 키는 반드시 대시 포함 형식으로 부착할 것.

critical (11 볼륨)

APISIX etcd ×3, Gitea PostgreSQL, Gitea 저장소, VictoriaMetrics, n8n, Outline, Portainer, SafeLine DB, Teleport. OpenMemory data/qdrant는 2026-07-27 서비스 폐기로 제외

standard (5 볼륨)

Gitea Valkey, VictoriaLogs (14d 보존), Grafana, RabbitMQ, SFTPGo.

백업 제외

SafeLine 런타임 로그/상태 6종 (휘발성 OK), nfs-provisioner 마운트 (10Mi 시스템).

신규 볼륨 분류 절차

vol=$(kubectl -n <ns> get pvc <pvc-name> -o jsonpath='{.spec.volumeName}')
kubectl -n longhorn-system label volume $vol \
  recurring-job-group.longhorn.io/critical=enabled --overwrite
# 또는 standard

복원 절차 (중요: PVC annotation 방식 안 됨)

Longhorn v1.8+ CSI 동적 프로비저닝에서 longhorn.io/fromBackup PVC annotation은 무시됨 (CSI가 annotation을 드라이버로 전달 안 함). 반드시 Volume CR 경유:

  1. Volume CR 생성 (fromBackup 스펙)

    apiVersion: longhorn.io/v1beta2
    kind: Volume
    metadata:
      name: restored-<tag>
      namespace: longhorn-system
    spec:
      fromBackup: "s3://longhorn-backup@auto/?backup=<backup-name>&volume=<orig-vol>"
      numberOfReplicas: 3
      size: "<bytes>"
      frontend: blockdev
      accessMode: rwo
    
  2. 복원 완료 대기state=detached 또는 state=attached + restoreRequired=false

    kubectl -n longhorn-system get volume restored-<tag> \
      -o jsonpath='{.status.state} {.status.restoreRequired}'
    
  3. PV 생성 (StorageClass는 longhorn-static — 동적 provisioning 회피)

    apiVersion: v1
    kind: PersistentVolume
    metadata: { name: restored-<tag>-pv }
    spec:
      capacity: { storage: <size> }
      accessModes: [ReadWriteOnce]
      storageClassName: longhorn-static
      csi:
        driver: driver.longhorn.io
        fsType: ext4
        volumeHandle: restored-<tag>
        volumeAttributes: { numberOfReplicas: "3", staleReplicaTimeout: "30" }
    
  4. PVC 생성 (PV에 직접 바인딩)

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata: { name: restored-<tag>-pvc, namespace: <ns> }
    spec:
      storageClassName: longhorn-static
      accessModes: [ReadWriteOnce]
      resources: { requests: { storage: <size> } }
      volumeName: restored-<tag>-pv
    
  5. Pod에 마운트 — 데이터 검증 후 원본 PVC로 swap (앱 재배치 필요)

[!info] 2026-04-14 검증 1Gi 볼륨에 10MB urandom + marker 파일 작성 → snap+backup → 삭제 → 복원 → MD5 완벽 일치 확인.

운영 명령

# BackupTarget 상태
kubectl -n longhorn-system get backuptarget default

# 볼륨별 백업 이력
kubectl -n longhorn-system get backupvolume

# 최근 백업 목록
kubectl -n longhorn-system get backups --sort-by='.metadata.creationTimestamp'

# 특정 볼륨의 수동 백업 트리거
cat <<EOF | kubectl apply -f -
apiVersion: longhorn.io/v1beta2
kind: Snapshot
metadata: { name: manual-$(date +%s), namespace: longhorn-system }
spec: { volume: <volume-name>, createSnapshot: true }
EOF

Longhorn UI: https://longhorn.inouter.com → Backup 탭에서 시각적 확인 가능.

TODO

  • R2 lifecycle rulelonghorn-backup 버킷에 7일 만료 규칙 longhorn-backup-7d-expire 등록 완료 (2026-04-14, API 경유). deleteObjectsTransition.condition.maxAge=604800. Longhorn retention(7일)과 정합.
  • vault, anvil, ironclad 등 추가 서비스 NFS 백업 CronJob 구성
  • postgres 백업 CronJob NFS 경로 /volume1/k3s-backup/postgres로 변경
  • 분기별 복원 드릴 (critical 그룹 1건 선정하여 실제 복원 절차 실행)