quality-inspection-platform/Jenkinsfile
qihongkun f5143aee09 feat: 添加 Docker 部署支持和 MCP 原生集成
- 添加 Dockerfile、docker-compose.yml 和 Jenkins 流水线配置
- 新增 MCP 原生集成模块 (mcp_native.py)
- 移除旧的 mcp_bridge.py,更新依赖和文档
- 添加部署文档 (Docker 和服务器部署指南)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 14:21:43 +08:00

181 lines
8.3 KiB
Groovy
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.

pipeline {
agent any
environment {
DEPLOY_DIR = '/opt/quality-inspection-platform'
DATA_DIR = '/docker_data'
}
parameters {
string(name: 'DEPLOY_HOST', defaultValue: '', description: '部署目标服务器 SSH 地址,如 root@10.0.0.5')
string(name: 'SSH_PORT', defaultValue: '22', description: 'SSH 端口')
string(name: 'SSH_CREDENTIALS', defaultValue: 'deploy-ssh-key', description: 'Jenkins 凭据 IDSSH 私钥或用户名密码)')
choice(name: 'ACTION', choices: ['deploy', 'restart', 'stop', 'logs'], description: '执行动作')
}
options {
timeout(time: 30, unit: 'MINUTES')
disableConcurrentBuilds()
buildDiscarder(logRotator(numToKeepStr: '20'))
}
stages {
// ──────────────────────────────────────
// 1. 拉取代码
// ──────────────────────────────────────
stage('Checkout') {
steps {
checkout scm
script {
env.GIT_COMMIT_SHORT = sh(script: 'git rev-parse --short HEAD', returnStdout: true).trim()
env.GIT_BRANCH_NAME = sh(script: 'git rev-parse --abbrev-ref HEAD', returnStdout: true).trim()
}
echo "分支: ${env.GIT_BRANCH_NAME} 提交: ${env.GIT_COMMIT_SHORT}"
}
}
// ──────────────────────────────────────
// 2. 推送源码到目标服务器
// ──────────────────────────────────────
stage('Sync Source') {
when { expression { params.ACTION == 'deploy' } }
steps {
sshagent(credentials: [params.SSH_CREDENTIALS]) {
sh """
ssh -p ${params.SSH_PORT} -o StrictHostKeyChecking=no ${params.DEPLOY_HOST} \
'mkdir -p ${DEPLOY_DIR}'
rsync -avz --delete \
--exclude '.git' \
--exclude '.venv' \
--exclude '__pycache__' \
--exclude 'node_modules' \
--exclude '*.pyc' \
--exclude '.env' \
-e "ssh -p ${params.SSH_PORT} -o StrictHostKeyChecking=no" \
./ ${params.DEPLOY_HOST}:${DEPLOY_DIR}/
"""
}
echo '源码同步完成'
}
}
// ──────────────────────────────────────
// 3. 远程服务器 build + 启动
// ──────────────────────────────────────
stage('Remote Build & Start') {
when { expression { params.ACTION == 'deploy' } }
steps {
sshagent(credentials: [params.SSH_CREDENTIALS]) {
sh """
ssh -p ${params.SSH_PORT} -o StrictHostKeyChecking=no ${params.DEPLOY_HOST} '
set -eu
cd ${DEPLOY_DIR}
# 确保 .env 存在(首次部署从 example 复制)
if [ ! -f .env ]; then
cp .env.example .env
echo "首次部署:已从 .env.example 创建 .env请稍后修改密码和密钥"
fi
# 确保数据目录存在
DATA_HOST_DIR=\$(grep "^QIP_DATA_HOST_DIR=" .env | cut -d= -f2 || echo "/docker_data")
[ -z "\$DATA_HOST_DIR" ] && DATA_HOST_DIR="/docker_data"
mkdir -p "\$DATA_HOST_DIR"
# 备份数据库
if [ -f "\$DATA_HOST_DIR/ai_test.db" ]; then
cp "\$DATA_HOST_DIR/ai_test.db" \
"\$DATA_HOST_DIR/ai_test.db.bak.\$(date +%Y%m%d%H%M%S)"
echo "数据库已备份"
fi
# 构建镜像(使用 BuildKit 加速)
DOCKER_BUILDKIT=1 docker compose build --pull
# 重启容器
docker compose down --remove-orphans
docker compose up -d
echo "等待容器启动..."
sleep 20
# 健康检查
PORT=\$(grep "^QIP_HOST_PORT=" .env | cut -d= -f2 || echo "8000")
[ -z "\$PORT" ] && PORT="8000"
STATUS=\$(curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:\$PORT/health || true)
if [ "\$STATUS" = "200" ]; then
echo "✓ 部署成功,健康检查通过 (HTTP 200)"
else
echo "✗ 健康检查未通过 (HTTP \$STATUS),查看日志:"
docker compose logs --tail 30
exit 1
fi
'
"""
}
}
}
// ──────────────────────────────────────
// 4. 仅重启(不重新 build
// ──────────────────────────────────────
stage('Restart Only') {
when { expression { params.ACTION == 'restart' } }
steps {
sshagent(credentials: [params.SSH_CREDENTIALS]) {
sh """
ssh -p ${params.SSH_PORT} -o StrictHostKeyChecking=no ${params.DEPLOY_HOST} '
cd ${DEPLOY_DIR}
docker compose restart
sleep 10
curl -sf http://127.0.0.1:\$(grep "^QIP_HOST_PORT=" .env | cut -d= -f2 || echo 8000)/health \
&& echo "重启成功" || echo "重启后健康检查失败"
'
"""
}
}
}
// ──────────────────────────────────────
// 5. 停止
// ──────────────────────────────────────
stage('Stop') {
when { expression { params.ACTION == 'stop' } }
steps {
sshagent(credentials: [params.SSH_CREDENTIALS]) {
sh """
ssh -p ${params.SSH_PORT} -o StrictHostKeyChecking=no ${params.DEPLOY_HOST} '
cd ${DEPLOY_DIR} && docker compose down
echo "容器已停止"
'
"""
}
}
}
// ──────────────────────────────────────
// 6. 查看日志
// ──────────────────────────────────────
stage('View Logs') {
when { expression { params.ACTION == 'logs' } }
steps {
sshagent(credentials: [params.SSH_CREDENTIALS]) {
sh """
ssh -p ${params.SSH_PORT} -o StrictHostKeyChecking=no ${params.DEPLOY_HOST} '
cd ${DEPLOY_DIR} && docker compose logs --tail 100
'
"""
}
}
}
}
post {
success { echo "✓ 流水线执行成功: ${params.ACTION}" }
failure { echo "✗ 流水线执行失败,请检查日志" }
always { cleanWs() }
}
}