fix(cicd): api 流水线 - 移除飞书通知(凭证缺失) + 部署改 SSH 直连 cd-target

- 移除 feishuNotify 闭包与 environment 中的 feishu-* credentials 绑定
  (凭证未在 Jenkins 配置,导致构建启动即 FAIL)
- 部署 stage: node(deploy-agent) → ssh cd-target 执行 docker pull/run
  (无 deploy-agent agent 节点)
- 新增 HealthCheck stage(try/catch 不阻塞)
- 清除硬编码 webhook URL 明文
This commit is contained in:
xiangning 2026-07-17 11:22:09 +08:00
parent 5239e59b4e
commit aab0db2b68

89
Jenkinsfile vendored
View File

@ -1,42 +1,7 @@
// BuildFlow buildflow-api CI/CD - clean version
// ①拉取代码 -> ②编译打包 -> 推送Harbor -> ③部署 + 飞书通知
def feishuNotify = { String result, String failedStageName = "" ->
def dur = currentBuild.durationString.replace(" and counting", "")
def commit = ""
try { commit = sh(script: "git log -1 --pretty=format:%s", returnStdout: true).trim() } catch(ignored) {}
def isOk = (result == "SUCCESS")
def color = isOk ? "green" : "red"
def statusText = isOk ? "成功" : "失败"
def title = "CI/CD " + statusText + " " + env.JOB_NAME + " #" + env.BUILD_NUMBER
def fields = [
[is_short: true, text: [tag: "lark_md", content: "**项目**\n" + env.JOB_NAME]],
[is_short: true, text: [tag: "lark_md", content: "**耗时**\n" + dur]],
[is_short: true, text: [tag: "lark_md", content: "**提交**\n" + commit.take(50)]],
[is_short: true, text: [tag: "lark_md", content: "**状态**\n" + statusText]]
]
def elements = [[tag: "div", fields: fields], [tag: "hr"]]
if (isOk) {
elements.add([tag: "div", text: [tag: "lark_md", content: "镜像地址\n`" + env.IMAGE + ":" + env.TAG + "`"]])
} else if (failedStageName) {
elements.add([tag: "div", text: [tag: "lark_md", content: "失败阶段\n" + failedStageName]])
}
def burl = env.BUILD_URL
if (burl == null) { burl = "http://115.191.51.246:8080/job/" + env.JOB_NAME.replace("/", "/job/") + "/" }
elements.add([tag: "action", actions: [[tag: "button", text: [tag: "plain_text", content: "查看构建"], url: burl, type: isOk ? "primary" : "danger"]]])
def card = [msg_type: "interactive", card: [header: [title: [tag: "plain_text", content: title], template: color], elements: elements]]
def ts = String.valueOf(System.currentTimeMillis() / 1000L as long)
def stringToSign = ts + "\n" + "${env.FEISHU_SIGN_SECRET}"
def mac = javax.crypto.Mac.getInstance("HmacSHA256")
mac.init(new javax.crypto.spec.SecretKeySpec(stringToSign.getBytes("UTF-8"), "HmacSHA256"))
def sign = mac.doFinal().encodeBase64().toString()
card.timestamp = ts
card.sign = sign
def jsonStr = groovy.json.JsonOutput.toJson(card)
writeFile file: "/tmp/feishu_msg.json", text: jsonStr
sh "curl -sS -X POST ${env.FEISHU_WEBHOOK_URL} -H \"Content-Type: application/json\" -d @/tmp/feishu_msg.json || true"
sh 'rm -f /tmp/feishu_msg.json'
}
// BuildFlow buildflow-api CI/CD
// 链路:①拉取代码 → ②编译打包(docker build) → 推送 Harbor → ③部署(cd-target SSH) → HealthCheck
// 注:飞书通知逻辑已移除(凭证未配齐);部署通过 ssh 直连 cd-target 执行。
// api 运行依赖:PostgreSQL(5库) / Redis / MongoDB(im_system) / RabbitMQ / S3(RustFS) / 本地LLM(1234) / KKFileView(8012)
pipeline {
agent any
@ -44,9 +9,8 @@ pipeline {
HARBOR = "43.134.235.58:58080"
IMAGE = "${HARBOR}/buildflow/buildflow-api"
TAG = "${env.BUILD_NUMBER}"
// 飞书通知签名密钥与 Webhook 地址从 Jenkins 凭证注入,禁止硬编码(已清除明文)
FEISHU_SIGN_SECRET = credentials('feishu-signature-key')
FEISHU_WEBHOOK_URL = credentials('feishu-webhook-url')
DEPLOY_HOST = "cd-target"
APP_PORT = "5667"
}
options {
timeout(time: 30, unit: "MINUTES")
@ -81,31 +45,42 @@ pipeline {
steps {
script {
try {
node("deploy-agent") {
sh '''
docker pull $IMAGE:latest
sh """
ssh -o StrictHostKeyChecking=accept-new ${DEPLOY_HOST} '
docker pull ${IMAGE}:latest
docker rm -f buildflow-api 2>/dev/null || true
docker run -d --name buildflow-api --restart unless-stopped -p 5667:5667 $IMAGE:latest
'''
}
docker run -d --name buildflow-api --restart unless-stopped -p ${APP_PORT}:${APP_PORT} ${IMAGE}:latest
'
"""
echo "部署完成"
} catch (e) {
echo "部署节点暂不可用,跳过自动部署。镜像已推送 Harbor。api依赖PG/Mongo/Redis/RabbitMQ"
echo "警告:部署节点 ${DEPLOY_HOST} 暂不可用,跳过自动部署(镜像已推送 Harbor)。原因:${e.getMessage()}"
}
}
}
}
stage("HealthCheck") {
steps {
script {
try {
sh """
sleep 8
ssh -o StrictHostKeyChecking=accept-new ${DEPLOY_HOST} 'wget -q --spider http://127.0.0.1:${APP_PORT}/health || wget -q --spider http://127.0.0.1:${APP_PORT}/ && echo HEALTHCHECK_OK'
"""
echo "=== HealthCheck OK: api http://110.42.240.10:${APP_PORT} ==="
} catch (e) {
echo "警告:HealthCheck 探测失败(容器可能仍在启动,或依赖的 PG/Redis/Mongo 未就绪)。镜像已推送 Harbor,可手动检查。"
}
}
}
}
}
post {
success {
script { feishuNotify("SUCCESS") }
}
failure {
script { feishuNotify("FAILURE", "构建失败,请查看日志") }
}
always {
success { echo '=== buildflow-api CI/CD SUCCESS ===' }
failure { echo '=== buildflow-api CI/CD FAILED ===' }
always {
sh "docker rmi ${IMAGE}:${TAG} ${IMAGE}:latest 2>/dev/null || true"
deleteDir()
}
}
}
}