개요 — 무엇을 하나
백업 스크립트(/backup/scripts)는 InfraGuard 에 등록된 백업 작업을 카드 그리드로 보여주고 관리하는 콘솔입니다. 각 카드는 하나의 백업 계획(infr_backup_job)과 그 계획의 최신 생성 스크립트(infr_generated_script), 그리고 최근 실행 이력(infr_backup_run)을 결합해 보여줍니다.
이 화면에서 하는 일은 세 가지입니다.
- 관리 — 스크립트를 러너 실행 대상으로 켜거나 끄고(
is_run토글), 계획을 일시정지/활성(status)하거나 삭제합니다. - 열람 — 대상 호스트에 배치할 생성 스크립트 본문(버전·체크섬 포함)을 읽기 전용 CodeMirror 로 확인합니다.
- 생성 — 상단 [스크립트 빌더] 버튼으로 빌더 모달을 열어 새 스크립트를 만들거나 기존 스크립트를 편집합니다(→ 스크립트 빌더).
InfraGuard 앱은 원격 crontab 을 직접 쓰지 않고, 대상 호스트에 SSH 로 접속해 백업을 실행하지도 않습니다. 실행은 백업 전용 서버의 pm2 러너(
scripts/infr_backup_runner.cjs)가 담당합니다. 러너는is_run이 켜진 due 스크립트를 골라 그대로 실행하고, 종료코드와 표준출력(INFR_ARTIFACT/INFR_BYTES/INFR_CHECKSUM)을 파싱해/api/v1/backup/report로 보고합니다. 이 화면은 표시·관리만 합니다.
언제 쓰나
- 새 백업을 만든 뒤 러너가 실제로 돌리도록 켤 때(스크립트를 완성하고
is_runON). - 특정 백업을 잠시 멈추거나(status → paused) 계획을 폐기할 때(삭제).
- 대상 호스트에 배치할 스크립트 본문을 복사하거나, 지금 돌고 있는 버전이 무엇인지(버전·체크섬) 확인할 때.
- 여러 백업의 소스 → 보관소 흐름, 주기, 성공률, 넛지(밀린 백업 경고)를 한눈에 훑을 때.
화면 구성
Hero + KPI
상단 히어로에 [스크립트 빌더]·새로고침 버튼이 있고, 그 아래 KPI 6칸이 BackupBoardService::board() 의 집계를 표시합니다.
| KPI | 의미 |
|---|---|
| 백업 계획 | 등록된 infr_backup_job 총 개수 |
| 활성 | status = active 인 계획 수 |
| 곧 실행 | 활성이면서 다음 실행이 임박(최근 60분 창 안)한 계획 수 |
| 최근 실패 | last_status = failed 인 계획 수 |
| 보호 용량 | 각 계획의 마지막 성공 아티팩트 용량 합계 |
| 보관소 | 등록된 백업 볼트(infr_backup_target) 수 |
스크립트 카드
카드 하나 = 백업 계획 하나. is_run 이 꺼져 있으면 카드가 흐리게(is-off) 표시됩니다. 카드는 드래그(그립 아이콘)로 재정렬할 수 있습니다.
- 헤더 — 소스 유형 아이콘, 작업 이름, 소속 프로젝트, 켜짐/꺼짐 배지, 최근 실행 상태 배지(성공/실패/실행중…).
- 흐름 —
소스 라벨 → 보관소 라벨(예:db@blue · coin_market → NAS(nas01:/backup)). 보관소 미지정이면 "보관소 미지정". - 지표 3종 — 주기(
schedule, 예6 H), 다음 실행(지연이면 강조), 성공률. - 스파크 — 최근 실행(최대 14개)의 상태·용량 막대. 이력이 없으면 "실행 이력 없음".
- 넛지 — 활성인데 마지막 성공이 주기의 2배(최소 3일)를 넘으면 경고, 4배를 넘으면 크리티컬.
- 푸터 — 중요도 칩 + 행동 버튼: 스크립트 보기 · 켜기/끄기 · 편집 · 삭제.
스크립트 보기 모달
</>(스크립트 보기) 버튼을 누르면 그 계획의 최신 버전 본문을 읽기 전용 CodeMirror(bash)로 보여줍니다. 상단에 v{버전} 배지와 [스크립트 복사] 버튼이 있습니다.
사용법
러너 실행 대상 켜기/끄기 (is_run 토글)
카드 푸터의 토글 스위치 아이콘을 누르면 POST /backup/scripts/toggle(field=is_run) 이 호출되어 is_run 불리언이 뒤집힙니다.
- 켜짐(on) — pm2 러너가 이 스크립트를 due 판정 시 실행 대상으로 삼습니다.
- 꺼짐(off) — 계획·스크립트는 남아 있지만 러너가 실행하지 않습니다(초안·정비 중).
스크립트를 먼저 완성한 뒤 켜세요. 빌더에서 저장하면 기본적으로 켜진 상태로 저장될 수 있으니, 자격 파일(
.cnf)·SSH 신뢰망·러너 등록이 끝났는지 체크리스트로 확인한 다음 ON 하는 것이 안전합니다.
같은 엔드포인트에 field=status 를 보내면 계획 상태를 활성 ↔ 일시정지로 토글합니다. 모든 토글은 infr_audit_log(backup.job.toggle)에 남고, 보드 캐시가 플러시됩니다.
스크립트 삭제
카드 푸터의 휴지통 버튼 → POST /backup/scripts/delete.
- 해당 계획의 모든 생성 스크립트 버전(
infr_generated_script)을 삭제한 뒤 계획(infr_backup_job)을 삭제합니다. - 실행 이력(
infr_backup_run)은 보존됩니다 — 복구지점 기록이 사라지지 않도록. backup.job.delete로 감사 로그가 남습니다.
삭제는 InfraGuard 의 등록만 지웁니다. 대상/백업 서버에 이미 배치된 스크립트 파일과 crontab·pm2 등록은 SE 가 직접 정리해야 합니다.
편집 · 새로 만들기
- 편집 — 카드의 연필 버튼은 그 계획을 담은 채 빌더 모달을 엽니다(
builder_open(id)). - 새로 만들기 — 히어로/빈 상태의 [스크립트 빌더] 버튼으로 빈 빌더를 엽니다. 자세한 작성 절차는 스크립트 빌더를 보세요.
실시간 갱신
페이지는 GET /backup/scripts/live 를 폴링해 board·targets 를 갱신합니다(BackupBoardService 15초 캐시).
데이터 소스
생성 스크립트 (infr_generated_script)
빌더 저장 시(storeScript) 스크립트 버전이 append-only 로 한 개씩 쌓입니다. version = 해당 job 의 max(version) + 1, checksum = 본문 체크섬.
| 컬럼 | 의미 |
|---|---|
job_id |
소속 백업 계획 |
lang |
항상 bash |
engine |
소스 유형별 엔진 — mysqldump·rsync·tar·custom |
body |
스크립트 전문(사용자 핸드코딩 본문 우선, 비어 있으면 골격 폴백) |
crontab_line |
빈 문자열 — 스케줄은 pm2 러너가 담당하므로 현재 모델에선 crontab 을 쓰지 않습니다 |
cnf_path |
DB 백업이면 --defaults-extra-file 경로 안내(비밀은 저장 안 함) |
checksum |
본문 체크섬 — 배치본 변조/드리프트 감지 |
version |
1부터 증가하는 버전(이력 보존) |
created_by · created_at |
작성자·시각 |
crontab_line컬럼은 스키마 호환을 위해 남아 있지만 현재 빌더는 항상 빈 값으로 저장합니다. "스케줄"은 계획의schedule(N U문법)과 러너가 담당합니다.
생성 골격의 해부 (ScriptGeneratorService)
빌더의 [미리보기 생성]과 저장 시 폴백은 ScriptGeneratorService::render() 가 만드는 셸 골격입니다. 자격증명은 절대 스크립트에 굽지 않습니다.
#!/bin/sh
# InfraGuard 백업 스크립트(골격) — job #12 "coin_market DB"
# 이 스크립트는 백업 러너(pm2 · infr_backup_runner.cjs)가 실행합니다.
# 자격증명은 이 스크립트에 없습니다 — /etc/infr/coin_market.cnf (chmod 600) 를 백업 서버에 생성합니다.
set -eu
JOB_ID=12
IDENT="coin_market"
TS="$(date +%Y%m%d%H%M)"
TARGET="/data/bk"
LOCK="/tmp/infr_backup_12.lock"
BYTES=0; SUM=""; OUT=""
mkdir -p "$TARGET"
exec 9>"$LOCK"; flock -n 9 || { echo "already running"; exit 0; }
# ── 백업 실행 ──
OUT="$TARGET/${IDENT}_${TS}.sql"
mysqldump --defaults-extra-file="/etc/infr/coin_market.cnf" --routines --opt --events -h203.0.113.10 coin_market > "$OUT"
# ── 무결성·용량(러너가 INFR_* 출력을 파싱해 보고) ──
BYTES=$(wc -c < "$OUT" 2>/dev/null || echo 0)
SUM=$(sha256sum "$OUT" 2>/dev/null | cut -d' ' -f1)
printf 'INFR_ARTIFACT=%s\n' "$OUT"
printf 'INFR_BYTES=%s\n' "$BYTES"
[ -n "$SUM" ] && printf 'INFR_CHECKSUM=%s\n' "$SUM"
골격 섹션 구성:
| 섹션 | 역할 |
|---|---|
| header | shebang + 주석(자격증명은 defaults-file·SSH 키만 참조) |
| preamble | set -eu, JOB_ID/IDENT/TS/TARGET, flock 동시실행 잠금 |
| core | 소스 유형별 명령 — db=mysqldump --defaults-extra-file, files=rsync -az -e ssh, volume=tar czf, custom=사용자 명령 |
| measure | 용량·체크섬 — files=du -sb, 그 외 wc -c + sha256sum |
| emit | 러너가 파싱하는 INFR_ARTIFACT/INFR_BYTES/INFR_CHECKSUM 출력 |
| offsite | 3-2-1 원격지 2차 사본(rsync, 실패해도 1차는 보존) |
| retention | keep_days(find -mtime) · keep_last(ls|tail|xargs rm) 보존 정리 |
셸 인자는 shellSafe() 로 안전화하고, 셸 리터럴($TARGET·$(date))은 nowdoc + {{토큰}} 치환으로 조립해 PHP 보간과 충돌하지 않습니다.
실행 모델 — 러너가 대상 호스트에서 실행
- SE 가 완성한 스크립트를 백업 서버에 배치하고, DB 백업이면
cnf_path(chmod 600) 자격 파일을 만듭니다(값은 앱에 저장되지 않음). - 백업 서버 pm2 에 러너(
scripts/infr_backup_runner.cjs, Inventory ▸ Tools 에 시드)를 등록합니다. - 스크립트를 켜면(
is_runON) 러너가 주기적으로 due 계획을 실행합니다. - 러너가 종료코드로 성공/실패를, 표준출력으로 아티팩트·용량·체크섬을 수집해
/api/v1/backup/report로 보고 →infr_backup_run기록(→ 리포트 콜백).
기본 경로 (config/backup.php)
| 키 | 기본값 | env |
|---|---|---|
| 자격 파일 디렉터리 | /etc/infr |
INFR_BACKUP_CNF_DIR |
| 스크립트 디렉터리 | /data/infr/scripts |
INFR_BACKUP_SCRIPT_DIR |
| 로그 디렉터리 | /var/log/infr |
INFR_BACKUP_LOG_DIR |
| 기본 저장 경로 | /data/bk |
INFR_BACKUP_DEFAULT_TARGET |
| 리포트 URL | {APP_URL}/api/v1/backup/report |
INFR_BACKUP_REPORT_URL |
권한
/backup/* 전체가 라우트 그룹 미들웨어 infr.level:2 로 보호됩니다. 등급 체계는 데모=1 · 스탭=5 · 관리자=10 입니다.
| 동작 | 필요 등급 |
|---|---|
| 페이지 조회(그리드·스크립트 보기) | ≥ 2(스탭·관리자). 데모(1)는 백업 영역 접근 제한 |
켜기/끄기·상태 토글(toggle) |
≥ 2 (컨트롤러 self-gate) |
삭제(delete) |
≥ 2 (컨트롤러 self-gate) |
| 스크립트 생성/저장(빌더) | ≥ 2 (→ 스크립트 빌더) |
쓰기 동작(토글·삭제·저장)은 모두 infr_audit_log 에 기록됩니다(→ 감사 로그). 권한이 없으면 403 + "권한이 없습니다(level ≥ 2 필요)".
문제해결 · FAQ
켰는데(on) 실행이 안 됩니다.
- 대상/백업 서버에 스크립트가 배치되어 있고, pm2 러너(
infr_backup_runner.cjs)가 떠 있는지 확인하세요. 앱의is_run은 "러너가 이 스크립트를 실행 대상으로 삼습니다"는 표시일 뿐, 앱이 직접 실행하지 않습니다. - 계획
status가active인지, 주기(schedule)와 다음 실행 시각이 지났는지 확인하세요.
카드에 "실행 이력 없음" 또는 넛지 경고가 뜹니다.
- 러너가 아직 한 번도 보고하지 않았거나 마지막 성공이 주기의 2배(최소 3일)를 넘긴 경우입니다. 러너 로그와
.cnf/SSH 키 배치를 점검하세요.
스크립트 보기가 골격만 보이고 제 코드가 없습니다.
- 저장 시 CodeMirror 본문이 비어 있으면 골격이 폴백으로 저장됩니다. 빌더에서 본문을 채운 뒤 다시 저장하면 새 버전으로 쌓입니다.
mysqldump 가 인증 실패합니다.
- 자격증명은 스크립트에 없고
--defaults-extra-file경로({cnf_path})에서 읽습니다. 백업 서버에 해당.cnf(chmod 600,[mysqldump]섹션)를 만들었는지 확인하세요. 값은 InfraGuard 에 저장되지 않습니다.
삭제하면 지난 백업 기록도 사라지나요?
- 아닙니다. 계획과 생성 스크립트 버전만 지워지고
infr_backup_run실행 이력은 보존됩니다.
체크섬(#xxxxxxxx)은 무엇인가요?
- 저장 시점 스크립트 본문 체크섬의 앞 8자리입니다. 대상 호스트에 배치된 스크립트가 원본과 같은지(드리프트) 대조하는 용도입니다. 백업 아티팩트의 무결성 검증은 별개입니다 — 복구 & 검증 참고.
관련 항목
- 스크립트 빌더 — 대상 프리필 → 골격 생성 → 핸드코딩 → 저장(버전).
- 스케줄 보드 — 계획·주기·다음 실행·배치 지도(3-2-1)·달력.
- 복구 & 검증 — 복구지점 인출·복원 명령·무결성 검증.
- 백업 리포트 콜백 — 러너 →
/api/v1/backup/report→infr_backup_run. - 백업 보관소 — 볼트 관리·오프사이트(3-2-1).
- 프로젝트 — 프로젝트의 백업 대상에서 계획을 프리필.
