初始化提交

This commit is contained in:
2025-10-07 15:58:15 +08:00
commit 0e593caf99
378 changed files with 77890 additions and 0 deletions

View File

@@ -0,0 +1 @@
timeout 60 bash -c 'until nc -z localhost 8000; do echo "Port is not available. Sleeping..."; sleep 5; done;'

View File

@@ -0,0 +1 @@
timeout 60 bash -c 'until nc -z localhost 8002; do echo "Port is not available. Sleeping..."; sleep 5; done;'

View File

@@ -0,0 +1,13 @@
#!/bin/bash
# 检查指定端口的节点状态up/down
PORT=$1
NGINX_CONFIG="/data/tengine/conf/vhosts/s1.jennie.im.conf"
if [ -z "$PORT" ]; then
echo "用法: $0 <port>"
exit 1
fi
# 检查配置中是否包含"down"关键字
STATUS=$(grep "server 10.0.0.5:$PORT" $NGINX_CONFIG | grep -q "down" && echo "down" || echo "up")
echo $STATUS # 输出结果down 或 up

View File

@@ -0,0 +1,33 @@
#!/bin/bash
# 项目目录及关键路径
PROJECT_DIR="/data/webapps/prod_lessie_sourcing_agents"
VENV_DIR="$PROJECT_DIR/venv"
PYTHON_SCRIPT="$PROJECT_DIR/server7001.py"
LOG_DIR="/data/sh/logs"
# 日志记录
WATCH_LOG="$LOG_DIR/watcher.log"
# 检查进程是否存活
if ! pgrep -f "python .*server7001.py" > /dev/null; then
echo "$(date '+%Y-%m-%d %H:%M:%S') server7001.py not running. Restarting..." >> "$WATCH_LOG"
# 初始化环境
conda activate search
source "$VENV_DIR/bin/activate"
# 启动服务
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
nohup env APP_ENV=prod python "$PYTHON_SCRIPT" --port 7001 > "$PROJECT_DIR/logs/lessie_sourcing_agents_${TIMESTAMP}.log" 2>&1 &
else
echo "$(date '+%Y-%m-%d %H:%M:%S') server7001.py is running." >> "$WATCH_LOG"
fi
crontab -e
*/5 * * * * bash /data/sh/check_start_server7001.sh

View File

@@ -0,0 +1,625 @@
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状态"
}
}

View File

@@ -0,0 +1,155 @@
pipeline {
agent any
environment {
REMOTE_HOST_A = "43.130.56.138"
REMOTE_HOST_B = "43.130.53.202"
NGINX_HOST = "49.51.46.148"
REMOTE_PROJECT_PATH_A = "/data/webapps/lessie_sourcing_agents"
VENV_DIR_A = "/data/webapps/lessie_sourcing_agents/venv"
REMOTE_PROJECT_PATH_B = "/data/webapps/lessie_sourcing_agents"
VENV_DIR_B = "/data/webapps/lessie_sourcing_agents/venv"
CONDA_PATH = "/root/miniconda3/bin/conda"
NGINX_PY_backend_A = "10.0.0.5"
NGINX_PY_backend_B = "10.0.0.13"
PORT_A = "8000"
PORT_B = "8002"
CONNECTION_TIMEOUT = "600" // 等待连接关闭的超时时间(秒)
NGINX_RELOAD_SCRIPT = "/data/sh/set_s1_backend_weight_new.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} 'sh ${NGINX_RELOAD_SCRIPT} ${NGINX_PY_backend_A} ${PORT_A} down'"
echo "等待实例A的现有连接关闭"
sh "ssh ${REMOTE_HOST_A} 'sh ${WAIT_CONNECTIONS_SCRIPT} ${PORT_A} ${CONNECTION_TIMEOUT}'"
}
}
stage('A下线&同步') {
steps {
echo("下线A后同步A")
sh "ssh ${REMOTE_HOST_A} 'sh /data/sh/kill_lessie_sourcing_agents.sh'"
sh """
ssh ${REMOTE_HOST_A} 'mkdir -p ${REMOTE_PROJECT_PATH_A}'
rsync -avz --exclude 'venv' --exclude '.git' ${WORKSPACE}/ ${REMOTE_HOST_A}:${REMOTE_PROJECT_PATH_A}/
"""
}
}
stage('A依赖&启动') {
steps {
echo("A依赖&启动")
sh """
ssh ${REMOTE_HOST_A} '
cd ${REMOTE_PROJECT_PATH_A}
source ~/.bashrc
conda activate search
source ${VENV_DIR_A}/bin/activate
pip install --upgrade pip
pip install -r requirements.txt
TIMESTAMP=\$(date +"%Y%m%d_%H%M%S")
LOGFILE="${REMOTE_PROJECT_PATH_A}/logs/lessie_sourcing_agents_\${TIMESTAMP}.log"
nohup env APP_ENV=s1 python ${REMOTE_PROJECT_PATH_A}/server.py --port 8000 > ${REMOTE_PROJECT_PATH_A}/logs/lessie_sourcing_agents_\${TIMESTAMP}.log 2>&1 &
ln -sf "\$LOGFILE" ${REMOTE_PROJECT_PATH_A}/logs/lessie_sourcing_agents_latest.log
'
"""
}
}
stage('探测A服务 ') {
steps {
echo("探测A服务")
sh "sleep 5"
sh """
ssh ${REMOTE_HOST_A} "head -n 300 ${REMOTE_PROJECT_PATH_A}/logs/lessie_sourcing_agents_latest.log | grep -i 'error' || true"
ssh ${REMOTE_HOST_A} "sh /data/sh/check_lessie_agents_8000.sh"
"""
}
}
stage('恢复A流量') {
steps {
echo "恢复实例A的流量"
sh "sleep 5"
sh "ssh ${NGINX_HOST} 'sh ${NGINX_RELOAD_SCRIPT} ${NGINX_PY_backend_A} ${PORT_A} up'"
echo "实例 A 部署完成"
}
}
stage('截B流量') {
steps {
echo "将实例B的权重设置为down停止接收新连接"
sh "ssh ${NGINX_HOST} 'sh ${NGINX_RELOAD_SCRIPT} ${NGINX_PY_backend_B} ${PORT_B} down'"
echo "等待实例B的现有连接关闭"
sh "ssh ${REMOTE_HOST_B} 'sh ${WAIT_CONNECTIONS_SCRIPT} ${PORT_B} ${CONNECTION_TIMEOUT}'"
}
}
stage('B下线&同步') {
steps {
echo("B下线&同步")
sh "ssh ${REMOTE_HOST_B} 'sh /data/sh/kill_lessie_sourcing_agents.sh'"
sh """
ssh ${REMOTE_HOST_B} 'mkdir -p ${REMOTE_PROJECT_PATH_B}'
rsync -avz --exclude 'venv' --exclude '.git' ${WORKSPACE}/ ${REMOTE_HOST_B}:${REMOTE_PROJECT_PATH_B}/
"""
}
}
stage('B依赖&启动') {
steps {
echo("B依赖&启动")
sh """
ssh ${REMOTE_HOST_B} '
cd ${REMOTE_PROJECT_PATH_B} &&
source ~/.bashrc &&
conda activate search &&
source ${VENV_DIR_B}/bin/activate &&
pip install --upgrade pip &&
pip install -r requirements.txt
TIMESTAMP=\$(date +"%Y%m%d_%H%M%S")
LOGFILE="${REMOTE_PROJECT_PATH_B}/logs/lessie_sourcing_agents_\${TIMESTAMP}.log"
nohup env APP_ENV=s1 python ${REMOTE_PROJECT_PATH_B}/server.py --port 8002 > ${REMOTE_PROJECT_PATH_B}/logs/lessie_sourcing_agents_\${TIMESTAMP}.log 2>&1 &
ln -sf "\$LOGFILE" ${REMOTE_PROJECT_PATH_B}/logs/lessie_sourcing_agents_latest.log
'
"""
}
}
stage('探测B服务 ') {
steps {
echo("探测B服务")
sh "sleep 5"
sh """
ssh ${REMOTE_HOST_B} "head -n 300 ${REMOTE_PROJECT_PATH_B}/logs/lessie_sourcing_agents_latest.log | grep -i 'error' || true"
ssh ${REMOTE_HOST_B} "sh /data/sh/check_lessie_agents_8002.sh"
"""
}
}
stage('恢复B流量') {
steps {
echo "恢复实例B的流量"
sh "sleep 5"
sh "ssh ${NGINX_HOST} 'sh ${NGINX_RELOAD_SCRIPT} ${NGINX_PY_backend_B} ${PORT_B} up'"
echo "实例 B 部署完成"
}
}
}
post {
success {
echo '✅ 部署成功!'
}
failure {
echo '❌ 部署失败,请检查日志!'
}
}
}

View File

@@ -0,0 +1,45 @@
#!/bin/bash
# Nginx 后端服务器上下线脚本
# 用法: set_backend_status.sh <ip> <port> <action>
# 示例:
# set_backend_status.sh 10.0.0.5 7001 down
# set_backend_status.sh 10.0.0.5 7001 up
IP=$1
PORT=$2
ACTION=$3 # down / up
NGINX_CONFIG="/data/tengine/vhosts/s1.jennie.im.conf"
BACKUP_CONFIG="${NGINX_CONFIG}.backup.$(date +%F_%T).bak"
# 参数检查
if [ -z "$IP" ] || [ -z "$PORT" ] || [ -z "$ACTION" ]; then
echo "用法: $0 <ip> <port> <action> (action: down/up)"
exit 1
fi
# 备份
cp -f "$NGINX_CONFIG" "$BACKUP_CONFIG" || {
echo "备份配置失败"
exit 1
}
# 修改
if [ "$ACTION" == "down" ]; then
sed -i "s/\(server[[:space:]]\+$IP:$PORT[[:space:]]*\)weight=[0-9]\+\(.*\)/\1down\2/" "$NGINX_CONFIG"
elif [ "$ACTION" == "up" ]; then
sed -i "s/\(server[[:space:]]\+$IP:$PORT[[:space:]]*\)down\(.*\)/\1weight=10\2/" "$NGINX_CONFIG"
else
echo "无效的 action: $ACTION"
exit 1
fi
# 验证 & 重载
if nginx -t; then
nginx -s reload
echo "✅ 已将 $IP:$PORT 设置为 $ACTION"
rm -f "$BACKUP_CONFIG"
else
echo "❌ 配置检查失败,回滚..."
cp -f "$BACKUP_CONFIG" "$NGINX_CONFIG"
exit 1
fi

View File

@@ -0,0 +1,48 @@
#!/bin/bash
# 设置后端服务器权重的脚本
# 使用方法: set_s1_backend_weight.sh <port> <weight>
# 示例: set_s1_backend_weight.sh 8000 down/up
#/data/tengine/vhosts/s1.jennie.im.conf
# Tengine 权重设置脚本(使用 down 参数)
PORT=$1
ACTION=$2 # 可选值: "down" 或 "up"
NGINX_CONFIG="/data/tengine/vhosts/s1.jennie.im.conf"
BACKUP_CONFIG="${NGINX_CONFIG}.bak"
# 检查参数
if [ -z "$PORT" ] || [ -z "$ACTION" ]; then
echo "用法: $0 <port> <action> (action 可选值: down/up)"
exit 1
fi
# 备份配置
cp -f $NGINX_CONFIG $BACKUP_CONFIG || {
echo "备份配置失败"
exit 1
}
# 根据 action 修改配置
if [ "$ACTION" == "down" ]; then
# 临时下线服务器(使用 down 参数)
sed -i "s/\(server 10.0.0.5:$PORT\s*\)weight=[0-9]*\(.*\)/\1down\2/g" $NGINX_CONFIG
elif [ "$ACTION" == "up" ]; then
# 恢复服务器(移除 down 参数,恢复默认权重)
sed -i "s/\(server 10.0.0.5:$PORT\s*\)down\(.*\)/\1weight=10\2/g" $NGINX_CONFIG
else
echo "无效的 action 参数: $ACTION"
exit 1
fi
# 验证配置并重载
nginx -t && nginx -s reload || {
echo "配置错误,恢复原配置"
cp -f $BACKUP_CONFIG $NGINX_CONFIG
exit 1
}
echo "配置生效:端口 $PORT 已设置为 $ACTION"
rm -f $BACKUP_CONFIG

View File

@@ -0,0 +1,121 @@
# -------------------------
#!/bin/bash
# 等待指定端口的连接数连续3次为0每次间隔5秒
# 使用方法: wait_s1_for_connections.sh <port> <timeout>
# 示例: wait_s1_for_connections.sh 8000 300最多等待300秒
PORT=$1
TIMEOUT=$2
START_TIME=$(date +%s)
END_TIME=$((START_TIME + TIMEOUT))
SUCCESS_COUNT=0 # 连续成功计数
REQUIRED_SUCCESS=5 # 需要连续成功的次数
CHECK_INTERVAL=5 # 每次检测间隔(秒)
if [ -z "$PORT" ]; then
echo "用法: $0 <port> <timeout>"
exit 1
fi
if [ -z "$TIMEOUT" ]; then
TIMEOUT=600 # 默认超时时间600秒
fi
echo "等待端口 $PORT 的连接数连续 $REQUIRED_SUCCESS 次为0每次检测间隔 $CHECK_INTERVAL 秒),超时时间 $TIMEOUT"
while [ $(date +%s) -lt $END_TIME ]; do
# 检测当前连接数
CONNECTIONS=$(netstat -anp | grep :$PORT | grep -w ESTABLISHED | wc -l)
echo "当前连接数: $CONNECTIONS(检测次数: $SUCCESS_COUNT/$REQUIRED_SUCCESS"
if [ "$CONNECTIONS" -eq 0 ]; then
SUCCESS_COUNT=$((SUCCESS_COUNT + 1))
echo "检测到连接数为0连续成功计数: $SUCCESS_COUNT/$REQUIRED_SUCCESS"
# 达到3次连续成功退出
if [ "$SUCCESS_COUNT" -eq "$REQUIRED_SUCCESS" ]; then
echo "已连续 $REQUIRED_SUCCESS 次(每次间隔 $CHECK_INTERVAL 秒)检测到端口 $PORT 无活跃连接"
exit 0
fi
else
# 连接数不为0重置计数器
SUCCESS_COUNT=0
echo "连接数不为0重置连续成功计数"
fi
# 每次检测后间隔5秒
echo "等待 $CHECK_INTERVAL 秒后进行下一次检测..."
echo " "
sleep $CHECK_INTERVAL
done
echo "超时! 端口 $PORT$TIMEOUT 秒内未达到连续 $REQUIRED_SUCCESS 次连接数为0当前连接数: $CONNECTIONS"
exit 1
# ---------超时就调用kill杀掉----------
#!/bin/bash
# /data/sh/wait_s1_for_connections.sh
# 等待指定端口的连接数连续 N 次为0否则超时后直接杀死进程
# 用法: wait_s1_for_connections.sh <port> <timeout>
# 示例: wait_s1_for_connections.sh 8000 300
PORT=$1
TIMEOUT=$2
START_TIME=$(date +%s)
END_TIME=$((START_TIME + TIMEOUT))
SUCCESS_COUNT=0 # 连续成功计数
REQUIRED_SUCCESS=5 # 需要连续成功的次数
CHECK_INTERVAL=5 # 每次检测间隔(秒)
KILL_SCRIPT="/data/sh/kill_lessie_sourcing_agents.sh"
if [ -z "$PORT" ]; then
echo "用法: $0 <port> <timeout>"
exit 1
fi
if [ -z "$TIMEOUT" ]; then
TIMEOUT=600 # 默认超时时间600秒
fi
echo "等待端口 $PORT 的连接数连续 $REQUIRED_SUCCESS 次为0每次检测间隔 $CHECK_INTERVAL 秒),超时时间 $TIMEOUT"
while [ $(date +%s) -lt $END_TIME ]; do
CONNECTIONS=$(netstat -anp 2>/dev/null | grep :$PORT | grep -w ESTABLISHED | wc -l)
echo "当前连接数: $CONNECTIONS(检测次数: $SUCCESS_COUNT/$REQUIRED_SUCCESS"
if [ "$CONNECTIONS" -eq 0 ]; then
SUCCESS_COUNT=$((SUCCESS_COUNT + 1))
echo "检测到连接数为0连续成功计数: $SUCCESS_COUNT/$REQUIRED_SUCCESS"
if [ "$SUCCESS_COUNT" -eq "$REQUIRED_SUCCESS" ]; then
echo "✅ 已连续 $REQUIRED_SUCCESS 次(每次间隔 $CHECK_INTERVAL 秒)检测到端口 $PORT 无活跃连接"
exit 0
fi
else
SUCCESS_COUNT=0
echo "⚠️ 连接数不为0重置连续成功计数"
fi
echo "等待 $CHECK_INTERVAL 秒后进行下一次检测..."
echo ""
sleep $CHECK_INTERVAL
done
echo "⏰ 超时! 端口 $PORT$TIMEOUT 秒内未达到连续 $REQUIRED_SUCCESS 次连接数为0"
echo "尝试杀死该端口的进程..."
if [ -x "$KILL_SCRIPT" ]; then
sh $KILL_SCRIPT $PORT
else
echo "❌ 错误:未找到 $KILL_SCRIPT,无法杀死进程"
exit 1
fi
exit 1