Files
offerpai_web/Jenkinsfile
T
2026-05-22 14:29:38 +08:00

209 lines
8.0 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.
/**
* OfferPie Web 前端蓝绿部署流水线
*
* 工作目录说明:
* - Jenkins 会自动为每个项目创建独立的工作空间:/var/jenkins_home/workspace/<项目名>/
* - docker-compose.yml、Dockerfile、nginx.conf 都在项目根目录,直接执行即可
* - nginx.conf 首次部署时 docker cp 进 nginx 容器
*
* 内层 Nginx 职责:
* - 蓝绿切换(前端静态文件 serve)
* - /api/ 代理到 Java 后端(10202
* - /ai-api/ 代理到 Python AI10502),rewrite 去掉前缀
*/
pipeline {
agent any
parameters {
choice(name: 'BRANCH', choices: ['master', 'pre', 'dev', 'test'], description: '选择要部署的分支')
}
environment {
CONTAINER_PREFIX = 'offerpie-web' // 容器名前缀,拼接 -blue / -green / -nginx
HEALTH_URL = 'http://localhost/' // 前端静态页面健康检查
}
stages {
stage('开始提示') {
steps {
echo "OfferPie Web 前端开始构建"
}
}
stage('拉取代码') {
steps {
echo "拉取 ${params.BRANCH} 分支代码"
git branch: "${params.BRANCH}",
credentialsId: 'ef5fffc1-9b35-403d-9ca6-e1b73eb0e45a',
url: 'https://codeup.aliyun.com/5f0ed3b9769820a3e817dee2/offerpie/offerpie_web.git'
}
}
/**
* 检测部署目标
* - 检查 blue 和 green 容器的运行状态
* - blue 在运行 → 部署 greengreen 在运行 → 部署 blue
* - 都不在或都在 → 默认部署 blue
*/
stage('检测部署目标') {
steps {
echo "检查当前容器状态"
script {
def blueRunning = sh(script: "docker ps -q -f name=${CONTAINER_PREFIX}-blue", returnStdout: true).trim()
def greenRunning = sh(script: "docker ps -q -f name=${CONTAINER_PREFIX}-green", returnStdout: true).trim()
env.DEPLOY_TARGET = ''
if (blueRunning && !greenRunning) {
env.DEPLOY_TARGET = 'green'
}
if (greenRunning && !blueRunning) {
env.DEPLOY_TARGET = 'blue'
}
if (!env.DEPLOY_TARGET) {
echo "当前环境未部署服务或状态异常,默认部署 blue"
env.DEPLOY_TARGET = 'blue'
}
env.OTHER_TARGET = (env.DEPLOY_TARGET == 'blue') ? 'green' : 'blue'
echo "当前激活: ${env.OTHER_TARGET},即将部署: ${env.DEPLOY_TARGET}"
}
}
}
/**
* 构建新版本
* - 先清理目标颜色的旧容器(如果残留)
* - docker-compose build 构建新镜像(含 pnpm build
*/
stage('构建新版本') {
steps {
script {
def existingContainer = sh(script: "docker ps -aq -f name=${CONTAINER_PREFIX}-${env.DEPLOY_TARGET}", returnStdout: true).trim()
if (existingContainer) {
echo "清理已存在的容器: ${CONTAINER_PREFIX}-${env.DEPLOY_TARGET}"
sh "docker rm -f ${CONTAINER_PREFIX}-${env.DEPLOY_TARGET}"
}
sh "docker-compose build ${env.DEPLOY_TARGET}"
}
}
}
/**
* 检查 Nginx
* - 检查 nginx 容器是否存在
* - 不存在则启动并复制配置文件(首次部署)
* - 存在则确保容器运行中
*/
stage('检查Nginx') {
steps {
script {
def nginxExists = sh(script: "docker ps -aq -f name=${CONTAINER_PREFIX}-nginx", returnStdout: true).trim()
if (!nginxExists) {
echo "首次部署,初始化 Nginx 容器"
sh "docker-compose up -d nginx"
sh "sleep 3"
// 复制配置文件到容器内
sh "docker cp proxy_nginx.conf ${CONTAINER_PREFIX}-nginx:/etc/nginx/nginx.conf"
sh "docker exec ${CONTAINER_PREFIX}-nginx nginx -s reload"
} else {
def nginxRunning = sh(script: "docker ps -q -f name=${CONTAINER_PREFIX}-nginx", returnStdout: true).trim()
if (!nginxRunning) {
echo "Nginx 容器已停止,重新启动"
sh "docker start ${CONTAINER_PREFIX}-nginx"
sh "sleep 2"
}
echo "Nginx 容器已存在且运行中"
}
}
}
}
stage('启动新版本') {
steps {
script {
sh "docker-compose up -d ${env.DEPLOY_TARGET}"
// 等待 Nginx 容器启动
sh 'sleep 5'
}
}
}
/**
* 健康检查
* - 进入容器检测静态页面是否正常返回
* - 最多重试 3 次,每次间隔 5 秒
* - 全部失败则终止部署流程
*/
stage('健康检查') {
steps {
script {
def maxRetries = 3
def retryCount = 0
def healthy = false
while (retryCount < maxRetries && !healthy) {
try {
sh "docker exec ${CONTAINER_PREFIX}-${env.DEPLOY_TARGET} wget --spider -q ${HEALTH_URL}"
healthy = true
} catch (Exception e) {
retryCount++
if (retryCount < maxRetries) {
echo "健康检查失败,5秒后重试 (${retryCount}/${maxRetries})"
sleep 5
}
}
}
if (!healthy) {
error "健康检查失败,部署中止"
}
echo "✅ ${CONTAINER_PREFIX}-${env.DEPLOY_TARGET} 健康检查通过"
}
}
}
/**
* 切换流量
* - 修改 nginx 配置中的 proxy_pass 指向新版本
* - nginx 不挂载宿主机文件,直接 sed -i 修改容器内配置
* - reload 使新配置生效,实现零停机切换
*/
stage('切换流量') {
steps {
script {
sh "docker exec ${CONTAINER_PREFIX}-nginx sed -i 's/proxy_pass http:\\/\\/\\(blue\\|green\\);/proxy_pass http:\\/\\/${env.DEPLOY_TARGET};/' /etc/nginx/nginx.conf"
sh "docker exec ${CONTAINER_PREFIX}-nginx nginx -s reload"
echo "✅ 流量已切换到 ${env.DEPLOY_TARGET}"
}
}
}
/**
* 停止并删除旧版本
* - 不能用 docker-compose down,会删除所有服务(包括 nginx)
* - 用 docker rm -f 只删除指定的旧颜色容器
*/
stage('删除旧版本') {
steps {
script {
def otherExists = sh(script: "docker ps -aq -f name=${CONTAINER_PREFIX}-${env.OTHER_TARGET}", returnStdout: true).trim()
if (otherExists) {
sh "docker rm -f ${CONTAINER_PREFIX}-${env.OTHER_TARGET}"
echo "旧版本 ${env.OTHER_TARGET} 已删除"
}
}
}
}
}
post {
success {
echo "✅ 蓝绿部署成功!当前运行: ${env.DEPLOY_TARGET}"
}
failure {
echo '❌ 部署失败,请检查日志'
}
}
}