From 210356d81609abe92906eca3cca09fd099aba120 Mon Sep 17 00:00:00 2001 From: dxin Date: Tue, 4 Nov 2025 14:43:52 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9Es4=E7=9A=84jenkins=E5=92=8Cng?= =?UTF-8?q?inx?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../go_中转服务/s4_go_lessie_sourcing_api.conf | 98 +++++++++ jenkins/流水线配置/s4.jennie.im.conf | 142 ++++++++++++ jenkins/流水线配置/s4.jennie.im_web.conf | 66 ++++++ nginx/apex_web.conf | 26 ++- nginx/s4.jennie.im.conf | 204 ++++++++++++++++++ 5 files changed, 533 insertions(+), 3 deletions(-) create mode 100644 jenkins/流水线配置/go_中转服务/s4_go_lessie_sourcing_api.conf create mode 100644 jenkins/流水线配置/s4.jennie.im.conf create mode 100644 jenkins/流水线配置/s4.jennie.im_web.conf create mode 100644 nginx/s4.jennie.im.conf diff --git a/jenkins/流水线配置/go_中转服务/s4_go_lessie_sourcing_api.conf b/jenkins/流水线配置/go_中转服务/s4_go_lessie_sourcing_api.conf new file mode 100644 index 0000000..a770416 --- /dev/null +++ b/jenkins/流水线配置/go_中转服务/s4_go_lessie_sourcing_api.conf @@ -0,0 +1,98 @@ +pipeline { + agent any + tools{ + go 'go1.24.0' + } + environment { + REMOTE_HOST_A = "43.130.56.138" + REMOTE_PROJECT_PATH_A = "/data/webapps/go_lessie_sourcing_api_s4" + PORT_A = "8101" + CONNECTION_TIMEOUT = "300" // 等待连接关闭的超时时间 + CHECK_PORT_SCRIPT = "/data/sh/check_port.sh" // 检查服务所运行的端口是否起起来 + SEND_STOP_GOAPP_SCRIPT = "/data/sh/send_stop_goapp_s4.sh" // 发送GO的优雅停止信号 + WAIT_CONNECTIONS_SCRIPT = "/data/sh/wait_for_connections.sh" // 监测实例A是否有连接 + } + + stages { + stage('Checkout代码') { + steps { + echo "阶段一" + git branch: "${params.Code_branch}", credentialsId: 'fly_gitlab_auth', url: 'http://172.24.16.20/go/lessie-sourcing-api.git' + } + } + stage('依赖&构建') { + steps { + echo "阶段二" + sh """ + cd ${WORKSPACE}/ + export GOVCS="git.deeplink.media:git,*:git" + echo "拉依赖" + go mod tidy -v -x + echo "构建二进制文件" + make build-linux + cp ./build/lessie-sourcing-api ./build/lessie-sourcing-api-s4 + chmod +x ./build/lessie-sourcing-api-s4 + """ + } + } + stage('A同步') { + steps { + echo "阶段三" + sh """ + echo "进入jenkins工作目录:${WORKSPACE}" + cd ${WORKSPACE}/ + echo "同步二进制产物" + rsync -avzuP ./build/lessie-sourcing-api-s4 ./configs/application_s4.yaml ${REMOTE_HOST_A}:${REMOTE_PROJECT_PATH_A}/ + """ + } + } + stage('A下线') { + steps { + echo "阶段三" + sh """ + ssh ${REMOTE_HOST_A} ' + echo "向实例A发送优雅关闭信号" + sh ${SEND_STOP_GOAPP_SCRIPT} + echo "监测实例A是否有连接" + sh ${WAIT_CONNECTIONS_SCRIPT} ${PORT_A} ${CONNECTION_TIMEOUT} + ' + """ + } + } + stage('A启动') { + steps { + echo "阶段四" + sh """ + ssh ${REMOTE_HOST_A} ' + cd ${REMOTE_PROJECT_PATH_A} + chmod +x ./lessie-sourcing-api-s4 + nohup env ENV=s4 ./lessie-sourcing-api-s4 --port 8101 > ./go.log 2>&1 & + ' + """ + } + } + stage('探测A服务 ') { + steps { + echo "阶段五" + sh "sleep 10" + sh """ + ssh ${REMOTE_HOST_A} ' + echo "查看实例A的启动日志" + head -n 5 ${REMOTE_PROJECT_PATH_A}/go.log || true + sh ${CHECK_PORT_SCRIPT} 8101 60 + sleep 5 + ps aux|grep lessie-sourcing-api-s4 + ' + """ + } + } + } + post { + success { + echo '✅ 部署成功!' + } + failure { + echo '❌ 部署失败,请检查日志!' + } + } +} \ No newline at end of file diff --git a/jenkins/流水线配置/s4.jennie.im.conf b/jenkins/流水线配置/s4.jennie.im.conf new file mode 100644 index 0000000..b517413 --- /dev/null +++ b/jenkins/流水线配置/s4.jennie.im.conf @@ -0,0 +1,142 @@ +node { + properties([ + parameters([ + // 分支选择参数 + gitParameter( + branchFilter: 'origin/(.*)', + defaultValue: 'master', + description: 's4环境,默认master分支', + name: 'Code_branch', + quickFilterEnabled: true, + selectedValue: 'DEFAULT', + sortMode: 'NONE', + type: 'PT_BRANCH', + size: 1 + ), + // 部署实例选择 + choice( + name: 'DEPLOY_TARGETS', + choices: ['A'], + description: '选择需要部署的实例' + ), + // 部署顺序 + string( + name: 'DEPLOY_ORDER', + defaultValue: 'A', + description: '指定部署顺序' + ) + ]) + ]) + + // 环境配置(集中管理实例参数) + def config = [ + A: [ + remoteHost: "43.130.56.138", + projectPath: "/data/webapps/lessie_sourcing_agents_s4", + venvDir: "/data/webapps/lessie_sourcing_agents_s4/.venv", + nginxBackend: "10.0.0.5", + port: "8001", + killScript: "/data/sh/kill_lessie_sourcing_agents.sh", + checkScript: "/data/sh/check_lessie_agents_8001.sh", + gunicornWorkers: 4 + ], + ] + + def commonConfig = [ + nginxHost: "43.130.56.138", + connectionTimeout: "300", + nginxReloadScript: "/data/sh/set_s4_backend_weight_new.sh", + waitConnectionsScript: "/data/sh/wait_s4_for_connections.sh" + ] + + stage('拉代码') { + checkout scm: [ + $class: 'GitSCM', + branches: [[name: params.Code_branch]], + userRemoteConfigs: [[ + url: 'http://172.24.16.20/python/lessie-sourcing-agents.git', + credentialsId: 'fly_gitlab_auth' + ]] + ] + } + + stage('验证参数') { + def selectedTargets = params.DEPLOY_TARGETS.split(',').toList() + def orderChars = params.DEPLOY_ORDER.split('').toList() + + if (orderChars.isEmpty()) { + error("部署顺序不能为空,请输入如AB、BA的顺序") + } + + orderChars.each { instance -> + if (!selectedTargets.contains(instance)) { + error("部署顺序包含未选择的实例: ${instance},已选实例:${params.DEPLOY_TARGETS}") + } + } + + def uniqueOrder = orderChars.unique() + if (uniqueOrder.size() != orderChars.size()) { + error("部署顺序包含重复实例: ${params.DEPLOY_ORDER}") + } + + echo "✅ 参数验证通过:已选实例=${selectedTargets},部署顺序=${orderChars}" + env.VALID_ORDER = params.DEPLOY_ORDER + } + + stage('动态部署') { + def orderChars = env.VALID_ORDER.split('').toList() + orderChars.each { instance -> + echo "===== 开始部署实例 ${instance} =====" + + // 实例部署的5个步骤(直接在循环中定义stage,无嵌套) + stage("${instance}:脱离后端组") { + def cfg = config[instance] + sh "ssh ${commonConfig.nginxHost} 'sh ${commonConfig.nginxReloadScript} ${cfg.nginxBackend} ${cfg.port} down'" + sh "ssh ${cfg.remoteHost} 'sh ${commonConfig.waitConnectionsScript} ${cfg.port} ${commonConfig.connectionTimeout}'" + } + + stage("${instance}下线&同步") { + def cfg = config[instance] + sh "ssh ${cfg.remoteHost} 'sh ${cfg.killScript} ${cfg.port}'" + sh """ + ssh ${cfg.remoteHost} 'mkdir -p ${cfg.projectPath}' + rsync -avz --exclude '.venv' --exclude '.git' ${WORKSPACE}/ ${cfg.remoteHost}:${cfg.projectPath}/ + """ + } + + stage("${instance}依赖&启动") { + def cfg = config[instance] + sh """ + ssh ${cfg.remoteHost} ' + cd ${cfg.projectPath} + uv sync + source ${cfg.venvDir}/bin/activate + TIMESTAMP=\$(date +"%Y%m%d_%H%M%S") + LOGFILE="${cfg.projectPath}/logs/lessie_sourcing_agents_\${TIMESTAMP}.log" + nohup env APP_ENV=s1 gunicorn -w ${cfg.gunicornWorkers} -k uvicorn.workers.UvicornWorker \ + -b 0.0.0.0:${cfg.port} --timeout 300 dialogue.app:app \ + --max-requests 200 --max-requests-jitter 50 \ + > "\$LOGFILE" 2>&1 & + ln -sf "\$LOGFILE" ${cfg.projectPath}/logs/lessie_sourcing_agents_latest.log + ' + """ + } + + stage("探测${instance}探测服务") { + def cfg = config[instance] + sh "sleep 5" + sh "ssh ${cfg.remoteHost} 'head -n 300 ${cfg.projectPath}/logs/lessie_sourcing_agents_latest.log | grep -i error || echo 未发现错误日志'" + sh "ssh ${cfg.remoteHost} 'sh ${cfg.checkScript}'" + } + + stage("恢复${instance}流量") { + def cfg = config[instance] + sh "ssh ${commonConfig.nginxHost} 'sh ${commonConfig.nginxReloadScript} ${cfg.nginxBackend} ${cfg.port} up'" + } + + echo "===== 实例 ${instance} 部署完成 =====" + } + } + + echo '✅ 所有选中的实例部署成功!' +} diff --git a/jenkins/流水线配置/s4.jennie.im_web.conf b/jenkins/流水线配置/s4.jennie.im_web.conf new file mode 100644 index 0000000..7c57326 --- /dev/null +++ b/jenkins/流水线配置/s4.jennie.im_web.conf @@ -0,0 +1,66 @@ +pipeline { + agent any + + parameters { + gitParameter( + branchFilter: 'origin/(.*)', + defaultValue: 'dev', + name: 'Code_branch', + type: 'PT_BRANCH_TAG', + selectedValue: 'DEFAULT', + sortMode: 'NONE', + description: '选择代码分支或标签: ', + quickFilterEnabled: true, + tagFilter: '*', + listSize: "1" + ) + } + environment { + WEB_HOST_IP = "43.130.56.138" + WEB_HOST_PROJECT_PATH = "/data/tengine/html/s4-jennie-im-web/dist" + } + + stages { + stage('拉取代码') { + steps { + git branch: "${params.Code_branch}", credentialsId: 'fly_gitlab_auth', url: 'http://172.24.16.20/web/jennie.git' + } + } + + stage('pnpm i&b') { + steps { + script { + sh """ + export PATH="/data/node-v20.15.0/bin:$PATH" + echo "开始安装依赖包" + cd ${WORKSPACE}/ && rm -rf node_modules && pnpm install + echo "开始构建" + pnpm build:im + mv dist/main/index.html dist/ + chmod -R 755 dist/ + """ + } + } + } + + stage('同步产物') { + steps { + script { + sh """ + cd ${WORKSPACE}/ + rsync -avzP --delete dist/ ${WEB_HOST_IP}:${WEB_HOST_PROJECT_PATH} + """ + } + } + } + } + + post { + success { + echo "构建成功!" + } + failure { + echo "构建失败!" + } + } +} \ No newline at end of file diff --git a/nginx/apex_web.conf b/nginx/apex_web.conf index 0564f1d..1f5c5a5 100644 --- a/nginx/apex_web.conf +++ b/nginx/apex_web.conf @@ -6,10 +6,10 @@ log_format apex_log '客户端IP: $remote_addr | 用户: $remote_user | 时间: server { listen 443 ssl; - server_name 127.0.0.1; + server_name apex.jennie.im; - ssl_certificate /data/tengine/conf/certificate/apex.deeplink.media_bundle.crt; - ssl_certificate_key /data/tengine/conf/certificate/apex.deeplink.media.key; + ssl_certificate /data/tengine/conf/certificate/jennie.im.crt; + ssl_certificate_key /data/tengine/conf/certificate/jennie.im.key; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; @@ -30,6 +30,26 @@ server { add_header Cache-Control "no-cache, no-store, must-revalidate"; } + + location /api/ { + proxy_pass http://127.0.0.1:8200; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_buffering off; + add_header 'Access-Control-Allow-Origin' "$http_origin" always; + add_header 'Access-Control-Allow-Credentials' 'true' always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE' always; + add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type,X-Requested-With,Accept,Origin' always; + + if ($request_method = OPTIONS ) { + return 204; + } + } + + # 错误页面 error_page 500 502 503 504 /50x.html; location = /50x.html { diff --git a/nginx/s4.jennie.im.conf b/nginx/s4.jennie.im.conf new file mode 100644 index 0000000..65b2269 --- /dev/null +++ b/nginx/s4.jennie.im.conf @@ -0,0 +1,204 @@ +# ============10-30============================================== + +upstream s4_jennie_im_backend { + server 10.0.0.5:8001 weight=10 max_fails=3 fail_timeout=30s; + keepalive 128; +} + + +log_format s4_jennie_im_log '客户端IP: $remote_addr | 用户: $remote_user | 时间: $time_local | ' + '请求方法和路径: "$request" | 状态码: $status | 响应大小: $body_bytes_sent | ' + '来源页面: "$http_referer" | 客户端UA: "$http_user_agent" | ' + '上游服务器: $upstream_addr | 上游响应耗时: $upstream_response_time | ' + '请求总耗时: $request_time | Host: $host'; + +server { + listen 443 ssl; + server_name s4.jennie.im; + + ssl_certificate /data/tengine/conf/certificate/jennie.im.crt; + ssl_certificate_key /data/tengine/conf/certificate/jennie.im.key; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + + # 单独日志文件 + access_log /data/tengine/logs/s4_jennie_im_access.log s4_jennie_im_log; + error_log /data/tengine/logs/s4_jennie_im_error.log; + + + # 前端静态文件 + location / { + root /data/tengine/html/s4-jennie-im-web/dist; + index index.html; + + try_files $uri $uri/ /index.html; + } + + # 精确匹配 index.html,禁用缓存 + location = /index.html { + root /data/tengine/html/s4-jennie-im-web/dist; + add_header Cache-Control "no-cache, no-store, must-revalidate"; + } + # 静态资源开启长缓存(带 hash) + location ~* \.(js|css|woff2|json|svg|png|jpg|jpeg|gif|ico|ttf|otf|eot|mp4|webm|webp)$ { + root /data/tengine/html/s4-jennie-im-web/dist; + add_header Cache-Control "public, max-age=31536000, immutable"; + } + + + # go的代理配置 + location ~ ^/(debug/pprof|api/chat|api/conversation/|api/shares|api/showcases|api/searches) { + proxy_pass http://10.0.0.5:8101; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_buffering off; + proxy_cache off; + proxy_http_version 1.1; + proxy_set_header Connection ""; + proxy_request_buffering off; + + add_header 'Access-Control-Allow-Origin' "$http_origin" always; + add_header 'Access-Control-Allow-Credentials' 'true' always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE' always; + add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type,X-Requested-With,Accept,Origin' always; + + if ($request_method = OPTIONS ) { + return 204; + } + } + + + location /api/chat/stream { + proxy_pass http://s4_jennie_im_backend; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_buffering off; + proxy_cache off; + proxy_http_version 1.1; + proxy_set_header Connection ""; + proxy_request_buffering off; + + add_header 'Access-Control-Allow-Origin' "$http_origin" always; + add_header 'Access-Control-Allow-Credentials' 'true' always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE' always; + add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type,X-Requested-With,Accept,Origin' always; + + # 增加客户端到Nginx的连接超时时间 + proxy_read_timeout 3600s; + proxy_send_timeout 3600s; + + if ($request_method = OPTIONS ) { + return 204; + } + } + + location /api/ { + proxy_pass http://s4_jennie_im_backend; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_buffering off; + proxy_cache off; + proxy_http_version 1.1; + proxy_set_header Connection ""; + proxy_request_buffering off; + + add_header 'Access-Control-Allow-Origin' "$http_origin" always; + add_header 'Access-Control-Allow-Credentials' 'true' always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE' always; + add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type,X-Requested-With,Accept,Origin' always; + + if ($request_method = OPTIONS ) { + return 204; + } + } + + + # sit的支付模块 + location /payment/webhook/ { + proxy_pass http://106.53.194.199:8010; #运维机器的8010(与容器的8090映射)代理到sit的8090 + proxy_set_header Host 106.53.194.199; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + proxy_intercept_errors off; + proxy_buffering off; + proxy_cache off; + proxy_set_header Connection keep-alive; + + add_header 'Access-Control-Allow-Origin' "$http_origin" always; + add_header 'Access-Control-Allow-Credentials' 'true' always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE' always; + add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type,X-Requested-With,Accept,Origin' always; + + if ($request_method = OPTIONS ) { + return 204; + } + } + + + # 打到国内sit的agent.jar包 + location /sit-api/agent/ { + proxy_pass http://106.53.194.199:8070; + proxy_set_header Host 106.53.194.199; + + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + proxy_intercept_errors off; + proxy_buffering off; + proxy_cache off; + proxy_set_header Connection keep-alive; + + client_max_body_size 300M; + + add_header 'Access-Control-Allow-Origin' "$http_origin" always; + add_header 'Access-Control-Allow-Credentials' 'true' always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE' always; + add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type,X-Requested-With,Accept,Origin' always; + + if ($request_method = OPTIONS ) { + return 204; + } + } + + + location /sit-api/system { + proxy_pass http://106.53.194.199:8070; + proxy_set_header Host 106.53.194.199; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + proxy_intercept_errors off; + proxy_buffering off; + proxy_cache off; + proxy_set_header Connection keep-alive; + + add_header 'Access-Control-Allow-Origin' "$http_origin" always; + add_header 'Access-Control-Allow-Credentials' 'true' always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE' always; + add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type,X-Requested-With,Accept,Origin' always; + + client_max_body_size 300M; + + if ($request_method = OPTIONS ) { + return 204; + } + } + + # 错误页面 + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /data/tengine/html/s4-jennie/dist; + } +} + +# ====================10-30======================================== \ No newline at end of file