Files
ctms/docs/guides/branch-environment-installation.md
T
Cheng Zhou efc325568d 美化终端脚本 UI 并修复对齐与闪屏
- 配色体系:256 色语义色板(primary/accent/success/warn/danger)与统一图标常量
- 修复右边框对齐:ctms_text_width 用 perl 精确计算显示宽度,剥离 sgr0 的 \e(B 序列
- 修复菜单闪屏:改用光标归位原地覆盖重绘,去掉每帧清屏
- 美化各面板:install.sh banner/确认/成功框、根菜单、status.sh 资源表格,标签列对齐
- 新增 ctms_pad_right 按显示宽度填充含中文标签

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 15:24:22 +08:00

14 KiB
Raw Blame History

CTMS 安装步骤向导

推荐使用安装脚本完成 Docker 部署、环境变量、健康检查和数据迁移。手工步骤保留为排障附录。

安装前准备

三个分支都先完成本节。

1. 准备安装目录

mkdir -p /opt/ctms
cd /opt/ctms

2. 安装 Docker

Linux 可使用 Docker Engine 或 Docker Desktop。安装完成后确认 Docker Compose v2 可用:

docker --version
docker compose version

如果当前用户不能执行 Docker 命令,将用户加入 docker 组后重新登录:

sudo usermod -aG docker "$USER"

macOS 安装 Docker Desktop 后执行:

docker --version
docker compose version

3. 安装基础工具

Linux

sudo apt-get update
sudo apt-get install -y git openssl curl lsof

macOS

brew install git openssl curl

4. 检查端口

lsof -nP -iTCP:8888 -sTCP:LISTEN
lsof -nP -iTCP:8000 -sTCP:LISTEN
lsof -nP -iTCP:5432 -sTCP:LISTEN

如果命令有输出,先停止占用这些端口的服务,或调整 docker-compose.yaml 中的端口映射。

5. 拉取代码

首次安装:

git clone https://github.com/chengchengzhou7/CTMS.git
cd CTMS

已有仓库:

cd /opt/ctms/CTMS
git fetch --prune origin

6. 确认本地配置不会提交

grep -n "^\\.env$" .gitignore
grep -n "^\\.env\\.\\*$" .gitignore

预期能看到 .env.env.* 已被忽略。

推荐脚本安装

推荐使用根目录交互入口:

./install.sh

执行后通过键盘 ↑/↓ 选择安装、更新、卸载、资源状态等操作;install.sh 不接受命令行参数。菜单顶部会常驻显示当前 CTMS 容器部署状态,包括已检测到的环境、Compose 项目和容器运行数量。

底层脚本入口(适合自动化或排障时直接调用):

scripts/install.sh     安装:依赖检查、配置准备、构建启动、迁移、健康检查
scripts/update.sh      更新:复用安装流程,不执行 git pull
scripts/uninstall.sh   卸载:默认仅停止并移除容器,不删除数据
scripts/status.sh      状态:使用 docker compose stats --no-stream 采集资源快照并美化展示
scripts/common.sh      公共函数:环境映射、输出样式、危险操作确认

安装脚本直接调用格式:

bash scripts/install.sh dev|main|release [选项]

更新、卸载、状态脚本直接调用格式:

bash scripts/update.sh dev|main|release [安装脚本选项]
bash scripts/uninstall.sh dev|main|release
bash scripts/status.sh dev|main|release

常用示例:

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

可选参数:

--base-url <url>   健康检查使用的访问地址。dev/main 默认 http://127.0.0.1:8888release 必填或交互输入。
--yes              跳过交互确认,适合自动化执行。
--skip-build       跳过镜像构建,仍会执行 docker compose up -d。
--skip-migrate     跳过 alembic upgrade head。

脚本会执行:

1. 检查 docker、docker compose、openssl、curl。
2. 检查 .env;已存在则保留不改,不存在则新建。
3. 新建 main/release 的 .env 时自动生成 JWT 和 RSA 私钥。
4. main/release 先执行 backend-init。
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。

脚本不会执行:

git checkout
git pull
docker compose down -v
删除 pg_data
删除数据库 volume
自动安装系统依赖

如果只想查看参数说明:

bash scripts/install.sh --help

手工安装/排障:dev 分支

1. 切换分支

git checkout dev
git pull --rebase origin dev

2. 写入环境配置

在仓库根目录创建或覆盖 .env

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. 构建镜像并启动

docker compose up -d --build

4. 执行数据库迁移

已有数据库升级到新代码时,启动后执行一次迁移:

docker compose run --rm backend python -m alembic upgrade head

首次空库安装也可以执行该命令;如果已是最新版本,Alembic 不会重复应用迁移。

5. 检查容器状态

docker compose ps

确认 ctms_dbctms_backendctms_nginx 都是 Up,且 ctms_dbhealthy

6. 检查后端环境

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)))"

预期输出:

ENV=development
JWT_SECRET_IS_DEV=True
LOGIN_RSA_PRIVATE_KEY_SET=False

7. 检查接口

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. 打开系统

http://localhost:8888

9. 运行验证

后端:

docker compose run --rm -v "$PWD/backend/tests:/code/tests:ro" backend python -m pytest

前端:

cd frontend
npm install
npm run test:unit
npm run type-check
npm run build
cd ..

手工安装/排障:main 分支

1. 切换分支

git checkout main
git pull --rebase origin main

2. 生成密钥

生成 JWT 密钥:

openssl rand -hex 32

生成 RSA 私钥文件:

openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out login_rsa_main.pem

生成可写入 .env 的 RSA 私钥单行文本:

awk '{printf "%s\\n", $0}' login_rsa_main.pem

也可以直接生成完整的 .env 配置行,复制输出结果替换 .env 中的 LOGIN_RSA_PRIVATE_KEY

printf 'LOGIN_RSA_PRIVATE_KEY=%s\n' "$(awk '{printf "%s\\n", $0}' login_rsa_main.pem)"

3. 写入环境配置

在仓库根目录创建或覆盖 .env,将占位符替换为上一步生成的值:

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 配置

docker compose config

确认输出中包含:

ENV: production
LOGIN_RSA_KEY_ID: main-YYYYMMDD
LOGIN_RSA_PRIVATE_KEY: '-----BEGIN PRIVATE KEY-----...'

5. 初始化数据库

docker compose run --rm backend-init

6. 构建镜像并启动

docker compose up -d --build

7. 执行数据库迁移

已有数据库升级到新代码时,启动后执行一次迁移:

docker compose run --rm backend python -m alembic upgrade head

backend-init 会在初始化时处理空库和已有库迁移;这里单独执行迁移用于确认部署代码已落到最新数据库版本。

8. 检查容器状态

docker compose ps

确认 ctms_dbctms_backendctms_nginx 都是 Up,且 ctms_dbhealthy

9. 检查后端环境

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)"

预期输出:

ENV=production
JWT_SECRET_IS_DEV=False
LOGIN_RSA_PRIVATE_KEY_SET=True
LOGIN_RSA_KEY_ID=main-YYYYMMDD

10. 检查接口

本机:

curl -i http://127.0.0.1:8888/health
curl -i http://127.0.0.1:8888/api/v1/auth/login-key

远程域名:

curl -i https://<main-domain>/health
curl -i https://<main-domain>/api/v1/auth/login-key

接口应返回 HTTP/1.1 200 OK

11. 打开系统

本机:

http://localhost:8888

远程访问:

https://<main-domain>

远程访问必须使用 HTTPS。

12. 运行验证

后端:

docker compose run --rm -v "$PWD/backend/tests:/code/tests:ro" backend python -m pytest

前端:

cd frontend
npm install
npm run test:unit
npm run type-check
npm run build
cd ..

手工安装/排障:release 分支

1. 切换分支

git checkout release
git pull --rebase origin release

2. 准备 HTTPS 域名

正式访问地址必须是:

https://<production-domain>

如果服务器前面有反向代理,确认代理规则:

/       -> CTMS nginx 8888
/api/*  -> CTMS nginx 8888
/health -> CTMS nginx 8888

3. 生成密钥

生成 JWT 密钥:

openssl rand -hex 32

生成 RSA 私钥文件:

openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out login_rsa_release.pem

生成可写入 .env 的 RSA 私钥单行文本:

awk '{printf "%s\\n", $0}' login_rsa_release.pem

也可以直接生成完整的 .env 配置行,复制输出结果替换 .env 中的 LOGIN_RSA_PRIVATE_KEY

printf 'LOGIN_RSA_PRIVATE_KEY=%s\n' "$(awk '{printf "%s\\n", $0}' login_rsa_release.pem)"

login_rsa_release.pem 保存到服务器安全目录或密钥管理系统。

4. 写入环境配置

在仓库根目录创建或覆盖 .env,将占位符替换为生产值:

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 暂存区:

git status --short .env

预期无输出。

5. 检查 Compose 配置

docker compose config

确认输出中包含:

ENV: production
JWT_SECRET_KEY: <不是 dev-secret>
LOGIN_RSA_KEY_ID: release-YYYYMMDD
LOGIN_RSA_PRIVATE_KEY: '-----BEGIN PRIVATE KEY-----...'

6. 初始化数据库

docker compose run --rm backend-init

确认命令成功后再启动服务。

7. 构建镜像并启动

docker compose up -d --build

8. 执行数据库迁移

已有数据库升级到新代码时,启动后执行一次迁移:

docker compose run --rm backend python -m alembic upgrade head

backend-init 会在初始化时处理空库和已有库迁移;这里单独执行迁移用于确认部署代码已落到最新数据库版本。

9. 检查容器状态

docker compose ps

确认 ctms_dbctms_backendctms_nginx 都是 Up,且 ctms_dbhealthy

10. 检查后端环境

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)"

预期输出:

ENV=production
JWT_SECRET_IS_DEV=False
LOGIN_RSA_PRIVATE_KEY_SET=True
LOGIN_RSA_KEY_ID=release-YYYYMMDD

11. 检查生产接口

curl -i https://<production-domain>/health
curl -i https://<production-domain>/api/v1/auth/login-key

两个接口都应返回 HTTP/1.1 200 OK

12. 打开系统并登录

https://<production-domain>

初始化管理员:

admin@huapont.cn / admin123

首次登录后立即修改初始密码。

13. 发布后检查

查看容器:

docker compose ps

查看后端日志:

docker compose logs --tail=200 backend

查看 nginx 日志:

docker compose logs --tail=200 nginx

执行 smoke

BASE_URL=https://<production-domain> EMAIL=<admin-email> PASSWORD=<admin-password> bash docs/setup-config-curl-smoke.sh

常见安装问题

端口被占用

检查:

lsof -nP -iTCP:8888 -sTCP:LISTEN
lsof -nP -iTCP:8000 -sTCP:LISTEN
lsof -nP -iTCP:5432 -sTCP:LISTEN

处理:停止占用进程,或调整 docker-compose.yaml 端口映射。

容器名冲突

检查:

docker ps -a --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"

处理:

docker compose down

如果同一台机器要同时运行多套 CTMS,需为每套环境调整 docker-compose.yaml 中的 container_name 和端口。

production 启动失败

检查:

grep -n "ENV\\|JWT_SECRET_KEY\\|LOGIN_RSA" .env

确认:

ENV=production
JWT_SECRET_KEY 不是 dev-secret
LOGIN_RSA_PRIVATE_KEY 不是空值
LOGIN_RSA_PRIVATE_KEY 包含 -----BEGIN PRIVATE KEY-----

远程访问无法登录

检查当前浏览器地址。如果不是 https://,改用 HTTPS 域名访问:

https://<domain>

本机 dev 可使用:

http://localhost:8888

切换分支后环境不正确

重新执行对应分支的 .env 配置,然后重建:

docker compose up -d --build backend nginx

再检查:

docker compose exec backend python -c "from app.core.config import settings; print(settings.ENV)"