diff --git a/newapi/env.cfg.example b/newapi/env.cfg.example index 9e3ee69..615150b 100644 --- a/newapi/env.cfg.example +++ b/newapi/env.cfg.example @@ -8,15 +8,17 @@ # $EDITOR env.cfg # 填入真实密码/密钥后保存 # docker compose -p newapi --env-file ./env.cfg -f ./stack.yml up -d # -# 前置:宿主机 PostgreSQL 建库建号(只需一次): -# sudo -u postgres psql -c "CREATE ROLE newapi LOGIN PASSWORD '<你的强密码>';" -# sudo -u postgres psql -c 'CREATE DATABASE new_api OWNER newapi;' -# sudo -u postgres psql -c 'GRANT ALL PRIVILEGES ON DATABASE new_api TO newapi;' -# # PG < 13 若建表报权限错,补:GRANT ALL ON SCHEMA public TO newapi; +# 说明:本栈为全容器化独立部署(new-api + Redis + PostgreSQL), +# 容器内 PostgreSQL 会自动初始化库和账号,无需在宿主机手动建库或配置 pg_hba。 +# 容器 PG 未映射宿主机端口,不会与宿主机已有的 PostgreSQL 服务产生端口冲突。 # # 注意:SQL_DSN / REDIS_CONN_STRING 为 URL 格式, # 密码建议纯字母+数字,含 @ : / # 等字符时需做百分号转义 +# ---------- 端口 ---------- +# new-api Web 服务对外暴露端口 +PORT=3000 + # ---------- 镜像 ---------- # new-api 版本号(与 GitHub release tag 同名;拉取失败可回退 latest) IMAGE_TAG_VER=v1.0.0-rc.30 @@ -24,20 +26,23 @@ IMAGE_TAG_VER=v1.0.0-rc.30 IMAGE_TAG=calciumion/new-api:${IMAGE_TAG_VER} # Redis 镜像 REDIS_IMAGE_TAG=redis:8.2 +# PostgreSQL 镜像 +PGSQL_IMAGE_TAG=postgres:16-alpine # ---------- 数据卷 ---------- -# 宿主机持久化目录,挂载到容器 /data 与 /app/logs -# 部署前手动创建:mkdir -pv /data/volumes/newapi/{data,logs} +# 宿主机持久化目录,挂载到容器 /data、/app/logs、redis 数据以及 pgsql 数据 +# 部署前手动创建:mkdir -pv /data/volumes/newapi/{data,logs,redis,pgsql_data} Volumes_Path=/data/volumes/newapi -# ---------- 数据库(宿主机已有 PostgreSQL,建议 13+)---------- -DB_HOST=127.0.0.1 +# ---------- 数据库(容器内 PostgreSQL)---------- +# 容器内网络互通,通过服务名 postgres 访问 +DB_HOST=postgres DB_PORT=5432 DB_NAME=new_api DB_USER=newapi DB_PASSWORD= -# ---------- Redis(本栈自建容器,host 网络,只绑 127.0.0.1)---------- +# ---------- Redis(容器内 Redis)---------- REDIS_PASSWORD= # ---------- new-api 应用 ---------- diff --git a/newapi/stack.yml b/newapi/stack.yml index 1d1bf2b..b8d6fb3 100644 --- a/newapi/stack.yml +++ b/newapi/stack.yml @@ -1,10 +1,10 @@ -# path:: mkdir -pv /data/volumes/newapi/{data,logs} +# path:: mkdir -pv /data/volumes/newapi/{data,logs,redis,pgsql_data} # pull:: docker compose -p newapi --env-file ./newapi/env.cfg -f ./newapi/stack.yml pull # run:: docker compose -p newapi --env-file ./newapi/env.cfg -f ./newapi/stack.yml up -d -# disc:: 数据库使用宿主机已有 PostgreSQL,需先建库建号(SQL 见 env.cfg.example),栈内不跑 PG -# disc:: new-api 与 redis 均为 host 网络:无 ports 映射,PG/Redis 经 127.0.0.1 直连, -# disc:: 宿主机 PG 保持默认 localhost 监听即可,无需改 listen_addresses / pg_hba.conf -# disc:: 第一个注册的账号自动成为管理员;公网只放行 80/443,3000 由 Nginx/Caddy 反代,勿直接暴露 +# disc:: 全栈容器化部署:包含 new-api、Redis 缓存及 PostgreSQL 数据库 +# disc:: 容器间处于自定义桥接网络 newapi 内,内部通过服务名 postgres:5432 / redis:6379 互通 +# disc:: 容器 PG 不暴露宿主机端口,与宿主机已有 PostgreSQL 服务互不冲突 +# disc:: 第一个注册的账号自动成为管理员;生产务必修改 env.cfg 中的全部密码 services: newapi: @@ -12,7 +12,13 @@ services: container_name: newapi_app restart: always command: --log-dir /app/logs - network_mode: host + ports: + - "${PORT:-3000}:3000" + networks: + - newapi + depends_on: + - redis + - postgres volumes: - ${Volumes_Path}/data:/data - ${Volumes_Path}/logs:/app/logs @@ -22,18 +28,18 @@ services: - SQL_DSN=postgresql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME} # 本机无 TLS 的 PG 也可显式关闭 SSL: # - SQL_DSN=postgresql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}?sslmode=disable - - REDIS_CONN_STRING=redis://:${REDIS_PASSWORD}@127.0.0.1:6379 + - REDIS_CONN_STRING=redis://:${REDIS_PASSWORD}@redis:6379 - TZ=Asia/Shanghai - BATCH_UPDATE_ENABLED=true - ERROR_LOG_ENABLED=true - NODE_NAME=${NODE_NAME} - SESSION_SECRET=${SESSION_SECRET} # 可选:独立日志库(PG 或 ClickHouse),不设则日志与业务同库 - # - LOG_SQL_DSN=postgresql://user:pass@127.0.0.1:5432/new_api_log + # - LOG_SQL_DSN=postgresql://${DB_USER}:${DB_PASSWORD}@postgres:5432/new_api_log # 流式无响应超时(秒),默认 120,出现空补全时调大: # - STREAMING_TIMEOUT=300 healthcheck: - test: ["CMD-SHELL", "wget -q -O - http://localhost:3000/api/status > /dev/null || exit 1"] + test: ["CMD-SHELL", "wget -q -O - http://127.0.0.1:3000/api/status > /dev/null || exit 1"] interval: 30s timeout: 10s retries: 3 @@ -42,11 +48,40 @@ services: image: ${REDIS_IMAGE_TAG} container_name: newapi_redis restart: always - network_mode: host - # 宿主网络下只绑 127.0.0.1,外部无法直连;宿主机 6379 已被占用时先处理冲突 - command: ["redis-server", "--requirepass", "${REDIS_PASSWORD}", "--bind", "127.0.0.1"] + networks: + - newapi + volumes: + - ${Volumes_Path}/redis:/data + command: ["redis-server", "--requirepass", "${REDIS_PASSWORD}"] healthcheck: test: ["CMD-SHELL", "redis-cli -a ${REDIS_PASSWORD} ping | grep -q PONG"] interval: 10s timeout: 5s retries: 5 + + postgres: + image: ${PGSQL_IMAGE_TAG} + container_name: newapi_pgsql + restart: always + shm_size: 256mb + environment: + - POSTGRES_USER=${DB_USER} + - POSTGRES_PASSWORD=${DB_PASSWORD} + - POSTGRES_DB=${DB_NAME} + - POSTGRES_HOST_AUTH_METHOD=scram-sha-256 + - TZ=Asia/Shanghai + volumes: + - ${Volumes_Path}/pgsql_data:/var/lib/postgresql/data + - /etc/timezone:/etc/timezone:ro + - /etc/localtime:/etc/localtime:ro + networks: + - newapi + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${DB_USER} -d ${DB_NAME}"] + interval: 10s + timeout: 5s + retries: 5 + +networks: + newapi: + driver: bridge