#!/usr/bin/env bash # 사용법: ./bin/restore-db.sh [docker|podman] <백업.dump> --confirm-db # 실행 중인 앱은 미리 정상 종료해야 한다. 현재 DB 자동 백업 후 새 DB로 복구한다. . "$(dirname -- "${BASH_SOURCE[0]}")/db-lib.sh" ARCHIVE="" CONFIRM_DB="" ENGINE_ARG="" while [ "$#" -gt 0 ]; do case "$1" in docker|podman) ENGINE_ARG="$1" ;; --confirm-db) [ "$#" -ge 2 ] || die "--confirm-db 뒤에 DB 이름을 적는다." CONFIRM_DB="$2"; shift ;; -h|--help) sed -n '2,3p' "$0"; exit 0 ;; -*) die "알 수 없는 인자: $1" ;; *) [ -z "${ARCHIVE}" ] || die "백업 파일은 하나만 지정한다."; ARCHIVE="$1" ;; esac shift done [ -n "${ARCHIVE}" ] || die "복구할 .dump 파일을 지정한다." db_lock db_init [ "${CONFIRM_DB}" = "${POSTGRESQL_DB}" ] || die "--confirm-db 에 대상 DB 이름(${POSTGRESQL_DB})을 정확히 적어야 한다." db_validate_archive "${ARCHIVE}" db_check_app_stopped # 대상 DB 를 지우기 전에 현재 상태를 별도 파일로 확보한다. 실패하면 복구를 시작하지 않는다. SAFETY_BACKUP="${DEPLOY_DIR}/backups/pre-restore_${DB_ARCHIVE_STEM}_$(date -u +%Y%m%dT%H%M%SZ).dump" log "현재 DB 안전 백업: ${SAFETY_BACKUP}" db_write_archive "${SAFETY_BACKUP}" warn "${POSTGRESQL_DB} 데이터베이스를 새로 만들고 ${ARCHIVE} 를 복구한다. 앱은 중지된 상태로 둔다." if ! engine exec "${PG_CONTAINER}" sh -ceu ' export PGPASSWORD="$POSTGRES_PASSWORD" # 앱은 이미 중지됐지만 엔진/healthcheck가 정리 중인 짧은 연결이 남을 수 있다. # FORCE는 대상 DB 연결만 종료하며, prepared transaction/replication blocker는 # 계속 실패시켜 복구를 안전하게 중단한다. exec dropdb --force -h 127.0.0.1 -U "$POSTGRES_USER" --maintenance-db=postgres "$POSTGRES_DB" '; then die "DB 삭제에 실패했다. 다른 접속이 남아 있는지 확인한다. 복구 전 백업: ${SAFETY_BACKUP}" fi if ! engine exec "${PG_CONTAINER}" sh -ceu ' export PGPASSWORD="$POSTGRES_PASSWORD" exec createdb -h 127.0.0.1 -U "$POSTGRES_USER" --maintenance-db=postgres --template=template0 --owner="$POSTGRES_USER" "$POSTGRES_DB" '; then die "DB 생성에 실패했다. 앱을 재시작하지 말고 원인을 확인한다. 복구 전 백업: ${SAFETY_BACKUP}" fi if ! engine exec -i "${PG_CONTAINER}" sh -ceu ' export PGPASSWORD="$POSTGRES_PASSWORD" exec pg_restore -h 127.0.0.1 -U "$POSTGRES_USER" -d "$POSTGRES_DB" --exit-on-error ' < "${ARCHIVE}"; then die "복구 실패. 앱을 재시작하지 말고 원인을 확인한다. 복구 전 백업: ${SAFETY_BACKUP}" fi log "복구 완료: ${POSTGRESQL_DB}. 앱 컨테이너를 다시 시작한다. 복구 전 백업: ${SAFETY_BACKUP}"