Documentation
¶
Index ¶
- Constants
- Variables
- func CheckPrerequisites(p Prerequisites) error
- func ErrBackupNotFound(id string) error
- func ErrChecksumMismatch(detail string) error
- func ErrDestinationUnavailable(detail string) error
- func ErrInvalidComponent(component string) error
- func ErrInvalidMode(mode string) error
- func ErrPrerequisitesMissing(detail string) error
- func ErrSchemaVersionMismatch(detail string) error
- func ErrStackRequired(components string) error
- type Artifact
- type BackupRun
- type Component
- type ComponentEntry
- type DanglingReference
- type EncryptionInfo
- type GatewayAliasesOutcome
- type HelmReleaseDrift
- type HelmReleaseSpec
- type IntegrityReport
- type Manifest
- type ManifestInput
- type Mode
- type Prerequisites
- type QuiescePlan
- type QuiesceTarget
- type QuiesceWindow
- type RestoreMode
- type RestoreRun
- type RestoreStatus
- type RetentionPolicy
- type RunSummary
- type SchemaCheckResult
- type SchemaState
- type SetMember
- type SetRestoreStep
- type SharedComponentsOutcome
- type StackRef
- type Status
- type Trigger
- type VaultImportOutcome
- type VolumeSpec
- type Workload
- type WorkloadSpec
Constants ¶
const EncryptionAlgorithm = "AES-256-GCM"
Variables ¶
var HistoryTables = []string{"backup_runs", "backup_artifacts", "restore_runs"}
HistoryTables 는 백업 모듈이 플랫폼 DB 에 두는 이력 테이블이다(마이그레이션 000075).
이력은 덤프하는 바로 그 DB 에 있다. 덤프에 담아 되돌리면 pg_restore --clean 이 지금의 이력을 지우고 백업 시점의 것으로 바꾼다 — 그 뒤에 뜬 백업이 목록에서 사라지고(객체는 버킷에 남아 아무도 못 찾는다), 진행 중인 복구의 기록까지 지워져 조회가 404 가 된다. 되돌린 백업 자신은 "running" 으로 돌아와 다시 복구할 수도 없다.
그래서 되돌릴 때 건드리지 않는다. 이력은 "지금" 의 사실이다. 덤프에는 남긴다 — 플랫폼 DB 를 통째로 잃었을 때 이전 백업들의 카탈로그를 되살릴 사본이 그것뿐이다(버킷에는 매니페스트가 없다).
Functions ¶
func CheckPrerequisites ¶
func CheckPrerequisites(p Prerequisites) error
CheckPrerequisites 는 빠진 것을 모두 모아 한 번에 알려준다.
하나씩 알려주면 사용자가 고치고 다시 시도하기를 반복하게 되고, 복구는 그만큼 늦어진다. 재해 상황에서 그 시간이 비싸다.
func ErrBackupNotFound ¶
func ErrChecksumMismatch ¶
func ErrInvalidComponent ¶
ErrInvalidComponent 는 모르는 백업 대상을 거부한다.
이름을 Detail 에 그대로 담는다 — 어느 값이 문제인지 말해 주지 않으면 사용자는 다섯 개 중 무엇을 고쳐야 할지 알 수 없다.
func ErrInvalidMode ¶
func ErrPrerequisitesMissing ¶
func ErrStackRequired ¶
ErrStackRequired 는 스택 클러스터가 있어야 뜰 수 있는 대상을 스택 없이 고른 요청을 거부한다.
리소스·볼륨은 스택 클러스터에서 뜬다. 서버는 스택 ID 로 그 클러스터를 찾으므로, 스택을 고르지 않은 요청은 닿을 곳이 없다. Detail 에 빠진 대상을 담는다.
Types ¶
type Artifact ¶
type Artifact struct {
ID string
BackupRunID string
Component Component
ResourceName string // Component=volume 일 때 PVC 이름
Location string
SizeBytes int64
ChecksumSHA256 string
EncryptionKeyID string
CreatedAt time.Time
}
Artifact 는 산출물 1건이다. 설계 §7.1
값 자체는 담지 않는다 — Location 은 오브젝트 스토리지 경로이고, EncryptionKeyID 는 "어떤 키로 잠갔는지" 만 가리킨다 (설계 §5.1).
type BackupRun ¶
type BackupRun struct {
ID string
OrgID string
StackID string
// SetID 는 이 실행이 속한 백업 세트다(backup_set.go). 비어 있으면 단독 실행이다.
SetID string
Trigger Trigger
Mode Mode
Scope []Component
Status Status
SchemaVersion int
QuiesceStartedAt *time.Time
QuiesceEndedAt *time.Time
Manifest map[string]any
TotalBytes int64
Error string
StartedAt *time.Time
FinishedAt *time.Time
CreatedAt time.Time
}
func NewBackupRun ¶
func (*BackupRun) BeginQuiesce ¶
func (r *BackupRun) BeginQuiesce()
func (*BackupRun) Complete ¶
Complete 는 컴포넌트별 결과로 최종 상태를 정한다.
결과가 비어 있으면 failed 다 — 아무것도 시도하지 못한 것은 성공이 아니다.
func (*BackupRun) EndQuiesce ¶
func (r *BackupRun) EndQuiesce()
func (*BackupRun) RequiresQuiesce ¶
RequiresQuiesce 는 정지 창이 필요한지 알려준다.
볼륨을 뜨지 않는 백업은 무중단이어야 한다 — 이유 없이 서비스를 멈추면 사용자가 백업을 피하게 되고, 피해진 백업은 없는 백업이다.
type Component ¶
type Component string
const ( ComponentPlatformDB Component = "platform_db" ComponentKeycloakDB Component = "keycloak_db" ComponentOpenBaoKV Component = "openbao_kv" ComponentNamespaceResources Component = "ns_resources" // ComponentSharedResources 는 클러스터의 마지막 스택을 지우면 회수되는, Nullus 가 설치한 // 공용 자원이다 — 설치 표시가 붙은 Gateway CRD·GatewayClass·내부 CA(ClusterIssuer· // Certificate·Secret). 네임스페이스 리소스가 기대는 것이라 복구는 이것을 먼저, 없을 // 때만 되살린다. 빠지면 복구가 Gateway CR 에서 "no matches for kind" 로 죽는다. ComponentVolume Component = "volume" )
func ModeComponents ¶
ModeComponents 는 모드별 대상 컴포넌트를 돌려준다 (설계 §6.5).
func ParseComponents ¶
ParseComponents 는 사용자가 고른 백업 대상을 검증해 도메인 값으로 바꾼다.
모르는 이름은 **거부한다.** 조용히 버리면 사용자가 고른 것과 실제로 백업된 것이 달라지고, 그 사실은 복구할 때에야 드러난다 — 그때는 늦다.
빈 입력은 nil 을 돌려준다. 호출부가 "고르지 않았다"(모드에서 파생) 와 "아무것도 고르지 않았다" 를 구분할 수 있어야 하기 때문이다.
type ComponentEntry ¶
type DanglingReference ¶
type DanglingReference struct {
TokenSourceID string `json:"token_source_id"`
Path string `json:"path"`
}
DanglingReference 는 DB 가 가리키는데 금고에 없는 시크릿 경로다 (설계 §6.4).
type EncryptionInfo ¶
EncryptionInfo 는 "어떤 키로 잠갔는지" 만 담는다. 키 자체는 절대 담지 않는다.
type GatewayAliasesOutcome ¶
type GatewayAliasesOutcome struct {
GatewayIP string `json:"gateway_ip,omitempty"`
Updated []string `json:"updated,omitempty"`
Error string `json:"error,omitempty"`
}
GatewayAliasesOutcome 은 게이트웨이 주소 재설정 결과다. Updated 가 비어 있으면 바꿀 것이 없었다 — 주소가 그대로였거나, 박아 둔 주소가 없었다(접근 도메인 없음·러너/Argo CD 릴리스 없음·설치 형식이 아닌 러너 설정). Error 가 있으면 일부 또는 전부를 맞추지 못했다 — 파이프라인이 "Could not resolve host" 로 멈출 수 있으니 손으로 맞춰야 한다(복구 자체는 성공이다).
type HelmReleaseDrift ¶
type HelmReleaseDrift struct {
Release string `json:"release"`
BackedUp string `json:"backed_up"`
Current string `json:"current"`
}
HelmReleaseDrift 는 백업 시점과 복구 대상의 차트 버전이 어긋난 것이다.
func CompareHelmReleases ¶
func CompareHelmReleases(backedUp, current []HelmReleaseSpec) []HelmReleaseDrift
CompareHelmReleases 는 대상 네임스페이스에 이미 설치된 차트가 백업 시점과 다른 버전인지 본다.
다르면 복구는 **새 버전 위에 옛 데이터를 얹게 된다.** 도구가 기동하며 스키마 마이그레이션을 돌리면 데이터는 백업 시점으로 돌아가지 않고, 그 변형은 되돌릴 수 없다 — 복구가 "성공" 을 반환한 뒤에 드러난다.
기록이 없는 백업(이 필드가 생기기 전의 것)은 비교하지 않는다. 없는 것을 "다르다" 로 읽으면 멀쩡한 복구가 경고투성이가 되어, 진짜 경고가 묻힌다.
type HelmReleaseSpec ¶
type HelmReleaseSpec struct {
Name string `json:"name"`
Chart string `json:"chart"`
Version string `json:"version"`
AppVersion string `json:"app_version,omitempty"`
Revision int `json:"revision,omitempty"`
}
HelmReleaseSpec 은 이 데이터를 만든 차트가 무엇이었는지 말한다.
복구가 다른 버전으로 재설치하면 도구들이 기동하며 **스키마 마이그레이션을 돌린다** — 그 순간 데이터는 백업 시점의 모습이 아니게 되고, 되돌릴 수 없다. "복구했다" 와 "이전 상태다" 가 갈리는 지점이라 산출물과 함께 남긴다.
출처는 네임스페이스의 Helm 릴리스 Secret(sh.helm.release.v1.*)이다. 그 Secret 은 이미 리소스 덤프에 담기지만, 그것은 암호화되고 통째로 풀어야 읽을 수 있다. 버전 선택은 **복구를 시작하기 전에** 해야 하므로 여기 둔다.
type IntegrityReport ¶
type IntegrityReport struct {
CheckedPaths int `json:"checked_paths"`
Dangling []DanglingReference `json:"dangling"`
CheckedAt time.Time `json:"checked_at"`
// GatewayAliases 는 복구 뒤 러너·Argo CD hostAliases 를 게이트웨이의 지금 주소로 맞춘 결과다.
// 스택을 되돌리지 않았으면 없다.
GatewayAliases *GatewayAliasesOutcome `json:"gateway_aliases,omitempty"`
// 스택을 되돌리지 않았거나 설치기가 배선되지 않았으면 없다.
SharedComponents *SharedComponentsOutcome `json:"shared_components,omitempty"`
// VaultImport 는 스택 금고로 KV 를 되돌린 결과다. 스택을 되돌리지 않았거나 백업에 금고 산출물이 없으면
// 없다. 실패해도 복구는 성공이다 — 데이터는 되돌아왔고, 금고만 손으로(또는 다시 복구해서) 채울 수 있다.
VaultImport *VaultImportOutcome `json:"vault_import,omitempty"`
}
IntegrityReport 는 복구 후 참조 정합성 검사 결과다.
dangling 은 에러 없이 지나갔다가 파이프라인 실행 시점에 인증 실패로 드러난다. 조용히 넘기지 않는 것이 이 보고서의 존재 이유다.
func (IntegrityReport) HasIssues ¶
func (r IntegrityReport) HasIssues() bool
type Manifest ¶
type Manifest struct {
BackupRunID string `json:"backup_run_id"`
OrgID string `json:"org_id"`
StackID string `json:"stack_id,omitempty"`
Mode Mode `json:"mode"`
Trigger Trigger `json:"trigger"`
SchemaVersion int `json:"schema_version"`
PlatformVersion string `json:"platform_version,omitempty"`
// Namespace 는 스택 백업이 뜬 네임스페이스다. 세트 복구는 스택을 어디로 되돌릴지 여기서 읽는다.
Namespace string `json:"namespace,omitempty"`
// pg_dump 는 서버 버전보다 낮으면 실패한다 (설계 §3.1 버전 함정).
PGServerVersion string `json:"pg_server_version,omitempty"`
PGDumpVersion string `json:"pg_dump_version,omitempty"`
Workloads []WorkloadSpec `json:"workloads,omitempty"`
Volumes []VolumeSpec `json:"volumes,omitempty"`
QuiesceWindow *QuiesceWindow `json:"quiesce_window,omitempty"`
// 이 데이터를 만든 차트들. 복구는 같은 버전으로 되돌려야 한다.
HelmReleases []HelmReleaseSpec `json:"helm_releases,omitempty"`
Components []ComponentEntry `json:"components"`
// 복구 시 참조 정합성 검사의 기대값 (설계 §6.4).
OpenBaoKVPathCount int `json:"openbao_kv_path_count,omitempty"`
Encryption EncryptionInfo `json:"encryption"`
CreatedAt time.Time `json:"created_at"`
}
func BuildManifest ¶
func BuildManifest(run *BackupRun, in ManifestInput) Manifest
type ManifestInput ¶
type ManifestInput struct {
// Namespace 는 스택 백업이 뜬 네임스페이스다. 복구(특히 세트 복구)가 어디로 되돌릴지 여기서 읽는다 —
// 비어 있으면 사용자가 네임스페이스를 직접 대야 한다.
Namespace string
PlatformVersion string
PGServerVersion string
PGDumpVersion string
EncryptionKeyID string
Plan QuiescePlan
Volumes []VolumeSpec
Artifacts []Artifact
OpenBaoKVPathCount int
HelmReleases []HelmReleaseSpec
}
type Prerequisites ¶
type Prerequisites struct {
// EncryptionKeyPresent — clusters.kubeconfig 복호화 키. 없으면 복구해도
// 등록된 어떤 클러스터도 조작할 수 없다 (설계 §1.3).
EncryptionKeyPresent bool
// BackupSealKeyPresent — 산출물 복호화 키.
BackupSealKeyPresent bool
// DestinationCredsPresent — 목적지 자격증명. 스택 OpenBao 가 아니라
// 컨트롤 플레인에서 온다 (설계 §4.2.1).
DestinationCredsPresent bool
DestinationReachable bool
}
Prerequisites 는 복구 착수 전에 확보돼야 하는 것들이다 (설계 §6.1 0단계).
type QuiescePlan ¶
type QuiescePlan struct {
Targets []QuiesceTarget
}
QuiescePlan 은 한 번의 정지 창에서 멈출 대상 전체다.
func NewQuiescePlan ¶
func NewQuiescePlan(workloads []Workload) QuiescePlan
NewQuiescePlan 은 워크로드 목록에서 정지 계획을 만든다.
이미 0 인 워크로드는 대상에서 제외한다. 그것을 "복원" 한다며 1 로 올리면 사용자가 의도적으로 꺼둔 것을 백업이 켜버린다.
func (QuiescePlan) IsEmpty ¶
func (p QuiescePlan) IsEmpty() bool
IsEmpty 는 멈출 것이 없는지 알려준다. 비어 있으면 정지 창 자체를 열지 않는다.
func (QuiescePlan) ResumeOrder ¶
func (p QuiescePlan) ResumeOrder() []QuiesceTarget
ResumeOrder 는 재개 순서를 돌려준다 — 정지의 역순이다.
의존 관계(예: 앱 → DB)는 정지 순서에 반영되므로, 되살릴 때 그 역순을 따르면 의존 대상이 먼저 뜬다.
type QuiesceTarget ¶
type QuiesceTarget struct {
Kind string
Namespace string
Name string
// OriginalReplicas 는 재개의 유일한 근거다. 매니페스트에 기록해 두지
// 않으면 복구 시점에 몇으로 되돌려야 하는지 알 수 없다.
OriginalReplicas int32
ScaleDownTo int32
// OwnerManaged 는 Workload 의 것을 그대로 잇는다 — 매니페스트까지 가야 복구가 본다.
OwnerManaged bool
}
QuiesceTarget 은 실제로 멈출 워크로드와 되돌릴 값이다.
type QuiesceWindow ¶
type QuiesceWindow struct {
StartedAt time.Time `json:"started_at"`
EndedAt time.Time `json:"ended_at"`
}
func (*QuiesceWindow) Duration ¶
func (w *QuiesceWindow) Duration() time.Duration
Duration 은 사용자가 실제로 감수한 다운타임이다. 정지 창 정책을 조정할 유일한 근거이므로 이력에 남긴다.
type RestoreMode ¶
type RestoreMode = Mode
type RestoreRun ¶
type RestoreRun struct {
ID string
BackupRunID string
Mode RestoreMode
Status RestoreStatus
SchemaCheck SchemaCheckResult
IntegrityReport IntegrityReport
Error string
StartedAt *time.Time
FinishedAt *time.Time
CreatedAt time.Time
}
RestoreRun 은 한 번의 복구 실행이다.
func NewRestoreRun ¶
func NewRestoreRun(backupRunID string, mode RestoreMode) *RestoreRun
func (*RestoreRun) Fail ¶
func (r *RestoreRun) Fail(reason string)
func (*RestoreRun) Start ¶
func (r *RestoreRun) Start() error
func (*RestoreRun) Succeed ¶
func (r *RestoreRun) Succeed()
type RestoreStatus ¶
type RestoreStatus = Status
type RetentionPolicy ¶
type RetentionPolicy struct {
Daily int
Weekly int
Monthly int
// MaxTotalBytes 가 0 이면 총량 상한을 적용하지 않는다.
MaxTotalBytes int64
}
func DefaultRetentionPolicy ¶
func DefaultRetentionPolicy() RetentionPolicy
DefaultRetentionPolicy 는 설계 §4.5 의 일7/주4/월3 이다.
func (RetentionPolicy) SelectForDeletion ¶
func (p RetentionPolicy) SelectForDeletion(runs []RunSummary) []string
SelectForDeletion 은 산출물을 지울 실행 ID 를 돌려준다. 이력 행 자체는 남는다.
어떤 경우에도 가장 최근 성공본은 남긴다 — 보존 정책이 백업을 0 개로 만들면 정책이 아니라 사고다.
type RunSummary ¶
RunSummary 는 보존 판단에 필요한 최소 정보다.
type SchemaCheckResult ¶
type SchemaCheckResult struct {
Allowed bool `json:"allowed"`
// MigrateAfterRestore 는 복원 뒤에 migrate up 이 필요한지 알려준다.
// 순서를 뒤집으면 실패한다 — 복원이 먼저다.
MigrateAfterRestore bool `json:"migrate_after_restore"`
BackupVersion int `json:"backup_version"`
CurrentVersion int `json:"current_version"`
Reason string `json:"reason,omitempty"`
}
func CheckSchemaVersion ¶
func CheckSchemaVersion(backupVersion int, current SchemaState) SchemaCheckResult
CheckSchemaVersion 은 백업본을 이 코드에 복원해도 되는지 판정한다.
type SchemaState ¶
SchemaState 는 복구 대상 DB 의 현재 마이그레이션 상태다 (golang-migrate).
type SetMember ¶
SetMember 는 세트의 실행 하나다.
func PlanBackupSet ¶
PlanBackupSet 은 세트의 실행 계획이다. 플랫폼이 먼저다 — 복구가 플랫폼 → 스택 순서라, 플랫폼 DB 가 스택 데이터보다 **오래된** 쪽이 안전하다(DB 가 모르는 저장소는 고아로 남지만, DB 가 아는 저장소가 없으면 파이프라인이 깨진다). 스택은 ID 순 — 같은 입력이면 같은 계획이다.
type SetRestoreStep ¶
type SetRestoreStep struct {
BackupRunID string
StackID string
Namespace string
Mode RestoreMode
}
SetRestoreStep 은 세트 복구의 한 단계다.
func PlanSetRestore ¶
func PlanSetRestore(runs []*BackupRun) (steps []SetRestoreStep, skipped []string)
PlanSetRestore 는 세트의 실행들을 되돌릴 순서로 늘어놓는다 — 플랫폼(platform_only) 먼저, 그 뒤 스택 (stack_only, 네임스페이스는 백업 매니페스트의 것). 실패한 멤버는 산출물이 없으니 건너뛰고 ID 를 돌려준다. partial 은 쓸 수 있는 산출물이 있어 되돌린다.
type SharedComponentsOutcome ¶
type SharedComponentsOutcome struct {
}
SharedComponentsOutcome 은 공용 컨트롤러 재설치 결과다. Steps 는 끝까지 돌린 설치 단계, Warnings 는 복구를 멈추지 않고 넘긴 실패다(metrics-server — HPA·자원 지표에만 쓰인다). cert-manager 실패는 여기 남지 않는다 — 복구가 그 자리에서 실패한다.
type Status ¶
type Status string
const ( StatusPending Status = "pending" StatusRunning Status = "running" StatusSucceeded Status = "succeeded" // StatusPartial 은 일부 컴포넌트만 성공한 상태다. // // failed 로 뭉뚱그리면 "부분적으로 쓸 수 있는 백업" 과 "아무것도 없는 // 상태" 가 구분되지 않는다. 복구 시점에 그 차이가 결정적이다. StatusPartial Status = "partial" StatusFailed Status = "failed" )
type VaultImportOutcome ¶
type VaultImportOutcome struct {
Imported bool `json:"imported"`
Attempts int `json:"attempts,omitempty"`
Error string `json:"error,omitempty"`
}
VaultImportOutcome 은 스택 금고 KV import 결과다. 로그로만 남기면 "안 돌았다" 와 "실패했다" 와 "성공했다" 를 응답에서 가를 수 없다 — 2026-10-12 두 스택 리허설에서 한 스택의 import 가 끝내 실패했는데 복구 응답은 succeeded 였다. Error 가 있으면 그 스택의 도구들은 금고의 자격증명을 못 찾는다.
type VolumeSpec ¶
type Workload ¶
type Workload struct {
Kind string // Deployment | StatefulSet
Namespace string
Name string
Replicas int32
// OwnerManaged 는 다른 리소스가 소유한 워크로드다(ownerReferences) — 오퍼레이터가 CR 을 읽어
// 만드는 Prometheus·Alertmanager StatefulSet 이 그렇다. 정지는 똑같이 멈추되(쓰기를 끊어야
// 한다) 복구의 재개는 건너뛴다: 덤프가 소유된 것을 담지 않으므로 복구 뒤에는 오퍼레이터가
// CR 에서 다시 만들고, 그때 재개가 그것을 찾지 못해 내는 "수동 조치" 경보는 거짓이다.
OwnerManaged bool
}
Workload 는 정지 대상 후보다.
type WorkloadSpec ¶
type WorkloadSpec struct {
Kind string `json:"kind"`
Namespace string `json:"namespace"`
Name string `json:"name"`
// OriginalReplicas 는 복원의 필수 입력이다 (설계 §3.4 3단계).
OriginalReplicas int32 `json:"original_replicas"`
// OwnerManaged 가 참이면 복구의 재개가 건너뛴다 — 오퍼레이터가 CR 에서 다시 만드는 것이다.
OwnerManaged bool `json:"owner_managed,omitempty"`
}