feat(cicd): 接入自动触发 + docker compose 部署

- Jenkinsfile: 加 GenericTrigger(token=buildflow-api),Gitea push 自动触发构建
- Jenkinsfile: 部署 stage 改 docker compose(原 docker run),去 try/catch 吞异常
- Jenkinsfile: HealthCheck 改轮询(最多60s),失败标 unstable 不再静默
- .dockerignore: 排除 appsettings.Secrets.json + bin/obj,防止密钥进镜像

链路:Gitea push → generic-webhook-trigger → Jenkins build → Harbor → cd-target compose up
This commit is contained in:
xiangning 2026-07-17 14:45:46 +08:00
parent 2489b33270
commit 61e106415b
2 changed files with 75 additions and 26 deletions

29
.dockerignore Normal file
View File

@ -0,0 +1,29 @@
# BuildFlow API .dockerignore
# 目标:让 docker build 只把源码进镜像,排除密钥/产物/IDE 文件
# 密钥靠容器启动时 volume 挂载 appsettings.Secrets.json 注入,绝不进镜像
# 🔒 密钥与机密配置(最重要:防止明文密码进镜像)
**/appsettings.Secrets.json
**/appsettings.*.Secrets.json
**/secrets.json
# 构建产物(镜像内会重新 dotnet publish,无需带旧产物)
**/bin/
**/obj/
# Git 与 IDE
.git/
.gitignore
.vscode/
.idea/
*.user
*.suo
# 系统与日志
.DS_Store
*.log
*.tmp
# 文档(镜像不需要)
*.md
docs/

72
Jenkinsfile vendored
View File

@ -1,10 +1,23 @@
// BuildFlow buildflow-api CI/CD
// 链路:①拉取代码 → ②编译打包(docker build) → 推送 Harbor → ③部署(cd-target SSH) → HealthCheck
// 注:飞书通知逻辑已移除(凭证未配齐);部署通过 ssh 直连 cd-target 执行。
// 链路:①拉取代码 → ②编译打包(docker build) → 推送 Harbor → ③部署(cd-target docker compose) → HealthCheck
// 自动触发:Gitea push → Generic Webhook Trigger(token=buildflow-api)
// Gitea webhook 指向:http://jenkins:8080/generic-webhook-trigger/invoke?token=buildflow-api
// 部署:docker compose;api 生产密钥通过 volume 挂载 appsettings.Secrets.json 注入(不进镜像)
// api 运行依赖:PostgreSQL(5库) / Redis / MongoDB(im_system) / RabbitMQ / S3(RustFS) / 本地LLM(1234) / KKFileView(8012)
pipeline {
agent any
triggers {
// Gitea push 触发:Generic Webhook Trigger 按 token 路由到本 job
GenericTrigger(
genericToken: 'buildflow-api',
causeString: 'Gitea push 触发',
printContributedVariables: false,
printPostContent: false,
regexpFilterText: '',
regexpFilterExpression: ''
)
}
environment {
HARBOR = "43.134.235.58:58080"
IMAGE = "${HARBOR}/buildflow/buildflow-api"
@ -12,6 +25,9 @@ pipeline {
// Jenkins 容器内无 ssh 别名,直接用 IP;ubuntu 用户 sudo 免密(NOPASSWD)
DEPLOY_HOST = "ubuntu@110.42.240.10"
APP_PORT = "5667"
// cd-target 上 compose 编排目录 + 本服务名
DEPLOY_DIR = "/home/ubuntu/deploy"
SERVICE = "buildflow-api"
}
options {
timeout(time: 30, unit: "MINUTES")
@ -55,36 +71,40 @@ pipeline {
}
stage("③ 部署") {
steps {
script {
try {
withCredentials([usernamePassword(credentialsId: "harbor-credentials", usernameVariable: "HUSER", passwordVariable: "HPASS")]) {
sh """
ssh -o StrictHostKeyChecking=accept-new ${DEPLOY_HOST} "
echo '${HPASS}' | sudo docker login ${HARBOR} -u ${HUSER} --password-stdin
sudo docker pull ${IMAGE}:latest
sudo docker rm -f buildflow-api 2>/dev/null || true
sudo docker run -d --name buildflow-api --restart unless-stopped -p ${APP_PORT}:${APP_PORT} ${IMAGE}:latest
"
"""
}
echo "部署完成"
} catch (e) {
echo "警告:部署节点 ${DEPLOY_HOST} 暂不可用,跳过自动部署(镜像已推送 Harbor)。原因:${e.getMessage()}"
}
withCredentials([usernamePassword(credentialsId: "harbor-credentials", usernameVariable: "HUSER", passwordVariable: "HPASS")]) {
sh """
ssh -o StrictHostKeyChecking=accept-new ${DEPLOY_HOST} "
cd ${DEPLOY_DIR}
echo '${HPASS}' | sudo docker login ${HARBOR} -u ${HUSER} --password-stdin
sudo docker compose pull ${SERVICE}
sudo docker compose up -d --no-deps ${SERVICE}
"
"""
}
echo "部署完成"
}
}
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,可手动检查。"
// .NET 启动较慢(连 PG/Redis/Mongo),轮询最多 60s
def healthy = false
for (int i = 1; i <= 12; i++) {
sleep 5
try {
sh """
ssh -o StrictHostKeyChecking=accept-new ${DEPLOY_HOST} 'wget -q --spider http://127.0.0.1:${APP_PORT}/health && echo HEALTHCHECK_OK'
"""
healthy = true
echo "=== HealthCheck OK: api http://110.42.240.10:${APP_PORT} ==="
break
} catch (e) {
echo "HealthCheck 第 ${i}/12 次探测未就绪,5s 后重试..."
}
}
if (!healthy) {
// 不再静默吞失败:标记 unstable,流水线变黄便于发现
unstable("HealthCheck 60s 内未通过,查日志:ssh cd-target 'sudo docker logs ${SERVICE} --tail 50'")
}
}
}