// live.fuhua91.com 部署流水线(基于 Jenkinsfile2 模板改造) // 构建前后端镜像推送 Harbor(harbor.fuhua91.com/live),并 SSH 到宝塔服务器(192.168.2.226) // 执行 /root/deploy.sh 拉取镜像更新容器。 // // Jenkins 凭据要求: // - harbor-live-push : Username with password,Harbor 项目 live 的 robot 账号 // (robot$live+live / harbor.json 中的 secret) // - deploy-server-ssh-key: SSH Username with private key,可登录 root@192.168.2.226 // // 服务器要求: /root/deploy.sh 已就位(见 deploy/deploy.sh),首次已手动跑通 pipeline { agent any options { timestamps() disableConcurrentBuilds() } parameters { choice( name: 'DEPLOY_MODE', choices: ['BUILD_AND_DEPLOY', 'DEPLOY_ONLY'], description: 'BUILD_AND_DEPLOY 构建新镜像并部署;DEPLOY_ONLY 部署 Harbor 中已有的镜像 tag(回滚用)' ) string( name: 'IMAGE_TAG', defaultValue: '', description: '要部署的镜像 tag。DEPLOY_ONLY 必填;BUILD_AND_DEPLOY 留空则使用当前 commit' ) } environment { APP_NAME = 'live' REGISTRY_HOST = 'harbor.fuhua91.com' REGISTRY_NAMESPACE = 'live' BACKEND_IMAGE = "${REGISTRY_HOST}/${REGISTRY_NAMESPACE}/backend" FRONTEND_IMAGE = "${REGISTRY_HOST}/${REGISTRY_NAMESPACE}/frontend" LIVEWEB_IMAGE = "${REGISTRY_HOST}/${REGISTRY_NAMESPACE}/live-web" DEPLOY_HOST = 'root@192.168.2.226' BIN_NAME = 'kratos-admin' APP_BASE = 'live' // 前端 vite base 与 nginx 服务名前缀 PNPM_VERSION = '10.15.1' DOCKER_BUILDKIT = '1' } stages { stage('Checkout') { steps { checkout scm } } stage('Prepare') { steps { script { env.GIT_COMMIT_SHORT = sh(script: 'git rev-parse --short=12 HEAD', returnStdout: true).trim() env.VERSION = sh(script: 'git describe --tags --always --dirty', returnStdout: true).trim() if (params.DEPLOY_MODE == 'DEPLOY_ONLY') { if (!params.IMAGE_TAG?.trim()) { error('IMAGE_TAG is required when DEPLOY_MODE=DEPLOY_ONLY') } env.DEPLOY_IMAGE_TAG = params.IMAGE_TAG.trim() } else { env.DEPLOY_IMAGE_TAG = params.IMAGE_TAG?.trim() ? params.IMAGE_TAG.trim() : env.GIT_COMMIT_SHORT } echo "Deploy mode: ${params.DEPLOY_MODE}" echo "Backend : ${env.BACKEND_IMAGE}:${env.DEPLOY_IMAGE_TAG}" echo "Frontend: ${env.FRONTEND_IMAGE}:${env.DEPLOY_IMAGE_TAG}" echo "LiveWeb : ${env.LIVEWEB_IMAGE}:${env.DEPLOY_IMAGE_TAG}" } } } stage('Test') { when { expression { params.DEPLOY_MODE == 'BUILD_AND_DEPLOY' } } steps { sh ''' go env -w GOPROXY=https://goproxy.cn,direct go test ./... ''' } } stage('Build Frontend') { when { expression { params.DEPLOY_MODE == 'BUILD_AND_DEPLOY' } } steps { // 容器内构建 dist(vite base 由 web/.env.production 的 VITE_APP_BASE=/admin/ 控制), // 并渲染前端 nginx 配置(/api 转发到 live-backend:8000) sh ''' docker run --rm \ -v "$PWD/web:/app" -w /app \ -e COREPACK_NPM_REGISTRY=https://registry.npmmirror.com \ -e npm_config_registry=https://registry.npmmirror.com \ -v kra-pnpm-store:/root/.local/share/pnpm/store \ docker.m.daocloud.io/node:20-slim \ bash -lc "corepack enable && corepack prepare pnpm@$PNPM_VERSION --activate && pnpm install --frozen-lockfile && pnpm build" sed "s/\\${KRA_APP}/$APP_BASE/g" web/.docker-compose/nginx/conf.d/my.conf > web/nginx.k8s.conf ''' } } stage('Build Live Web') { when { expression { params.DEPLOY_MODE == 'BUILD_AND_DEPLOY' } } steps { // PC 直播用户端与后端同仓维护,确保当前提交中的接口与页面一起发布。 // HTTP/WS 均请求同源 /api,由站点 nginx 去前缀转发到后端。 sh ''' docker run --rm \ -v "$PWD/frontend:/app" -w /app \ -e npm_config_registry=https://registry.npmmirror.com \ docker.m.daocloud.io/node:20-slim \ bash -lc "npm ci --no-audit --no-fund && npm run build" ''' } } stage('Build Images') { when { expression { params.DEPLOY_MODE == 'BUILD_AND_DEPLOY' } } steps { sh ''' CGO_ENABLED=0 go build -ldflags "-X main.Version=${VERSION}" -o bin/${BIN_NAME} ./cmd docker build \ --build-arg BIN_NAME=${BIN_NAME} \ --tag ${BACKEND_IMAGE}:${DEPLOY_IMAGE_TAG} \ --tag ${BACKEND_IMAGE}:latest \ . docker build \ --tag ${FRONTEND_IMAGE}:${DEPLOY_IMAGE_TAG} \ --tag ${FRONTEND_IMAGE}:latest \ web docker build \ --tag ${LIVEWEB_IMAGE}:${DEPLOY_IMAGE_TAG} \ --tag ${LIVEWEB_IMAGE}:latest \ frontend ''' } } stage('Push Images') { when { expression { params.DEPLOY_MODE == 'BUILD_AND_DEPLOY' } } steps { withCredentials([usernamePassword(credentialsId: 'harbor-live-push', usernameVariable: 'HARBOR_USER', passwordVariable: 'HARBOR_PASS')]) { sh ''' echo "${HARBOR_PASS}" | docker login "${REGISTRY_HOST}" -u "${HARBOR_USER}" --password-stdin docker push ${BACKEND_IMAGE}:${DEPLOY_IMAGE_TAG} docker push ${BACKEND_IMAGE}:latest docker push ${FRONTEND_IMAGE}:${DEPLOY_IMAGE_TAG} docker push ${FRONTEND_IMAGE}:latest docker push ${LIVEWEB_IMAGE}:${DEPLOY_IMAGE_TAG} docker push ${LIVEWEB_IMAGE}:latest docker logout "${REGISTRY_HOST}" ''' } } } stage('Deploy') { steps { sshagent(credentials: ['deploy-server-ssh-key']) { sh ''' ssh -o StrictHostKeyChecking=no ${DEPLOY_HOST} "bash /root/deploy.sh ${DEPLOY_IMAGE_TAG}" ''' } } } } post { success { echo "Deployed ${BACKEND_IMAGE}:${DEPLOY_IMAGE_TAG} / ${FRONTEND_IMAGE}:${DEPLOY_IMAGE_TAG} / ${LIVEWEB_IMAGE}:${DEPLOY_IMAGE_TAG}" } } }