# 17 domainCheck 手工部署实操手册 ## 一、文档目标 这份文档只讲一件事: > 不依赖一键脚本,完全手工完成部署、更新、排障和扩容。 它不是设计说明,也不是零散检查单,而是给实际部署时直接照着做的“手工操作手册”。 文档边界: - 这里只讲手工部署 - 不使用 `install_overseas_quick.sh` - 不使用 `install_mainland_controller_quick.sh` - 不使用 `install_mainland_worker_quick.sh` - 如果你想走傻瓜式复制部署,请改看: - [18_domainCheck_CentOS9一键复制部署与更新文档.md](/www/wwwroot/getDomain/docs/18_domainCheck_CentOS9一键复制部署与更新文档.md:1) 适用场景: - 先在国外机器完成单机部署与联调 - 后续再扩到“国外控制面 + 大陆执行面” - 当前暂时无法把代码真正部署到大陆机器时,先在国外机器模拟多节点联调 - 最后再把同样的部署方式复制到其他机器 一句话理解: > 先把国外主控机部署好,再按同样套路扩第二台、第三台,不靠临场猜。 并发配置补充: - 系统支持 `默认线程数 + 节点单独覆盖` - 节点单独覆盖按机器自己的 `NODE_CODE` 命中 - 某台机器没配置覆盖值时,自动回退到默认线程数 ## 二、推荐部署形态 ### 1. 当前最推荐起步形态 - 国外机器 `1` 台: - `domain-web` - `domain-api` - PostgreSQL - Redis - `domaincheck-worker` - 后续扩容时: - 新增大陆 `controller` - 新增大陆 `worker` 说明: - 因为你当前还不能直接把代码稳定部署到大陆机器,所以第一阶段先把国外机器单机跑稳 - 这台国外机器同时承担: - 后台 - API - 数据库 - Redis - Worker - 等这套稳定后,再把多机脚本复制到其他机器 ### 2. 最终推荐形态 - 国外 `control`: - `domain-web` - `domain-api` - 主 PostgreSQL - 结果归档 - 大陆 `controller`: - Redis - 运行态 PostgreSQL - `domaincheck-worker` - `domaincheck-sync-agent` - 大陆 `worker`: - `domaincheck-worker` ## 三、服务器准备 ### 1. 系统要求 - CentOS Stream 9 - Python `3.11` - PostgreSQL `14+` - Redis `6+` - Nginx 关键说明: - 这里的 Python 不是“系统自带什么就用什么” - 必须明确安装 `python3.11` - 不能只装系统默认 `python3` - 因为后续部署命令直接使用的是 `python3.11 -m venv .venv` 推荐先执行: ```bash dnf install -y python3.11 python3.11-devel python3.11 --version ``` 期望输出类似: ```text Python 3.11.x ``` ### 2. 目录约定 统一使用: ```text /opt/domaincheck ├── domain-api ├── domain-web └── domainCheck ``` ### 3. 当前仓库与运行态关系 如果你像当前测试机一样,用仓库目录做源码源头,也可以用软链接: ```bash ln -s /www/wwwroot/getDomain/domain-api /opt/domaincheck/domain-api ln -s /www/wwwroot/getDomain/domain-web /opt/domaincheck/domain-web ln -s /www/wwwroot/getDomain/domainCheck /opt/domaincheck/domainCheck ``` 如果你是完整复制代码到目标机,也可以直接把目录上传到 `/opt/domaincheck/`。 ## 四、第一阶段:国外单机部署 这一阶段的目标是: - 后台可访问 - API 正常 - 数据库已初始化 - Worker 可跑 - 运行中心正常 - smoke test 通过 ### 1. 拉取代码 当前建议统一走 `git` 管理和更新,不再手工散传目录。 执行口径: - 这里建议直接使用 `root` - 不建议使用 `www` 用户执行整套部署命令 - 因为后面还会接着写 `systemd`、`/etc/default/`、`/opt/domaincheck/` 和服务启停 第一次部署建议: ```bash mkdir -p /www/wwwroot cd /www/wwwroot git clone 你的仓库地址 getDomain cd getDomain git checkout main git pull origin main ``` 然后建立运行目录软链接: ```bash mkdir -p /opt/domaincheck ln -s /www/wwwroot/getDomain/domain-api /opt/domaincheck/domain-api ln -s /www/wwwroot/getDomain/domain-web /opt/domaincheck/domain-web ln -s /www/wwwroot/getDomain/domainCheck /opt/domaincheck/domainCheck ``` 后续更新统一使用: ```bash cd /www/wwwroot/getDomain git fetch --all git checkout main git pull --ff-only origin main ``` ### 1.1 先确认 Python 3.11 已安装 如果当前机器还没有 `python3.11`,先执行: ```bash dnf install -y python3.11 python3.11-devel python3.11 --version ``` 只有确认 `python3.11` 命令存在后,再继续下面的虚拟环境步骤。 ### 2. 创建 Python 虚拟环境 ```bash cd /opt/domaincheck/domainCheck python3.11 -m venv .venv source .venv/bin/activate pip install --upgrade pip python3.11 - <<'PY' from pathlib import Path source = Path("requirements.txt") target = Path("requirements.linux.txt") raw = source.read_bytes() for encoding in ("utf-8", "utf-16", "utf-16-le", "utf-16-be", "gbk"): try: text = raw.decode(encoding) break except UnicodeDecodeError: continue else: raise SystemExit("无法解析 requirements.txt 编码") skip_prefixes = ( "pywin32==", "pywin32-ctypes==", "twisted-iocpsupport==", "win32-setctime==", ) lines = [] for line in text.splitlines(): normalized = line.strip().lstrip("\ufeff") if normalized.lower().startswith(skip_prefixes): continue lines.append(normalized) target.write_text("\n".join(lines) + "\n", encoding="utf-8") PY pip install -r requirements.linux.txt ``` 然后补 API 依赖: ```bash cd /opt/domaincheck/domain-api /opt/domaincheck/domainCheck/.venv/bin/pip install fastapi uvicorn pydantic-settings psycopg2-binary redis openpyxl python-multipart ``` 补充说明: - 这里不能直接在 Linux 上裸跑 `pip install -r requirements.txt` - 因为桌面版历史依赖里包含 `pywin32` 等 Windows-only 包 - 手工部署时也必须先生成 `requirements.linux.txt` 再安装 ### 3. 配置数据库和 Redis 确保 PostgreSQL 和 Redis 可用。 建议先确认: ```bash psql -h 127.0.0.1 -U postgres -d domain -c "select 1;" redis-cli ping ``` ### 4. 配置 `domainCheck/.env` 至少确认这些项: ```env DB_HOST=127.0.0.1 DB_PORT=5432 DB_DATABASE=domain DB_USER=postgres DB_PASSWORD=你的密码 REDIS_HOST=127.0.0.1 REDIS_PORT=6379 REDIS_PASSWORD= REDIS_DB=0 ``` ### 5. 初始化数据库 这是最重要的一步,新库必须先做: ```bash cd /opt/domaincheck/domainCheck python3 init_database.py ``` 如果不先执行,至少这些接口会直接 `500`: - `/api/v1/dashboard/overview` - `/api/v1/detect/status` - `/api/v1/imports/summary` ### 6. 构建前端 进入 `domain-web`,配置生产环境 API 地址: ```bash cd /opt/domaincheck/domain-web cp .env.production.example .env.production ``` 把 `VITE_API_BASE_URL` 改成目标 API,例如: ```env VITE_API_BASE_URL=https://api.domain.com/api/v1 ``` 然后构建: ```bash npm install npm run build ``` ### 7. 配置 Nginx 参考: - `domain-web/deploy/nginx/domain-web.conf` 把静态目录指到: ```text /opt/domaincheck/domain-web/dist ``` 常见做法: - `admin.domain` 对外提供后台页面 - `api.domain.com` 对外提供 API ### 8. 安装 systemd 服务 复制模板: ```bash cp /opt/domaincheck/domain-api/deploy/systemd/domain-api.service /etc/systemd/system/domaincheck-api.service cp /opt/domaincheck/domain-api/deploy/systemd/domain-worker.service /etc/systemd/system/domaincheck-worker.service ``` ### 9. 配置 API 环境变量 建议使用: ```bash cp /opt/domaincheck/domain-api/deploy/multi-region/templates/domaincheck-api.env.example /etc/default/domaincheck-api ``` 至少改这些: ```env WORKER_MODE=linux-systemd API_HOST=0.0.0.0 API_PORT=8100 DOMAIN_ROOT=/opt/domaincheck/domainCheck NODE_CODE=overseas-control-01 NODE_REGION=overseas NODE_ROLE=control CORS_ORIGINS='["http://127.0.0.1:3201","http://localhost:3201","http://你的服务器IP:3201"]' SYNC_PUSH_ENABLED=false ``` 如果你已经固定域名,建议直接改成: ```env CORS_ORIGINS='["https://admin.domain","http://127.0.0.1:3201","http://localhost:3201"]' ``` ### 10. 修正权限 ```bash mkdir -p /opt/domaincheck/domain-api/runtime touch /opt/domaincheck/domainCheck/detect_worker.log chown -R www:www /opt/domaincheck/domain-api/runtime chown www:www /opt/domaincheck/domainCheck/detect_worker.log chmod 664 /opt/domaincheck/domainCheck/detect_worker.log ``` ### 11. 启动服务 ```bash systemctl daemon-reload systemctl enable domaincheck-api systemctl enable domaincheck-worker systemctl restart domaincheck-api systemctl restart domaincheck-worker ``` ### 12. 检查服务状态 ```bash systemctl status domaincheck-api --no-pager -l systemctl status domaincheck-worker --no-pager -l ``` ## 五、第一阶段验收 ### 1. 接口检查 ```bash curl http://127.0.0.1:8100/health curl http://127.0.0.1:8100/api/v1/runtime/preflight curl http://127.0.0.1:8100/api/v1/runtime/status curl http://127.0.0.1:8100/api/v1/runtime/readiness ``` 期望: - `/health.status=ok` - `/health.worker_mode=linux-systemd` - `/runtime/preflight.ok=true` - `/runtime/status.worker.running=true` - `/runtime/readiness.status` 至少不是 `blocking` ### 2. smoke test ```bash cd /opt/domaincheck/domain-api/deploy/linux python3 smoke_test.py --base-url http://127.0.0.1:8100 ``` 如果要连 Web 一起检查: ```bash python3 smoke_test.py --base-url http://127.0.0.1:8100 --web-url http://127.0.0.1:3201 ``` 期望: - `ok=true` ### 3. 后台页面检查 浏览器打开: ```text https://admin.domain ``` 至少检查: - 登录 - 运行中心 - 系统设置 - 域名筛选 - 导入 - 导出 ## 六、第二阶段:国外机器模拟多机联调 如果你暂时还不能把代码部署到大陆机器,就先在国外机器做这一步。 ### 1. 一键多机演练 ```bash cd /opt/domaincheck/domain-api bash deploy/multi-region/rehearse_multi_region.sh http://127.0.0.1:8100 ``` 它会自动模拟: - 一个大陆 controller - 两个大陆 worker 并自动检查: - `runtime/readiness` - `runtime/cluster` - online control / online worker 数量 - 节点状态是否符合预期 ### 2. 通过标准 如果输出里出现: ```text rehearsal passed ``` 说明当前这台国外机器上的多机模拟联调已通过,可以继续部署到其他机器。 ### 3. 如果想手工模拟 也可以单独跑: ```bash cd /opt/domaincheck/domain-api bash deploy/multi-region/simulate_multi_region.sh http://127.0.0.1:8100 ``` 停止时按: ```text Ctrl+C ``` ### 4. 清理旧节点残影 如果之前测试过多轮,集群里可能残留老节点: ```bash cd /opt/domaincheck/domain-api bash deploy/multi-region/prune_cluster_nodes.sh --minutes 30 --dry-run bash deploy/multi-region/prune_cluster_nodes.sh --minutes 30 ``` 如果只删某个旧节点: ```bash bash deploy/multi-region/prune_cluster_nodes.sh --node-code mainland-worker-01 ``` ## 七、第三阶段:部署到其他机器 等国外单机和模拟多机都通过后,就可以把同样的代码与脚本部署到其他机器。 ### A. 新海外控制机 在目标机执行: ```bash cd /opt/domaincheck/domain-api bash deploy/multi-region/bootstrap_overseas.sh /opt/domaincheck ``` 然后完善: - `/etc/default/domaincheck-api` - Nginx - PostgreSQL - Redis 最后检查: ```bash bash deploy/multi-region/check_cluster.sh http://127.0.0.1:8100 ``` ### B. 大陆 controller 在目标机执行: ```bash cd /opt/domaincheck/domain-api bash deploy/multi-region/bootstrap_mainland.sh /opt/domaincheck controller ``` 然后检查: ```bash bash deploy/multi-region/check_mainland_controller.sh ``` 关键配置是: ```env NODE_CODE=mainland-controller-01 NODE_REGION=mainland NODE_ROLE=control SYNC_PUSH_ENABLED=true SYNC_SOURCE_REGION=mainland SYNC_TARGET_REGION=overseas SYNC_TARGET_API_BASE_URL=http://海外控制面IP:8100/api/v1 SYNC_SHARED_TOKEN=你自己的共享令牌 ``` ### C. 大陆 worker 在目标机执行: ```bash cd /opt/domaincheck/domain-api bash deploy/multi-region/bootstrap_mainland.sh /opt/domaincheck worker ``` 关键配置是: ```env NODE_CODE=mainland-worker-01 NODE_REGION=mainland NODE_ROLE=worker SYNC_PUSH_ENABLED=true SYNC_SOURCE_REGION=mainland SYNC_TARGET_REGION=overseas SYNC_TARGET_API_BASE_URL=http://海外控制面IP:8100/api/v1 ``` ## 八、部署到其他机器后的联调顺序 建议按这个顺序,不容易乱: 1. 先让海外控制机稳定 2. 再接大陆 controller 3. 再接第一台大陆 worker 4. 再接第二台、第三台 worker 每接一台都执行: ```bash curl http://海外控制机:8100/api/v1/runtime/readiness curl http://海外控制机:8100/api/v1/runtime/cluster curl http://海外控制机:8100/api/v1/runtime/sync-summary ``` 如果海外 API 已经挂到正式域名,建议直接写成: ```bash curl https://api.domain.com/api/v1/runtime/readiness curl https://api.domain.com/api/v1/runtime/cluster curl https://api.domain.com/api/v1/runtime/sync-summary ``` ### 联调通过标准 - `runtime/cluster` 能看到新节点 - `last_heartbeat_at` 持续刷新 - 大陆 controller 为 `role=control` - 大陆 worker 为 `role=worker` - 执行任务时 worker 状态能变成 `busy` - `runtime/readiness` 至少不是 `blocking` - `runtime/sync-summary` 能看到 `detect_result_batches` ## 九、上线前最后检查 按这份文档部署完成后,再回看: - [14_domainCheck_正式上线前最终检查单.md](/www/wwwroot/getDomain/docs/14_domainCheck_正式上线前最终检查单.md:1) 重点保留: - `systemctl status` - `journalctl` - `/health` - `/runtime/preflight` - `/runtime/readiness` - `/runtime/sync-summary` - `smoke test` - 诊断包 ## 十、常见问题 ### 1. API 启动了,但接口 500 优先检查有没有先执行: ```bash cd /opt/domaincheck/domainCheck python3 init_database.py ``` ### 2. Worker 一直重启 优先检查: - `/opt/domaincheck/domainCheck/detect_worker.log` 权限 - `/opt/domaincheck/domain-api/runtime/` 权限 - `domainCheck/.env` 数据库和 Redis 配置 ### 3. readiness 一直是 `attention` 优先检查: - 集群里是否残留旧离线节点 - 是否还没接入大陆 controller - 是否还没有在线 worker 必要时先清理旧节点: ```bash bash deploy/multi-region/prune_cluster_nodes.sh --minutes 30 ``` ### 4. 模拟多机通过了,真实机器还没接上 这是正常的。 模拟多机的意义是: - 验证代码、脚本、页面、状态口径一致 - 不代表真实大陆网络、代理、同步链路已经完成 真实机器接入时,重点要再看: - 节点心跳 - 同步目标地址 - 共享 token - 真实 Redis / PostgreSQL 连接 ## 十一、最短执行版本 如果你只想看最短版,可以照这个跑: ### 国外单机先跑通 ```bash cd /opt/domaincheck/domainCheck python3.11 -m venv .venv source .venv/bin/activate pip install -r requirements.txt python3 init_database.py cd /opt/domaincheck/domain-api /opt/domaincheck/domainCheck/.venv/bin/pip install fastapi uvicorn pydantic-settings psycopg2-binary redis openpyxl python-multipart systemctl daemon-reload systemctl enable domaincheck-api domaincheck-worker systemctl restart domaincheck-api domaincheck-worker curl http://127.0.0.1:8100/health curl http://127.0.0.1:8100/api/v1/runtime/preflight curl http://127.0.0.1:8100/api/v1/runtime/readiness ``` ### 再跑多机模拟验收 ```bash cd /opt/domaincheck/domain-api bash deploy/multi-region/rehearse_multi_region.sh http://127.0.0.1:8100 ``` ### 通过后再上其他机器 ```bash bash deploy/multi-region/bootstrap_overseas.sh /opt/domaincheck bash deploy/multi-region/bootstrap_mainland.sh /opt/domaincheck controller bash deploy/multi-region/bootstrap_mainland.sh /opt/domaincheck worker ``` ## 十二、最终结论 当前最稳的推进方式是: 1. 先在国外机器完成单机部署 2. 再在国外机器完成多机模拟演练 3. 演练通过后,再复制到其他机器 4. 最后再做真实跨地域联调 一句话总结: > 先把单机跑稳,再把多机脚本跑通,最后再扩机器;每一步都有现成脚本,不靠现场猜。