Files
wecom_it_smart_desk/docs/10-项目管理/任务说明书/任务说明书-77-后端部署卷挂载改造.md
T
Simon bea288e414 feat: 2026-07-11 全量更新 - 代办集成+会议室预定+知识迭代修复+UI统一+Bug修复
== 已部署上线 (9项) ==
- 代办事项真实数据源集成 (企微审批API 8bug修复链)
- H5/坐席端 Logo样式统一+绿色背景
- 视频引导页修复 (localStorage key v2)
- 坐席端 v9 Vue版本修复 (ElMessage._context)
- 截图按钮 v10 修复 (getDisplayMedia user gesture)
- 扫码样式恢复+H5扫码登录跳转修复
- H5截图快捷键提示

== 代码完成待部署 (3项) ==
- 知识迭代3Bug修复 (#8 POST端点/#7 MERGE幂等/#6 过期检查)
- 会议室预定-小鱼易联终端 (40文件, 40/40测试通过)
- IT资产升级审批推送 (asset_service.py)

== 需求文档 (2项) ==
- 坐席端AI辅助消息框-PRD (4项新功能确认)
- 坐席端布局优化建议 v2.0 (7天计划)

== 新增文档 ==
- 日报-2026-07-11.md
- 知识迭代Bug修复报告-20260711.md
- 会议室预定-部署指南.md
- CHANGELOG.md 更新

== 测试 ==
- test_todo_integration.py: 40/40
- test_meetingroom.py: 40/40
- test_bugfix_ki_suggestions.py: 21/21
2026-07-11 23:13:10 +08:00

647 lines
21 KiB
Markdown
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.
# 任务说明书 — 后端部署卷挂载改造
> **版本**: v1.0 | **日期**: 2026-07-10
---
## 📋 基本信息
| 项目 | 内容 |
|------|------|
| **任务名称** | 后端部署架构改造:镜像烘焙 → 代码卷挂载 |
| **任务ID** | #107 |
| **优先级** | 🟠 P1 |
| **类型** | 部署优化 |
| **状态** | 待开始 |
| **负责人** | 宋献 |
| **创建日期** | 2026-07-10 |
| **计划完成日期** | 2026-07-11 |
---
## 📥 输入项来源
### 产品需求
| 来源文档 | 相关章节 | 说明 |
|----------|----------|------|
| 无 | — | 运维需求,非产品功能 |
### 技术架构
| 来源文档 | 相关章节 | 说明 |
|----------|----------|------|
| `03-技术架构/IT智能服务台-系统架构设计文档v2.md` | §5.0 部署模式演进 | 方案 C 设计说明 |
| `09-部署运维/卷挂载重构方案.md` | 全文 | 完整 8 章节方案(架构师高见远产出) |
| `09-部署运维/00-标准故障排查手册.md` | §1.4 + CASE-20260710-02 | 部署前同步检查清单 + 镜像缺文件案例 |
### 事故背景
| 日期 | 事故 | 根因 |
|------|------|------|
| 2026-07-07 | 认证路由缺失 | Docker 镜像未重新构建 |
| 2026-07-10 | auth.py 缺失导致认证全断 | 镜像从 backend/app/(旧代码)构建,两份代码不同步 |
**共同根因**:代码通过 `COPY . .` 烘焙进镜像,服务器两份代码不同步导致构建出缺文件的镜像。
---
## 📤 输出成果要求
### 交付物清单
| # | 交付物 | 类型 | 说明 |
|---|--------|------|------|
| 1 | `backend/Dockerfile` | 配置 | 删除 `COPY . .`,新增 `ENV PYTHONDONTWRITEBYTECODE=1` |
| 2 | `docker-compose.yml` | 配置 | backend 服务 volumes 新增 `./app:/app/app` |
| 3 | 服务器代码目录调整 | 运维 | `app/` 成为唯一代码源,`backend/app/` 保留 48h 后删除 |
| 4 | 部署验证通过 | 验证 | 健康检查 + auth 模块 + 卷挂载 + 代码一致性 |
### 代码要求
- Dockerfile 变更:仅删除 `COPY . .`(第 53 行),新增 `ENV PYTHONDONTWRITEBYTECODE=1`,其余不变
- docker-compose.yml 变更:backend 服务 volumes 段新增一行 `./app:/app/app`,插入到 `backend-uploads` 行之前
- 不涉及任何 Python 业务代码变更
### 文档要求
- 架构设计文档已更新(§5.0 部署模式演进,v2.1)
- 项目管理主文档已更新(看板新增 #107
- 完整方案文档已归档:`docs/09-部署运维/卷挂载重构方案.md`
---
## 🔧 验证方式
### 功能验证
| 验证项 | 验证方法 | 预期结果 |
|--------|----------|-----------|
| 容器运行状态 | `docker compose ps backend` | Status 为 `Up (healthy)` |
| 健康检查 | `curl -sf http://localhost:8000/health` | 返回 `{"status":"healthy"}` 或类似 |
| **Auth 模块** | `docker exec wecom_it_backend python -c "from app.auth import router; print('OK')"` | 输出 `OK`(曾因缺失导致故障) |
| 卷挂载 | `docker exec wecom_it_backend ls -la /app/app/main.py` | 文件存在且可读 |
| 代码一致性 | `md5sum` 对比宿主机与容器内 `main.py` | md5 值一致 |
| 日志检查 | `docker compose logs --tail=50 backend` | 无 `ModuleNotFoundError` / `ImportError` |
### 安全验证
| 验证项 | 验证方法 | 预期结果 |
|--------|----------|-----------|
| `COPY . .` 已移除 | `grep -c "COPY . ." backend/Dockerfile` | 返回 0 |
| 卷挂载已添加 | `grep "app:/app/app" docker-compose.yml` | 返回匹配 |
| `__pycache__` 禁止 | `docker exec wecom_it_backend python -c "import sys; print(sys.dont_write_bytecode)"` | 输出 `True` |
### 性能验证
| 验证项 | 验证方法 | 预期结果 |
|--------|----------|-----------|
| 容器重启速度 | 部署后 `docker compose restart backend` + `time` 计时 | < 15 秒(此前需 4-6 分钟) |
| 健康检查就绪 | 重启后 `curl /health` 轮询 | 15 秒内就绪 |
---
## 🔄 回滚策略(CRITICAL
### 回滚触发条件
满足以下 **任一** 条件即触发回滚:
| # | 触发条件 | 检测方法 |
|---|----------|----------|
| 1 | 容器启动失败(反复重启) | `docker compose ps backend` 状态为 `restarting``unhealthy` |
| 2 | 健康检查连续失败 | `curl -sf http://localhost:8000/health` 返回非 200 |
| 3 | 关键模块导入失败(如 auth) | `docker exec wecom_it_backend python -c "from app.auth import router"` 报错 |
| 4 | 卷挂载路径不存在或权限拒绝 | 容器日志出现 `ModuleNotFoundError``PermissionError` |
| 5 | 业务接口大面积 500 错误 | Nginx 日志或后端日志大量 500 状态码 |
### 回滚步骤(可通过 jumpserver-ops 执行)
```bash
#!/bin/bash
# =============================================================================
# 回滚脚本:卷挂载方案 → 镜像烘焙方案
# 执行方式:通过 jumpserver-ops 在 10.90.5.110 上执行
# 前提:备份文件存在(部署时已创建 .bak.{TIMESTAMP} 后缀文件)
# =============================================================================
set -e
cd /opt/wecom-it-desk
echo "===== 回滚开始: $(date) ====="
# --- 步骤 1: 恢复备份的配置文件 ---
echo ">>> [1/6] 恢复配置文件..."
COMPOSE_BAK=$(ls -t /opt/wecom-it-desk/docker-compose.yml.bak.* 2>/dev/null | head -1)
if [ -z "$COMPOSE_BAK" ]; then
echo "ERROR: 未找到 docker-compose.yml 备份文件!"
echo "可手动从 git 恢复: git checkout -- docker-compose.yml"
exit 1
fi
cp "$COMPOSE_BAK" /opt/wecom-it-desk/docker-compose.yml
echo " 已恢复 docker-compose.yml <- $COMPOSE_BAK"
DOCKERFILE_BAK=$(ls -t /opt/wecom-it-desk/backend/Dockerfile.bak.* 2>/dev/null | head -1)
if [ -z "$DOCKERFILE_BAK" ]; then
echo "ERROR: 未找到 Dockerfile 备份文件!"
echo "可手动从 git 恢复: git checkout -- backend/Dockerfile"
exit 1
fi
cp "$DOCKERFILE_BAK" /opt/wecom-it-desk/backend/Dockerfile
echo " 已恢复 Dockerfile <- $DOCKERFILE_BAK"
# --- 步骤 2: 确保 backend/app/ 存在(回滚安全网) ---
echo ">>> [2/6] 检查 backend/app/ 目录..."
if [ ! -d /opt/wecom-it-desk/backend/app/ ] || [ -z "$(ls -A /opt/wecom-it-desk/backend/app/ 2>/dev/null)" ]; then
echo " backend/app/ 不存在或为空,从 app/ 同步代码..."
mkdir -p /opt/wecom-it-desk/backend/app/
cp -r /opt/wecom-it-desk/app/* /opt/wecom-it-desk/backend/app/
cp -r /opt/wecom-it-desk/app/.* /opt/wecom-it-desk/backend/app/ 2>/dev/null || true
echo " 已同步代码到 backend/app/"
else
echo " backend/app/ 已存在,跳过同步"
fi
# --- 步骤 3: 重新构建镜像(使用原始 Dockerfile,含 COPY . . ---
echo ">>> [3/6] 重新构建后端镜像..."
docker compose build --no-cache backend
# --- 步骤 4: 重启容器 ---
echo ">>> [4/6] 重启后端容器..."
docker compose up -d backend
# --- 步骤 5: 等待服务就绪 ---
echo ">>> [5/6] 等待服务启动..."
echo " 等待 45 秒(healthcheck start_period..."
sleep 45
# --- 步骤 6: 验证 ---
echo ">>> [6/6] 验证回滚结果..."
echo "--- 容器状态 ---"
docker compose ps backend
echo "--- 健康检查 ---"
if curl -sf http://localhost:8000/health > /dev/null 2>&1; then
echo " PASS: /health 返回正常"
else
echo " WARN: /health 未就绪,再等待 15 秒..."
sleep 15
if curl -sf http://localhost:8000/health > /dev/null 2>&1; then
echo " PASS: /health 返回正常(延迟就绪)"
else
echo " FAIL: /health 仍然失败"
echo " 查看日志: docker compose logs --tail=50 backend"
fi
fi
echo "--- Auth 模块验证 ---"
if docker exec wecom_it_backend python -c "from app.auth import router; print('auth OK')" 2>/dev/null; then
echo " PASS: auth 模块可导入"
else
echo " FAIL: auth 模块导入失败"
echo " 查看日志: docker compose logs --tail=50 backend"
fi
echo ""
echo "===== 回滚完成: $(date) ====="
echo ""
echo "如回滚后仍有问题,请检查:"
echo " 1. backend/app/ 代码是否完整: ls -la /opt/wecom-it-desk/backend/app/"
echo " 2. 镜像构建是否成功: docker images | grep wecom-it-desk-backend"
echo " 3. 容器日志: docker compose logs -f backend"
```
### 回滚后验证
| 验证项 | 命令 | 预期结果 |
|--------|------|----------|
| 容器运行状态 | `docker compose ps backend` | Status 为 `Up (healthy)` |
| 健康检查 | `curl -sf http://localhost:8000/health` | 返回正常 |
| Auth 模块 | `docker exec wecom_it_backend python -c "from app.auth import router; print('OK')"` | 输出 `OK` |
| Nginx 代理 | `curl -sf http://localhost:80/itdesk/health` | 返回正常 |
| 日志无异常 | `docker compose logs --tail=50 backend` | 无 `ModuleNotFoundError` / `ImportError` |
### 回滚时间预估
| 步骤 | 耗时 |
|------|------|
| 恢复配置文件 | 5 秒 |
| 检查/同步 backend/app/ | 5-30 秒 |
| 重建镜像 | 2-4 分钟 |
| 重启容器 | 10 秒 |
| 等待就绪 | 45 秒 |
| 验证 | 15 秒 |
| **总计** | **3.5-5.5 分钟** |
---
## ✅ 完成标准
### 验收条件
- [ ] Dockerfile 已删除 `COPY . .`,已新增 `PYTHONDONTWRITEBYTECODE=1`
- [ ] docker-compose.yml 已新增 `./app:/app/app` 卷挂载
- [ ] 镜像已重建并重启成功
- [ ] 健康检查通过(`/health` 返回正常)
- [ ] Auth 模块可导入(`from app.auth import router` 成功)
- [ ] 卷挂载验证通过(容器内 `/app/app/main.py` 可访问)
- [ ] 代码一致性验证通过(宿主机与容器 md5 一致)
- [ ] 日志无 `ModuleNotFoundError` / `ImportError`
- [ ] 部署 48 小时后 `backend/app/` 已清理
- [ ] 文档已更新(架构设计文档 v2.1、项目管理主文档 v2.1)
### 产出确认
- [ ] 服务器 Dockerfile 已更新
- [ ] 服务器 docker-compose.yml 已更新
- [ ] 镜像重建成功
- [ ] 容器运行正常
- [ ] 回滚脚本已验证可用
- [ ] 备份文件已创建(`.bak.{TIMESTAMP}`
- [ ] `.rollback-info` 文件已记录
---
## 📊 工作分解
### 子任务
| 子任务 | 负责人 | 预估工时 | 状态 | 依赖 |
|--------|--------|----------|------|------|
| S1: 前置验证与备份 | 宋献 | 2 分钟 | 待开始 | 无 |
| S2: 代码同步与验证 | 宋献 | 1 分钟 | 待开始 | S1 |
| S3: 修改 Dockerfile | 宋献 | 1 分钟 | 待开始 | S2 |
| S4: 修改 docker-compose.yml | 宋献 | 1 分钟 | 待开始 | S3 |
| S5: 重建镜像并重启 | 宋献 | 3 分钟 | 待开始 | S4 |
| S6: 部署后验证 | 宋献 | 2 分钟 | 待开始 | S5 |
| S7: 清理 backend/app/48h 后) | 宋献 | 1 分钟 | 待开始 | S6 + 48h |
### 预估总时间
| 阶段 | 步骤 | 耗时 |
|------|------|------|
| 准备 | S1 + S2 | 3 分钟 |
| 变更 | S3 + S4 | 2 分钟 |
| 部署 | S5 | 3 分钟 |
| 验证 | S6 | 2 分钟 |
| **总计** | S1-S6 | **约 10 分钟** |
| 清理 | S748h 后) | 1 分钟 |
| **回滚(如需)** | 回滚脚本 | **3.5-5.5 分钟** |
---
## 📞 依赖与阻塞
### 前置依赖
| 依赖任务 | 依赖说明 | 状态 |
|----------|----------|------|
| 无 | 独立运维任务 | — |
### 阻塞因素
| 阻塞项 | 影响范围 | 解决方案 |
|--------|----------|-----------|
| 无 | — | — |
---
## ⚠️ 风险评估
| # | 风险 | 概率 | 等级 | 对策 |
|---|------|------|------|------|
| R1 | `__pycache__` 污染宿主机代码目录 | 中 | 中 | Dockerfile 设置 `PYTHONDONTWRITEBYTECODE=1` |
| R2 | 宿主机代码被意外修改导致运行中服务异常 | 低 | 中 | 生产不启用 `--reload`;限制目录写权限 |
| R3 | `backend/app/` 被提前删除导致回滚失败 | 低 | 高 | 48 小时内不删除;回滚脚本含自动同步逻辑 |
| R4 | requirements.txt 与代码不同步 | 低 | 中 | 部署前 diff 对比;新增依赖时先重建镜像 |
| R5 | 卷挂载路径与现有挂载冲突 | 极低 | 低 | `/app/app``/app/uploads``/app/logs` 无交集 |
---
## 📈 变更记录
| 日期 | 变更内容 | 变更人 | 说明 |
|------|----------|--------|------|
| 2026-07-10 | 创建任务 | 宋献 | 初始版本,基于架构师高见远的卷挂载重构方案 |
---
## 📎 附件
- **完整方案文档**`docs/09-部署运维/卷挂载重构方案.md`(含完整命令块、时序图、风险评估)
- **架构设计文档**`docs/03-技术架构/IT智能服务台-系统架构设计文档v2.md` §5.0
- **故障排查手册**`docs/09-部署运维/00-标准故障排查手册.md` §1.4 + CASE-20260710-02
- **deploy-troubleshoot skill**`~/.workbuddy/skills/deploy-troubleshoot/SKILL.md` Step -1 部署前同步检查
- **task-intake skill**`.workbuddy/skills/task-intake/SKILL.md` Step 3.1 部署运维前置检查
---
## 📝 完整部署命令块
以下命令可通过 jumpserver-ops 在服务器 10.90.5.110 上按步骤执行。
### S1: 前置验证与备份
```bash
#!/bin/bash
set -e
cd /opt/wecom-it-desk
# 1. 验证当前服务正常
echo ">>> 验证当前服务状态..."
curl -sf http://localhost:8000/health > /dev/null && echo " PASS: 当前服务正常" || { echo " FAIL: 当前服务异常,请先修复再部署"; exit 1; }
# 2. 备份配置文件
BACKUP_TS=$(date +%Y%m%d%H%M%S)
cp /opt/wecom-it-desk/docker-compose.yml /opt/wecom-it-desk/docker-compose.yml.bak.${BACKUP_TS}
cp /opt/wecom-it-desk/backend/Dockerfile /opt/wecom-it-desk/backend/Dockerfile.bak.${BACKUP_TS}
echo " PASS: 备份完成 (timestamp: ${BACKUP_TS})"
# 3. 记录回滚信息
cat > /opt/wecom-it-desk/.rollback-info << EOF
ROLLBACK_TIMESTAMP=${BACKUP_TS}
COMPOSE_BAK=/opt/wecom-it-desk/docker-compose.yml.bak.${BACKUP_TS}
DOCKERFILE_BAK=/opt/wecom-it-desk/backend/Dockerfile.bak.${BACKUP_TS}
DEPLOY_DATE=$(date)
EOF
echo " PASS: 回滚信息已记录到 .rollback-info"
echo ""
echo "===== S1 完成 ====="
```
### S2: 代码同步与验证
```bash
#!/bin/bash
set -e
cd /opt/wecom-it-desk
# 1. 验证 app/ 目录存在且包含关键文件
echo ">>> 验证代码目录..."
for f in app/__init__.py app/main.py app/config.py app/database.py; do
if [ -f "$f" ]; then
echo " PASS: $f 存在"
else
echo " FAIL: $f 不存在!请先解压部署包: tar -xf /tmp/deploy-backend.tar -C ./"
exit 1
fi
done
# 2. 验证 auth 模块(关键!曾因缺失导致故障)
if [ -f "app/api/auth.py" ]; then
echo " PASS: app/api/auth.py 存在"
else
echo " FAIL: app/api/auth.py 不存在!认证功能将不可用"
exit 1
fi
# 3. 统计代码文件数
FILE_COUNT=$(find app/ -name "*.py" | wc -l)
echo " INFO: app/ 目录共 ${FILE_COUNT} 个 Python 文件"
echo ""
echo "===== S2 完成 ====="
```
### S3: 修改 Dockerfile
```bash
#!/bin/bash
set -e
DOCKERFILE=/opt/wecom-it-desk/backend/Dockerfile
echo ">>> 修改 Dockerfile..."
# 直接写入完整文件(最可靠)
cat > "$DOCKERFILE" << 'DOCKERFILE_EOF'
# =============================================================================
# 企微IT智能服务台 — 后端 Docker 镜像构建文件
# =============================================================================
# 说明:基于 Python 3.12 构建后端镜像
# 变更:2025-07-10 方案C — 代码改为 volume 挂载,镜像不再 COPY 业务代码
# 用法:docker build -t wecom-it-desk-backend .
# =============================================================================
# --------------------------------------------------------------------------
# 第一阶段:构建阶段
# --------------------------------------------------------------------------
FROM python:3.12-slim AS builder
# 设置工作目录
WORKDIR /app
# 安装系统依赖(psycopg2 编译需要 + qrcode 图片处理需要 + healthcheck 需要 curl
RUN apt-get update && \
apt-get install -y --no-install-recommends gcc libpq-dev libjpeg-dev zlib1g-dev curl && \
rm -rf /var/lib/apt/lists/*
# 复制依赖声明文件并安装(利用 Docker 层缓存,依赖不变则不重新安装)
COPY requirements.txt .
RUN pip install --no-cache-dir \
--timeout 180 \
--retries 5 \
-i https://mirrors.aliyun.com/pypi/simple/ \
--trusted-host mirrors.aliyun.com \
-r requirements.txt
# --------------------------------------------------------------------------
# 第二阶段:运行阶段(更小的镜像体积)
# --------------------------------------------------------------------------
FROM python:3.12-slim
# 设置标签信息
LABEL maintainer="IT服务台开发团队"
LABEL description="企微IT智能服务台后端服务"
LABEL changelog="2025-07-10: 移除 COPY . .,代码改为 volume 挂载"
# 安装运行时依赖(psycopg2 运行时需要 libpq + healthcheck 需要 curl
RUN apt-get update && \
apt-get install -y --no-install-recommends libpq5 curl && \
rm -rf /var/lib/apt/lists/*
# 设置工作目录
WORKDIR /app
# 禁止 Python 写入 __pycache__(防止污染宿主机代码目录)
ENV PYTHONDONTWRITEBYTECODE=1
# 从构建阶段复制已安装的 Python 包
COPY --from=builder /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
COPY --from=builder /usr/local/bin /usr/local/bin
# 业务代码通过 docker-compose volumes 挂载(./app:/app/app),不再 COPY 进镜像
# 暴露端口
EXPOSE 8000
# 启动命令(Docker Compose 中会覆盖)
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
DOCKERFILE_EOF
# 验证
if grep -q "COPY . ." "$DOCKERFILE"; then
echo " FAIL: Dockerfile 仍包含 COPY . ."
exit 1
fi
if grep -q "PYTHONDONTWRITEBYTECODE" "$DOCKERFILE"; then
echo " PASS: PYTHONDONTWRITEBYTECODE 已设置"
else
echo " FAIL: PYTHONDONTWRITEBYTECODE 未找到"
exit 1
fi
echo " PASS: Dockerfile 已更新"
echo ""
echo "===== S3 完成 ====="
```
### S4: 修改 docker-compose.yml
```bash
#!/bin/bash
set -e
cd /opt/wecom-it-desk
COMPOSE_FILE=/opt/wecom-it-desk/docker-compose.yml
echo ">>> 修改 docker-compose.yml..."
# 在 backend-uploads 行之前插入代码卷挂载行
sed -i '/backend-uploads:\/app\/uploads/i\ - ./app:/app/app # 代码卷挂载(方案C)' "$COMPOSE_FILE"
# 验证
if grep -q "./app:/app/app" "$COMPOSE_FILE"; then
echo " PASS: 代码卷挂载已添加"
else
echo " FAIL: 代码卷挂载未找到,请手动编辑 docker-compose.yml"
echo " 在 backend 服务的 volumes: 下添加:"
echo " - ./app:/app/app"
exit 1
fi
echo ""
echo "===== S4 完成 ====="
```
### S5: 重建镜像并重启
```bash
#!/bin/bash
set -e
cd /opt/wecom-it-desk
echo ">>> 重建后端镜像..."
docker compose build backend
echo " PASS: 镜像构建完成"
echo ""
echo ">>> 重启后端容器..."
docker compose up -d backend
echo " PASS: 容器已启动"
echo ""
echo ">>> 等待服务就绪 (45秒)..."
sleep 45
echo ""
echo "===== S5 完成 ====="
```
### S6: 部署后验证
```bash
#!/bin/bash
cd /opt/wecom-it-desk
echo "===== 部署后验证 ====="
echo ""
# 1. 容器状态
echo "--- 1. 容器状态 ---"
docker compose ps backend
echo ""
# 2. 健康检查
echo "--- 2. 健康检查 ---"
if curl -sf http://localhost:8000/health; then
echo ""
echo " PASS: /health 正常"
else
echo " FAIL: /health 异常"
fi
echo ""
# 3. Auth 模块验证
echo "--- 3. Auth 模块验证 ---"
if docker exec wecom_it_backend python -c "from app.auth import router; print(' auth module: OK')" 2>/dev/null; then
echo " PASS: auth 模块可导入"
else
echo " FAIL: auth 模块导入失败"
echo " 查看日志: docker compose logs --tail=50 backend"
fi
echo ""
# 4. 卷挂载验证
echo "--- 4. 卷挂载验证 ---"
if docker exec wecom_it_backend ls -la /app/app/main.py > /dev/null 2>&1; then
echo " PASS: /app/app/main.py 可访问(卷挂载正常)"
else
echo " FAIL: /app/app/main.py 不可访问(卷挂载异常)"
fi
echo ""
# 5. 代码来源验证
echo "--- 5. 代码来源验证 ---"
HOST_HASH=$(md5sum /opt/wecom-it-desk/app/main.py | awk '{print $1}')
CONTAINER_HASH=$(docker exec wecom_it_backend md5sum /app/app/main.py 2>/dev/null | awk '{print $1}')
if [ "$HOST_HASH" = "$CONTAINER_HASH" ]; then
echo " PASS: 宿主机与容器代码一致 (md5: ${HOST_HASH})"
else
echo " WARN: 宿主机与容器代码不一致"
echo " 宿主机: $HOST_HASH"
echo " 容器: $CONTAINER_HASH"
fi
echo ""
# 6. 日志检查
echo "--- 6. 最近 20 行日志 ---"
docker compose logs --tail=20 backend
echo ""
echo "===== 验证完成 ====="
echo ""
echo "如全部 PASS,部署成功。"
echo "如出现 FAIL,请执行回滚脚本(见上方回滚策略章节)。"
```
### S7: 清理(48 小时后执行)
```bash
#!/bin/bash
set -e
cd /opt/wecom-it-desk
echo ">>> 清理旧代码目录..."
echo " 注意:仅在部署成功 48 小时后执行此步骤!"
echo ""
# 确认服务稳定
curl -sf http://localhost:8000/health > /dev/null && echo " 服务正常" || { echo " 服务异常,取消清理"; exit 1; }
# 删除 backend/app/(不再需要)
if [ -d /opt/wecom-it-desk/backend/app/ ]; then
echo " 删除 backend/app/..."
rm -rf /opt/wecom-it-desk/backend/app/
echo " PASS: backend/app/ 已删除"
else
echo " INFO: backend/app/ 已不存在,跳过"
fi
echo ""
echo "===== 清理完成 ====="
```