#!/bin/bash # ============================================================ # NAC Knowledge Engine - MongoDB每日备份脚本 v2 # 新增:备份失败时自动发送Webhook告警(企业微信/钉钉/飞书/通用) # 数据库:nac_knowledge_engine(多语言合规知识库) # 备份目录:/opt/nac/backups/mongodb/ # 保留策略:保留最近30天的备份,自动清理旧备份 # 日志:/var/log/nac_mongo_backup.log # ============================================================ set -euo pipefail # ─── 配置 ──────────────────────────────────────────────────── BACKUP_BASE="/opt/nac/backups/mongodb" LOG_FILE="/var/log/nac_mongo_backup.log" RETENTION_DAYS=30 DB_NAME="nac_knowledge_engine" DATE=$(date +%Y%m%d_%H%M%S) BACKUP_DIR="${BACKUP_BASE}/${DATE}" ENV_FILE="/opt/nac/services/nac-admin/.env" # ─── 日志函数 ───────────────────────────────────────────────── log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE" } log_error() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] [ERROR] $*" | tee -a "$LOG_FILE" >&2 } # ─── Webhook告警函数 ────────────────────────────────────────── # 从.env文件读取Webhook配置并发送告警 send_webhook_alert() { local TITLE="$1" local CONTENT="$2" local LEVEL="${3:-error}" # error | warning | info # 从.env读取Webhook URL local WECOM_URL DINGTALK_URL FEISHU_URL GENERIC_URL WECOM_URL=$(grep "^NAC_NOTIFY_WECOM_WEBHOOK=" "${ENV_FILE}" 2>/dev/null | cut -d'=' -f2- | tr -d '"' | tr -d "'" | tr -d '[:space:]') DINGTALK_URL=$(grep "^NAC_NOTIFY_DINGTALK_WEBHOOK=" "${ENV_FILE}" 2>/dev/null | cut -d'=' -f2- | tr -d '"' | tr -d "'" | tr -d '[:space:]') FEISHU_URL=$(grep "^NAC_NOTIFY_FEISHU_WEBHOOK=" "${ENV_FILE}" 2>/dev/null | cut -d'=' -f2- | tr -d '"' | tr -d "'" | tr -d '[:space:]') GENERIC_URL=$(grep "^NAC_NOTIFY_WEBHOOK_URL=" "${ENV_FILE}" 2>/dev/null | cut -d'=' -f2- | tr -d '"' | tr -d "'" | tr -d '[:space:]') local SENT=0 local TIMESTAMP TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S') # 企业微信 if [ -n "${WECOM_URL}" ]; then local WECOM_PAYLOAD WECOM_PAYLOAD=$(cat < 时间:${TIMESTAMP}\n> 服务:NAC MongoDB备份\n> 级别:${LEVEL}" } } EOF ) if curl -s -X POST "${WECOM_URL}" \ -H "Content-Type: application/json" \ -d "${WECOM_PAYLOAD}" \ --connect-timeout 10 \ --max-time 15 \ -o /dev/null 2>>"${LOG_FILE}"; then log "[Webhook] 企业微信告警发送成功" SENT=$((SENT + 1)) else log_error "[Webhook] 企业微信告警发送失败" fi fi # 钉钉 if [ -n "${DINGTALK_URL}" ]; then local DINGTALK_PAYLOAD DINGTALK_PAYLOAD=$(cat < 时间:${TIMESTAMP}\n> 服务:NAC MongoDB备份\n> 级别:${LEVEL}" }, "at": { "isAtAll": true } } EOF ) if curl -s -X POST "${DINGTALK_URL}" \ -H "Content-Type: application/json" \ -d "${DINGTALK_PAYLOAD}" \ --connect-timeout 10 \ --max-time 15 \ -o /dev/null 2>>"${LOG_FILE}"; then log "[Webhook] 钉钉告警发送成功" SENT=$((SENT + 1)) else log_error "[Webhook] 钉钉告警发送失败" fi fi # 飞书 if [ -n "${FEISHU_URL}" ]; then local COLOR case "${LEVEL}" in error) COLOR="red" ;; warning) COLOR="orange" ;; *) COLOR="blue" ;; esac local FEISHU_PAYLOAD FEISHU_PAYLOAD=$(cat <>"${LOG_FILE}"; then log "[Webhook] 飞书告警发送成功" SENT=$((SENT + 1)) else log_error "[Webhook] 飞书告警发送失败" fi fi # 通用Webhook if [ -n "${GENERIC_URL}" ]; then local GENERIC_PAYLOAD GENERIC_PAYLOAD=$(cat <>"${LOG_FILE}"; then log "[Webhook] 通用Webhook告警发送成功" SENT=$((SENT + 1)) else log_error "[Webhook] 通用Webhook告警发送失败" fi fi if [ "${SENT}" -eq 0 ]; then log "[Webhook] 未配置任何Webhook,告警仅记录到日志" fi } # ─── 错误处理:捕获脚本异常退出 ────────────────────────────── BACKUP_FAILED=0 trap 'if [ $? -ne 0 ] && [ "${BACKUP_FAILED}" -eq 0 ]; then BACKUP_FAILED=1 log_error "备份脚本异常退出(非预期错误)" send_webhook_alert \ "NAC MongoDB备份异常退出" \ "备份脚本在执行过程中发生未预期的错误,请立即检查服务器状态。\n\n**日志文件:** ${LOG_FILE}\n**备份目录:** ${BACKUP_BASE}" \ "error" fi' EXIT # ─── 主备份流程 ─────────────────────────────────────────────── log "======================================================" log "NAC MongoDB备份开始 v2 - 数据库: ${DB_NAME}" log "备份目录: ${BACKUP_DIR}" # 创建备份目录 mkdir -p "${BACKUP_DIR}" # 读取MongoDB连接URL MONGO_URL="" MONGO_URL_FILE="/opt/nac/services/nac-admin/mongo_url.conf" if [ -f "${MONGO_URL_FILE}" ]; then MONGO_URL=$(cat "${MONGO_URL_FILE}" | tr -d '[:space:]') else MONGO_URL=$(grep "^NAC_MONGO_URL=" "${ENV_FILE}" 2>/dev/null | cut -d'=' -f2- | tr -d '"' | tr -d "'") fi if [ -z "${MONGO_URL}" ]; then log_error "无法读取MongoDB连接URL,备份失败" BACKUP_FAILED=1 send_webhook_alert \ "NAC MongoDB备份失败 - 无法读取连接URL" \ "备份脚本无法从配置文件中读取MongoDB连接URL。\n\n**检查文件:** ${ENV_FILE}\n**所需变量:** NAC_MONGO_URL" \ "error" exit 1 fi # 执行mongodump备份 log "开始执行 mongodump..." MONGODUMP_LOG="${BACKUP_DIR}/mongodump.log" if mongodump \ --uri="${MONGO_URL}" \ --db="${DB_NAME}" \ --out="${BACKUP_DIR}" \ --gzip \ --quiet 2>"${MONGODUMP_LOG}"; then # 计算备份大小 BACKUP_SIZE=$(du -sh "${BACKUP_DIR}" | cut -f1) log "备份成功 - 大小: ${BACKUP_SIZE}" # 创建备份清单文件 cat > "${BACKUP_DIR}/BACKUP_MANIFEST.txt" << EOF NAC Knowledge Engine MongoDB备份清单 v2 ======================================== 备份时间: $(date '+%Y-%m-%d %H:%M:%S') 数据库名: ${DB_NAME} 备份大小: ${BACKUP_SIZE} 备份工具: mongodump $(mongodump --version 2>&1 | head -1 | awk '{print $3}' || echo "unknown") 备份内容: $(ls -la "${BACKUP_DIR}/${DB_NAME}/" 2>/dev/null || echo " (无集合文件)") EOF log "备份清单已创建: ${BACKUP_DIR}/BACKUP_MANIFEST.txt" # 备份成功时发送成功通知(可选,避免频繁通知可注释此段) # send_webhook_alert "NAC MongoDB备份成功" "数据库 ${DB_NAME} 备份完成,大小: ${BACKUP_SIZE}" "info" else MONGODUMP_ERROR=$(cat "${MONGODUMP_LOG}" 2>/dev/null | head -5 || echo "无错误详情") log_error "mongodump执行失败" log_error "错误详情: ${MONGODUMP_ERROR}" rm -rf "${BACKUP_DIR}" BACKUP_FAILED=1 # 发送告警 send_webhook_alert \ "NAC MongoDB备份失败 - mongodump执行失败" \ "mongodump命令执行失败,数据库 **${DB_NAME}** 备份未完成。\n\n**错误信息:** ${MONGODUMP_ERROR}\n\n**日志文件:** ${LOG_FILE}\n\n请立即检查MongoDB服务状态和网络连接。" \ "error" exit 1 fi # ─── 清理旧备份(保留最近30天)──────────────────────────────── log "清理${RETENTION_DAYS}天前的旧备份..." DELETED_COUNT=0 while IFS= read -r -d '' old_dir; do log " 删除旧备份: $(basename "${old_dir}")" rm -rf "${old_dir}" DELETED_COUNT=$((DELETED_COUNT + 1)) done < <(find "${BACKUP_BASE}" -maxdepth 1 -type d -mtime +${RETENTION_DAYS} -print0 2>/dev/null) if [ "${DELETED_COUNT}" -gt 0 ]; then log "已清理 ${DELETED_COUNT} 个旧备份" else log "无需清理旧备份" fi # ─── 备份统计 ───────────────────────────────────────────────── TOTAL_BACKUPS=$(find "${BACKUP_BASE}" -maxdepth 1 -type d | wc -l) TOTAL_SIZE=$(du -sh "${BACKUP_BASE}" 2>/dev/null | cut -f1) log "当前备份总数: $((TOTAL_BACKUPS - 1)) 个,总占用: ${TOTAL_SIZE}" log "NAC MongoDB备份完成 v2 ✓" log "======================================================" # 正常完成,取消错误trap BACKUP_FAILED=1 # 防止EXIT trap误触发 exit 0