From 35eb6d5db537710f9f8196475d03a7718afbc549 Mon Sep 17 00:00:00 2001 From: karuo Date: Sun, 22 Feb 2026 19:02:31 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=84=20=E5=8D=A1=E8=8B=A5AI=20=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=202026-02-22=2019:02=20|=20=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=EF=BC=9A=E9=87=91=E4=BB=93=E3=80=81=E8=BF=90=E8=90=A5=E4=B8=AD?= =?UTF-8?q?=E6=9E=A2=E5=B7=A5=E4=BD=9C=E5=8F=B0=20|=20=E6=8E=92=E9=99=A4?= =?UTF-8?q?=20>20MB:=208=20=E4=B8=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../服务器管理/references/kr宝塔_宝塔终端执行指南.md | 54 ++++++++ .../scripts/kr宝塔_运行堵塞与Node深度修复_宝塔终端执行.sh | 4 +- .../scripts/腾讯云_TAT_kr宝塔_仅批量启动Node.py | 2 +- .../服务器管理/scripts/腾讯云_TAT_kr宝塔_强制停启Node.py | 123 ++++++++++++++++++ .../scripts/腾讯云_TAT_kr宝塔_运行堵塞与Node深度修复.py | 10 +- .../群晖NAS管理/scripts/mount_ckb_nas_1tb.sh | 35 +++++ .../群晖NAS管理/参考资料/CKB_NAS_外网挂载到Finder侧栏.md | 45 +++++++ 运营中枢/工作台/gitea_push_log.md | 1 + 运营中枢/工作台/代码管理.md | 1 + 9 files changed, 266 insertions(+), 9 deletions(-) create mode 100644 01_卡资(金)/金仓_存储备份/服务器管理/references/kr宝塔_宝塔终端执行指南.md create mode 100644 01_卡资(金)/金仓_存储备份/服务器管理/scripts/腾讯云_TAT_kr宝塔_强制停启Node.py create mode 100755 01_卡资(金)/金仓_存储备份/群晖NAS管理/scripts/mount_ckb_nas_1tb.sh create mode 100644 01_卡资(金)/金仓_存储备份/群晖NAS管理/参考资料/CKB_NAS_外网挂载到Finder侧栏.md diff --git a/01_卡资(金)/金仓_存储备份/服务器管理/references/kr宝塔_宝塔终端执行指南.md b/01_卡资(金)/金仓_存储备份/服务器管理/references/kr宝塔_宝塔终端执行指南.md new file mode 100644 index 00000000..77929502 --- /dev/null +++ b/01_卡资(金)/金仓_存储备份/服务器管理/references/kr宝塔_宝塔终端执行指南.md @@ -0,0 +1,54 @@ +# kr 宝塔 · 宝塔终端执行指南 + +> 当 TAT 超时或 Node 批量启动失败时,在**宝塔面板终端**执行修复脚本,无时间限制。 + +--- + +## 一、执行步骤 + +### 1. 打开宝塔终端 + +1. 浏览器访问:https://43.139.27.93:9988 +2. 登录宝塔 +3. 左侧菜单 → **终端** +4. 点击「**连接**」或创建新终端 + +### 2. 上传脚本(二选一) + +**方式 A:文件管理上传** + +1. 宝塔 → **文件** → 进入 `/root` +2. 上传本地文件:`scripts/kr宝塔_运行堵塞与Node深度修复_宝塔终端执行.sh` +3. 终端执行:`bash /root/kr宝塔_运行堵塞与Node深度修复_宝塔终端执行.sh` + +**方式 B:直接粘贴执行** + +1. 用本地编辑器打开 `scripts/kr宝塔_运行堵塞与Node深度修复_宝塔终端执行.sh` +2. 全选复制 +3. 在宝塔终端中粘贴,回车执行 + +### 3. 脚本会完成 + +- 结束异常 Node 进程(含 PID 异常的项目) +- 停止全部 Node 项目 +- 修复 site.db 启动命令为 `cd /path && (pnpm start || npm run start)` +- 查看 Node 日志 +- 批量启动(3 轮,每轮间隔 10s) +- 输出最终运行状态 + +--- + +## 二、常见问题 + +| 问题 | 处理 | +|------|------| +| 部分项目仍 FAIL | 在宝塔「网站 → Node 项目」中,对该项目点「设置」,检查启动命令是否为 `cd /路径 && (pnpm start \|\| npm run start)`;查看日志排查依赖/端口 | +| 中文目录路径 | 如 `/www/wwwroot/self/wanzhi/玩值大屏` 可保留,脚本已支持;若需改英文需另做目录迁移 | +| 执行超时 | 宝塔终端无超时限制,可耐心等待(约 2~3 分钟) | + +--- + +## 三、脚本路径 + +- 本地:`01_卡资(金)/金仓_存储备份/服务器管理/scripts/kr宝塔_运行堵塞与Node深度修复_宝塔终端执行.sh` +- 宝塔 API 密钥:`qcWubCdlfFjS2b2DMT1lzPFaDfmv1cBT`(脚本内已配置) diff --git a/01_卡资(金)/金仓_存储备份/服务器管理/scripts/kr宝塔_运行堵塞与Node深度修复_宝塔终端执行.sh b/01_卡资(金)/金仓_存储备份/服务器管理/scripts/kr宝塔_运行堵塞与Node深度修复_宝塔终端执行.sh index 47744088..49cae8e7 100644 --- a/01_卡资(金)/金仓_存储备份/服务器管理/scripts/kr宝塔_运行堵塞与Node深度修复_宝塔终端执行.sh +++ b/01_卡资(金)/金仓_存储备份/服务器管理/scripts/kr宝塔_运行堵塞与Node深度修复_宝塔终端执行.sh @@ -11,6 +11,8 @@ echo "--- 结束异常高 CPU node 进程 ---" for pid in $(ps aux | awk '$3>80 && /node|npm|pnpm/ && !/grep/ {print $2}' 2>/dev/null); do echo " kill $pid"; kill -9 $pid 2>/dev/null done +echo "--- 清理所有 Node 相关孤儿进程(含异常 PID 状态)---" +pkill -9 -f "node.*www/wwwroot" 2>/dev/null || true sleep 2 python3 << 'PY' @@ -54,7 +56,7 @@ if os.path.isfile(db): if not proj or not os.path.isdir(proj): print(" 跳过",name); continue cmd="cd %s && (pnpm start 2>/dev/null || npm run start)"%proj old=str(cfg.get("project_script")or cfg.get("run_cmd")or"").strip() - if "cd " not in old or proj not in old: + if True: cfg["project_script"]=cfg["run_cmd"]=cmd; cfg["path"]=proj cur.execute("UPDATE sites SET path=?,project_config=? WHERE id=?",(proj,json.dumps(cfg,ensure_ascii=False),sid)); fixed+=1 print(" 修复:",name,"->",proj) diff --git a/01_卡资(金)/金仓_存储备份/服务器管理/scripts/腾讯云_TAT_kr宝塔_仅批量启动Node.py b/01_卡资(金)/金仓_存储备份/服务器管理/scripts/腾讯云_TAT_kr宝塔_仅批量启动Node.py index 2ef7b9cb..c8c5bab8 100644 --- a/01_卡资(金)/金仓_存储备份/服务器管理/scripts/腾讯云_TAT_kr宝塔_仅批量启动Node.py +++ b/01_卡资(金)/金仓_存储备份/服务器管理/scripts/腾讯云_TAT_kr宝塔_仅批量启动Node.py @@ -65,7 +65,7 @@ for it in to_start: try: r=post('/project/nodejs/start_project',{'project_name':n}) ok=r.get('status') or '成功' in str(r.get('msg','')) - print(n,':','OK' if ok else 'FAIL', r.get('msg','')[:80] if not ok else '') + print(n,':','OK' if ok else 'FAIL') except Exception as e: print(n,': ERR',str(e)[:30]) time.sleep(1.5) items2=post('/project/nodejs/get_project_list').get('data')or post('/project/nodejs/get_project_list').get('list')or[] diff --git a/01_卡资(金)/金仓_存储备份/服务器管理/scripts/腾讯云_TAT_kr宝塔_强制停启Node.py b/01_卡资(金)/金仓_存储备份/服务器管理/scripts/腾讯云_TAT_kr宝塔_强制停启Node.py new file mode 100644 index 00000000..ab877c01 --- /dev/null +++ b/01_卡资(金)/金仓_存储备份/服务器管理/scripts/腾讯云_TAT_kr宝塔_强制停启Node.py @@ -0,0 +1,123 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +"""TAT:强制停止全部 Node + 修复 site.db + 批量启动(精简版,约 90s)""" +import base64, json, os, re, sys, time + +KR_INSTANCE_ID, REGION = "ins-aw0tnqjo", "ap-guangzhou" + +SHELL = r'''#!/bin/bash +set -e +echo "【1】宝塔" +! ss -tlnp 2>/dev/null | grep -q ':9988 ' && /etc/init.d/bt start 2>/dev/null; sleep 5 +echo "【2】强制结束 Node 进程" +pkill -9 -f "node.*www/wwwroot" 2>/dev/null || true +sleep 2 +echo "【3】修复 site.db + 停+启" +PYTHONUNBUFFERED=1 python3 -u -c " +import hashlib,json,os,re,sqlite3,subprocess,time,urllib.request,urllib.parse,ssl +ssl._create_default_https_context=ssl._create_unverified_context +P,K='https://127.0.0.1:9988','qcWubCdlfFjS2b2DMT1lzPFaDfmv1cBT' +def sg(): t=int(time.time()); return {'request_time':t,'request_token':hashlib.md5((str(t)+hashlib.md5(K.encode()).hexdigest()).encode()).hexdigest()} +def post(u,d=None): pl=sg(); (pl.update(d) if d else None); r=urllib.request.Request(P+u,data=urllib.parse.urlencode(pl).encode()); return json.loads(urllib.request.urlopen(r,timeout=20).read().decode()) +def pids(port): + try: return {int(x) for x in re.findall(r'pid=(\d+)',subprocess.check_output(\"ss -tlnp 2>/dev/null | grep ':%s ' || true\"%port,shell=True).decode())} + except: return set() +def ports(it): + cfg=it.get('project_config') or {} + if isinstance(cfg,str): cfg=json.loads(cfg) if cfg else {} + p=[int(cfg['port'])] if cfg.get('port') else [] + p.extend(int(m) for m in re.findall(r'-p\s*(\d+)',str(cfg.get('project_script','')))) + return sorted(set(p)) +FB={'玩值大屏':['/www/wwwroot/self/wanzhi/玩值大屏','/www/wwwroot/self/wanzhi/玩值'],'tongzhi':['/www/wwwroot/self/wanzhi/tongzhi','/www/wwwroot/self/wanzhi/tong'],'神射手':['/www/wwwroot/self/kr/kr-use','/www/wwwroot/self/kr/kr-users'],'AITOUFA':['/www/wwwroot/ext/tools/AITOUFA','/www/wwwroot/ext/tools/AITOL']} +db='/www/server/panel/data/db/site.db' +if os.path.isfile(db): + c=sqlite3.connect(db); cur=c.cursor(); cur.execute(\"SELECT id,name,path,project_config FROM sites WHERE project_type='Node'\") + for r in cur.fetchall(): + sid,nm,path,cfg=r[0],r[1],r[2],r[3]or'{}' + proj=(json.loads(cfg) if cfg else {}).get('path') or path or '' + if not proj or not os.path.isdir(proj): + for p in FB.get(nm,[]): + if os.path.isdir(p): proj=p; break + if not proj or not os.path.isdir(proj): continue + cmd='cd %s && (pnpm start 2>/dev/null || npm run start)'%proj + cfg=json.loads(cfg) if isinstance(cfg,str) else (cfg or {}) + cfg['project_script']=cfg['run_cmd']=cmd; cfg['path']=proj + cur.execute('UPDATE sites SET path=?, project_config=? WHERE id=?',(proj,json.dumps(cfg,ensure_ascii=False),sid)) + c.commit(); c.close() +print('site.db 已修复') +items=post('/project/nodejs/get_project_list').get('data')or post('/project/nodejs/get_project_list').get('list')or[] +for it in items: + n=it.get('name') + if not n: continue + try: + for port in ports(it): + for pid in pids(port): subprocess.call('kill -9 %s'%pid,shell=True) + pf='/www/server/nodejs/vhost/pids/%s.pid'%n + if os.path.exists(pf): open(pf,'w').write('0') + post('/project/nodejs/stop_project',{'project_name':n}) + except: pass + time.sleep(0.3) +time.sleep(3) +print('停止完成,开始启动') +for it in items: + n=it.get('name') + if not n: continue + try: + r=post('/project/nodejs/start_project',{'project_name':n}) + ok=r.get('status') or '成功' in str(r.get('msg','')) + print(n,':','OK' if ok else 'FAIL') + except Exception as e: print(n,': ERR') + time.sleep(1.2) +r2=post('/project/nodejs/get_project_list').get('data')or post('/project/nodejs/get_project_list').get('list')or[] +print('运行',sum(1 for x in r2 if x.get('run')),'/',len(r2)) +" 2>&1 +echo "【4】完成" +uptime +''' + +def _creds(): + d = os.path.dirname(os.path.abspath(__file__)) + for _ in range(6): + p = os.path.join(d, "运营中枢", "工作台", "00_账号与API索引.md") + if os.path.isfile(p): + t = open(p).read() + sid = skey = None + for L in t.splitlines(): + m = re.search(r"SecretId[^|]*\|\s*`([^`]+)`", L, re.I) + if m and "AKID" in m.group(1): sid = m.group(1).strip() + m = re.search(r"SecretKey\s*\|\s*`([^`]+)`", L, re.I) + if m: skey = m.group(1).strip() + return sid or os.environ.get("TENCENTCLOUD_SECRET_ID"), skey or os.environ.get("TENCENTCLOUD_SECRET_KEY") + d = os.path.dirname(d) + return None, None + +def main(): + sid, skey = _creds() + if not sid or not skey: + print("❌ 未配置凭证"); return 1 + from tencentcloud.common import credential + from tencentcloud.tat.v20201028 import tat_client, models + cred = credential.Credential(sid, skey) + cli = tat_client.TatClient(cred, REGION) + req = models.RunCommandRequest() + req.Content = base64.b64encode(SHELL.encode("utf-8")).decode() + req.InstanceIds = [KR_INSTANCE_ID] + req.CommandType = "SHELL" + req.Timeout = 120 + req.CommandName = "kr宝塔_强制停启Node" + r = cli.RunCommand(req) + print("✅ TAT inv:", r.InvocationId) + time.sleep(100) + req2 = models.DescribeInvocationTasksRequest() + f = models.Filter(); f.Name, f.Values = "invocation-id", [r.InvocationId] + req2.Filters = [f] + for t in (cli.DescribeInvocationTasks(req2).InvocationTaskSet or []): + print("状态:", getattr(t, "TaskStatus", "")) + tr = getattr(t, "TaskResult", None) + if tr: + out = getattr(tr, "Output", tr.__dict__.get("Output", "")) + if out: + print(base64.b64decode(out).decode("utf-8", errors="replace")) + return 0 + +if __name__ == "__main__": sys.exit(main()) diff --git a/01_卡资(金)/金仓_存储备份/服务器管理/scripts/腾讯云_TAT_kr宝塔_运行堵塞与Node深度修复.py b/01_卡资(金)/金仓_存储备份/服务器管理/scripts/腾讯云_TAT_kr宝塔_运行堵塞与Node深度修复.py index 6ca75350..384e65d1 100644 --- a/01_卡资(金)/金仓_存储备份/服务器管理/scripts/腾讯云_TAT_kr宝塔_运行堵塞与Node深度修复.py +++ b/01_卡资(金)/金仓_存储备份/服务器管理/scripts/腾讯云_TAT_kr宝塔_运行堵塞与Node深度修复.py @@ -30,19 +30,15 @@ if ! ss -tlnp 2>/dev/null | grep -q ':9988 '; then fi ss -tlnp 2>/dev/null | grep 9988 || echo " 9988 未监听,API 可能失败" -# 【0】运行堵塞诊断 +# 【0】运行堵塞诊断 + 清理异常 Node 进程 echo "" echo "【0】运行堵塞诊断" -echo "--- 负载 ---" uptime -echo "--- 内存 ---" -free -m | head -2 -echo "--- CPU TOP10 ---" -ps aux --sort=-%cpu 2>/dev/null | head -11 -echo "--- 结束异常 node/npm/pnpm 进程(占用>80%%CPU) ---" +echo "--- 结束异常 node/npm/pnpm 进程 + 清理 www/wwwroot 下 Node ---" for pid in $(ps aux | awk '$3>80 && /node|npm|pnpm/ && !/grep/ {print $2}' 2>/dev/null); do echo " kill $pid"; kill -9 $pid 2>/dev/null done +pkill -9 -f "node.*www/wwwroot" 2>/dev/null || true sleep 2 python3 - << 'PYMAIN' diff --git a/01_卡资(金)/金仓_存储备份/群晖NAS管理/scripts/mount_ckb_nas_1tb.sh b/01_卡资(金)/金仓_存储备份/群晖NAS管理/scripts/mount_ckb_nas_1tb.sh new file mode 100755 index 00000000..fba4a86b --- /dev/null +++ b/01_卡资(金)/金仓_存储备份/群晖NAS管理/scripts/mount_ckb_nas_1tb.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# ============================================ +# 存客宝 CKB NAS 共享盘 - 外网挂载到 Finder 侧栏「位置」 +# 挂载后可直接存文件,Finder 拷贝时会显示速率 +# 外网通过 frp 端口 4450 访问 SMB +# ============================================ + +NAS_HOST="open.quwanzhi.com" +NAS_PORT="4450" +NAS_USER="fnvtk" +# 密码:与 DSM 登录一致,若非 zhiqun1984 请修改 +NAS_PASS="zhiqun1984" +SHARE="homes" +MOUNT_POINT="$HOME/CKB-NAS-1TB" + +# 已挂载则先卸载 +if mount | grep -q "CKB-NAS-1TB"; then + echo "正在卸载旧挂载..." + umount "$MOUNT_POINT" 2>/dev/null + sleep 1 +fi + +mkdir -p "$MOUNT_POINT" +echo "正在挂载存客宝 NAS (${NAS_HOST}:${NAS_PORT})..." +mount_smbfs "//${NAS_USER}:${NAS_PASS}@${NAS_HOST}:${NAS_PORT}/${SHARE}" "$MOUNT_POINT" 2>&1 + +if mount | grep -q "CKB-NAS-1TB"; then + echo "挂载成功: $MOUNT_POINT" + echo "添加到 Finder 侧栏:在 Finder 中把「CKB-NAS-1TB」拖到侧栏「位置」下即可" + echo "直接往里拷贝文件,Finder 会显示传输速率" + open "$MOUNT_POINT" +else + echo "挂载失败。若提示 Authentication error,请修改本脚本中的 NAS_PASS 为 DSM 登录密码" + exit 1 +fi diff --git a/01_卡资(金)/金仓_存储备份/群晖NAS管理/参考资料/CKB_NAS_外网挂载到Finder侧栏.md b/01_卡资(金)/金仓_存储备份/群晖NAS管理/参考资料/CKB_NAS_外网挂载到Finder侧栏.md new file mode 100644 index 00000000..bf73637a --- /dev/null +++ b/01_卡资(金)/金仓_存储备份/群晖NAS管理/参考资料/CKB_NAS_外网挂载到Finder侧栏.md @@ -0,0 +1,45 @@ +# 存客宝 CKB NAS 外网挂载到 Finder 侧栏「位置」 + +把 NAS 的 1TB 共享盘映射到 Finder 侧栏,外网可用,拷贝时显示速率。 + +--- + +## 一、已完成的配置 + +- **SMB 外网穿透**:frp 已开放端口 **4450** → NAS 445 +- **共享文件夹**:`homes`(对应 /volume1/homes/fnvtk,可用空间 21TB) + +--- + +## 二、挂载方式(任选其一) + +### 方式 A:Finder 连接服务器(推荐,可保存密码) + +1. Finder → **前往** → **连接服务器**(⌘K) +2. 输入:`smb://open.quwanzhi.com:4450/homes` +3. 点**连接**,输入 DSM 用户名和密码,勾选「在钥匙串中记住此密码」 +4. 连接成功后,该共享会出现在 Finder 侧栏「位置」下 +5. 右键该共享 → **制作替身** 或 拖到侧栏,可固定显示 + +### 方式 B:脚本挂载 + +```bash +/Users/karuo/Documents/个人/卡若AI/01_卡资(金)/金仓_存储备份/群晖NAS管理/scripts/mount_ckb_nas_1tb.sh +``` + +- 若提示 **Authentication error**:编辑脚本,把 `NAS_PASS` 改为你的 DSM 登录密码 +- 挂载后位置:`~/CKB-NAS-1TB`,在 Finder 中把它拖到侧栏「位置」即可固定 + +--- + +## 三、添加「位置」到侧栏 + +挂载成功后,在 Finder 左侧「位置」区域: + +- 将 `CKB-NAS-1TB` 或 `homes` 拖到侧栏,即可像 Synology Drive 一样固定显示 + +--- + +## 四、传输速率 + +在 Finder 中往该共享拷贝文件时,会显示进度和传输速率(与本地磁盘相同)。 diff --git a/运营中枢/工作台/gitea_push_log.md b/运营中枢/工作台/gitea_push_log.md index 8e823d33..7497017d 100644 --- a/运营中枢/工作台/gitea_push_log.md +++ b/运营中枢/工作台/gitea_push_log.md @@ -96,3 +96,4 @@ | 2026-02-22 14:44:11 | 🔄 卡若AI 同步 2026-02-22 14:43 | 更新:金仓、运营中枢工作台 | 排除 >20MB: 8 个 | | 2026-02-22 14:59:42 | 🔄 卡若AI 同步 2026-02-22 14:59 | 更新:金仓、卡木、运营中枢工作台 | 排除 >20MB: 8 个 | | 2026-02-22 15:08:03 | 🔄 卡若AI 同步 2026-02-22 15:07 | 更新:金仓、运营中枢工作台 | 排除 >20MB: 8 个 | +| 2026-02-22 16:00:09 | 🔄 卡若AI 同步 2026-02-22 16:00 | 更新:金仓、运营中枢工作台 | 排除 >20MB: 8 个 | diff --git a/运营中枢/工作台/代码管理.md b/运营中枢/工作台/代码管理.md index 8eacdce5..9c20b23f 100644 --- a/运营中枢/工作台/代码管理.md +++ b/运营中枢/工作台/代码管理.md @@ -99,3 +99,4 @@ | 2026-02-22 14:44:11 | 成功 | 成功 | 🔄 卡若AI 同步 2026-02-22 14:43 | 更新:金仓、运营中枢工作台 | 排除 >20MB: 8 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) | | 2026-02-22 14:59:42 | 成功 | 成功 | 🔄 卡若AI 同步 2026-02-22 14:59 | 更新:金仓、卡木、运营中枢工作台 | 排除 >20MB: 8 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) | | 2026-02-22 15:08:03 | 成功 | 成功 | 🔄 卡若AI 同步 2026-02-22 15:07 | 更新:金仓、运营中枢工作台 | 排除 >20MB: 8 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) | +| 2026-02-22 16:00:09 | 成功 | 成功 | 🔄 卡若AI 同步 2026-02-22 16:00 | 更新:金仓、运营中枢工作台 | 排除 >20MB: 8 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |