zhizhi/.github/workflows/deploy-cn-llm-relay.yml

223 lines
8.4 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

name: 🇨🇳 CN LLM中继 · 部署
# ═══════════════════════════════════════════════════════════
# 广州国内LLM API中继服务部署
# 编号: ZY-WF-CN-RELAY
# 服务器: ZY-SVR-003 · 43.138.243.30 · 广州
# 守护: 铸渊 · ICE-GL-ZY001
# 版权: 国作登字-2026-A-00037559
#
# 功能: 将 cn-llm-relay 代理服务部署到广州服务器
# 注入国内LLM API密钥 + 中继鉴权密钥
# PM2 守护进程管理
# ═══════════════════════════════════════════════════════════
on:
workflow_dispatch:
inputs:
action:
description: '部署动作'
required: true
default: 'deploy'
type: choice
options:
- deploy
- health-check
- restart
concurrency:
group: cn-llm-relay-deploy
cancel-in-progress: false
permissions:
contents: read
jobs:
deploy:
name: 🚀 部署CN中继
if: github.event.inputs.action == 'deploy' || github.event.inputs.action == ''
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: 🔐 配置SSH
env:
SSH_KEY: ${{ secrets.ZY_CN_LLM_KEY }}
run: |
mkdir -p ~/.ssh
chmod 700 ~/.ssh
# 写入私钥 · 确保末尾有换行符
printf '%s\n' "$SSH_KEY" > ~/.ssh/cn_key
chmod 600 ~/.ssh/cn_key
# 格式校验
if head -1 ~/.ssh/cn_key | grep -q "BEGIN" && tail -1 ~/.ssh/cn_key | grep -q "END"; then
echo "✅ SSH私钥格式正确"
else
echo "❌ SSH私钥格式异常 — 请检查 ZY_CN_LLM_KEY"
echo "首行: $(head -1 ~/.ssh/cn_key)"
echo "末行: $(tail -1 ~/.ssh/cn_key)"
exit 1
fi
# 显示密钥指纹用于调试(不泄露私钥内容)
ssh-keygen -l -f ~/.ssh/cn_key && echo "✅ 密钥指纹读取成功" || echo "⚠️ 无法读取密钥指纹"
# 写入 SSH config · 统一连接参数
cat > ~/.ssh/config << 'SSHCONF'
Host cn-relay
StrictHostKeyChecking accept-new
UserKnownHostsFile ~/.ssh/known_hosts
IdentityFile ~/.ssh/cn_key
IdentitiesOnly yes
ServerAliveInterval 15
ServerAliveCountMax 3
ConnectTimeout 30
SSHCONF
# 注入实际 Host/User避免 heredoc 内插值泄露)
sed -i "1a\\ HostName ${{ secrets.ZY_CN_LLM_HOST }}" ~/.ssh/config
sed -i "2a\\ User ${{ secrets.ZY_CN_LLM_USER }}" ~/.ssh/config
chmod 600 ~/.ssh/config
# 扫描主机公钥(不静默·便于排查)
echo "═══ 扫描目标主机公钥 ═══"
ssh-keyscan -T 10 ${{ secrets.ZY_CN_LLM_HOST }} >> ~/.ssh/known_hosts 2>&1 || echo "⚠️ ssh-keyscan 未返回主机密钥(可能被安全组拦截)"
echo "known_hosts 条目数: $(wc -l < ~/.ssh/known_hosts)"
- name: 🔗 SSH连接测试
run: |
echo "═══ SSH连接测试verbose模式 ═══"
ssh -vvv -o BatchMode=yes -o ConnectTimeout=15 \
-i ~/.ssh/cn_key \
${{ secrets.ZY_CN_LLM_USER }}@${{ secrets.ZY_CN_LLM_HOST }} \
"echo '✅ SSH连接成功 · $(hostname) · $(date)'" \
2>&1 || {
echo ""
echo "═══ SSH连接失败 · 排查方向 ═══"
echo "1. 检查广州服务器 ~/.ssh/authorized_keys 是否包含对应公钥"
echo "2. 检查权限: chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys"
echo "3. 检查 /etc/ssh/sshd_config: PubkeyAuthentication yes"
echo "4. 检查腾讯云安全组是否放行 GitHub Actions IP 的 22 端口"
echo "5. 查看服务器 SSH 日志: journalctl -u sshd -n 50"
exit 1
}
- name: 📦 同步代码到广州
run: |
rsync -avz --delete \
-e "ssh -i ~/.ssh/cn_key -o StrictHostKeyChecking=accept-new -o ConnectTimeout=30" \
--exclude='node_modules' \
--exclude='.env.relay' \
--exclude='logs' \
server/cn-llm-relay/ \
${{ secrets.ZY_CN_LLM_USER }}@${{ secrets.ZY_CN_LLM_HOST }}:/opt/cn-llm-relay/
- name: 📥 安装依赖 & 配置 & 启动
env:
ZY_DEEPSEEK_API_KEY: ${{ secrets.ZY_DEEPSEEK_API_KEY }}
ZY_QIANWEN_API_KEY: ${{ secrets.ZY_QIANWEN_API_KEY }}
ZY_KIMI_API_KEY: ${{ secrets.ZY_KIMI_API_KEY }}
ZY_QINGYAN_API_KEY: ${{ secrets.ZY_QINGYAN_API_KEY }}
ZY_CN_RELAY_API_KEY: ${{ secrets.ZY_CN_LLM_RELAY_KEY }}
run: |
ssh -i ~/.ssh/cn_key \
${{ secrets.ZY_CN_LLM_USER }}@${{ secrets.ZY_CN_LLM_HOST }} << 'DEPLOY_CMD'
set -e
cd /opt/cn-llm-relay
# 创建日志目录
mkdir -p /opt/cn-llm-relay/logs
# 安装依赖
npm install --production 2>&1
DEPLOY_CMD
# 写入环境变量在本地构建后通过SSH写入避免heredoc变量展开问题
ssh -i ~/.ssh/cn_key \
${{ secrets.ZY_CN_LLM_USER }}@${{ secrets.ZY_CN_LLM_HOST }} \
"cat > /opt/cn-llm-relay/.env.relay << 'ENVEOF'
RELAY_PORT=3900
ZY_CN_RELAY_API_KEY=${ZY_CN_RELAY_API_KEY}
ZY_DEEPSEEK_API_KEY=${ZY_DEEPSEEK_API_KEY}
ZY_QIANWEN_API_KEY=${ZY_QIANWEN_API_KEY}
ZY_KIMI_API_KEY=${ZY_KIMI_API_KEY}
ZY_QINGYAN_API_KEY=${ZY_QINGYAN_API_KEY}
ENVEOF
chmod 600 /opt/cn-llm-relay/.env.relay"
# PM2 启动
ssh -i ~/.ssh/cn_key \
${{ secrets.ZY_CN_LLM_USER }}@${{ secrets.ZY_CN_LLM_HOST }} << 'PM2_CMD'
set -e
cd /opt/cn-llm-relay
pm2 delete cn-llm-relay 2>/dev/null || true
pm2 start ecosystem.config.js
pm2 save
# 健康检查
sleep 3
HEALTH_RESULT=$(curl -s http://127.0.0.1:3900/health 2>/dev/null || echo "")
if [ -n "$HEALTH_RESULT" ]; then
echo "✅ CN LLM Relay 健康检查通过"
echo "$HEALTH_RESULT" | head -c 500
else
echo "⚠️ 健康检查未通过 · 查看日志"
pm2 logs cn-llm-relay --lines 20 --nostream
fi
PM2_CMD
health-check:
name: 🩺 健康检查
if: github.event.inputs.action == 'health-check'
runs-on: ubuntu-latest
steps:
- name: 🔐 配置SSH
env:
SSH_KEY: ${{ secrets.ZY_CN_LLM_KEY }}
run: |
mkdir -p ~/.ssh && chmod 700 ~/.ssh
printf '%s\n' "$SSH_KEY" > ~/.ssh/cn_key
chmod 600 ~/.ssh/cn_key
ssh-keyscan -T 10 ${{ secrets.ZY_CN_LLM_HOST }} >> ~/.ssh/known_hosts 2>&1 || true
- name: 🩺 检查服务状态
run: |
ssh -i ~/.ssh/cn_key -o StrictHostKeyChecking=accept-new -o ConnectTimeout=15 \
${{ secrets.ZY_CN_LLM_USER }}@${{ secrets.ZY_CN_LLM_HOST }} << 'CMD'
echo "═══ PM2 状态 ═══"
pm2 list
echo ""
echo "═══ 健康检查 ═══"
curl -s http://127.0.0.1:3900/health || echo "❌ 服务未响应"
echo ""
echo "═══ 最近日志 ═══"
pm2 logs cn-llm-relay --lines 10 --nostream 2>/dev/null || echo "无日志"
CMD
restart:
name: 🔄 重启服务
if: github.event.inputs.action == 'restart'
runs-on: ubuntu-latest
steps:
- name: 🔐 配置SSH
env:
SSH_KEY: ${{ secrets.ZY_CN_LLM_KEY }}
run: |
mkdir -p ~/.ssh && chmod 700 ~/.ssh
printf '%s\n' "$SSH_KEY" > ~/.ssh/cn_key
chmod 600 ~/.ssh/cn_key
ssh-keyscan -T 10 ${{ secrets.ZY_CN_LLM_HOST }} >> ~/.ssh/known_hosts 2>&1 || true
- name: 🔄 重启
run: |
ssh -i ~/.ssh/cn_key -o StrictHostKeyChecking=accept-new -o ConnectTimeout=15 \
${{ secrets.ZY_CN_LLM_USER }}@${{ secrets.ZY_CN_LLM_HOST }} << 'CMD'
cd /opt/cn-llm-relay
pm2 restart cn-llm-relay
sleep 2
curl -s http://127.0.0.1:3900/health || echo "❌ 重启后服务未响应"
CMD