# 18 domainCheck CentOS9 一键复制部署与更新文档 ## 一、文档用途 这份文档只做一件事: > 给你一套可以直接复制执行的命令,完成 `1 台国外机器 + 2 台国内机器` 的傻瓜式部署和后续更新。 统一前提: - 系统:`CentOS Stream 9` - 代码管理:统一 `git` - API 域名:`api.domain.com` - 后台域名:`admin.domain` - 分支:默认 `main` 目标机器: - 国外机器 `1` 台 - 角色:`overseas-control` - 国内机器 `2` 台 - `mainland-controller-01` - `mainland-worker-01` 一句话部署口径: - 国外机器:`宝塔管理 Nginx / PostgreSQL / Redis + systemd 管理项目服务` - 国内机器:`纯 systemd 执行节点,不装宝塔` ## 二、先改这里 正式执行本文命令前,先把下面这些变量替换成你自己的真实值。 ```text GIT_BRANCH=main API_DOMAIN=api.domain.com ADMIN_DOMAIN=admin.domain DB_NAME=domain DB_USER=domainuser DB_PASSWORD=请改成你的强密码 SYNC_SHARED_TOKEN=请改成你的共享令牌 OVERSEAS_NODE_CODE=overseas-control-01 MAINLAND_CONTROLLER_NODE_CODE=mainland-controller-01 MAINLAND_WORKER_NODE_CODE=mainland-worker-01 MAINLAND_CONTROLLER_IP=国内controller机器IP NODE_VERSION=20 ``` 最少必须先替换这 6 个: - `DB_PASSWORD` - `SYNC_SHARED_TOKEN` - `API_DOMAIN` - `ADMIN_DOMAIN` - `MAINLAND_CONTROLLER_IP` ## 三、统一约定 ### 1. 仓库目录 ```text /www/wwwroot/getDomain ``` ### 2. 运行目录 ```text /opt/domaincheck ``` ### 3. 统一更新命令 后续所有机器代码更新统一执行: ```bash cd /www/wwwroot/getDomain git fetch --all git checkout main git pull --ff-only origin main ``` ### 3.1 首次全新机器先做什么 如果这台机器是第一次部署,而且本机还没有: ```text /www/wwwroot/getDomain ``` 那么要先手动拉一次代码,因为脚本文件本身也在仓库里。 首次最小步骤: ```bash mkdir -p /www/wwwroot cd /www/wwwroot git clone 你的仓库地址 getDomain cd getDomain git checkout main git pull --ff-only origin main ``` 然后再: 1. 复制对应的 `.conf.example` 2. 编辑 `.conf` 3. 执行对应的 `.sh` 如果这台机器已经有仓库目录了,后面再执行脚本时,脚本内部会自动做 `git fetch / checkout / pull`,不需要你每次手动拉代码。 关键结论: - 新机器第一次:必须先手动 `git clone` - 后续执行脚本:不再负责 `clone` - 脚本只负责“基于已存在仓库做部署或更新” ### 3.2 这些命令用哪个用户执行 结论: - 整套部署命令建议统一使用 `root` - 不建议用 `www` 执行部署脚本 原因: - 脚本会写: - `/etc/default/...` - `/etc/systemd/system/...` - `/opt/domaincheck/...` - 脚本会执行: - `systemctl enable` - `systemctl restart` - `chown` - 可能还有 `dnf` 这些都属于 `root` 口径,不适合 `www` 用户执行。 最稳的执行方式: ```bash sudo -i ``` 然后再继续后面的复制、编辑和执行脚本。 ### 4. 统一软链接 所有机器都统一建立: ```bash mkdir -p /opt/domaincheck ln -sfn /www/wwwroot/getDomain/domain-api /opt/domaincheck/domain-api ln -sfn /www/wwwroot/getDomain/domain-web /opt/domaincheck/domain-web ln -sfn /www/wwwroot/getDomain/domainCheck /opt/domaincheck/domainCheck ``` ### 5. 并发配置约定 - 默认检测并发由后台系统设置里的 `默认检测线程数` 控制 - 若某台机器需要单独并发,可在后台系统设置里增加 `节点独立线程覆盖` - 规则是: - 节点已单独配置:走该节点自己的线程数 - 节点未单独配置:回退到默认线程数 - 节点编码必须和该机器 `/etc/default/domaincheck-worker` 里的 `NODE_CODE` 一致 - 配置会同时写入: - Redis:`domain_tool:thread_count` - Redis:`domain_tool:node_thread_counts` - 本地文件:`thread_count.json` - 本地文件:`node_thread_counts.json` ### 6. 宝塔与 `nvm` 口径 - 国外主控机: - 你如果已经长期用宝塔管理 `PostgreSQL`、`Redis`、`Nginx`,可以继续用 - 但 `domain-api`、`domaincheck-worker`、`domaincheck-sync-agent` 仍建议走 `systemd` - 国内机器: - 不建议为了纯 `worker` 节点额外安装宝塔 - 原因不是不能用,而是会多一层面板进程、端口、权限和故障面 - 国内机器的最佳形态是: - 只装 Python 运行环境 - 只装项目代码 - 只跑 `domaincheck-worker` - 若是 controller,再加 `domaincheck-sync-agent` - Node: - 继续用 `nvm` 没问题,不需要改成系统全局安装 - 建议统一到 `Node 20` - 生产构建时只要保证执行构建命令前已经 `nvm use 20` ### 7. 你实际应该怎么选 - 如果国外主控机已经是宝塔机: - 继续沿用宝塔即可 - 宝塔负责: - `Nginx` - `PostgreSQL` - `Redis` - SSL 证书 - 项目自身服务继续交给: - `domaincheck-api.service` - `domaincheck-worker.service` - 如果国内机器只是跑检测: - 不要装宝塔 - 直接按本文的纯命令部署 - 这样最轻、最稳、最容易横向复制 ### 8. Python 3.11 必须单独安装 - 这里不能只依赖系统默认 `python3` - 必须明确安装 `python3.11` - 因为本文后续所有部署命令都直接使用: - `python3.11 -m venv .venv` 安装命令: ```bash dnf install -y python3.11 python3.11-devel ``` 安装后先验证: ```bash python3.11 --version ``` 期望输出类似: ```text Python 3.11.x ``` ## 四、最短复制块 这一节给你三段最短命令。 用法: - 急着部署时,先用这里 - 想看每一步解释,再看后面的完整章节 ### 1. 国外主控机最短复制块 先把下面 7 个值替换掉再执行: ```text GIT_BRANCH API_DOMAIN ADMIN_DOMAIN DB_PASSWORD SYNC_SHARED_TOKEN OVERSEAS_NODE_CODE NODE_VERSION ``` 也可以直接改脚本头部变量后执行: ```bash cp /www/wwwroot/getDomain/domain-api/deploy/multi-region/install_overseas_quick.conf.example \ /www/wwwroot/getDomain/domain-api/deploy/multi-region/install_overseas_quick.conf # 先编辑 install_overseas_quick.conf bash /www/wwwroot/getDomain/domain-api/deploy/multi-region/install_overseas_quick.sh ``` ```bash cd /www/wwwroot/getDomain git fetch --all git checkout GIT_BRANCH git pull --ff-only origin GIT_BRANCH mkdir -p /opt/domaincheck ln -sfn /www/wwwroot/getDomain/domain-api /opt/domaincheck/domain-api ln -sfn /www/wwwroot/getDomain/domain-web /opt/domaincheck/domain-web ln -sfn /www/wwwroot/getDomain/domainCheck /opt/domaincheck/domainCheck cd /opt/domaincheck/domainCheck python3.11 -m venv .venv || true source .venv/bin/activate pip install --upgrade pip pip install -r requirements.txt /opt/domaincheck/domainCheck/.venv/bin/pip install fastapi uvicorn pydantic-settings psycopg2-binary redis openpyxl python-multipart cat >/opt/domaincheck/domainCheck/.env </opt/domaincheck/domain-web/.env.production </opt/domaincheck/domainCheck/.env </etc/default/domaincheck-worker </opt/domaincheck/domainCheck/.env </etc/default/domaincheck-worker </opt/domaincheck/domainCheck/.env <<'EOF' DB_HOST=127.0.0.1 DB_PORT=5432 DB_DATABASE=domain DB_USER=domainuser DB_PASSWORD=请改成你的强密码 REDIS_HOST=127.0.0.1 REDIS_PORT=6379 REDIS_PASSWORD= REDIS_DB=0 EOF ``` ### 5. 初始化数据库结构 ```bash cd /opt/domaincheck/domainCheck /opt/domaincheck/domainCheck/.venv/bin/python init_database.py ``` ### 6. 配置前端生产环境 ```bash cat >/opt/domaincheck/domain-web/.env.production <<'EOF' VITE_API_BASE_URL=https://api.domain.com/api/v1 EOF ``` ### 7. 用 `nvm` 构建前端 如果你平时就是 `nvm`,建议直接固定: ```bash export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" nvm install 20 nvm use 20 node -v ``` 然后再构建: ```bash cd /opt/domaincheck/domain-web npm install npm run build ``` ### 8. 配置 API 环境变量 ```bash cp /opt/domaincheck/domain-api/deploy/multi-region/templates/domaincheck-api.env.example /etc/default/domaincheck-api sed -i 's#^DOMAIN_ROOT=.*#DOMAIN_ROOT=/opt/domaincheck/domainCheck#' /etc/default/domaincheck-api sed -i 's#^API_HOST=.*#API_HOST=0.0.0.0#' /etc/default/domaincheck-api sed -i 's#^API_PORT=.*#API_PORT=8100#' /etc/default/domaincheck-api sed -i 's#^NODE_CODE=.*#NODE_CODE=overseas-control-01#' /etc/default/domaincheck-api sed -i 's#^NODE_REGION=.*#NODE_REGION=overseas#' /etc/default/domaincheck-api sed -i 's#^NODE_ROLE=.*#NODE_ROLE=control#' /etc/default/domaincheck-api sed -i 's#^SYNC_PUSH_ENABLED=.*#SYNC_PUSH_ENABLED=false#' /etc/default/domaincheck-api sed -i 's#^CORS_ORIGINS=.*#CORS_ORIGINS=https://admin.domain,http://127.0.0.1:3201,http://localhost:3201#' /etc/default/domaincheck-api ``` ### 9. 安装 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 ``` ### 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. 配置 Nginx 如果你已经用宝塔建好了: - `admin.domain` - `api.domain.com` 并且已经在宝塔里配好了反代和静态站点,那么这一节可以不执行。 如果你不用宝塔,就直接执行下面命令。 后台站点: ```bash cat >/etc/nginx/conf.d/admin.domain.conf <<'EOF' server { listen 80; server_name admin.domain; root /opt/domaincheck/domain-web/dist; index index.html; location / { try_files $uri $uri/ /index.html; } } EOF ``` API 站点: ```bash cat >/etc/nginx/conf.d/api.domain.com.conf <<'EOF' server { listen 80; server_name api.domain.com; location / { proxy_pass http://127.0.0.1:8100; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } EOF ``` 启动 Nginx: ```bash nginx -t systemctl enable nginx systemctl restart nginx ``` ### 13. 国外机器验收 ```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/readiness cd /opt/domaincheck/domain-api/deploy/linux python3 smoke_test.py --base-url http://127.0.0.1:8100 ``` ## 七、国内 controller 一键部署 这一节默认你是: - 国内 controller - 不装宝塔 - 只跑 `domaincheck-worker + domaincheck-sync-agent` - 本机承载 Redis / PostgreSQL 控制面 ### 1. 先准备 Redis 和 PostgreSQL ```bash postgresql-setup --initdb systemctl enable postgresql systemctl start postgresql systemctl enable redis systemctl start redis ``` 创建数据库: ```bash sudo -u postgres psql <<'SQL' CREATE USER domainuser WITH PASSWORD '请改成你的强密码'; CREATE DATABASE domain OWNER domainuser; GRANT ALL PRIVILEGES ON DATABASE domain TO domainuser; SQL ``` ### 2. 配置 `domainCheck/.env` ```bash cat >/opt/domaincheck/domainCheck/.env <<'EOF' DB_HOST=127.0.0.1 DB_PORT=5432 DB_DATABASE=domain DB_USER=domainuser DB_PASSWORD=请改成你的强密码 REDIS_HOST=127.0.0.1 REDIS_PORT=6379 REDIS_PASSWORD= REDIS_DB=0 EOF ``` ### 3. 执行 bootstrap ```bash cd /opt/domaincheck/domain-api bash deploy/multi-region/bootstrap_mainland.sh /opt/domaincheck controller ``` ### 4. 配置 `/etc/default/domaincheck-worker` ```bash cat >/etc/default/domaincheck-worker <<'EOF' WORKER_MODE=linux-systemd QT_QPA_PLATFORM=offscreen NODE_CODE=mainland-controller-01 NODE_REGION=mainland NODE_ROLE=control DB_HOST=127.0.0.1 DB_PORT=5432 DB_DATABASE=domain DB_USER=domainuser DB_PASSWORD=请改成你的强密码 REDIS_HOST=127.0.0.1 REDIS_PORT=6379 REDIS_PASSWORD= REDIS_DB=0 SYNC_PUSH_ENABLED=true SYNC_SOURCE_REGION=mainland SYNC_TARGET_REGION=overseas SYNC_TARGET_API_BASE_URL=https://api.domain.com/api/v1 SYNC_SHARED_TOKEN=请改成你的共享令牌 SYNC_BATCH_SIZE=200 SYNC_POLL_INTERVAL_SECONDS=30 EOF ``` ### 5. 启动 controller 服务 ```bash systemctl daemon-reload systemctl enable domaincheck-worker systemctl enable domaincheck-sync-agent systemctl restart domaincheck-worker systemctl restart domaincheck-sync-agent ``` ### 6. 本机检查 ```bash cd /opt/domaincheck/domain-api bash deploy/multi-region/check_mainland_controller.sh ``` ## 八、国内 worker 一键部署 这一节默认你是: - 国内纯 worker 节点 - 不装宝塔 - 不承载后台 - 不承载 API - 不承载 Nginx ### 1. 配置 `domainCheck/.env` 如果它连接 controller 的同一套 Redis / PostgreSQL,就改成 controller 地址: ```bash cat >/opt/domaincheck/domainCheck/.env <<'EOF' DB_HOST=国内controller机器IP DB_PORT=5432 DB_DATABASE=domain DB_USER=domainuser DB_PASSWORD=请改成你的强密码 REDIS_HOST=国内controller机器IP REDIS_PORT=6379 REDIS_PASSWORD= REDIS_DB=0 EOF ``` ### 2. 执行 bootstrap ```bash cd /opt/domaincheck/domain-api bash deploy/multi-region/bootstrap_mainland.sh /opt/domaincheck worker ``` ### 3. 配置 `/etc/default/domaincheck-worker` ```bash cat >/etc/default/domaincheck-worker <<'EOF' WORKER_MODE=linux-systemd QT_QPA_PLATFORM=offscreen NODE_CODE=mainland-worker-01 NODE_REGION=mainland NODE_ROLE=worker DB_HOST=国内controller机器IP DB_PORT=5432 DB_DATABASE=domain DB_USER=domainuser DB_PASSWORD=请改成你的强密码 REDIS_HOST=国内controller机器IP REDIS_PORT=6379 REDIS_PASSWORD= REDIS_DB=0 SYNC_PUSH_ENABLED=true SYNC_SOURCE_REGION=mainland SYNC_TARGET_REGION=overseas SYNC_TARGET_API_BASE_URL=https://api.domain.com/api/v1 SYNC_SHARED_TOKEN=请改成你的共享令牌 SYNC_BATCH_SIZE=200 SYNC_POLL_INTERVAL_SECONDS=30 EOF ``` ### 4. 启动 worker ```bash systemctl daemon-reload systemctl enable domaincheck-worker systemctl restart domaincheck-worker ``` ## 九、统一更新命令 以后你更新代码,三台机器统一执行: ```bash cd /www/wwwroot/getDomain git fetch --all git checkout main git pull --ff-only origin main ``` 然后: ### 国外机器 如果国外机器前端构建使用 `nvm`,更新时建议固定这么跑: ```bash export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" nvm use 20 cd /opt/domaincheck/domain-web npm install npm run build systemctl restart domaincheck-api systemctl restart domaincheck-worker systemctl restart nginx ``` ### 国内 controller ```bash systemctl restart domaincheck-worker systemctl restart domaincheck-sync-agent ``` ### 国内 worker ```bash systemctl restart domaincheck-worker ``` ## 十、最终联调检查 在国外机器执行: ```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/readiness.status` 不是 `blocking` - `runtime/cluster` 能看到: - `overseas-control-01` - `mainland-controller-01` - `mainland-worker-01` - `runtime/sync-summary` 能看到 `detect_result_batches` ## 十一、如果当前还不能上国内机器 先在国外机器演练: ```bash cd /opt/domaincheck/domain-api bash deploy/multi-region/rehearse_multi_region.sh http://127.0.0.1:8100 ``` 如果它输出: ```text rehearsal passed ``` 说明: - 多机脚本没问题 - readiness 判断没问题 - cluster 视图没问题 - 可以开始把同样方式复制到其他机器 ## 十二、最推荐的真实落地顺序 如果按你的使用习惯,我建议你就按下面走: ### 方案 A:最符合你现在的习惯 - 国外主控机: - 宝塔管理 `Nginx / PostgreSQL / Redis / SSL` - `systemd` 管理 `domaincheck-api / domaincheck-worker` - 前端构建使用 `nvm` - 国内 controller: - 不装宝塔 - 跑 `PostgreSQL / Redis / domaincheck-worker / domaincheck-sync-agent` - 国内 worker: - 不装宝塔 - 只跑 `domaincheck-worker` ### 方案 B:如果以后你想进一步简化 - 国外机继续保持不变 - 国内 controller 也可以后续去掉本地 PostgreSQL,只保留: - `Redis` - `domaincheck-worker` - `domaincheck-sync-agent` - 国内 worker 全部连 controller 的 Redis 和数据库 ### 当前阶段我建议你先不要改的 - 不要为了统一而让国内 worker 也装宝塔 - 不要为了“更标准”把 `nvm` 改成全局 Node - 不要让项目服务交给宝塔守护进程 ## 十三、最终建议 你现在最稳的部署顺序就是: 1. 先部署国外机器 2. 国外机器 smoke test 通过 3. 国外机器多机模拟演练通过 4. 再部署国内 controller 5. 再部署国内 worker 6. 最后看 `api.domain.com` 的 readiness / cluster / sync-summary 一句话总结: > 先把国外主控机跑稳,再用同样脚本扩到 2 台国内机器;代码更新统一走 git,部署执行直接复制这份文档里的命令。