Files
ctms/docs/guides/branch-environment-installation.md
T
Cheng Zhou 44db5db838
Client Quality Gates / Shared client and Web (push) Has been cancelled
Client Quality Gates / macOS Desktop (push) Has been cancelled
功能(文档与桌面):完善文件预览下载与客户端构建基线
- 保存文档版本原始文件名,规范下载响应并持久化上传目录\n- 增加 PDF.js 预览、桌面保存打开流程及统一错误反馈\n- 统一 Node.js 22.13 构建基线并收紧临时文件权限门禁\n- 补充迁移、单元测试、发布检查与运维文档
2026-07-13 18:40:48 +08:00

694 lines
14 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.
# CTMS 安装步骤向导
推荐使用安装脚本完成 Docker 部署、环境变量、健康检查和数据迁移。手工步骤保留为排障附录。
- [安装前准备](#安装前准备)
- [推荐脚本安装](#推荐脚本安装)
- [手工安装/排障:dev 分支](#手工安装排障dev-分支)
- [手工安装/排障:main 分支](#手工安装排障main-分支)
- [手工安装/排障:release 分支](#手工安装排障release-分支)
- [常见安装问题](#常见安装问题)
## 安装前准备
三个分支都先完成本节。
### 1. 准备安装目录
```bash
mkdir -p /opt/ctms
cd /opt/ctms
```
### 2. 安装 Docker
Linux 可使用 Docker Engine 或 Docker Desktop。安装完成后确认 Docker Compose v2 可用:
```bash
docker --version
docker compose version
```
如果当前用户不能执行 Docker 命令,将用户加入 `docker` 组后重新登录:
```bash
sudo usermod -aG docker "$USER"
```
macOS 安装 Docker Desktop 后执行:
```bash
docker --version
docker compose version
```
### 3. 安装基础工具
Linux
```bash
sudo apt-get update
sudo apt-get install -y git openssl curl lsof
```
macOS
```bash
brew install git openssl curl
```
### 4. 检查端口
```bash
lsof -nP -iTCP:8888 -sTCP:LISTEN
lsof -nP -iTCP:8000 -sTCP:LISTEN
lsof -nP -iTCP:5432 -sTCP:LISTEN
```
如果命令有输出,先停止占用这些端口的服务,或调整 `docker-compose.yaml` 中的端口映射。
### 5. 拉取代码
首次安装:
```bash
git clone https://github.com/chengchengzhou7/CTMS.git
cd CTMS
```
已有仓库:
```bash
cd /opt/ctms/CTMS
git fetch --prune origin
```
### 6. 确认本地配置不会提交
```bash
grep -n "^\\.env$" .gitignore
grep -n "^\\.env\\.\\*$" .gitignore
```
预期能看到 `.env``.env.*` 已被忽略。
## 推荐脚本安装
推荐使用根目录交互入口:
```bash
./install.sh
```
执行后通过键盘 `↑/↓` 选择安装、更新、卸载、资源状态等操作;`install.sh` 不接受命令行参数。菜单顶部会常驻显示当前 CTMS 容器部署状态,包括已检测到的环境、Compose 项目和容器运行数量。
底层脚本入口(适合自动化或排障时直接调用):
```text
scripts/install.sh 安装:依赖检查、配置准备、构建启动、迁移、健康检查
scripts/update.sh 更新:复用安装流程,不执行 git pull
scripts/uninstall.sh 卸载:默认仅停止并移除容器,不删除数据
scripts/status.sh 状态:使用 docker compose stats --no-stream 采集资源快照并美化展示
scripts/common.sh 公共函数:环境映射、输出样式、危险操作确认
```
安装脚本直接调用格式:
```bash
bash scripts/install.sh dev|main|release [选项]
```
更新、卸载、状态脚本直接调用格式:
```bash
bash scripts/update.sh dev|main|release [安装脚本选项]
bash scripts/uninstall.sh dev|main|release
bash scripts/status.sh dev|main|release
```
常用示例:
```bash
bash scripts/install.sh dev
bash scripts/install.sh main --base-url http://127.0.0.1:8888
bash scripts/install.sh release --base-url https://ctms.example.com
```
可选参数:
```text
--base-url <url> 健康检查使用的访问地址。dev/main 默认 http://127.0.0.1:8888release 必填或交互输入。
--yes 跳过交互确认,适合自动化执行。
--skip-build 跳过镜像构建,仍会执行 docker compose up -d。
--skip-migrate 跳过 alembic upgrade head。
```
脚本会执行:
```text
1. 检查 docker、docker compose、openssl、curl。
2. 检查 .env;已存在则保留不改,不存在则新建。
3. 新建 main/release 的 .env 时自动生成 JWT 和 RSA 私钥。
4. main/release 先构建并执行 backend-init,确保数据库迁移使用当前代码中的 Alembic revision。
5. 启动容器;默认执行 docker compose up -d --build--skip-build 时执行 docker compose up -d。
6. 执行 docker compose run --rm backend python -m alembic upgrade head。
7. 检查容器状态、后端环境、/health、/api/v1/auth/login-key。
```
更新进入“执行部署更新”后会持续显示 Docker 镜像拉取与构建进度:交互终端使用滚动实时输出窗口,CI、远程面板或管道环境直接流式输出构建日志,并在两种模式下显示累计耗时。
脚本不会执行:
```text
git checkout
git pull
docker compose down -v
删除 pg_data
删除 backend/app/uploads
删除数据库 volume
自动安装系统依赖
```
如果只想查看参数说明:
```bash
bash scripts/install.sh --help
```
## 手工安装/排障:dev 分支
### 1. 切换分支
```bash
git checkout dev
git pull --rebase origin dev
```
### 2. 写入环境配置
在仓库根目录创建或覆盖 `.env`
```bash
cat > .env <<'EOF'
COMPOSE_PROJECT_NAME=ctms_dev
ENV=development
JWT_SECRET_KEY=dev-secret
LOGIN_RSA_KEY_ID=default
LOGIN_RSA_PRIVATE_KEY=
EOF
```
### 3. 构建镜像并启动
```bash
docker compose up -d --build
```
### 4. 执行数据库迁移
已有数据库升级到新代码时,启动后执行一次迁移:
```bash
docker compose run --rm backend python -m alembic upgrade head
```
首次空库安装也可以执行该命令;如果已是最新版本,Alembic 不会重复应用迁移。
### 5. 检查容器状态
```bash
docker compose ps
```
确认 `ctms_db``ctms_backend``ctms_nginx` 都是 `Up`,且 `ctms_db``healthy`
### 6. 检查后端环境
```bash
docker compose exec backend python -c "from app.core.config import settings; print('ENV=' + settings.ENV); print('JWT_SECRET_IS_DEV=' + str(settings.JWT_SECRET_KEY == 'dev-secret')); print('LOGIN_RSA_PRIVATE_KEY_SET=' + str(bool(settings.LOGIN_RSA_PRIVATE_KEY)))"
```
预期输出:
```text
ENV=development
JWT_SECRET_IS_DEV=True
LOGIN_RSA_PRIVATE_KEY_SET=False
```
### 7. 检查接口
```bash
curl -i http://127.0.0.1:8888/health
curl -i http://127.0.0.1:8888/api/v1/auth/login-key
```
两个接口都应返回 `HTTP/1.1 200 OK`
### 8. 打开系统
```text
http://localhost:8888
```
### 9. 运行验证
后端:
```bash
docker compose run --rm -v "$PWD/backend/tests:/code/tests:ro" backend python -m pytest
```
前端:
```bash
cd frontend
npm install
npm run test:unit
npm run type-check
npm run build
cd ..
```
## 手工安装/排障:main 分支
### 1. 切换分支
```bash
git checkout main
git pull --rebase origin main
```
### 2. 生成密钥
生成 JWT 密钥:
```bash
openssl rand -hex 32
```
生成 RSA 私钥文件:
```bash
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out login_rsa_main.pem
```
生成可写入 `.env` 的 RSA 私钥单行文本:
```bash
awk '{printf "%s\\n", $0}' login_rsa_main.pem
```
也可以直接生成完整的 `.env` 配置行,复制输出结果替换 `.env` 中的 `LOGIN_RSA_PRIVATE_KEY`
```bash
printf 'LOGIN_RSA_PRIVATE_KEY=%s\n' "$(awk '{printf "%s\\n", $0}' login_rsa_main.pem)"
```
### 3. 写入环境配置
在仓库根目录创建或覆盖 `.env`,将占位符替换为上一步生成的值:
```bash
cat > .env <<'EOF'
COMPOSE_PROJECT_NAME=ctms_main
ENV=production
JWT_SECRET_KEY=<替换为 JWT 密钥>
LOGIN_RSA_KEY_ID=main-YYYYMMDD
LOGIN_RSA_PRIVATE_KEY=<替换为 RSA 私钥单行文本>
EOF
```
### 4. 检查 Compose 配置
```bash
docker compose config
```
确认输出中包含:
```text
ENV: production
LOGIN_RSA_KEY_ID: main-YYYYMMDD
LOGIN_RSA_PRIVATE_KEY: '-----BEGIN PRIVATE KEY-----...'
```
### 5. 初始化数据库
```bash
docker compose run --rm --build backend-init
```
### 6. 构建镜像并启动
```bash
docker compose up -d --build
```
### 7. 执行数据库迁移
已有数据库升级到新代码时,启动后执行一次迁移:
```bash
docker compose run --rm backend python -m alembic upgrade head
```
`backend-init` 会在初始化时处理空库和已有库迁移;这里单独执行迁移用于确认部署代码已落到最新数据库版本。
### 8. 检查容器状态
```bash
docker compose ps
```
确认 `ctms_db``ctms_backend``ctms_nginx` 都是 `Up`,且 `ctms_db``healthy`
### 9. 检查后端环境
```bash
docker compose exec backend python -c "from app.core.config import settings; print('ENV=' + settings.ENV); print('JWT_SECRET_IS_DEV=' + str(settings.JWT_SECRET_KEY == 'dev-secret')); print('LOGIN_RSA_PRIVATE_KEY_SET=' + str(bool(settings.LOGIN_RSA_PRIVATE_KEY))); print('LOGIN_RSA_KEY_ID=' + settings.LOGIN_RSA_KEY_ID)"
```
预期输出:
```text
ENV=production
JWT_SECRET_IS_DEV=False
LOGIN_RSA_PRIVATE_KEY_SET=True
LOGIN_RSA_KEY_ID=main-YYYYMMDD
```
### 10. 检查接口
本机:
```bash
curl -i http://127.0.0.1:8888/health
curl -i http://127.0.0.1:8888/api/v1/auth/login-key
```
远程域名:
```bash
curl -i https://<main-domain>/health
curl -i https://<main-domain>/api/v1/auth/login-key
```
接口应返回 `HTTP/1.1 200 OK`
### 11. 打开系统
本机:
```text
http://localhost:8888
```
远程访问:
```text
https://<main-domain>
```
远程访问必须使用 HTTPS。
### 12. 运行验证
后端:
```bash
docker compose run --rm -v "$PWD/backend/tests:/code/tests:ro" backend python -m pytest
```
前端:
```bash
cd frontend
npm install
npm run test:unit
npm run type-check
npm run build
cd ..
```
## 手工安装/排障:release 分支
### 1. 切换分支
```bash
git checkout release
git pull --rebase origin release
```
### 2. 准备 HTTPS 域名
正式访问地址必须是:
```text
https://<production-domain>
```
如果服务器前面有反向代理,确认代理规则:
```text
/ -> CTMS nginx 8888
/api/* -> CTMS nginx 8888
/health -> CTMS nginx 8888
```
### 3. 生成密钥
生成 JWT 密钥:
```bash
openssl rand -hex 32
```
生成 RSA 私钥文件:
```bash
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out login_rsa_release.pem
```
生成可写入 `.env` 的 RSA 私钥单行文本:
```bash
awk '{printf "%s\\n", $0}' login_rsa_release.pem
```
也可以直接生成完整的 `.env` 配置行,复制输出结果替换 `.env` 中的 `LOGIN_RSA_PRIVATE_KEY`
```bash
printf 'LOGIN_RSA_PRIVATE_KEY=%s\n' "$(awk '{printf "%s\\n", $0}' login_rsa_release.pem)"
```
`login_rsa_release.pem` 保存到服务器安全目录或密钥管理系统。
### 4. 写入环境配置
在仓库根目录创建或覆盖 `.env`,将占位符替换为生产值:
```bash
cat > .env <<'EOF'
COMPOSE_PROJECT_NAME=ctms_release
ENV=production
JWT_SECRET_KEY=<替换为生产 JWT 密钥>
LOGIN_RSA_KEY_ID=release-YYYYMMDD
LOGIN_RSA_PRIVATE_KEY=<替换为生产 RSA 私钥单行文本>
EOF
```
确认 `.env` 没有进入 Git 暂存区:
```bash
git status --short .env
```
预期无输出。
### 5. 检查 Compose 配置
```bash
docker compose config
```
确认输出中包含:
```text
ENV: production
JWT_SECRET_KEY: <不是 dev-secret>
LOGIN_RSA_KEY_ID: release-YYYYMMDD
LOGIN_RSA_PRIVATE_KEY: '-----BEGIN PRIVATE KEY-----...'
```
### 6. 初始化数据库
```bash
docker compose run --rm --build backend-init
```
确认命令成功后再启动服务。
### 7. 构建镜像并启动
```bash
docker compose up -d --build
```
### 8. 执行数据库迁移
已有数据库升级到新代码时,启动后执行一次迁移:
```bash
docker compose run --rm backend python -m alembic upgrade head
```
`backend-init` 会在初始化时处理空库和已有库迁移;这里单独执行迁移用于确认部署代码已落到最新数据库版本。
### 9. 检查容器状态
```bash
docker compose ps
```
确认 `ctms_db``ctms_backend``ctms_nginx` 都是 `Up`,且 `ctms_db``healthy`
### 10. 检查后端环境
```bash
docker compose exec backend python -c "from app.core.config import settings; print('ENV=' + settings.ENV); print('JWT_SECRET_IS_DEV=' + str(settings.JWT_SECRET_KEY == 'dev-secret')); print('LOGIN_RSA_PRIVATE_KEY_SET=' + str(bool(settings.LOGIN_RSA_PRIVATE_KEY))); print('LOGIN_RSA_KEY_ID=' + settings.LOGIN_RSA_KEY_ID)"
```
预期输出:
```text
ENV=production
JWT_SECRET_IS_DEV=False
LOGIN_RSA_PRIVATE_KEY_SET=True
LOGIN_RSA_KEY_ID=release-YYYYMMDD
```
### 11. 检查生产接口
```bash
curl -i https://<production-domain>/health
curl -i https://<production-domain>/api/v1/auth/login-key
```
两个接口都应返回 `HTTP/1.1 200 OK`
### 12. 打开系统并登录
```text
https://<production-domain>
```
初始化管理员:
```text
admin@huapont.cn / admin123
```
首次登录后立即修改初始密码。
### 13. 发布后检查
查看容器:
```bash
docker compose ps
```
查看后端日志:
```bash
docker compose logs --tail=200 backend
```
查看 nginx 日志:
```bash
docker compose logs --tail=200 nginx
```
执行 smoke
```bash
BASE_URL=https://<production-domain> EMAIL=<admin-email> PASSWORD=<admin-password> bash docs/setup-config-curl-smoke.sh
```
## 常见安装问题
### 端口被占用
检查:
```bash
lsof -nP -iTCP:8888 -sTCP:LISTEN
lsof -nP -iTCP:8000 -sTCP:LISTEN
lsof -nP -iTCP:5432 -sTCP:LISTEN
```
处理:停止占用进程,或调整 `docker-compose.yaml` 端口映射。
### 容器名冲突
检查:
```bash
docker ps -a --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
```
处理:
```bash
docker compose down
```
如果同一台机器要同时运行多套 CTMS,需为每套环境调整 `docker-compose.yaml` 中的 `container_name` 和端口。
### production 启动失败
检查:
```bash
grep -n "ENV\\|JWT_SECRET_KEY\\|LOGIN_RSA" .env
```
确认:
```text
ENV=production
JWT_SECRET_KEY 不是 dev-secret
LOGIN_RSA_PRIVATE_KEY 不是空值
LOGIN_RSA_PRIVATE_KEY 包含 -----BEGIN PRIVATE KEY-----
```
### 远程访问无法登录
检查当前浏览器地址。如果不是 `https://`,改用 HTTPS 域名访问:
```text
https://<domain>
```
本机 `dev` 可使用:
```text
http://localhost:8888
```
### 切换分支后环境不正确
重新执行对应分支的 `.env` 配置,然后重建:
```bash
docker compose up -d --build backend nginx
```
再检查:
```bash
docker compose exec backend python -c "from app.core.config import settings; print(settings.ENV)"
```