228 lines
9.0 KiB
Markdown
228 lines
9.0 KiB
Markdown
---
|
|
title: 백업 파이프라인
|
|
updated: 2026-04-20
|
|
tags: [infra, backup]
|
|
---
|
|
|
|
## Velero (K8s 표준 백업 도구)
|
|
|
|
네임스페이스 · 앱 단위 전체 복원을 위한 표준 백업 도구. Longhorn BackupTarget(볼륨 단위)과 공존 — 목적이 다름.
|
|
|
|
| 항목 | 값 |
|
|
|------|-----|
|
|
| Namespace | velero |
|
|
| Chart | vmware-tanzu/velero `12.0.0` (app `v1.18.0`) |
|
|
| Plugin | `velero/velero-plugin-for-aws:v1.14.0` (initContainer) |
|
|
| Features | `EnableCSI` |
|
|
| BackupStorageLocation | `default` → R2 버킷 `velero-backup` (ENAM), endpoint `d8e5997eb4040f8b489f09095c0f623c.r2.cloudflarestorage.com` |
|
|
| VolumeSnapshotLocation | `default` (provider=csi) |
|
|
| VolumeSnapshotClass | `longhorn-snapshot` (driver.longhorn.io, type=snap) |
|
|
| Credentials 시크릿 | `velero-cloud-credentials` (namespace: velero). Vault `secret/cloud/cloudflare/r2` 재사용 (기존 `longhorn-backup-r2`와 동일 키) |
|
|
| 클라이언트 | `brew install velero` (macOS) |
|
|
|
|
### 백업 스케줄 `daily-full`
|
|
|
|
| 항목 | 값 |
|
|
|------|-----|
|
|
| Cron | `0 16 * * *` UTC (KST 01:00) |
|
|
| TTL | 720h (30일) |
|
|
| 스코프 | 전체 네임스페이스 (`*`) + cluster-scoped |
|
|
| 제외 네임스페이스 | kube-system, kube-public, kube-node-lease, velero, longhorn-system, democratic-csi, metallb-system, cert-manager, monitoring, logging, external-secrets, nfs-provisioner, rabbitmq-system |
|
|
| 볼륨 | CSI 스냅샷 (Longhorn 네이티브 스냅샷으로 생성) |
|
|
|
|
기존 Longhorn BackupTarget은 유지 (볼륨 단위 장애 복구용). Velero는 네임스페이스 단위 전체 복구용.
|
|
|
|
### 운영 명령
|
|
|
|
```bash
|
|
velero backup get -n velero
|
|
velero backup describe <name> -n velero --details
|
|
velero backup logs <name> -n velero
|
|
velero backup create adhoc-<name> --include-namespaces <ns> --snapshot-volumes -n velero --wait
|
|
|
|
velero schedule get -n velero
|
|
velero restore create --from-backup <name> -n velero
|
|
```
|
|
|
|
### snapshot-controller (선결 인프라)
|
|
|
|
| 항목 | 값 |
|
|
|------|-----|
|
|
| snapshot-controller | v8.5.0, Deployment (kube-system, replicas=2) |
|
|
| CRDs | snapshot.storage.k8s.io/v1 — VolumeSnapshot, VolumeSnapshotContent, VolumeSnapshotClass |
|
|
|
|
도입 이력: [[2026-04-20-snapshot-controller-velero-prep|prep]] · [[2026-04-20-velero-install|install]]
|
|
|
|
## Longhorn PVC 백업 (K3s)
|
|
|
|
BackupTarget `default` → R2 버킷 `longhorn-backup` (시크릿 `longhorn-backup-r2`). RecurringJob 4종 (critical-snapshot 매시 UTC, critical-backup 6h UTC, standard-snapshot `0 18 * * *` UTC = KST 03:00, standard-backup `0 19 * * *` UTC = KST 04:00).
|
|
|
|
### RecurringJob 그룹 볼륨 라벨 — **정확한 키 주의**
|
|
|
|
Longhorn 컨트롤러가 인식하는 라벨 키는 **`recurring-job-group.longhorn.io/<group>=enabled`** (대시 포함). `recurringjob-group.longhorn.io/...` (대시 누락) 은 무효이며 컨트롤러가 볼륨을 찾지 못한다.
|
|
|
|
```bash
|
|
# 신규 볼륨을 critical 그룹에 등록
|
|
kubectl -n longhorn-system label volumes.longhorn.io <pvc-...> \
|
|
recurring-job-group.longhorn.io/critical=enabled --overwrite
|
|
|
|
# 라벨 검증 (선택자가 볼륨을 실제로 잡는지)
|
|
kubectl -n longhorn-system get volumes.longhorn.io \
|
|
-l recurring-job-group.longhorn.io/critical=enabled
|
|
```
|
|
|
|
라벨 기록이 꼬였을 때의 대응은 [[2026-04-15-longhorn-backup-label-typo|history]] 참고.
|
|
|
|
## incus 백업 (inbest 데이터)
|
|
|
|
3단계 백업 파이프라인. 소스: incus-kr2 inbest 프로젝트 `inbest-data` 커스텀 볼륨.
|
|
|
|
### 1. rsync → NAS
|
|
|
|
- **호스트**: incus-kr2
|
|
- **스크립트**: `/usr/local/bin/backup-inbest.sh`
|
|
- **systemd**: `backup-inbest.timer` / `backup-inbest.service`
|
|
- **스케줄**: 매일 03:00 (±5분)
|
|
- **소스**: `/var/lib/incus/storage-pools/default/custom/inbest_inbest-data/`
|
|
- **대상**: `kaffa@192.168.205.100:/volume1/incus/inbest/`
|
|
- **제외**: `*/data/session/`
|
|
- **SSH 키**: `/home/kaffa/.ssh/id_ed25519`
|
|
- **옵션**: `rsync -rlz --omit-dir-times --delete` (Synology 퍼미션 호환)
|
|
|
|
### 2. btrfs 스냅샷 (NAS)
|
|
|
|
- rsync 완료 직후 자동 실행 (같은 스크립트)
|
|
- **스냅샷 경로**: `/volume1/incus/.snapshots/incus-YYYYMMDD`
|
|
- **타입**: 읽기 전용 (`btrfs subvolume snapshot -r`)
|
|
- **보관**: 3일 초과 자동 삭제
|
|
- **용도**: 논리적 복구 (실수 삭제/덮어쓰기), NAS 내부에서만 유효
|
|
|
|
### 3. R2 sync (NAS → Cloudflare R2)
|
|
|
|
- **호스트**: Synology NAS (192.168.205.100)
|
|
- **systemd**: `r2-incus-backup.timer` / `r2-incus-backup.service`
|
|
- **스케줄**: 매일 06:00 (±5분)
|
|
- **소스**: `/volume1/incus/`
|
|
- **대상**: R2 버킷 `incus-backup` (APAC 리전)
|
|
- **제외**: `.snapshots/**`, `@eaDir/**`
|
|
- **rclone**: Docker (`rclone/rclone:latest`), 설정 `/volume1/docker/rclone/rclone.conf`
|
|
- **성능**: transfers 32, checkers 32, 첫 전체 업로드(7.97GB) 약 12분
|
|
- **TimeoutStartSec**: 3600 (1시간)
|
|
|
|
### NAS 설정 메모
|
|
|
|
- NAS `/volume1/incus/inbest/` 소유자: `kaffa:users` (rsync 쓰기용)
|
|
- btrfs subvolume: `/volume1/incus` (ID 741)
|
|
- 모든 백업 스크립트에 NAS 접근 불가 시 스킵/로컬 보관 로직 포함
|
|
- NFS 마운트는 반드시 `soft,timeo=50,retrans=3` 사용 (hard 금지, [[nas-storage]] 참조)
|
|
|
|
### 복구 시나리오
|
|
|
|
| 상황 | 복구 방법 |
|
|
|------|----------|
|
|
| 파일 실수 삭제/덮어쓰기 | NAS btrfs 스냅샷에서 복원 |
|
|
| NAS 장애 | R2에서 rclone copy로 복원 |
|
|
| kr2 장애 | NAS rsync 미러에서 복원 |
|
|
|
|
## NocoDB PostgreSQL 백업
|
|
|
|
NocoDB가 사용하는 PostgreSQL(Incus 컨테이너) 백업. pg_dump → NAS.
|
|
|
|
### 1. pg_dump (kr2)
|
|
|
|
- **호스트**: incus-kr2
|
|
- **스크립트**: `/usr/local/bin/pg-backup.sh`
|
|
- **systemd**: `pg-backup.timer` / `pg-backup.service`
|
|
- **스케줄**: 매일 03:00
|
|
- **DB**: `10.100.2.5` (Incus 컨테이너 PostgreSQL)
|
|
- **인증**: `PGPASSWORD=nocodb`, user `nocodb`, db `nocodb`
|
|
- **출력**: `/mnt/nas-backup/daily/nocodb_YYYYMMDD_HHMMSS.dump` (NAS NFS 마운트)
|
|
- **보관**: 30일 초과 자동 삭제
|
|
- **NAS 마운트**: 스크립트 내에서 `soft,timeo=50,retrans=3`으로 자동 마운트
|
|
- **NAS 미접근 시**: 10초 타임아웃 후 스킵
|
|
|
|
## kine 백업 (Supabase PostgreSQL)
|
|
|
|
K3s datastore인 Supabase PostgreSQL의 kine 테이블 백업. pg_dump → NAS → R2 3단계.
|
|
|
|
### 1. pg_dump (kr2)
|
|
|
|
- **호스트**: incus-kr2
|
|
- **스크립트**: `/usr/local/bin/kine-backup.sh`
|
|
- **systemd**: `kine-backup.timer` / `kine-backup.service`
|
|
- **스케줄**: 매일 03:30 (±5분)
|
|
- **DB**: Supabase Pooler (`aws-1-ap-southeast-1.pooler.supabase.com`)
|
|
- **인증**: Vault `secret/cloud/supabase`
|
|
- **출력**: `/opt/kine-backup/kine-YYYYMMDD.sql.gz`
|
|
- **보관**: 7일 초과 자동 삭제
|
|
- **크기**: ~9.3MB (gzip)
|
|
|
|
### 2. rsync → NAS (같은 스크립트)
|
|
|
|
- pg_dump 완료 직후 자동 실행 (같은 스크립트)
|
|
- **대상**: `kaffa@192.168.205.100:/volume1/k3s-backup/kine/`
|
|
- **SSH 키**: `/home/kaffa/.ssh/id_ed25519`
|
|
|
|
### 3. R2 sync (기존 r2-backup.timer로 자동 포함)
|
|
|
|
NAS `/volume1/k3s-backup/` → R2 `k3s-backup` 버킷 (매일 05:00)
|
|
|
|
### 복구 방법
|
|
|
|
```bash
|
|
# NAS 또는 R2에서 덤프 파일 가져온 후
|
|
gunzip kine-YYYYMMDD.sql.gz
|
|
psql "$DB_URL" < kine-YYYYMMDD.sql
|
|
```
|
|
|
|
## etcd 스냅샷 백업 (비활성)
|
|
|
|
K3s가 kine(PostgreSQL)으로 전환되어 etcd 백업은 불필요. etcd-backup.timer, etcd-backup-sync.timer 비활성화됨. kine 백업이 대체.
|
|
|
|
### 1. etcd snapshot (hp2 etcd 컨테이너)
|
|
|
|
- **호스트**: incus-hp2, etcd 컨테이너
|
|
- **스크립트**: `/usr/local/bin/etcd-backup.sh`
|
|
- **systemd**: `etcd-backup.timer` / `etcd-backup.service`
|
|
- **스케줄**: 매일 03:30 (±5분)
|
|
- **출력**: `/backup/etcd-YYYYMMDD_HHMMSS.db` (컨테이너) = `/opt/etcd-backup/` (호스트)
|
|
- **보관**: 7일 초과 자동 삭제
|
|
- **크기**: ~65MB
|
|
|
|
### 2. rsync → NAS (hp2 호스트)
|
|
|
|
- **호스트**: incus-hp2
|
|
- **스크립트**: `/usr/local/bin/etcd-backup-sync.sh`
|
|
- **systemd**: `etcd-backup-sync.timer` / `etcd-backup-sync.service`
|
|
- **스케줄**: 매일 04:00 (±5분)
|
|
- **소스**: `/opt/etcd-backup/`
|
|
- **대상**: `kaffa@192.168.9.100:/volume1/k3s-backup/etcd/`
|
|
- **SSH 키**: `/home/kaffa/.ssh/id_ed25519`
|
|
- NAS IP: hp2에서는 192.168.9.100 사용 (kr2에서는 192.168.205.100)
|
|
|
|
### 3. R2 sync (기존 r2-backup.timer로 자동 포함)
|
|
|
|
NAS `/volume1/k3s-backup/` → R2 `k3s-backup` 버킷 (매일 05:00)
|
|
|
|
## OpenWrt 라우터 백업
|
|
|
|
- **호스트**: openwrt-gw (root@100.66.60.66)
|
|
- **스크립트**: `/usr/local/bin/backup-openwrt.sh`
|
|
- **스케줄**: cron 매일 03:30
|
|
- **방식**: `sysupgrade -b /tmp/backup-openwrt.tar.gz` → scp → NAS
|
|
- **대상**: `kaffa@192.168.9.100:/volume1/k3s-backup/openwrt/`
|
|
- **SSH 키**: `/root/.ssh/id_ed25519` (Dropbear, dbclient 또는 `ssh -i` 필요)
|
|
- **보관**: 7일 초과 자동 삭제
|
|
- **크기**: ~18KB
|
|
- **포함**: `/etc/` 전체 (haproxy.cfg, nftables.d/, config/firewall, config/network, crontabs/, ssh 키 등)
|
|
- **복원**: `sysupgrade -r backup.tar.gz`
|
|
|
|
## k3s 백업 (기존)
|
|
|
|
- **호스트**: Synology NAS
|
|
- **systemd**: `r2-backup.timer` / `r2-backup.service`
|
|
- **스케줄**: 매일 05:00 (±5분)
|
|
- **소스**: `/volume1/k3s-backup/`
|
|
- **대상**: R2 버킷 `k3s-backup` (ENAM 리전)
|
|
- **rclone**: Docker, transfers 4, checkers 8
|