diff --git a/01_卡资(金)/金仓_存储备份/群晖NAS管理/脚本/oss_sync/README.md b/01_卡资(金)/金仓_存储备份/群晖NAS管理/脚本/oss_sync/README.md new file mode 100644 index 00000000..99c8034a --- /dev/null +++ b/01_卡资(金)/金仓_存储备份/群晖NAS管理/脚本/oss_sync/README.md @@ -0,0 +1,100 @@ +# 阿里云 OSS → 公司 NAS 每日定时同步 + +## 概述 + +将阿里云 OSS Bucket `kr-cypd`(华北2/北京)的全部数据每日自动同步到公司 NAS(Synology DS1825+ / 192.168.1.201),并生成费用报告。 + +## 架构 + +``` +┌──────────────────┐ ossutil sync ┌───────────────────────────┐ +│ 阿里云 OSS │ ──────────────────────▶ │ Synology DS1825+ │ +│ kr-cypd (北京) │ 每天 03:00 │ /volume1/backup/ │ +│ │ │ oss_kr-cypd/ │ +└──────────────────┘ └───────────────────────────┘ +``` + +## NAS 目录结构 + +``` +/volume1/backup/oss_kr-cypd/ +├── data/ ← OSS 文件同步到这里(按原始目录结构) +│ ├── test/ +│ │ └── 2026-03/ +│ ├── images/ +│ └── ... +├── _snapshots/ ← 每日快照(硬链接,不额外占空间) +│ ├── 2026-03-15/ +│ ├── 2026-03-16/ +│ └── ... +├── _overwritten/ ← 被覆盖文件的备份 +├── _logs/ ← 同步日志 + 每日报告 +│ ├── sync_2026-03-15.log +│ ├── report_2026-03-15.md +│ └── cron.log +└── _cost_reports/ ← OSS 月度费用报告 + └── cost_2026-03.json +``` + +## 凭证信息 + +| 项目 | 值 | +|:---|:---| +| AccessKeyId | `LTAI5t7ixwYZBqYc4bFpe5tc` | +| AccessKeySecret | `Bm1JAMT5U2oyaKLqhbtIPojNQWd5YA` | +| RAM 用户 | gameshop | +| OSS Endpoint | `oss-cn-beijing.aliyuncs.com` | +| Bucket | kr-cypd | + +## 费用参考 + +| 月份 | OSS 费用 | 备注 | +|:---|:---|:---| +| 2026-02 | ¥10.32 | 已结算 | +| 2026-03(至15日) | ¥4.83 | 进行中 | + +费用主要来自:存储费用 + 请求次数 + 外网流出流量。每日同步走内网不产生流量费(需 NAS 与 OSS 在同一地域,或走公网则产生流出费)。 + +## 一键部署 + +```bash +cd "01_卡资(金)/金仓_存储备份/群晖NAS管理/脚本/oss_sync" +bash deploy_to_nas.sh +``` + +该脚本会自动: +1. 在 NAS 上创建目录结构 +2. 上传同步脚本 +3. 安装 ossutil(如未安装) +4. 配置 crontab 定时任务(每天 03:00) + +## 手动执行同步(测试) + +SSH 登录 NAS 后: + +```bash +bash /volume1/backup/oss_kr-cypd/oss_sync_to_nas.sh +``` + +## 同步策略 + +- **增量同步**:ossutil sync 只下载新增/修改的文件,不重复下载 +- **每日快照**:用硬链接创建当日快照,不额外占磁盘空间 +- **被覆盖备份**:远端文件更新时,旧版本自动备份到 `_overwritten/` +- **分类统计**:按 OSS 顶级目录分类统计文件数量和大小 +- **费用监控**:每次同步后查询当月 OSS 费用并写入报告 + +## 备选方案:DSM 任务计划器 + +如果 NAS 不支持 crontab,可在 DSM 控制面板 → 任务计划 中手动添加: + +1. 控制面板 → 任务计划 → 新增 → 计划的任务 → 用户定义的脚本 +2. 常规:任务名称「OSS 每日同步」,用户「root」 +3. 计划:每天 03:00 +4. 任务设置 → 用户定义的脚本: + +```bash +/bin/bash /volume1/backup/oss_kr-cypd/oss_sync_to_nas.sh +``` + +5. 勾选「将运行详情以电子邮件发送」(可选) diff --git a/01_卡资(金)/金仓_存储备份/群晖NAS管理/脚本/oss_sync/deploy_to_nas.sh b/01_卡资(金)/金仓_存储备份/群晖NAS管理/脚本/oss_sync/deploy_to_nas.sh new file mode 100755 index 00000000..d4488f31 --- /dev/null +++ b/01_卡资(金)/金仓_存储备份/群晖NAS管理/脚本/oss_sync/deploy_to_nas.sh @@ -0,0 +1,67 @@ +#!/usr/bin/env bash +# 一键部署 OSS 同步脚本到公司 NAS(Synology DS1825+) +# 使用方式:bash deploy_to_nas.sh +set -euo pipefail + +NAS_IP="192.168.1.201" +NAS_USER="fnvtk" +NAS_PASS="zhiqun1984" +REMOTE_DIR="/volume1/backup/oss_kr-cypd" +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" + +echo "====== 部署 OSS→NAS 同步脚本 ======" + +echo "[1/4] 创建远程目录..." +sshpass -p "${NAS_PASS}" ssh -o StrictHostKeyChecking=no "${NAS_USER}@${NAS_IP}" \ + "mkdir -p ${REMOTE_DIR}/_logs ${REMOTE_DIR}/_cost_reports ${REMOTE_DIR}/_snapshots" + +echo "[2/4] 上传同步脚本..." +sshpass -p "${NAS_PASS}" scp -o StrictHostKeyChecking=no \ + "${SCRIPT_DIR}/oss_sync_to_nas.sh" \ + "${NAS_USER}@${NAS_IP}:${REMOTE_DIR}/oss_sync_to_nas.sh" + +sshpass -p "${NAS_PASS}" ssh -o StrictHostKeyChecking=no "${NAS_USER}@${NAS_IP}" \ + "chmod +x ${REMOTE_DIR}/oss_sync_to_nas.sh" + +echo "[3/4] 安装 ossutil(如未安装)..." +sshpass -p "${NAS_PASS}" ssh -o StrictHostKeyChecking=no "${NAS_USER}@${NAS_IP}" bash <<'REMOTE_INSTALL' +if ! command -v /usr/local/bin/ossutil &>/dev/null; then + echo "正在下载 ossutil..." + ARCH=$(uname -m) + if [ "$ARCH" = "x86_64" ]; then + URL="https://gosspublic.alicdn.com/ossutil/v2/2.0.3/ossutil-v2.0.3-linux-amd64.zip" + else + URL="https://gosspublic.alicdn.com/ossutil/v2/2.0.3/ossutil-v2.0.3-linux-arm64.zip" + fi + cd /tmp + wget -q "${URL}" -O ossutil.zip + unzip -o ossutil.zip -d ossutil_pkg + cp ossutil_pkg/ossutil*/ossutil /usr/local/bin/ossutil + chmod +x /usr/local/bin/ossutil + rm -rf ossutil.zip ossutil_pkg + echo "ossutil 安装完成: $(/usr/local/bin/ossutil version)" +else + echo "ossutil 已安装: $(/usr/local/bin/ossutil version)" +fi +REMOTE_INSTALL + +echo "[4/4] 配置 NAS 定时任务(每天凌晨 03:00)..." +CRON_LINE="0 3 * * * /bin/bash ${REMOTE_DIR}/oss_sync_to_nas.sh >> ${REMOTE_DIR}/_logs/cron.log 2>&1" +sshpass -p "${NAS_PASS}" ssh -o StrictHostKeyChecking=no "${NAS_USER}@${NAS_IP}" bash </dev/null || true) +if echo "\${EXISTING}" | grep -q "oss_sync_to_nas"; then + echo "定时任务已存在,跳过" +else + (echo "\${EXISTING}"; echo "${CRON_LINE}") | crontab - + echo "定时任务已添加: 每天 03:00" +fi +REMOTE_CRON + +echo "" +echo "====== 部署完成 ======" +echo "同步脚本: ${NAS_USER}@${NAS_IP}:${REMOTE_DIR}/oss_sync_to_nas.sh" +echo "备份目录: ${REMOTE_DIR}/data/" +echo "每日快照: ${REMOTE_DIR}/_snapshots/YYYY-MM-DD/" +echo "费用报告: ${REMOTE_DIR}/_cost_reports/" +echo "同步日志: ${REMOTE_DIR}/_logs/" +echo "定时任务: 每天 03:00 自动执行" diff --git a/01_卡资(金)/金仓_存储备份/群晖NAS管理/脚本/oss_sync/oss_sync_to_nas.sh b/01_卡资(金)/金仓_存储备份/群晖NAS管理/脚本/oss_sync/oss_sync_to_nas.sh new file mode 100755 index 00000000..1dbed410 --- /dev/null +++ b/01_卡资(金)/金仓_存储备份/群晖NAS管理/脚本/oss_sync/oss_sync_to_nas.sh @@ -0,0 +1,130 @@ +#!/usr/bin/env bash +# OSS Bucket kr-cypd → NAS 每日定时同步脚本 +# 部署目标:Synology DS1825+(CKBNAS / 192.168.1.201) +# 计划任务:每天凌晨 03:00 +set -euo pipefail + +# ──────────────────── 配置区 ──────────────────── +OSS_ENDPOINT="oss-cn-beijing.aliyuncs.com" +OSS_BUCKET="kr-cypd" +ACCESS_KEY_ID="LTAI5t7ixwYZBqYc4bFpe5tc" +ACCESS_KEY_SECRET="Bm1JAMT5U2oyaKLqhbtIPojNQWd5YA" + +NAS_BACKUP_ROOT="/volume1/backup/oss_kr-cypd" +LOG_DIR="${NAS_BACKUP_ROOT}/_logs" +COST_DIR="${NAS_BACKUP_ROOT}/_cost_reports" +ALIYUN_CLI="/usr/local/bin/aliyun" +OSSUTIL="/usr/local/bin/ossutil" + +DATE_TAG=$(date +%Y-%m-%d) +MONTH_TAG=$(date +%Y-%m) +LOG_FILE="${LOG_DIR}/sync_${DATE_TAG}.log" +# ──────────────────────────────────────────────── + +mkdir -p "${NAS_BACKUP_ROOT}" "${LOG_DIR}" "${COST_DIR}" + +log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "${LOG_FILE}"; } + +log "========== OSS 同步开始 ==========" +log "Bucket: oss://${OSS_BUCKET} → ${NAS_BACKUP_ROOT}" + +# ──────────────── 1. ossutil 增量同步 ──────────────── +SYNC_START=$(date +%s) + +"${OSSUTIL}" sync \ + "oss://${OSS_BUCKET}/" \ + "${NAS_BACKUP_ROOT}/data/" \ + --endpoint "${OSS_ENDPOINT}" \ + --access-key-id "${ACCESS_KEY_ID}" \ + --access-key-secret "${ACCESS_KEY_SECRET}" \ + --force \ + --backup-dir "${NAS_BACKUP_ROOT}/_overwritten" \ + --include "*" \ + 2>&1 | tee -a "${LOG_FILE}" + +SYNC_END=$(date +%s) +SYNC_ELAPSED=$(( SYNC_END - SYNC_START )) +log "同步耗时: ${SYNC_ELAPSED}s" + +# ──────────── 2. 按日期归档(硬链接,不额外占空间) ────────── +DAILY_SNAPSHOT="${NAS_BACKUP_ROOT}/_snapshots/${DATE_TAG}" +if [ ! -d "${DAILY_SNAPSHOT}" ]; then + mkdir -p "${DAILY_SNAPSHOT}" + cp -al "${NAS_BACKUP_ROOT}/data/" "${DAILY_SNAPSHOT}/" + log "每日快照已创建: ${DAILY_SNAPSHOT}" +fi + +# ──────────── 3. 统计本次同步文件数与大小 ────────── +FILE_COUNT=$(find "${NAS_BACKUP_ROOT}/data/" -type f 2>/dev/null | wc -l | tr -d ' ') +TOTAL_SIZE=$(du -sh "${NAS_BACKUP_ROOT}/data/" 2>/dev/null | cut -f1) +log "当前文件总数: ${FILE_COUNT},总大小: ${TOTAL_SIZE}" + +# ──────────── 4. 分类存储统计 ────────── +log "--- 分类存储统计 ---" +for dir in "${NAS_BACKUP_ROOT}/data"/*/; do + [ -d "${dir}" ] || continue + CATEGORY=$(basename "${dir}") + CAT_COUNT=$(find "${dir}" -type f | wc -l | tr -d ' ') + CAT_SIZE=$(du -sh "${dir}" | cut -f1) + log " [${CATEGORY}] 文件数: ${CAT_COUNT}, 大小: ${CAT_SIZE}" +done + +# ──────────── 5. OSS 费用查询(本月) ────────── +COST_FILE="${COST_DIR}/cost_${MONTH_TAG}.json" +if command -v "${ALIYUN_CLI}" &>/dev/null; then + log "正在查询 OSS 本月费用..." + "${ALIYUN_CLI}" bssopenapi QueryBill \ + --region cn-beijing \ + --BillingCycle "${MONTH_TAG}" \ + --ProductCode oss \ + --access-key-id "${ACCESS_KEY_ID}" \ + --access-key-secret "${ACCESS_KEY_SECRET}" \ + > "${COST_FILE}" 2>&1 || true + + if [ -f "${COST_FILE}" ]; then + AMOUNT=$(python3 -c " +import json, sys +try: + d = json.load(open('${COST_FILE}')) + items = d.get('Data',{}).get('Items',{}).get('Item',[]) + total = sum(i.get('PretaxAmount',0) for i in items) + print(f'{total:.2f}') +except: print('N/A') +" 2>/dev/null || echo "N/A") + log "OSS 本月费用: ¥${AMOUNT}" + fi +else + log "aliyun CLI 未安装,跳过费用查询" +fi + +# ──────────── 6. 生成每日同步报告 ────────── +REPORT_FILE="${LOG_DIR}/report_${DATE_TAG}.md" +cat > "${REPORT_FILE}" <20MB: 11 个 | | 2026-03-15 07:05:48 | 🔄 卡若AI 同步 2026-03-15 07:05 | 更新:水桥平台对接、运营中枢、运营中枢工作台 | 排除 >20MB: 11 个 | | 2026-03-15 07:12:23 | 🔄 卡若AI 同步 2026-03-15 07:12 | 更新:运营中枢工作台 | 排除 >20MB: 11 个 | +| 2026-03-15 07:18:57 | 🔄 卡若AI 同步 2026-03-15 07:18 | 更新:火炬、火种知识模型、运营中枢参考资料、运营中枢工作台 | 排除 >20MB: 11 个 | diff --git a/运营中枢/工作台/代码管理.md b/运营中枢/工作台/代码管理.md index 4864b222..816e5a4d 100644 --- a/运营中枢/工作台/代码管理.md +++ b/运营中枢/工作台/代码管理.md @@ -359,3 +359,4 @@ | 2026-03-14 10:36:14 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-14 10:36 | 更新:水桥平台对接、水溪整理归档、火炬、运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) | | 2026-03-15 07:05:48 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-15 07:05 | 更新:水桥平台对接、运营中枢、运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) | | 2026-03-15 07:12:23 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-15 07:12 | 更新:运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) | +| 2026-03-15 07:18:57 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-15 07:18 | 更新:火炬、火种知识模型、运营中枢参考资料、运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |