Files
2025-10-07 15:58:15 +08:00

625 lines
26 KiB
Plaintext
Raw Permalink 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 {
REMOTE_HOST = "43.130.56.138"
NGINX_HOST = "49.51.46.148"
REMOTE_PROJECT_PATH = "/data/webapps/lessie_sourcing_agents"
VENV_DIR = "/data/webapps/lessie_sourcing_agents/venv"
REMOTE_PROJECT_PATH_02 = "/data/webapps/lessie_sourcing_agents_02"
VENV_DIR_02 = "/data/webapps/lessie_sourcing_agents_02/venv"
CONDA_PATH = "/root/miniconda3/bin/conda"
PORT_A = "8000"
PORT_B = "8002"
CONNECTION_TIMEOUT = "500" // 等待连接关闭的超时时间(秒)
NGINX_RELOAD_SCRIPT = "/data/sh/set_s1_backend_weight.sh" // 设置nginx后端组up/down
WAIT_CONNECTIONS_SCRIPT = "/data/sh/wait_s1_for_connections.sh" // 等待连接数变为0
CHECK_STATUS_SCRIPT = "/data/sh/check_s1_backend_status.sh" // 检查后端组状态
}
stages {
stage('Checkout 代码') {
steps {
git branch: "${params.Code_branch}", credentialsId: 'fly_gitlab_auth', url: 'http://172.24.16.20/python/lessie-sourcing-agents.git'
}
}
stage('A脱离后端组') {
steps {
echo "将实例A的权重设置为down停止接收新连接"
sh "ssh ${NGINX_HOST} '${NGINX_RELOAD_SCRIPT} ${PORT_A} down'"
echo "等待实例A的现有连接关闭"
sh "ssh ${REMOTE_HOST} '${WAIT_CONNECTIONS_SCRIPT} ${PORT_A} ${CONNECTION_TIMEOUT}'"
}
}
stage('A下线&同步') {
steps {
echo("下线A后同步A")
sh "ssh ${REMOTE_HOST} 'sh /data/sh/kill_lessie_sourcing_agents.sh'"
sh """
ssh ${REMOTE_HOST} 'mkdir -p ${REMOTE_PROJECT_PATH}'
rsync -avz --exclude 'venv' ${WORKSPACE}/ ${REMOTE_HOST}:${REMOTE_PROJECT_PATH}/
"""
}
}
stage('A依赖&启动') {
steps {
echo("A依赖&启动")
sh """
ssh ${REMOTE_HOST} '
cd ${REMOTE_PROJECT_PATH}
source ~/.bashrc
conda activate search
source ${VENV_DIR}/bin/activate
pip install --upgrade pip
pip install -r requirements.txt
TIMESTAMP=\$(date +"%Y%m%d_%H%M%S")
LOGFILE="${REMOTE_PROJECT_PATH}/logs/lessie_sourcing_agents_\${TIMESTAMP}.log"
nohup env APP_ENV=sit python ${REMOTE_PROJECT_PATH}/server.py > ${REMOTE_PROJECT_PATH}/logs/lessie_sourcing_agents_\${TIMESTAMP}.log 2>&1 &
ln -sf "\$LOGFILE" ${REMOTE_PROJECT_PATH}/logs/lessie_sourcing_agents_latest.log
'
"""
}
}
stage('恢复A流量') {
steps {
echo "恢复实例A的流量"
sh "sleep 5"
sh "ssh ${NGINX_HOST} '${NGINX_RELOAD_SCRIPT} ${PORT_A} up'"
echo "实例 A 部署完成"
}
}
stage('探测A服务 ') {
steps {
echo("探测A服务")
sh "ssh ${REMOTE_HOST} 'sh /data/sh/check_lessie_agents_8000.sh' "
}
}
stage('截B流量') {
steps {
echo "将实例B的权重设置为down停止接收新连接"
sh "ssh ${NGINX_HOST} '${NGINX_RELOAD_SCRIPT} ${PORT_B} down'"
echo "等待实例B的现有连接关闭"
sh "ssh ${REMOTE_HOST} '${WAIT_CONNECTIONS_SCRIPT} ${PORT_B} ${CONNECTION_TIMEOUT}'"
}
}
stage('B下线&同步') {
steps {
echo("B下线&同步")
sh "ssh ${REMOTE_HOST} 'sh /data/sh/kill_lessie_sourcing_agents_8002.sh'"
sh """
ssh ${REMOTE_HOST} 'mkdir -p ${REMOTE_PROJECT_PATH_02}'
rsync -avz --exclude 'venv' ${WORKSPACE}/ ${REMOTE_HOST}:${REMOTE_PROJECT_PATH_02}/
"""
}
}
stage('B依赖&启动') {
steps {
echo("B依赖&启动")
sh """
ssh ${REMOTE_HOST} '
cd ${REMOTE_PROJECT_PATH_02} &&
source ~/.bashrc &&
conda activate search &&
source ${VENV_DIR_02}/bin/activate &&
pip install --upgrade pip &&
pip install -r requirements.txt
TIMESTAMP_02=\$(date +"%Y%m%d_%H%M%S")
LOGFILE="${REMOTE_PROJECT_PATH_02}/logs/lessie_sourcing_agents_\${TIMESTAMP_02}.log"
nohup env APP_ENV=sit python ${REMOTE_PROJECT_PATH_02}/server8002.py --port 8002 > ${REMOTE_PROJECT_PATH_02}/logs/lessie_sourcing_agents_\${TIMESTAMP_02}.log 2>&1 &
ln -sf "\$LOGFILE" ${REMOTE_PROJECT_PATH_02}/logs/lessie_sourcing_agents_latest.log
'
"""
}
}
stage('恢复B流量') {
steps {
echo "恢复实例B的流量"
sh "sleep 5"
sh "ssh ${NGINX_HOST} '${NGINX_RELOAD_SCRIPT} ${PORT_B} up'"
echo "实例 B 部署完成"
}
}
stage('探测B服务 ') {
steps {
echo("探测B服务")
sh "ssh ${REMOTE_HOST} 'sh /data/sh/check_lessie_agents_8002.sh' "
}
}
}
post {
success {
echo '✅ 部署成功!'
}
failure {
echo '❌ 部署失败,请检查日志!'
}
}
}
# ==========================原本=======
pipeline {
agent any
environment {
REMOTE_HOST = "43.130.56.138"
NGINX_HOST = "49.51.46.148"
REMOTE_PROJECT_PATH = "/data/webapps/lessie_sourcing_agents"
VENV_DIR = "/data/webapps/lessie_sourcing_agents/venv"
REMOTE_PROJECT_PATH_02 = "/data/webapps/lessie_sourcing_agents_02"
VENV_DIR_02 = "/data/webapps/lessie_sourcing_agents_02/venv"
CONDA_PATH = "/root/miniconda3/bin/conda"
PORT_A = "8000"
PORT_B = "8002"
CONNECTION_TIMEOUT = "500" // 等待连接关闭的超时时间(秒)
NGINX_RELOAD_SCRIPT = "/data/sh/set_s1_backend_weight.sh" // 设置nginx后端组up/down
WAIT_CONNECTIONS_SCRIPT = "/data/sh/wait_s1_for_connections.sh" // 等待连接数变为0
CHECK_STATUS_SCRIPT = "/data/sh/check_s1_backend_status.sh" // 检查后端组状态
}
stages {
stage('Checkout 代码') {
steps {
git branch: "${params.Code_branch}", credentialsId: 'fly_gitlab_auth', url: 'http://172.24.16.20/python/lessie-sourcing-agents.git'
}
}
stage('部署实例A') {
steps {
script {
// 部署前检查确保B节点处于up状态避免单节点部署时服务不可用
checkOtherNodeStatus(env.PORT_B, "A")
// 执行部署若失败则进入post的failure块回滚
deployInstance("A", env.PORT_A, env.REMOTE_PROJECT_PATH, env.VENV_DIR)
}
}
post {
failure {
echo "实例A部署失败开始回滚..."
rollbackInstance("A", env.PORT_A) // 回滚A节点状态
}
}
}
stage('部署实例B') {
steps {
script {
// 部署前检查确保A节点处于up状态
checkOtherNodeStatus(env.PORT_A, "B")
// 执行部署若失败则进入post的failure块回滚
deployInstance("B", env.PORT_B, env.REMOTE_PROJECT_PATH_02, env.VENV_DIR_02)
}
}
post {
failure {
echo "实例B部署失败开始回滚..."
rollbackInstance("B", env.PORT_B) // 回滚B节点状态
}
}
}
}
post {
success {
echo '✅ 部署成功!'
}
failure {
echo '❌ 部署失败,请检查日志!'
}
}
}
// 部署前检查确保其他节点处于up状态避免服务中断
def checkOtherNodeStatus(otherPort, currentInstance) {
echo "部署${currentInstance}前,检查另一节点(端口${otherPort})是否可用..."
def status = sh(
script: "ssh ${env.NGINX_HOST} '${env.CHECK_STATUS_SCRIPT} ${otherPort}'",
returnStdout: true
).trim()
if (status != "up") {
error "另一节点(端口${otherPort})当前状态为${status},无法部署${currentInstance}(避免服务不可用)"
}
echo "另一节点(端口${otherPort}状态正常up可部署${currentInstance}"
}
// 定义部署单个实例的函数
def deployInstance(instanceName, port, projectPath, venvDir) {
echo "开始部署实例 $instanceName (端口 $port)"
// 步骤1: 将实例权重设置为down停止接收新连接
echo "将实例 $instanceName 的权重设置为down停止接收新连接"
sh "ssh ${NGINX_HOST} '${NGINX_RELOAD_SCRIPT} ${port} down'"
// 步骤2: 等待现有连接关闭
echo "等待实例 $instanceName 的现有连接关闭"
sh "ssh ${REMOTE_HOST} '${WAIT_CONNECTIONS_SCRIPT} ${port} ${CONNECTION_TIMEOUT}'"
// 步骤3: 停止实例
echo "停止实例 $instanceName"
if (instanceName == "A") {
sh "ssh ${REMOTE_HOST} 'sh /data/sh/kill_lessie_sourcing_agents.sh'"
} else {
sh "ssh ${REMOTE_HOST} 'sh /data/sh/kill_lessie_sourcing_agents_8002.sh'"
}
// 步骤4: 同步代码
echo "同步实例 $instanceName 的代码"
sh """
ssh ${REMOTE_HOST} 'mkdir -p ${projectPath}'
rsync -avz --exclude 'venv' ${WORKSPACE}/ ${REMOTE_HOST}:${projectPath}/
"""
// 步骤5: 安装依赖
echo "安装实例 $instanceName 的依赖"
sh """
ssh ${REMOTE_HOST} '
cd ${projectPath} &&
source ~/.bashrc &&
conda activate search &&
source ${venvDir}/bin/activate &&
pip install --upgrade pip &&
pip install -r requirements.txt
'
"""
// 步骤6: 启动实例
echo "启动实例 $instanceName"
if (instanceName == "A") {
sh """
ssh ${REMOTE_HOST} '
conda activate search
source ${venvDir}/bin/activate
TIMESTAMP=\$(date +"%Y%m%d_%H%M%S")
LOGFILE="${projectPath}/logs/lessie_sourcing_agents_\${TIMESTAMP}.log"
nohup env APP_ENV=sit python ${projectPath}/server.py > ${projectPath}/logs/lessie_sourcing_agents_\${TIMESTAMP}.log 2>&1 &
ln -sf "\$LOGFILE" ${projectPath}/logs/lessie_sourcing_agents_latest.log
'
"""
} else {
sh """
ssh ${REMOTE_HOST} '
conda activate search
source ${venvDir}/bin/activate
TIMESTAMP=\$(date +"%Y%m%d_%H%M%S")
LOGFILE="${projectPath}/logs/lessie_sourcing_agents_\${TIMESTAMP}.log"
nohup env APP_ENV=sit python ${projectPath}/server.py --port ${port} > ${projectPath}/logs/lessie_sourcing_agents_\${TIMESTAMP}.log 2>&1 &
ln -sf "\$LOGFILE" ${projectPath}/logs/lessie_sourcing_agents_latest.log
'
"""
}
// 步骤7: 等待服务启动并检查健康状态
echo "检查实例 $instanceName 的健康状态"
sh "sleep 5" // 等待服务启动
sh "ssh ${REMOTE_HOST} 'sh /data/sh/check_lessie_agents_${port}.sh'"
// 步骤8: 恢复流量
echo "恢复实例 $instanceName 的流量"
sh "sleep 5"
sh "ssh ${NGINX_HOST} '${NGINX_RELOAD_SCRIPT} ${port} up'"
echo "实例 $instanceName 部署完成"
}
// 回滚函数若部署失败将节点恢复为up确保服务可用
def rollbackInstance(instanceName, port) {
echo "回滚实例${instanceName}(端口${port})状态..."
// 无论原状态如何失败后强制恢复为up避免节点长期down
sh "ssh ${env.NGINX_HOST} '${env.NGINX_RELOAD_SCRIPT} ${port} up'"
// 检查回滚后状态
def status = sh(
script: "ssh ${env.NGINX_HOST} '${env.CHECK_STATUS_SCRIPT} ${port}'",
returnStdout: true
).trim()
if (status == "up") {
echo "实例${instanceName}回滚成功当前状态为up"
} else {
error "实例${instanceName}回滚失败请手动检查nginx状态"
}
}
# --------------------------------------------------------------------------------------------------------------------------------------------
# --------------------------------------------------------------------------------------------------------------------------------------------
# --------------------------------------------------------------------------------------------------------------------------------------------
# --------------------------------------------------------------------------------------------------------------------------------------------
# --------------------------------------------------------------------------------------------------------------------------------------------
# --------------------------------------------------------------------------------------------------------------------------------------------
# --------------------------------------------------------------------------------------------------------------------------------------------
pipeline {
agent any
environment {
REMOTE_HOST = "3.130.56.138"
NGINX_HOST = "9.51.46.148"
REMOTE_PROJECT_PATH = "/data/webapps/lessie_sourcing_agents"
VENV_DIR = "/data/webapps/lessie_sourcing_agents/venv"
REMOTE_PROJECT_PATH_02 = "/data/webapps/lessie_sourcing_agents_02"
VENV_DIR_02 = "/data/webapps/lessie_sourcing_agents_02/venv"
CONDA_PATH = "/root/miniconda3/bin/conda"
PORT_A = "8000"
PORT_B = "8002"
CONNECTION_TIMEOUT = "500" // 等待连接关闭的超时时间(秒)
NGINX_RELOAD_SCRIPT = "/data/sh/set_s1_backend_weight.sh" // 设置nginx后端组up/down
WAIT_CONNECTIONS_SCRIPT = "/data/sh/wait_s1_for_connections.sh" // 等待连接数变为0
CHECK_STATUS_SCRIPT = "/data/sh/check_s1_backend_status.sh" // 检查后端组状态
}
stages {
stage('Checkout 代码') {
steps {
echo "🔍 开始拉取代码,分支:${params.Code_branch}"
git branch: "${params.Code_branch}", credentialsId: 'fly_gitlab_auth', url: 'http://172.24.16.20/python/lessie-sourcing-agents.git'
echo "✅ 代码拉取完成"
}
}
stage('部署实例A') {
stages {
stage('A-前置检查:另一节点状态') {
steps {
script {
checkOtherNodeStatus(env.PORT_B, "A")
}
}
}
stage('A-1. 设置实例A为down') {
steps {
echo "📌 开始将实例A端口${PORT_A}设为down停止接收新连接"
sh label: "执行nginx down命令", script: "ssh ${NGINX_HOST} '${NGINX_RELOAD_SCRIPT} ${PORT_A} down'"
echo "✅ 实例A已设为down"
}
}
stage('A-2. 等待实例A连接关闭') {
steps {
echo "📌 等待实例A端口${PORT_A})现有连接关闭,超时${CONNECTION_TIMEOUT}秒"
sh label: "执行等待连接脚本", script: "ssh ${REMOTE_HOST} '${WAIT_CONNECTIONS_SCRIPT} ${PORT_A} ${CONNECTION_TIMEOUT}'"
echo "✅ 实例A连接已关闭"
}
}
stage('A-3. 停止实例A进程') {
steps {
echo "📌 停止实例A端口${PORT_A})进程"
sh label: "执行停止脚本", script: "ssh ${REMOTE_HOST} 'sh /data/sh/kill_lessie_sourcing_agents.sh'"
echo "✅ 实例A进程已停止"
}
}
stage('A-4. 同步实例A代码') {
steps {
echo "📌 同步代码到实例A目录${REMOTE_PROJECT_PATH}"
sh label: "执行rsync同步", script: """
ssh ${REMOTE_HOST} 'mkdir -p ${REMOTE_PROJECT_PATH}'
rsync -avz --exclude 'venv' ${WORKSPACE}/ ${REMOTE_HOST}:${REMOTE_PROJECT_PATH}/
"""
echo "✅ 实例A代码同步完成"
}
}
stage('A-5. 安装实例A依赖') {
steps {
echo "📌 安装实例A依赖目录${REMOTE_PROJECT_PATH}"
sh label: "执行pip安装", script: """
ssh ${REMOTE_HOST} '
cd ${REMOTE_PROJECT_PATH} &&
source ~/.bashrc &&
conda activate search &&
source ${VENV_DIR}/bin/activate &&
pip install --upgrade pip &&
pip install -r requirements.txt
'
"""
echo "✅ 实例A依赖安装完成"
}
}
stage('A-6. 启动实例A') {
steps {
echo "📌 启动实例A端口${PORT_A}"
sh label: "执行启动命令", script: """
ssh ${REMOTE_HOST} '
conda activate search
source ${VENV_DIR}/bin/activate
TIMESTAMP=\$(date +"%Y%m%d_%H%M%S")
LOGFILE="${REMOTE_PROJECT_PATH}/logs/lessie_sourcing_agents_\${TIMESTAMP}.log"
nohup env APP_ENV=sit python ${REMOTE_PROJECT_PATH}/server.py > \$LOGFILE 2>&1 &
ln -sf "\$LOGFILE" ${REMOTE_PROJECT_PATH}/logs/lessie_sourcing_agents_latest.log
'
"""
echo "✅ 实例A启动命令已执行"
}
}
stage('A-7. 检查实例A健康状态') {
steps {
echo "📌 等待实例A端口${PORT_A})启动并检查健康状态"
sh label: "等待服务就绪", script: "sleep 5"
sh label: "执行健康检查脚本", script: "ssh ${REMOTE_HOST} 'sh /data/sh/check_lessie_agents_${PORT_A}.sh'"
echo "✅ 实例A健康检查通过"
}
}
stage('A-8. 恢复实例A流量') {
steps {
echo "📌 恢复实例A端口${PORT_A}流量设为up"
sh label: "执行nginx up命令", script: "ssh ${NGINX_HOST} '${NGINX_RELOAD_SCRIPT} ${PORT_A} up'"
echo "✅ 实例A流量已恢复"
}
}
}
post {
failure {
echo "❌ 实例A部署失败开始回滚..."
rollbackInstance("A", env.PORT_A)
}
}
}
stage('部署实例B') {
stages {
stage('B-前置检查:另一节点状态') {
steps {
script {
checkOtherNodeStatus(env.PORT_A, "B")
}
}
}
stage('B-1. 设置实例B为down') {
steps {
echo "📌 开始将实例B端口${PORT_B}设为down停止接收新连接"
sh label: "执行nginx down命令", script: "ssh ${NGINX_HOST} '${NGINX_RELOAD_SCRIPT} ${PORT_B} down'"
echo "✅ 实例B已设为down"
}
}
stage('B-2. 等待实例B连接关闭') {
steps {
echo "📌 等待实例B端口${PORT_B})现有连接关闭,超时${CONNECTION_TIMEOUT}秒"
sh label: "执行等待连接脚本", script: "ssh ${REMOTE_HOST} '${WAIT_CONNECTIONS_SCRIPT} ${PORT_B} ${CONNECTION_TIMEOUT}'"
echo "✅ 实例B连接已关闭"
}
}
stage('B-3. 停止实例B进程') {
steps {
echo "📌 停止实例B端口${PORT_B})进程"
sh label: "执行停止脚本", script: "ssh ${REMOTE_HOST} 'sh /data/sh/kill_lessie_sourcing_agents_8002.sh'"
echo "✅ 实例B进程已停止"
}
}
stage('B-4. 同步实例B代码') {
steps {
echo "📌 同步代码到实例B目录${REMOTE_PROJECT_PATH_02}"
sh label: "执行rsync同步", script: """
ssh ${REMOTE_HOST} 'mkdir -p ${REMOTE_PROJECT_PATH_02}'
rsync -avz --exclude 'venv' ${WORKSPACE}/ ${REMOTE_HOST}:${REMOTE_PROJECT_PATH_02}/
"""
echo "✅ 实例B代码同步完成"
}
}
stage('B-5. 安装实例B依赖') {
steps {
echo "📌 安装实例B依赖目录${REMOTE_PROJECT_PATH_02}"
sh label: "执行pip安装", script: """
ssh ${REMOTE_HOST} '
cd ${REMOTE_PROJECT_PATH_02} &&
source ~/.bashrc &&
conda activate search &&
source ${VENV_DIR_02}/bin/activate &&
pip install --upgrade pip &&
pip install -r requirements.txt
'
"""
echo "✅ 实例B依赖安装完成"
}
}
stage('B-6. 启动实例B') {
steps {
echo "📌 启动实例B端口${PORT_B}"
sh label: "执行启动命令", script: """
ssh ${REMOTE_HOST} '
conda activate search
source ${VENV_DIR_02}/bin/activate
TIMESTAMP=\$(date +"%Y%m%d_%H%M%S")
LOGFILE="${REMOTE_PROJECT_PATH_02}/logs/lessie_sourcing_agents_\${TIMESTAMP}.log"
nohup env APP_ENV=sit python ${REMOTE_PROJECT_PATH_02}/server.py --port ${PORT_B} > \$LOGFILE 2>&1 &
ln -sf "\$LOGFILE" ${REMOTE_PROJECT_PATH_02}/logs/lessie_sourcing_agents_latest.log
'
"""
echo "✅ 实例B启动命令已执行"
}
}
stage('B-7. 检查实例B健康状态') {
steps {
echo "📌 等待实例B端口${PORT_B})启动并检查健康状态"
sh label: "等待服务就绪", script: "sleep 5"
sh label: "执行健康检查脚本", script: "ssh ${REMOTE_HOST} 'sh /data/sh/check_lessie_agents_${PORT_B}.sh'"
echo "✅ 实例B健康检查通过"
}
}
stage('B-8. 恢复实例B流量') {
steps {
echo "📌 恢复实例B端口${PORT_B}流量设为up"
sh label: "执行nginx up命令", script: "ssh ${NGINX_HOST} '${NGINX_RELOAD_SCRIPT} ${PORT_B} up'"
echo "✅ 实例B流量已恢复"
}
}
}
post {
failure {
echo "❌ 实例B部署失败开始回滚..."
rollbackInstance("B", env.PORT_B)
}
}
}
}
post {
success {
echo '🎉 所有实例部署成功!'
}
failure {
echo '❌ 部署失败,请查看上面的步骤日志定位问题!'
}
}
}
// 部署前检查确保其他节点处于up状态避免服务中断
def checkOtherNodeStatus(otherPort, currentInstance) {
echo "🔍 部署${currentInstance}前,检查另一节点(端口${otherPort})是否可用..."
def status = sh(
label: "检查节点${otherPort}状态",
script: "ssh ${env.NGINX_HOST} '${env.CHECK_STATUS_SCRIPT} ${otherPort}'",
returnStdout: true
).trim()
if (status != "up") {
error "❌ 另一节点(端口${otherPort})当前状态为${status},无法部署${currentInstance}(避免服务不可用)"
}
echo "✅ 另一节点(端口${otherPort}状态正常up可部署${currentInstance}"
}
// 回滚函数若部署失败将节点恢复为up确保服务可用
def rollbackInstance(instanceName, port) {
echo "🔄 回滚实例${instanceName}(端口${port})状态..."
sh label: "执行回滚up命令", script: "ssh ${env.NGINX_HOST} '${env.NGINX_RELOAD_SCRIPT} ${port} up'"
// 检查回滚后状态
def status = sh(
label: "检查回滚后状态",
script: "ssh ${env.NGINX_HOST} '${env.CHECK_STATUS_SCRIPT} ${port}'",
returnStdout: true
).trim()
if (status == "up") {
echo "✅ 实例${instanceName}回滚成功当前状态为up"
} else {
error "❌ 实例${instanceName}回滚失败请手动检查nginx状态"
}
}