From 67a72f7255d24243dc2dcb222c3ee01f1db06342 Mon Sep 17 00:00:00 2001 From: zizi Date: Sat, 11 Apr 2026 22:57:26 +0800 Subject: [PATCH] chore: switch new-api deployment to shared infra --- .env.example | 8 ++ CLAUDE.md | 87 ++++++++----------- README.md | 31 +++++-- README.zh_CN.md | 31 +++++-- docker-compose.yml | 86 +++--------------- ops/remote/README.md | 9 ++ .../minione-ubuntu-infra-4c16g120g.AGENT.md | 63 ++++++++++++++ 7 files changed, 174 insertions(+), 141 deletions(-) create mode 100644 ops/remote/README.md create mode 100644 ops/remote/minione-ubuntu-infra-4c16g120g.AGENT.md diff --git a/.env.example b/.env.example index 0a64758d..72675aa2 100644 --- a/.env.example +++ b/.env.example @@ -21,6 +21,10 @@ # 数据库相关配置 # 数据库连接字符串 # SQL_DSN=user:password@tcp(127.0.0.1:3306)/dbname?parseTime=true +# Host process profile on infra host: +# SQL_DSN=postgresql://root:example-password@127.0.0.1:5433/new-api +# Docker profile on same host: +# SQL_DSN=postgresql://root:example-password@infra-postgres:5432/new-api # 日志数据库连接字符串 # LOG_SQL_DSN=user:password@tcp(127.0.0.1:3306)/logdb?parseTime=true # SQLite数据库路径 @@ -36,6 +40,10 @@ # 缓存相关配置 # Redis连接字符串 # REDIS_CONN_STRING=redis://user:password@localhost:6379/0 +# Host process profile on infra host: +# REDIS_CONN_STRING=redis://:example-password@127.0.0.1:6379/0 +# Docker profile on same host: +# REDIS_CONN_STRING=redis://:example-password@infra-redis:6379/0 # 同步频率(单位:秒) # SYNC_FREQUENCY=60 # 内存缓存启用 diff --git a/CLAUDE.md b/CLAUDE.md index 220ea3b6..6be79b38 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -224,71 +224,52 @@ For request structs that are parsed from client JSON and then re-marshaled to up - 是上游不通 - 还是服务端计费配置缺失 -## 9. 当前线上部署形态(2026-04-04 更新) +## 9. 当前目标部署形态(2026-04-11 更新) - 远程服务器仍是:`个人-minione-ubuntu-infra-4c16g120g` -- `new-api` **不再**以 Docker 应用容器运行;当前由宿主机 `systemd` 服务启动: +- `new-api` 继续以宿主机 `systemd` 进程运行: - 服务名:`new-api` - - `systemctl is-active new-api` 应返回 `active` - - `systemctl is-enabled new-api` 应返回 `enabled` -- 当前线上运行版本固定为最新稳定 tag: - - `v0.11.9` -- 实际部署目录不是 `/root/new-api`,而是单独的源码 worktree: - - `/root/new-api-v0.11.9` + - 只管理应用进程,不管理基础设施生命周期 +- 远程部署目录应为正常 Git checkout: + - 目标目录:`/root/new-api-deploy` - 关键文件: - - 二进制:`/root/new-api-v0.11.9/new-api` - - 运行环境:`/root/new-api-v0.11.9/.env.runtime` - - 启动脚本:`/root/new-api-v0.11.9/run-new-api.sh` + - 二进制:`/root/new-api-deploy/new-api` + - 运行环境:`/root/new-api-deploy/.env.runtime` - systemd 单元文件:`/etc/systemd/system/new-api.service` -## 10. 依赖服务与连接方式(2026-04-04 更新) -- PostgreSQL 和 Redis 仍然跑在 Docker 中,但**只作为依赖容器**存在,不再承载应用本体。 -- 当前容器: - - PostgreSQL:`postgres` - - Redis:`redis` -- 当前宿主机固定入口: +## 10. 依赖服务与连接方式(2026-04-11 更新) +- PostgreSQL 和 Redis 是共享基础设施,不属于 `new-api` 仓库内嵌部署的一部分。 +- 宿主机进程模式固定入口: - PostgreSQL:`127.0.0.1:5433` - Redis:`127.0.0.1:6379` -- `new-api` 宿主机进程必须连接宿主机固定入口,不要再依赖容器名或容器 IP: - - `SQL_DSN=postgresql://root:123456@127.0.0.1:5433/new-api` - - `REDIS_CONN_STRING=redis://127.0.0.1:6379` -- 原因: - - 容器 IP 会变,写死就是垃圾设计。 - - 用宿主机固定入口,重建 PG/Redis 容器时不需要改应用配置。 +- 同宿主机 Docker 模式固定入口: + - PostgreSQL:`infra-postgres:5432` + - Redis:`infra-redis:6379` +- `new-api` 不应再依赖容器 IP,也不应再依赖 `postgres` / `redis` 这种应用级旧名字。 -## 11. 数据保护与备份(2026-04-04 更新) -- PostgreSQL 数据仍保存在 Docker volume: - - `new-api_pg_data` -- **不要**删除、重建、覆盖这个 volume,除非明确知道自己在做什么。 -- 本次切换前已做 PG 备份: - - `/root/backups/new-api/new-api-cutover-20260404-094849.dump` -- 这次切换后已核对关键表仍在: - - `channels=10` - - `abilities=153` - - `options=9` +## 11. 共享数据库事实(2026-04-11 更新) +- 当前 PostgreSQL 是共享基础设施,至少同时承载: + - `new-api` + - `gitea` +- 迁移 PostgreSQL 时不要把它当成 `new-api` 独占数据库。 +- Redis 目前主要视为共享缓存基础设施。 -## 12. 运维入口与排障顺序(2026-04-04 更新) -- 现在排障先看 `systemd`,不是先看 Docker 应用容器: +## 12. 运维入口与排障顺序(2026-04-11 更新) +- `new-api` 排障先看: - `systemctl status new-api` - `journalctl -u new-api -n 200 --no-pager` - `journalctl -u new-api -f` -- 服务健康检查: +- `new-api` 健康检查: - `curl http://127.0.0.1:3000/api/status` -- 当前线上版本应看到: - - `v0.11.9` -- Docker 现在只需要关心依赖容器是否活着: - - `docker ps | grep -E 'postgres|redis'` -- 不要再默认使用 `/root/new-api/docker-compose.yml` 管理应用本体。 - - 这个仓库目录现在主要是源码主仓库,不是实际运行目录。 - - 实际运行目录是 `/root/new-api-v0.11.9` +- 基础设施排障再看: + - `docker ps | grep -E 'infra-postgres|infra-redis|gitea'` + - `ss -lntp | grep -E ':5433|:6379|:3000|:3001|:2222'` +- 不要再把仓库里的 `docker-compose.yml` 当成生产真相;它只描述 app-only Docker 运行方式。 -## 13. 后续升级原则(2026-04-04 更新) -- 升级时优先选择新的**稳定 tag**,不要直接拿 `main` 或 `latest` 当生产版本。 -- 合理流程应该是: - 1. 为目标稳定 tag 建单独部署目录或 worktree - 2. 编译产出新二进制 - 3. 保留 PG volume,不迁移数据库文件路径 - 4. 让 systemd 指向新版本 +## 13. 后续升级原则(2026-04-11 更新) +- 远程升级以 Git 可拉取 checkout 为前提,不再使用 detached tag worktree 作为长期部署形态。 +- 合理流程: + 1. 在 `/root/new-api-deploy` 拉取最新目标分支 + 2. 编译新二进制 + 3. 确认共享 PostgreSQL / Redis 健康 + 4. `systemd` 重启 `new-api` 5. 验证 `api/status`、日志、数据库连接再收尾 -- 如果有人再次看到 `docker-compose.yml` 里定义了 `new-api` 服务,不要想当然地认定线上还在用容器跑应用;先查: - - `systemctl status new-api` - - `ss -lntp | grep :3000` diff --git a/README.md b/README.md index 8f23d5dc..4896cdb7 100644 --- a/README.md +++ b/README.md @@ -106,18 +106,37 @@ ## 🚀 Quick Start -### Using Docker Compose (Recommended) +### Using Docker Compose ```bash # Clone the project git clone https://github.com/QuantumNous/new-api.git cd new-api -# Edit docker-compose.yml configuration -nano docker-compose.yml +# Copy environment template +cp .env.example .env.runtime + +# Edit SQL_DSN and REDIS_CONN_STRING for your runtime profile +nano .env.runtime # Start the service -docker-compose up -d +docker compose --env-file .env.runtime up -d +``` + +This compose file is app-only. PostgreSQL and Redis are expected to be external shared infrastructure. + +Host process profile on the infra host: + +```bash +SQL_DSN=postgresql://root:${POSTGRES_PASSWORD}@127.0.0.1:5433/new-api +REDIS_CONN_STRING=redis://:${REDIS_PASSWORD}@127.0.0.1:6379/0 +``` + +Docker profile on the same host: + +```bash +SQL_DSN=postgresql://root:${POSTGRES_PASSWORD}@infra-postgres:5432/new-api +REDIS_CONN_STRING=redis://:${REDIS_PASSWORD}@infra-redis:6379/0 ```
@@ -310,8 +329,8 @@ docker run --name new-api -d --restart always \ |--------|------|--------| | `SESSION_SECRET` | Session secret (required for multi-machine deployment) | - | | `CRYPTO_SECRET` | Encryption secret (required for Redis) | - | -| `SQL_DSN` | Database connection string | - | -| `REDIS_CONN_STRING` | Redis connection string | - | +| `SQL_DSN` | Database connection string. Use `127.0.0.1:5433` for host mode or `infra-postgres:5432` for same-host Docker mode | - | +| `REDIS_CONN_STRING` | Redis connection string. Use `127.0.0.1:6379` for host mode or `infra-redis:6379` for same-host Docker mode | - | | `STREAMING_TIMEOUT` | Streaming timeout (seconds) | `300` | | `STREAM_SCANNER_MAX_BUFFER_MB` | Max per-line buffer (MB) for the stream scanner; increase when upstream sends huge image/base64 payloads | `64` | | `MAX_REQUEST_BODY_MB` | Max request body size (MB, counted **after decompression**; prevents huge requests/zip bombs from exhausting memory). Exceeding it returns `413` | `32` | diff --git a/README.zh_CN.md b/README.zh_CN.md index 92e5baa1..5ac04e8d 100644 --- a/README.zh_CN.md +++ b/README.zh_CN.md @@ -106,18 +106,37 @@ ## 🚀 快速开始 -### 使用 Docker Compose(推荐) +### 使用 Docker Compose ```bash # 克隆项目 git clone https://github.com/QuantumNous/new-api.git cd new-api -# 编辑 docker-compose.yml 配置 -nano docker-compose.yml +# 复制环境变量模板 +cp .env.example .env.runtime + +# 按运行模式填写 SQL_DSN 和 REDIS_CONN_STRING +nano .env.runtime # 启动服务 -docker-compose up -d +docker compose --env-file .env.runtime up -d +``` + +当前 `docker-compose.yml` 只负责应用本体,PostgreSQL 和 Redis 应作为外部共享基础设施提供。 + +宿主机进程模式: + +```bash +SQL_DSN=postgresql://root:${POSTGRES_PASSWORD}@127.0.0.1:5433/new-api +REDIS_CONN_STRING=redis://:${REDIS_PASSWORD}@127.0.0.1:6379/0 +``` + +同宿主机 Docker 模式: + +```bash +SQL_DSN=postgresql://root:${POSTGRES_PASSWORD}@infra-postgres:5432/new-api +REDIS_CONN_STRING=redis://:${REDIS_PASSWORD}@infra-redis:6379/0 ```
@@ -310,8 +329,8 @@ docker run --name new-api -d --restart always \ |--------|--------------------------------------------------------------|--------| | `SESSION_SECRET` | 会话密钥(多机部署必须) | - | | `CRYPTO_SECRET` | 加密密钥(Redis 必须) | - | -| `SQL_DSN` | 数据库连接字符串 | - | -| `REDIS_CONN_STRING` | Redis 连接字符串 | - | +| `SQL_DSN` | 数据库连接字符串。宿主机模式使用 `127.0.0.1:5433`,同宿主机 Docker 模式使用 `infra-postgres:5432` | - | +| `REDIS_CONN_STRING` | Redis 连接字符串。宿主机模式使用 `127.0.0.1:6379`,同宿主机 Docker 模式使用 `infra-redis:6379` | - | | `STREAMING_TIMEOUT` | 流式超时时间(秒) | `300` | | `STREAM_SCANNER_MAX_BUFFER_MB` | 流式扫描器单行最大缓冲(MB),图像生成等超大 `data:` 片段(如 4K 图片 base64)需适当调大 | `64` | | `MAX_REQUEST_BODY_MB` | 请求体最大大小(MB,**解压后**计;防止超大请求/zip bomb 导致内存暴涨),超过将返回 `413` | `32` | diff --git a/docker-compose.yml b/docker-compose.yml index 3c56faf3..83775ee6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,19 +1,3 @@ -# New-API Docker Compose Configuration -# -# Quick Start: -# 1. docker-compose up -d -# 2. Access at http://localhost:3000 -# -# Using MySQL instead of PostgreSQL: -# 1. Comment out the postgres service and SQL_DSN line 15 -# 2. Uncomment the mysql service and SQL_DSN line 16 -# 3. Uncomment mysql in depends_on (line 28) -# 4. Uncomment mysql_data in volumes section (line 64) -# -# ⚠️ IMPORTANT: Change all default passwords before deploying to production! - -version: '3.4' # For compatibility with older Docker versions - services: new-api: image: calciumion/new-api:latest @@ -26,71 +10,21 @@ services: - ./data:/data - ./logs:/app/logs environment: - - SQL_DSN=postgresql://root:123456@postgres:5432/new-api # ⚠️ IMPORTANT: Change the password in production! -# - SQL_DSN=root:123456@tcp(mysql:3306)/new-api # Point to the mysql service, uncomment if using MySQL - - REDIS_CONN_STRING=redis://redis - - TZ=Asia/Shanghai - - ERROR_LOG_ENABLED=true # 是否启用错误日志记录 (Whether to enable error log recording) - - BATCH_UPDATE_ENABLED=true # 是否启用批量更新 (Whether to enable batch update) -# - STREAMING_TIMEOUT=300 # 流模式无响应超时时间,单位秒,默认120秒,如果出现空补全可以尝试改为更大值 (Streaming timeout in seconds, default is 120s. Increase if experiencing empty completions) -# - SESSION_SECRET=random_string # 多机部署时设置,必须修改这个随机字符串!! (multi-node deployment, set this to a random string!!!!!!!) -# - SYNC_FREQUENCY=60 # Uncomment if regular database syncing is needed -# - GOOGLE_ANALYTICS_ID=G-XXXXXXXXXX # Google Analytics 的测量 ID (Google Analytics Measurement ID) -# - UMAMI_WEBSITE_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx # Umami 网站 ID (Umami Website ID) -# - UMAMI_SCRIPT_URL=https://analytics.umami.is/script.js # Umami 脚本 URL,默认为官方地址 (Umami Script URL, defaults to official URL) - - depends_on: - - redis - - postgres -# - mysql # Uncomment if using MySQL + SQL_DSN: ${SQL_DSN:?SQL_DSN is required} + REDIS_CONN_STRING: ${REDIS_CONN_STRING:?REDIS_CONN_STRING is required} + TZ: ${TZ:-Asia/Shanghai} + ERROR_LOG_ENABLED: ${ERROR_LOG_ENABLED:-true} + BATCH_UPDATE_ENABLED: ${BATCH_UPDATE_ENABLED:-true} networks: - - new-api-network + - default + - infra-shared healthcheck: test: ["CMD-SHELL", "wget -q -O - http://localhost:3000/api/status | grep -o '\"success\":\\s*true' || exit 1"] interval: 30s timeout: 10s retries: 3 - redis: - image: redis:latest - container_name: redis - restart: always - networks: - - new-api-network - - postgres: - image: postgres:15 - container_name: postgres - restart: always - environment: - POSTGRES_USER: root - POSTGRES_PASSWORD: 123456 # ⚠️ IMPORTANT: Change this password in production! - POSTGRES_DB: new-api - volumes: - - pg_data:/var/lib/postgresql/data - networks: - - new-api-network -# ports: -# - "5432:5432" # Uncomment if you need to access PostgreSQL from outside Docker - -# mysql: -# image: mysql:8.2 -# container_name: mysql -# restart: always -# environment: -# MYSQL_ROOT_PASSWORD: 123456 # ⚠️ IMPORTANT: Change this password in production! -# MYSQL_DATABASE: new-api -# volumes: -# - mysql_data:/var/lib/mysql -# networks: -# - new-api-network -# ports: -# - "3306:3306" # Uncomment if you need to access MySQL from outside Docker - -volumes: - pg_data: -# mysql_data: - networks: - new-api-network: - driver: bridge + infra-shared: + external: true + name: infra-shared diff --git a/ops/remote/README.md b/ops/remote/README.md new file mode 100644 index 00000000..5cfcfdb6 --- /dev/null +++ b/ops/remote/README.md @@ -0,0 +1,9 @@ +# Remote Runtime Notes + +这个目录记录远程主机运行事实,避免把主机级流水账继续堆回根文档。 + +约定: + +- 一台主机一份 `*.AGENT.md` +- 只写运行事实、入口、路径、端口、依赖和排障命令 +- 项目规则仍放在根 `AGENTS.md` / `CLAUDE.md` diff --git a/ops/remote/minione-ubuntu-infra-4c16g120g.AGENT.md b/ops/remote/minione-ubuntu-infra-4c16g120g.AGENT.md new file mode 100644 index 00000000..cb2cbe43 --- /dev/null +++ b/ops/remote/minione-ubuntu-infra-4c16g120g.AGENT.md @@ -0,0 +1,63 @@ +# Remote Host AGENT — minione-ubuntu-infra-4c16g120g + +## Host Identity + +- Host name: `minione-ubuntu-infra` +- Tailscale IP: `100.64.0.11` +- LAN IP: `192.168.1.3` +- Access profile: `个人-minione-ubuntu-infra-4c16g120g` + +## Runtime Topology + +- `new-api` runs as a host `systemd` process +- `gitea` runs in Docker Compose under `/opt/gitea` +- PostgreSQL and Redis run as shared Docker infrastructure +- Shared Docker network: `infra-shared` + +## Shared Infrastructure + +### PostgreSQL + +- Container name: `infra-postgres` +- Host port: `127.0.0.1:5433` +- Docker alias: `infra-postgres:5432` +- Databases: + - `new-api` + - `gitea` +- Data path: `/srv/infra/postgres/data` +- Backup path: `/srv/infra/postgres/backup` + +### Redis + +- Container name: `infra-redis` +- Host port: `127.0.0.1:6379` +- Docker alias: `infra-redis:6379` +- Data path: `/srv/infra/redis/data` + +## new-api + +- Service name: `new-api` +- Deploy path: `/root/new-api-deploy` +- Runtime env: `/root/new-api-deploy/.env.runtime` +- systemd unit: `/etc/systemd/system/new-api.service` +- Health check: `curl --noproxy '*' http://127.0.0.1:3000/api/status` + +Host-process connection profile: + +- `SQL_DSN=postgresql://root:@127.0.0.1:5433/new-api` +- `REDIS_CONN_STRING=redis://:@127.0.0.1:6379/0` + +## gitea + +- Compose path: `/opt/gitea/docker-compose.yml` +- Config path: `/opt/gitea/data/gitea/conf/app.ini` +- Web: `http://100.64.0.11:3001/` +- SSH: `ssh -p 2222 git@100.64.0.11` +- Database host: `infra-postgres:5432` + +## Routine Checks + +- `systemctl status new-api` +- `journalctl -u new-api -n 200 --no-pager` +- `docker ps --format '{{.Names}} | {{.Image}} | {{.Ports}}'` +- `ss -lntp | egrep ':3000|:3001|:2222|:5433|:6379'`