diff --git a/deploy/infra/nacos/.gitignore b/deploy/infra/nacos/.gitignore new file mode 100644 index 00000000..84a671cb --- /dev/null +++ b/deploy/infra/nacos/.gitignore @@ -0,0 +1,4 @@ +# 运行时密钥文件:.env 只在服务器上 chmod 600 存在,权威副本在 docs/内网凭据与端点.md,不入仓。 +.env +# 容器运行时产物(Nacos 日志),不入仓。 +data/ diff --git a/deploy/infra/nacos/docker-compose.yml b/deploy/infra/nacos/docker-compose.yml new file mode 100644 index 00000000..43b35cd1 --- /dev/null +++ b/deploy/infra/nacos/docker-compose.yml @@ -0,0 +1,53 @@ +# ============================================================================= +# Nacos 2.4.3 自托管 —— standalone + 外部 MySQL 后端 + lean JVM(切片一 阶段〇 B1) +# ----------------------------------------------------------------------------- +# 配置控制面设计 §3.7:game-cloud 本是 Spring Cloud Alibaba,Nacos 是其原生生产基建 +# (配置中心 + 服务发现)。自托管在 mini-infra,纯增量、不动既有 9 个容器。 +# +# 三条部署纪律都编进了这里: +# - MODE=standalone:镜像默认是 cluster 模式(实测启动 banner "Running in cluster mode"), +# 单机自托管必须显式压成 standalone,否则起不来。 +# - lean JVM 512m:mini-infra 可用内存有限,Nacos 默认 -Xmx2g 会挤压 RAGflow/MySQL。 +# standalone + 单操作者(dev/MVP)512m 足够,显式压死默认 2g。 +# - network_mode: host:与既有 infra-* 容器一致,直连本机 3306 MySQL;占 8848(HTTP)、 +# 9848(gRPC client)、9849(gRPC server)三个 host 端口(实测均未被既有容器占用)。 +# +# 密钥注入:全部经 ${VAR} 从同目录 .env 读取(compose 起时自动加载),compose 文件本身 +# 不落任何明文密钥;.env 只在服务器上 chmod 600 存在、不入仓。密钥权威副本见 +# docs/内网凭据与端点.md(内网阶段密钥进文档铁律)。.env 需含: +# MYSQL_ROOT_PW / NACOS_AUTH_TOKEN / NACOS_AUTH_IDENTITY_KEY / NACOS_AUTH_IDENTITY_VALUE +# +# admin 账号初始化:v2.4.3 已移除内置 nacos/nacos 默认账号,且该镜像**不认** +# NACOS_AUTH_ADMIN_PASSWORD 环境变量(实测 docker-startup.sh 无此映射)。故首启后需调一次 +# 首启 API 建 admin(用户名固定 nacos、仅首次生效): +# curl -X POST 'http://127.0.0.1:8848/nacos/v1/auth/users/admin' -d 'password=<见凭据文档>' +# ============================================================================= +services: + nacos: + image: nacos/nacos-server:v2.4.3 + container_name: infra-nacos + restart: unless-stopped + network_mode: host + environment: + MODE: standalone + PREFER_HOST_MODE: ip + NACOS_SERVER_PORT: "8848" + # ── lean JVM:standalone 512m 够用,显式压死默认 2g ── + JVM_XMS: "512m" + JVM_XMX: "512m" + JVM_XMN: "256m" + # ── MySQL 后端(复用既有 mini-infra 实例的 nacos 库,不新增 MySQL 实例)── + SPRING_DATASOURCE_PLATFORM: mysql + MYSQL_SERVICE_HOST: 100.64.0.8 + MYSQL_SERVICE_PORT: "3306" + MYSQL_SERVICE_DB_NAME: nacos + MYSQL_SERVICE_USER: root + MYSQL_SERVICE_PASSWORD: "${MYSQL_ROOT_PW}" + MYSQL_SERVICE_DB_PARAM: "characterEncoding=utf8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true" + # ── 鉴权:生产基建不裸奔,开 token + server identity(密钥见凭据文档)── + NACOS_AUTH_ENABLE: "true" + NACOS_AUTH_TOKEN: "${NACOS_AUTH_TOKEN}" # token.secret.key:base64、解码后 ≥32 字节 + NACOS_AUTH_IDENTITY_KEY: "${NACOS_AUTH_IDENTITY_KEY}" # server 间鉴权请求头名 + NACOS_AUTH_IDENTITY_VALUE: "${NACOS_AUTH_IDENTITY_VALUE}" + volumes: + - ./data/logs:/home/nacos/logs diff --git a/deploy/infra/nacos/health-check.sh b/deploy/infra/nacos/health-check.sh new file mode 100755 index 00000000..aa29c55d --- /dev/null +++ b/deploy/infra/nacos/health-check.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +# ============================================================================= +# Nacos 健康探针 —— 部署后就绪判定(切片一 阶段〇 B1) +# ----------------------------------------------------------------------------- +# 只做一件事:探 Nacos 的 readiness 端点。绿 = HTTP 200,红 = 非 200 / 超时。 +# +# 两处内网纪律: +# - `--noproxy '*'`:本机系统代理是 fake-ip(198.18.x);内网直连(Tailscale 100.64.x) +# 必须绕过它,否则连接被代理拦下返 000。这是内网外呼铁律。 +# - `/nacos/v1/console/health/readiness` 在 Nacos 的 auth 白名单(nacos.security.ignore.urls +# 含 /v1/console/health/**)内,开鉴权后仍可无 token 访问,适合做就绪探针。 +# +# 用法:NACOS=http://100.64.0.8:8848 bash deploy/infra/nacos/health-check.sh +# ============================================================================= +set -uo pipefail + +NACOS="${NACOS:-http://100.64.0.8:8848}" + +# curl -w 恒会输出 http_code(失败时为 000);仅在 curl 二进制本身异常返空时兜底 000。 +# 不用 `|| echo 000` 兜底 —— 那会与 -w 的 000 叠加成 "000000"。 +code="$(curl -s -o /dev/null -w '%{http_code}' --noproxy '*' --max-time 8 \ + "${NACOS}/nacos/v1/console/health/readiness" 2>/dev/null)" +code="${code:-000}" + +if [[ "$code" == "200" ]]; then + echo "PASS Nacos readiness 200 @ ${NACOS}" + exit 0 +fi +echo "FAIL Nacos readiness=${code} @ ${NACOS}" +exit 1 diff --git a/deploy/infra/nacos/init-nacos-schema.sh b/deploy/infra/nacos/init-nacos-schema.sh new file mode 100644 index 00000000..4d861349 --- /dev/null +++ b/deploy/infra/nacos/init-nacos-schema.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +# ============================================================================= +# 在既有 mini-infra MySQL 建 nacos 库 + 灌官方 schema(切片一 阶段〇 B1) +# ----------------------------------------------------------------------------- +# 纯增量:只新建 `nacos` 库 + 建表,绝不 drop / 不动任何既有库。 +# +# 两个关键取舍(资深工程师视角): +# 1) 复用正在运行的 infra-mysql 容器执行 mysql 客户端(docker exec -i),而不是 +# `docker run --rm mysql:8`。原因:mini-infra 本地镜像标签是 mysql:8.4.8,`mysql:8` +# 并不存在,一旦 run 会触发一次时长不可控的 docker pull —— 违反"纯增量、不引入 +# 不确定拉取"的部署纪律。exec 进 DB 容器走容器内本地 socket,零网络、零代理、零拉取。 +# 2) schema 从本地 Nacos 镜像 docker cp 取出(/home/nacos/conf/mysql-schema.sql), +# 而不是从网上下 —— 保证 schema 与镜像版本严格对齐。docker create 只建不启、不拉取。 +# +# 注:官方 mysql-schema.sql 用裸 CREATE TABLE(非 IF NOT EXISTS),故本脚本按"全新库 +# 一次性初始化"设计;库已建表的场景不重复灌(建库那步 IF NOT EXISTS 幂等,灌表那步不重跑)。 +# +# 用法(在 mini-infra 上执行,MySQL root 口令见 docs/内网凭据与端点.md): +# MYSQL_ROOT_PW=<见凭据文档> bash init-nacos-schema.sh +# ============================================================================= +set -euo pipefail + +MYSQL_CONTAINER="${MYSQL_CONTAINER:-infra-mysql}" # 既有运行中的 MySQL 容器 +MYSQL_ROOT_PW="${MYSQL_ROOT_PW:?需传 MySQL root 密码(见 docs/内网凭据与端点.md)}" +NACOS_IMAGE="${NACOS_IMAGE:-nacos/nacos-server:v2.4.3}" +SCHEMA_TMP="/tmp/nacos-mysql-schema.sql" + +echo "[1/3] 从本地 Nacos 镜像取版本对齐的 schema(docker create 不启动、不拉取)..." +cid="$(docker create "$NACOS_IMAGE")" +trap 'docker rm -f "$cid" >/dev/null 2>&1 || true' EXIT +docker cp "$cid:/home/nacos/conf/mysql-schema.sql" "$SCHEMA_TMP" +echo " 已取出 schema:$SCHEMA_TMP($(wc -l < "$SCHEMA_TMP") 行)" + +echo "[2/3] 建 nacos 库(utf8mb4;IF NOT EXISTS 幂等,绝不 drop)..." +docker exec -i "$MYSQL_CONTAINER" mysql -uroot -p"$MYSQL_ROOT_PW" \ + -e "CREATE DATABASE IF NOT EXISTS nacos DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;" + +echo "[3/3] 灌 schema 进 nacos 库..." +docker exec -i "$MYSQL_CONTAINER" mysql -uroot -p"$MYSQL_ROOT_PW" nacos < "$SCHEMA_TMP" + +echo "PASS nacos schema 已灌入 容器 ${MYSQL_CONTAINER} 的 nacos 库" diff --git a/docs/内网凭据与端点.md b/docs/内网凭据与端点.md index cbda7179..91fe5662 100644 --- a/docs/内网凭据与端点.md +++ b/docs/内网凭据与端点.md @@ -52,6 +52,25 @@ --- +## Nacos 配置中心 + 服务发现(mini-infra `100.64.0.8` · 2026-07-01 自托管落档 · 切片一 阶段〇 B1) + +> game-cloud 是 Spring Cloud Alibaba,Nacos 是其原生配置中心 + 服务发现。自托管在 mini-infra,standalone + 外部 MySQL 后端 + lean 512m JVM,纯增量部署(不动既有容器)。配置控制面设计 §3.7 采纳。**C1/C2/D 引用的 `${NACOS_PASSWORD}` = 下面的 admin 口令。** + +| 项 | 值 | +|---|---| +| **控制台 / OpenAPI** | `http://100.64.0.8:8848/nacos`(readiness 探针 `/nacos/v1/console/health/readiness`,在 auth 白名单内、免鉴权) | +| **admin 账号** | 用户名 `nacos` / 口令 `3157df7c3edf6c1ecc8a0a58a6efe3a9`(v2.4.3 无内置默认账号,首启 API 建;登录返 globalAdmin JWT) | +| **鉴权 token**(`NACOS_AUTH_TOKEN` = token.secret.key) | `wBMa0tgBihFX6IqJvq364+xIgTb0O9ZpRGY1xE+lTWg=`(base64,解码 32 字节;JWT 签名密钥) | +| **server identity**(server 间鉴权头) | key `nacosServerIdentity` / value `f358e96034ab2cd5e41c1a691b4200bb6f576849d61ed4dd` | +| **MySQL 后端** | 复用既有 `100.64.0.8:3306` 的 `nacos` 库(root/`ZRH3jwYLOrntBcTAw29MW9BP`,不新增实例);12 张官方表 | +| **部署位置** | mini-infra `/opt/infra-nacos`(compose 源在仓 `deploy/infra/nacos/`);镜像 `nacos/nacos-server:v2.4.3` | + +- **密钥注入**:上面四个密钥在服务器上物化为 `/opt/infra-nacos/.env`(chmod 600、不入仓);本文档是权威副本,compose 文件只用 `${VAR}` 引用、无明文。 +- **运维**:起/停 `cd /opt/infra-nacos && docker compose up -d / down`;探活 `NACOS=http://100.64.0.8:8848 bash deploy/infra/nacos/health-check.sh`(绿=readiness 200)。standalone 单机 512m,实测常驻内存 ~627M。 +- admin 口令由首启 API `POST /nacos/v1/auth/users/admin` 一次性设定(重复调用无效);改口令走登录后的用户管理 API,并同步回本档。 + +--- + ## tier2 P4 服务化部署拓扑(2026-06-24 首次部署成功落档 · 团队共享) > 内部开发阶段 · 内网环境;为开发方便,端点 + 凭据明文记录(铁律授权)。下面是「服务跑在哪、怎么起、连什么」。