Files

8.9 KiB

Jenkins 灰度部署

现有灰度环境使用 Jenkinsfile、Dockerfile 和 deploy/ 发布独立物流聊天服务。流水线构建并测试镜像,通过严格校验主机指纹的 SSH 发送到专用 Docker Compose 服务,Nginx 提供 HTTPS;客户聊天免登录,客服和其他非白名单路径使用访问密码。

应用使用单个 Waitress 进程、8 个线程和 UID 10001,宿主机端口仅绑定回环地址。运行密钥、聊天数据、附件和证书不进入镜像。游客历史和附件在应用内按归属隔离;客服仍依赖 Nginx 密码保护,不能裸露上游端口。客户登录与订单关联尚未接入,匿名查单不会读取订单数据。

容器时区设为 Asia/Shanghai,营业时间与聊天时间按中国时间计算。

Jenkins 任务

任务名为 baiyue-logistics-chat-gray。定义选择 Pipeline script from SCM,本项目 Git 地址为仓库,分支字段为 ${SOURCE_REF},脚本路径为 Jenkinsfile。公开仓库可匿名读取;转为私有后配置只读 SCM 凭据。

java-builder 标签代理须有 Docker、Bash、Python 3、Node.js 18+、OpenSSL、SSH,并能下载所选 Python 基础镜像和 PyPI 依赖。标签不表示固定物理节点。

以下参数由私有灰度配置提供,实际地址和凭据值不写入源码:

参数 含义
ENVIRONMENT 单选 gray,流水线拒绝其他值
SOURCE_REF 本次发布的不可变标签或提交,也可明确选择开发分支
PYTHON_BASE_IMAGE 已验证的官方 Python 3.12 基础镜像
DEBIAN_MIRROR 默认 https://deb.debian.org;国内可选 https://mirrors.tuna.tsinghua.edu.cn,保留 Debian 签名校验
PUBLIC_ORIGIN 独立 HTTPS 域名,不带子路径
HOST_PORT 已确认空闲的宿主机回环端口,如 29013
GRAY_DEPLOY_DIR 专用目录,末级必须为 gray-logistics-chat
GRAY_PROXY_CONF_DIR 宿主机 Nginx 实际加载的站点目录
GRAY_TLS_CERT_FILE / GRAY_TLS_KEY_FILE 本服务独立证书和私钥路径
SSH_CREDENTIAL_ID SSH 用户与私钥凭据引用
SSH_HOST_CREDENTIAL_ID SSH 目标的 Secret text 引用
SSH_KNOWN_HOSTS_CREDENTIAL_ID 已核实的 known_hosts 文件引用
DEEPSEEK_CREDENTIAL_ID 本服务模型密钥的 Secret text 引用
PREVIEW_AUTH_CREDENTIAL_ID 专用验收用户名和密码引用
ASR_PROVIDER baidu 启用语音;空值关闭
BAIDU_ASR_API_KEY_CREDENTIAL_ID / BAIDU_ASR_SECRET_KEY_CREDENTIAL_ID 本服务百度语音专用 Secret text 引用
IMPORT_ORDER_SAMPLES 默认关闭;明确需要补样本时才启用
ORDER_SNAPSHOT_CREDENTIAL_ID / TRACKING_SNAPSHOT_CREDENTIAL_ID 本次导入的临时 Secret file 引用

运行密钥和验收账号保存在私有灰度配置与 Jenkins 凭据库,供后续发布持续复用;轮换时同步更新。不要将密钥放在构建参数、Git URL、镜像 ARG、日志或示例文件中。

语音运行配置只注入 ASR_PROVIDER、BAIDU_ASR_API_KEY、BAIDU_ASR_SECRET_KEY,与 DS 密钥一起写入权限 600 的 runtime.env。容器使用镜像内的 FFmpeg,不传本机 FFMPEG_BIN,也不使用 OCR 凭据。缺少任一百度凭据时拒绝生成发布配置。

私有订单样本不进入 Git、构建上下文或镜像。可在明确授权后临时上传为 Jenkins Secret file 并启用 IMPORT_ORDER_SAMPLES;发布脚本核验快照校验和与实际运行提交,在线备份聊天 SQLite,再调用 scripts/import_order_test_data.py 默认导入订单、以 --tracking-only 补充轨迹。两步均不使用 --replace,保留手工订单字段和已有非空轨迹。临时文件在导入后清除;验收后移除临时 Jenkins 文件凭据并关闭导入开关。此操作只访问聊天服务自己的 SQLite。

发布步骤

  1. 完成检查并提交代码,创建 gray-chat-YYYYMMDD-<commit12> 一类不可变发布标签。不要重写已有标签或强推覆盖远端分支;分支有其他更新时先明确发布基线。
  2. 推送标签,在任务 SOURCE_REF 选择该标签。Jenkins 按此引用加载流水线并检出代码,镜像记录完整提交 SHA。
  3. 流水线检查 Bash 语法,运行 Node 回归,再构建 test 目标执行 Python 回归;通过后构建 production 应用镜像及 certbot 运维镜像。
  4. 构建完成后才绑定运行凭据。发布脚本校验路径、域名和源提交,生成私有配置并发送镜像及发布文件。服务器验证镜像归档的 SHA-256 后加载,记录目标主机的镜像 ID。
  5. 首次签发域名证书,等待应用健康,再安装本服务的 Nginx 配置。已有业务的容器和站点配置不参与本次发布。
  6. Jenkins 使用验收账号验证公网 HTTPS /healthz;之后在浏览器验证 AI 流式回复、上传、转人工和工作台。

应用镜像必须选择 production 构建目标;certbot 仅用于证书运维。每个构建生成独立镜像标签,不依赖 latest。Docker 的 classic 与 containerd 镜像存储可能返回不同 ID;跨主机以归档校验和与源提交标签核验传输,激活前再与 loaded-image-ids.env 中的目标 ID 比较,拒绝加载后被替换的镜像。归档加载后删除,构建机 ID 保留在 release.env 供追溯。

数据与失败回退

GRAY_DEPLOY_DIR 如 /data/services/gray-logistics-chat,包含:

路径 内容
.project 服务所有权标记,拒绝复用未知目录
data/ SQLite、附件和备份,跨发布保留
logs/ 应用日志
releases/<commit12>-b<build>/ Compose、镜像坐标、私有运行配置和站点候选
current-release 已通过应用及入口检查的发布目录
tls/ 独立 ACME 账号、证书、日志和续期脚本

模型密钥写入权限为 600 的 runtime.env,由 Compose 注入进程。验收密码只在 Jenkins 生成 Nginx 哈希,服务器保存哈希文件。

密码哈希位于独立的 /var/lib/baiyue-logistics-chat-gray-proxy/access.htpasswd,目录 755、文件 644,供 Nginx 工作进程读取;不放在可能只有 root 可访问的宝塔站点配置目录,也不放明文密码。该目录有本服务所有权标记,不复用未知目录。

更新前执行 SQLite 在线备份。应用启动或 Nginx 检查失败时,仅恢复本服务之前的 Compose 和站点配置,保留数据;不自动用旧库覆盖新记录。失败发布目录保留供定位,数据库降级及删除数据需另行处理。

新环境自动创建业务表,不创建默认客服账号或演示数据。专用访问密码用于客服工作台及受保护接口;Nginx 账号不是应用内客服账号。客户首页无需密码,客户端先自动建立访客会话,再访问自己的历史。

HTTPS 及续期

域名须解析到已核实的灰度入口,公网 80、443 端口可达。其他域名的证书不能直接用于新域名。

独立 Certbot 镜像通过 HTTP-01 webroot 签发证书;首次只新增本服务的 HTTP 验证站点,业务接口尚不公开。验证目录为 /var/lib/baiyue-logistics-chat-acme,最终配置持续保留该 HTTP 路径。

证书参数须指向:

<GRAY_DEPLOY_DIR>/tls/config/live/<域名>/fullchain.pem
<GRAY_DEPLOY_DIR>/tls/config/live/<域名>/privkey.pem

ACME 账号和私钥仅保存在服务器私有目录,当前使用无邮箱账号。专用 baiyue-logistics-chat-tls-renew.timer 每日检查本服务证书,内容变化后检查并重载 Nginx,不接管其他证书任务。

排查

先从 Jenkins 构建记录核对阶段及源 SHA。服务器检查:

docker ps --filter name=baiyue-logistics-chat-gray
docker logs --tail 100 baiyue-logistics-chat-gray
systemctl status baiyue-logistics-chat-tls-renew.timer --no-pager
nginx -t
  • 构建失败:核对镜像和 PyPI 网络,不跳过测试发布。
  • SSH 失败:核对受管凭据和 known_hosts,不禁用指纹检查。
  • 证书失败:核对 DNS 和 HTTP 验证路径,保留本服务的验证站点与私有 ACME 状态。
  • 容器不健康:检查独立目录的 UID 10001 权限、日志和 /healthz;健康检查不计入业务限流。
  • 客户首页应匿名返回 200,不出现密码弹窗;客服后台、全站搜索和导出匿名返回 401。客户历史 API 在未建立访客会话时由应用返回 JSON 401,自动建立 /api/visitor/session 后应返回当前访客的记录。发布激活脚本同时检查这些边界,不能只删除原有密码配置。
  • 流式显示延迟:检查实际 Nginx 或 CDN 是否重新启用了响应缓冲。

独立主机安装另见 Linux 手动参考。凭据与 API 依据 Jenkins 官方文档 和 Remote API,证书验证与续期依据 Certbot 文档。