🔄 卡若AI 同步 2026-03-09 05:51 | 更新:金仓、水桥平台对接、卡木、运营中枢工作台 | 排除 >20MB: 11 个

This commit is contained in:
2026-03-09 05:51:28 +08:00
parent ce70d60188
commit 1345fa0a6b
19 changed files with 795 additions and 17 deletions

View File

@@ -51,7 +51,7 @@ kr宝塔: qcWubCdlfFjS2b2DMT1lzPFaDfmv1cBT
### 强制规则(每次执行必守)
1. **宝塔优先确认**:操作腾讯云服务器时,**先确认是否为宝塔服务器**。若是,**统一用宝塔 API + 宝塔 Node 管理,禁止使用 PM2**。所有 Node 项目启停、重启、状态查询一律通过宝塔面板 API`/project/nodejs/start_project``stop_project``get_project_list`
1. **宝塔优先确认**:操作腾讯云服务器时,**先确认是否为宝塔服务器**。若是,**彻底去除 PM2一律使用宝塔原生 Node 管理器**。所有 Node 项目启停、重启、状态查询通过宝塔面板(网站 → Node 项目)及 API。脚本`kr宝塔_彻底去除PM2_仅用宝塔Node_宝塔终端执行.sh`
2. **SSH 统一配置**:账号 **root**、密码 **Zhiqun1984**Z 大写),端口 22022 或 22或使用 id_ed25519 密钥。详见 `references/SSH登录方式与故障排查.md`。SSH 不通时用 TAT腾讯云自动化助手
3. **宝塔 443 优先**:宝塔服务器 443 不监听时,**优先**检查是否运行系统 Nginx 而非宝塔 Nginx若是`killall nginx` 后启动宝塔 Nginx。
4. **经验沉淀**:每次涉及服务器/宝塔/部署的操作结束后,必须把经验写入 `02_卡人/水溪_整理归档/经验库/待沉淀/`,防止同类问题重复出现。

View File

@@ -4,6 +4,8 @@
**执行顺序(强制)**:宝塔 API 优先 → SSH → TAT。每次修改前**必须先检查目标项目及周边项目/应用**,确认不影响其他应用后再执行。详见 SKILL.md 强制规则 8、9。
**彻底去除 PM2一律用宝塔 Node**:脚本 `kr宝塔_彻底去除PM2_仅用宝塔Node_宝塔终端执行.sh`,会停止并禁用 PM2、清理残留、结束高 CPU Node、修复 site.db、通过宝塔 Node 批量启动,缓解卡顿。
---
## 一、执行步骤

View File

@@ -52,11 +52,11 @@ echo "=== 内存 TOP5 ===" && ps aux --sort=-%mem | head -6
- **Nginx/应用日志**:看是否有大量请求或慢请求。
- **带宽/流量**:宝塔面板「监控」或 `vnstat`(若已装)。
### 2.4 针对「服务器卡」的检查
### 2.4 针对「服务器卡 / 负载高 / CPU 100%」的检查与处理
| 现象 | 检查命令/位置 | 处理思路 |
|------------|--------------------------|------------------------------|
| CPU | `top``ps aux --sort=-%cpu` | 结束异常进程或优化程序 |
| CPU 100% | `top``ps aux --sort=-%cpu` | 常见原因PM2 重启循环、Node 进程异常。执行 `kr宝塔_负载CPU修复_宝塔终端执行.sh` 或 TAT `腾讯云_TAT_kr宝塔_负载CPU修复.py` |
| 内存不足 | `free -m` | 关停非必要服务、加 swap 或升配 |
| 磁盘满 | `df -h``du -sh /www/*` | 清日志、删临时文件、扩容 |
| 磁盘 I/O 高| `iostat -x 1 3`(若已装)| 减少写操作、查大文件/日志 |
@@ -64,25 +64,38 @@ echo "=== 内存 TOP5 ===" && ps aux --sort=-%mem | head -6
---
## 三、常见处理动作(登录后执行)
## 三、负载与 CPU 100% 一键修复
**现象**:负载 77%、CPU 100%、磁盘 89%。常见原因PM2 自动重启失败 Node 导致死循环、或多个 Node 进程抢占 CPU。
**执行顺序**:宝塔 API → SSH → TAT。
**方式一(推荐)**:在 **宝塔面板 → 终端** 打开 `01_卡资/金仓_存储备份/服务器管理/scripts/kr宝塔_负载CPU修复_宝塔终端执行.sh`,全文复制粘贴到终端执行。
**方式二**:本机执行 TAT需腾讯云凭证
```bash
cd /Users/karuo/Documents/个人/卡若AI
./01_卡资/金仓_存储备份/服务器管理/scripts/.venv_tx/bin/python \
"01_卡资/金仓_存储备份/服务器管理/scripts/腾讯云_TAT_kr宝塔_负载CPU修复.py"
```
脚本会PM2 清理 → 杀高 CPU Node 进程 → 停全部 Node → 修复 site.db → 批量启动。执行后刷新面板首页,负载与 CPU 应回落。
---
## 四、其他常见处理动作(登录后执行)
```bash
# 清理系统日志(慎用,仅当磁盘紧张时)
# find /var/log -name "*.log" -mtime +7 -delete
# 重载 Nginx
nginx -s reload
# 查看宝塔/Node 相关进程
ps aux | grep -E 'nginx|node|pm2'
# 若使用 PM2查看列表
pm2 list
```
---
## 、宝塔 API 远程检查(需白名单)
## 、宝塔 API 远程检查(需白名单)
若本机 IP 已加入 kr宝塔 的「API 白名单」可用卡若AI 脚本批量看 CPU/内存/磁盘:
@@ -94,7 +107,7 @@ python3 "/Users/karuo/Documents/个人/卡若AI/01_卡资/金仓_存储
---
## 、带宽使用情况(近期已查)
## 、带宽使用情况(近期已查)
kr宝塔 为腾讯云广州 CVM实例 ID: ins-aw0tnqjo带宽 5M。可用脚本查看近 24 小时监控:
@@ -112,7 +125,7 @@ kr宝塔 为腾讯云广州 CVM实例 ID: ins-aw0tnqjo带宽 5M。可
---
## 、直接处理「带宽卡」——在宝塔面板终端执行
## 、直接处理「带宽卡」——在宝塔面板终端执行
以下整段复制到 **kr宝塔 宝塔面板 → 终端** 执行,用于排查并做基础限流。

View File

@@ -0,0 +1,88 @@
#!/bin/bash
# kr宝塔 全面检查:进程、病毒可疑项、卡顿,并清理
# 执行:宝塔面板 → 终端 或 SSH
echo "========== 全面检查与清理 =========="
echo ""
echo "【1】负载与 CPU TOP15"
uptime
ps aux --sort=-%cpu 2>/dev/null | head -16
echo ""
echo "【2】可疑进程检测矿机/病毒常见名)"
for p in kdevtmpfsi kinsing xmrig miner; do
found=$(ps aux | grep -E "$p" | grep -v grep 2>/dev/null)
if [ -n "$found" ]; then
echo " 可疑: $found"
ps aux | grep -E "$p" | grep -v grep | awk '{print $2}' | xargs -r kill -9 2>/dev/null
fi
done
echo " 检查完成"
echo ""
echo "【3】crontab 与定时任务"
crontab -l 2>/dev/null || echo " 无 crontab"
ls -la /etc/cron.d/ 2>/dev/null | head -10
grep -r "wget\|curl.*\|\|" /var/spool/cron/ /etc/cron.d/ 2>/dev/null | head -5 || true
echo ""
echo "【4】/tmp 与 /var/tmp 可疑可执行文件"
find /tmp /var/tmp -type f -executable 2>/dev/null | head -10 || true
echo ""
echo "【5】PM2 与 Node 清理"
pm2 kill 2>/dev/null || true
systemctl stop pm2-root 2>/dev/null || true
systemctl disable pm2-root 2>/dev/null || true
pkill -9 -f "pm2" 2>/dev/null || true
for pid in $(ps aux | awk '$3>80 && /node|npm|pnpm/ && !/grep/ {print $2}' 2>/dev/null); do
kill -9 $pid 2>/dev/null
done
pkill -9 -f "node.*www/wwwroot" 2>/dev/null || true
sleep 2
echo ""
echo "【6】通过宝塔 Node 修复并启动"
python3 << 'PY'
import hashlib,json,os,sqlite3,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(p,d=None): pl=sg(); (pl.update(d) if d else None); r=urllib.request.Request(P+p,data=urllib.parse.urlencode(pl).encode()); return json.loads(urllib.request.urlopen(r,timeout=25).read().decode())
PATH_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"]}
items=post("/project/nodejs/get_project_list").get("data")or[]
for it in items:
if it.get("name"): post("/project/nodejs/stop_project",{"project_name":it["name"]}); time.sleep(0.3)
time.sleep(3)
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 row in cur.fetchall():
sid,name,path,cfg=row[0],row[1],row[2],row[3]or"{}"
path=(path or"").strip(); cfg=json.loads(cfg) if cfg else {}
proj=cfg.get("path")or cfg.get("project_path")or path
if not proj or not os.path.isdir(proj):
for p in PATH_FB.get(name,[]):
if os.path.isdir(p): proj=p; break
if proj and os.path.isdir(proj):
cmd="cd %s && (pnpm start 2>/dev/null || npm run start)"%proj
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()
for rnd in range(3):
items=post("/project/nodejs/get_project_list").get("data")or[]
to_start=[it for it in items if it.get("name") and not it.get("run")]
if not to_start: break
for it in to_start:
if it.get("name"): post("/project/nodejs/start_project",{"project_name":it["name"]}); time.sleep(1.5)
time.sleep(8)
run=sum(1 for x in (post("/project/nodejs/get_project_list").get("data")or[]) if x.get("run"))
print(" 运行 %d 个 Node" % run)
PY
echo ""
echo "【7】清理后负载"
uptime
echo ""
echo "========== 完成 =========="

View File

@@ -0,0 +1,30 @@
#!/bin/bash
# 强制降负载:先停所有 Node/PM2等负载回落后再手动启动
echo "========== 强制降负载 =========="
echo "【1】停 PM2"
pm2 kill 2>/dev/null || true
systemctl stop pm2-root 2>/dev/null || true
systemctl disable pm2-root 2>/dev/null || true
pkill -9 -f pm2 2>/dev/null || true
echo "【2】结束全部 Node 进程"
pkill -9 -f "node" 2>/dev/null || true
pkill -9 -f "npm" 2>/dev/null || true
pkill -9 -f "pnpm" 2>/dev/null || true
pkill -9 -f "next-server" 2>/dev/null || true
sleep 3
echo "【3】通过宝塔 API 停止所有 Node 项目"
python3 -c "
import hashlib,json,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(p,d=None): pl=sg(); pl.update(d or {}); r=urllib.request.Request(P+p,data=urllib.parse.urlencode(pl).encode()); return json.loads(urllib.request.urlopen(r,timeout=20).read().decode())
for it in post('/project/nodejs/get_project_list').get('data')or[]:
n=it.get('name')
if n: post('/project/nodejs/stop_project',{'project_name':n}); time.sleep(0.5)
print('已停止全部')
"
sleep 5
echo "【4】当前负载"
uptime
echo "========== 完成。负载应已下降。需启动的项目请到宝塔 Node 项目里手动点启动 =========="

View File

@@ -0,0 +1,95 @@
#!/bin/bash
# kr宝塔 彻底去除 PM2一律使用宝塔原生 Node 管理器
# 执行:宝塔面板 → 终端 或 SSH全文复制粘贴运行
echo "========== 彻底去除 PM2仅用宝塔 Node =========="
echo "【1】停止并禁用 PM2"
pm2 kill 2>/dev/null || true
systemctl stop pm2-root 2>/dev/null || true
systemctl disable pm2-root 2>/dev/null || true
systemctl mask pm2-root 2>/dev/null || true
rm -f /etc/systemd/system/pm2-root.service 2>/dev/null
rm -f /usr/lib/systemd/system/pm2-root.service 2>/dev/null
systemctl daemon-reload 2>/dev/null || true
echo " PM2 已停止并禁用"
echo ""
echo "【2】清理 PM2 残留进程与配置"
pkill -9 -f "pm2" 2>/dev/null || true
rm -rf /root/.pm2 2>/dev/null
crontab -l 2>/dev/null | grep -v pm2 | crontab - 2>/dev/null || true
echo " PM2 残留已清理"
echo ""
echo "【3】结束高 CPU 与全部 Node 进程(解决卡顿)"
for pid in $(ps aux | awk '$3>80 && /node|npm|pnpm/ && !/grep/ {print $2}' 2>/dev/null); do
echo " kill 高CPU $pid"; kill -9 $pid 2>/dev/null
done
pkill -9 -f "node.*www/wwwroot" 2>/dev/null || true
sleep 2
echo " Node 进程已清理"
echo ""
echo "【4】修复 site.db 启动命令并停止残留"
python3 << 'FIX'
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(p,d=None): pl=sg(); (pl.update(d) if d else None); r=urllib.request.Request(P+p,data=urllib.parse.urlencode(pl).encode()); return json.loads(urllib.request.urlopen(r,timeout=25).read().decode())
PATH_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"]}
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 n:
try: post("/project/nodejs/stop_project",{"project_name":n}); print(" 停:",n)
except: pass
time.sleep(0.4)
time.sleep(3)
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'")
fixed=0
for row in cur.fetchall():
sid,name,path,cfg=row[0],row[1],row[2],row[3]or"{}"
path=(path or"").strip(); cfg=json.loads(cfg) if cfg else {}
proj=cfg.get("path")or cfg.get("project_path")or path
if not proj or not os.path.isdir(proj):
for p in PATH_FB.get(name,[]):
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["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
c.commit(); c.close()
print(" site.db 修复 %d 个" % fixed)
FIX
echo ""
echo "【5】通过宝塔 Node 管理器批量启动"
python3 << 'PY'
import hashlib,json,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(p,d=None): pl=sg(); (pl.update(d) if d else None); r=urllib.request.Request(P+p,data=urllib.parse.urlencode(pl).encode()); return json.loads(urllib.request.urlopen(r,timeout=25).read().decode())
items=post("/project/nodejs/get_project_list").get("data")or post("/project/nodejs/get_project_list").get("list")or[]
to_start=[it for it in items if it.get("name") and not it.get("run")]
print(" 待启动 %d 个" % len(to_start))
for it in to_start:
n=it.get("name")
if n:
try: post("/project/nodejs/start_project",{"project_name":n}); print(" 启:",n)
except: pass
time.sleep(1.5)
items2=post("/project/nodejs/get_project_list").get("data")or post("/project/nodejs/get_project_list").get("list")or[]
run=sum(1 for x in items2 if x.get("run"))
print(" 运行 %d / %d" % (run,len(items2)))
PY
echo ""
echo "【6】负载检查"
uptime
echo ""
echo "========== 完成PM2 已去除,仅用宝塔 Node 管理器,卡顿应缓解 =========="

View File

@@ -0,0 +1,90 @@
#!/bin/bash
# kr宝塔 负载与 CPU 过载修复 - 宝塔面板「终端」或 SSH 执行
# 1. PM2 清理 2. 杀高 CPU 进程 3. 停 Node 4. 修复 site.db 5. 批量启动
echo "========== kr宝塔 负载与 CPU 修复 =========="
echo "【0】PM2 清理(防止重启循环导致 CPU 100%"
pm2 kill 2>/dev/null || true
systemctl stop pm2-root 2>/dev/null || true
systemctl disable pm2-root 2>/dev/null || true
echo " PM2 已清理"
echo ""
echo "【1】负载与 CPU 诊断"
uptime
echo "--- CPU TOP10 ---"
ps aux --sort=-%cpu | head -11
echo ""
echo "【2】结束高 CPU Node 进程CPU>80%"
for pid in $(ps aux | awk '$3>80 && /node|npm|pnpm/ && !/grep/ {print $2}' 2>/dev/null); do
echo " kill -9 $pid"; kill -9 $pid 2>/dev/null
done
echo "--- 清理异常 Node 进程 ---"
pkill -9 -f "node.*www/wwwroot" 2>/dev/null || true
sleep 3
echo ""
echo "【3】通过宝塔 API 停止全部 Node 并修复 site.db然后批量启动"
python3 << 'PY'
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(p,d=None): pl=sg(); (pl.update(d) if d else None); r=urllib.request.Request(P+p,data=urllib.parse.urlencode(pl).encode()); return json.loads(urllib.request.urlopen(r,timeout=25).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=[]; [p.append(int(cfg["port"])) if cfg.get("port") else None]
p.extend(int(m) for m in re.findall(r"-p\s*(\d+)",str(cfg.get("project_script",""))))
return sorted(set(p))
PATH_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"]}
items=post("/project/nodejs/get_project_list").get("data")or post("/project/nodejs/get_project_list").get("list")or[]
print("停止 Node 项目")
for it in items:
n=it.get("name")
if n:
try:
for port in ports(it): [subprocess.call("kill -9 %s 2>/dev/null"%pid,shell=True) for pid in pids(port)]
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}); print(" 停:",n)
except: pass
time.sleep(0.4)
time.sleep(4)
print("\n修复 site.db")
db="/www/server/panel/data/db/site.db"; fixed=0
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 row in cur.fetchall():
sid,name,path,cfg=row[0],row[1],row[2],row[3]or"{}"
path=(path or"").strip(); cfg=json.loads(cfg) if cfg else {}
proj=cfg.get("path")or cfg.get("project_path")or path
if not proj or not os.path.isdir(proj):
for p in PATH_FB.get(name,[]):
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["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)
c.commit(); c.close()
print(" 共修复 %d 个"%fixed)
print("\n批量启动 Node")
for rnd in range(3):
items=post("/project/nodejs/get_project_list").get("data")or post("/project/nodejs/get_project_list").get("list")or[]
to_start=[it for it in items if it.get("name") and not it.get("run")]
if not to_start: print(" 全部已运行"); break
print(" 第%d轮: %d 个"%(rnd+1,len(to_start)))
for it in to_start:
n=it.get("name")
if n:
try: post("/project/nodejs/start_project",{"project_name":n}); print(" 启:",n)
except: pass
time.sleep(1.5)
time.sleep(10)
items2=post("/project/nodejs/get_project_list").get("data")or post("/project/nodejs/get_project_list").get("list")or[]
run=sum(1 for x in items2 if x.get("run"))
print("\n运行 %d / %d"%(run,len(items2)))
print("========== 完成 ==========")
PY

View File

@@ -0,0 +1,53 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""TATkr宝塔 彻底去除 PM2仅用宝塔 Node 管理器"""
import base64, os, re, sys, time
KR_INSTANCE_ID, REGION = "ins-aw0tnqjo", "ap-guangzhou"
SCRIPT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "kr宝塔_彻底去除PM2_仅用宝塔Node_宝塔终端执行.sh")
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
with open(SCRIPT, "r", encoding="utf-8") as f:
shell = f.read()
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宝塔_彻底去除PM2"
r = cli.RunCommand(req)
print("✅ TAT 已下发")
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 []):
tr = getattr(t, "TaskResult", None)
if tr and getattr(tr, "Output", None):
try: print(base64.b64decode(tr.Output).decode("utf-8", errors="replace"))
except: pass
return 0
if __name__ == "__main__": sys.exit(main())

View File

@@ -0,0 +1,65 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""TATkr宝塔 负载与 CPU 过载修复PM2 清理 + 杀高 CPU Node + 停/修/启 Node"""
import base64, os, re, sys, time
KR_INSTANCE_ID, REGION = "ins-aw0tnqjo", "ap-guangzhou"
SCRIPT_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "kr宝塔_负载CPU修复_宝塔终端执行.sh")
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
with open(SCRIPT_PATH, "r", encoding="utf-8") as f:
shell = f.read()
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宝塔_负载CPU修复"
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]
r2 = cli.DescribeInvocationTasks(req2)
for t in (r2.InvocationTaskSet or []):
print("状态:", getattr(t, "TaskStatus", ""))
tr = getattr(t, "TaskResult", None)
if tr:
out = getattr(tr, "Output", tr.__dict__.get("Output", ""))
if out:
try:
print(base64.b64decode(out).decode("utf-8", errors="replace"))
except Exception:
print(str(out)[:2000])
return 0
if __name__ == "__main__":
sys.exit(main())