🔄 卡若AI 同步 2026-03-15 12:31 | 更新:金仓、运营中枢工作台 | 排除 >20MB: 11 个
This commit is contained in:
100
01_卡资(金)/金仓_存储备份/群晖NAS管理/脚本/oss_sync/README.md
Normal file
100
01_卡资(金)/金仓_存储备份/群晖NAS管理/脚本/oss_sync/README.md
Normal file
@@ -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. 勾选「将运行详情以电子邮件发送」(可选)
|
||||
67
01_卡资(金)/金仓_存储备份/群晖NAS管理/脚本/oss_sync/deploy_to_nas.sh
Executable file
67
01_卡资(金)/金仓_存储备份/群晖NAS管理/脚本/oss_sync/deploy_to_nas.sh
Executable file
@@ -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 <<REMOTE_CRON
|
||||
EXISTING=\$(crontab -l 2>/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 自动执行"
|
||||
130
01_卡资(金)/金仓_存储备份/群晖NAS管理/脚本/oss_sync/oss_sync_to_nas.sh
Executable file
130
01_卡资(金)/金仓_存储备份/群晖NAS管理/脚本/oss_sync/oss_sync_to_nas.sh
Executable file
@@ -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}" <<REPORT_EOF
|
||||
# OSS 同步报告 — ${DATE_TAG}
|
||||
|
||||
| 项目 | 值 |
|
||||
|:---|:---|
|
||||
| Bucket | oss://${OSS_BUCKET} |
|
||||
| 目标路径 | ${NAS_BACKUP_ROOT}/data/ |
|
||||
| 同步耗时 | ${SYNC_ELAPSED}s |
|
||||
| 文件总数 | ${FILE_COUNT} |
|
||||
| 数据总量 | ${TOTAL_SIZE} |
|
||||
| 本月 OSS 费用 | ¥${AMOUNT:-N/A} |
|
||||
|
||||
## 分类明细
|
||||
|
||||
$(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)
|
||||
echo "- **${CATEGORY}**: ${CAT_COUNT} 个文件, ${CAT_SIZE}"
|
||||
done)
|
||||
|
||||
## 快照
|
||||
|
||||
每日快照: \`${DAILY_SNAPSHOT}\`
|
||||
REPORT_EOF
|
||||
|
||||
log "报告已生成: ${REPORT_FILE}"
|
||||
log "========== OSS 同步完成 =========="
|
||||
@@ -356,3 +356,4 @@
|
||||
| 2026-03-14 10:36:14 | 🔄 卡若AI 同步 2026-03-14 10:36 | 更新:水桥平台对接、水溪整理归档、火炬、运营中枢工作台 | 排除 >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 个 |
|
||||
|
||||
@@ -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) |
|
||||
|
||||
Reference in New Issue
Block a user