8.4 KiB
title, updated, tags
| title | updated | tags | ||||||
|---|---|---|---|---|---|---|---|---|
| K3s 백업 파이프라인 | 2026-04-15 Longhorn 라벨 키 오타 수정 (recurring-job-group, 대시 포함). 자세히는 history/2026-04-15-longhorn-backup-label-typo.md 참조 |
|
아키텍처 (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/default → s3://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 (13 볼륨)
APISIX etcd ×3, Gitea PostgreSQL, Gitea 저장소, VictoriaMetrics, n8n, OpenMemory data, OpenMemory qdrant, Outline, Portainer, SafeLine DB, Teleport.
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 경유:
-
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 -
복원 완료 대기 —
state=detached또는state=attached+restoreRequired=falsekubectl -n longhorn-system get volume restored-<tag> \ -o jsonpath='{.status.state} {.status.restoreRequired}' -
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" } -
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 -
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 rule —
longhorn-backup버킷에 7일 만료 규칙longhorn-backup-7d-expire등록 완료 (2026-04-14, API 경유).deleteObjectsTransition.condition.maxAge=604800. Longhorn retention(7일)과 정합. - vault, openmemory, anvil, ironclad 등 추가 서비스 NFS 백업 CronJob 구성
- postgres 백업 CronJob NFS 경로
/volume1/k3s-backup/postgres로 변경 - 분기별 복원 드릴 (critical 그룹 1건 선정하여 실제 복원 절차 실행)