chore: 重构 CI/CD 与 Docker 发布流程
Some checks failed
CI / ci (push) Failing after 2s

将部署链路调整为 CI 构建推送镜像、服务器拉取镜像运行,并拆分/复用 Gitea workflow 与公共准备脚本;同时统一 APP_NAME 与端口变量配置,补充 Docker 与 ESLint 相关配置文件以提升可维护性。

Made-with: Cursor
This commit is contained in:
2026-04-28 01:44:37 +08:00
parent 132f51705e
commit 3076b7ec54
16 changed files with 751 additions and 275 deletions

View File

@@ -0,0 +1,167 @@
# ChatOne Service Docker 部署Compose
本文提供单机 Docker Compose 部署方案,包含 `app`(数据库与 Redis 使用远程实例)。
域名、HTTPS、反向代理统一在宿主机 Nginx 处理。
## 1. 文件位置
- `deploy/docker/Dockerfile`
- `deploy/docker/app.entrypoint.sh`
- `deploy/docker/ecosystem.config.cjs`
- `deploy/docker/docker-compose.yml`
- `deploy/docker/.env.example`
## 2. 初始化
```bash
cd deploy/docker
cp .env.example .env
```
修改 `.env` 中所有密钥与密码,至少包括:
- `JWT_ACCESS_SECRET`
- `JWT_REFRESH_SECRET`
- `QWEN_API_KEY`(如使用)
- `DATABASE_URL`
- `REDIS_PASSWORD`
- `IMAGE_REPO`
- `IMAGE_TAG`
请将 `DATABASE_URL``REDIS_HOST``REDIS_PASSWORD` 替换为远程实例配置。
镜像发布模式说明:
- CI 负责构建并推送 `${IMAGE_REPO}:${IMAGE_TAG}`
- 目标服务器仅执行 `docker compose pull + up`
端口统一约定:
- `PORT`:容器内应用监听端口
- `HOST_BIND_PORT`:宿主机绑定端口(供宿主机 Nginx 反代)
## 3. 启动
在项目根目录执行:
```bash
docker compose -f deploy/docker/docker-compose.yml --env-file deploy/docker/.env up -d --build
```
查看状态:
```bash
docker compose -f deploy/docker/docker-compose.yml ps
docker compose -f deploy/docker/docker-compose.yml logs -f app
```
## 4. 验证
```bash
curl -i http://127.0.0.1:${HOST_BIND_PORT}/api/docs
```
SSE 冒烟:
- `POST /api/client/v1/chat/completions/stream`
## 5. 发布升级
拉取新代码后执行:
```bash
docker compose -f deploy/docker/docker-compose.yml --env-file deploy/docker/.env up -d --build app
```
数据库迁移会在 `app` 容器启动时自动执行(`npx prisma migrate deploy`)。
应用进程由容器内 `pm2-runtime` 管理。
## 6. 回滚
推荐在发布前打镜像标签,例如:
```bash
docker build -f deploy/docker/Dockerfile -t chat-one-service:20260426 .
```
回滚时将 compose 中 `app.image` 改为旧标签,然后:
```bash
docker compose -f deploy/docker/docker-compose.yml --env-file deploy/docker/.env up -d app
```
## 7. 生产建议
- 不要把 `.env` 提交到仓库。
- `app` 仅监听本机 `127.0.0.1:${HOST_BIND_PORT}`,由宿主机 Nginx 反向代理。
- PostgreSQL/Redis 建议使用托管或远程实例,并通过白名单限制访问来源。
- HTTPS 由宿主机 Nginx 统一终止,保留 SSE 反代配置(`proxy_buffering off`、长超时)。
- 定时备份 Postgres
- `pg_dump` 每日一次,保留 7-14 天并异地存储。
## 8. 宿主机 Nginx 配置示例
将域名流量转发到本机 `127.0.0.1:${HOST_BIND_PORT}`(容器 app 端口),并确保 SSE 可用。
### 8.1 HTTP 示例
```nginx
server {
listen 80;
server_name api.your-domain.com;
client_max_body_size 20m;
location / {
proxy_pass http://127.0.0.1:${HOST_BIND_PORT};
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;
# SSE support
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 3600;
proxy_send_timeout 3600;
chunked_transfer_encoding off;
}
}
```
### 8.2 HTTPS 示例(推荐)
```nginx
server {
listen 443 ssl http2;
server_name api.your-domain.com;
ssl_certificate /etc/letsencrypt/live/api.your-domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.your-domain.com/privkey.pem;
client_max_body_size 20m;
location / {
proxy_pass http://127.0.0.1:${HOST_BIND_PORT};
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;
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 3600;
proxy_send_timeout 3600;
chunked_transfer_encoding off;
}
}
```
应用配置后执行:
```bash
sudo nginx -t && sudo systemctl reload nginx
```

View File

@@ -1,249 +0,0 @@
# ChatOne Service 单机部署指南Ubuntu + PM2 + Nginx
本文给出 `chat-one-service` 在单机 Linux 环境的可执行部署流程,覆盖:
- 服务器基线检查
- 生产环境变量合同
- 发布与回滚流程
- Nginx 反向代理(含 SSE
- 监控、备份与巡检
## 1. 适用范围
- OSUbuntu 22.04 LTS
- RuntimeNode.js 22.x
- 进程管理PM2
- 反向代理Nginx
- 依赖PostgreSQL、Redis可为外部托管
## 2. 服务器基线检查(部署前)
### 2.1 主机与网络
- [ ] 已准备公网域名(示例:`api.example.com`
- [ ] `22/80/443` 已开放
- [ ] 应用端口(默认 `3000`)仅允许本机访问
- [ ] 时区与 NTP 已校准(`timedatectl status`
### 2.2 账号与权限
- [ ] 创建专用用户:`chatone`
- [ ] 禁止 root 直登,仅 SSH Key 登录
- [ ] `chatone` 拥有 `/srv/chat-one-service` 读写权限
### 2.3 依赖连通性
- [ ] PostgreSQL 可连接(`DATABASE_URL` 可用)
- [ ] Redis 可连接(`REDIS_HOST/PORT` 可用)
- [ ] 第三方 AI API Key 已可用(如 `QWEN_API_KEY`
## 3. 目录约定
```bash
/srv/chat-one-service/
releases/
20260423_120000/
current -> /srv/chat-one-service/releases/20260423_120000
shared/
.env
logs/
```
初始化目录:
```bash
sudo mkdir -p /srv/chat-one-service/{releases,shared/logs}
sudo chown -R chatone:chatone /srv/chat-one-service
```
## 4. 运行时安装
```bash
# Node.js 22nvm 方式,推荐)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
source ~/.nvm/nvm.sh
nvm install 22
nvm use 22
# Yarn + PM2
npm i -g yarn pm2
# Nginx + certbot
sudo apt-get update
sudo apt-get install -y nginx certbot python3-certbot-nginx postgresql-client redis-tools
```
## 5. 生产环境变量合同shared/.env
`/srv/chat-one-service/shared/.env` 写入:
```dotenv
# app
NODE_ENV=production
PORT=3000
APP_NAME=chat-one-service
# jwt至少 32 位随机串)
JWT_ACCESS_SECRET=replace-with-long-random-string
JWT_REFRESH_SECRET=replace-with-long-random-string
JWT_ACCESS_EXPIRES_IN=2h
JWT_REFRESH_EXPIRES_IN=30d
# database
DATABASE_URL=postgresql://user:password@host:5432/chat_one?schema=public
# redis
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_PASSWORD=
REDIS_DB=0
REDIS_KEY_PREFIX_CLIENT=chatone:client
REDIS_KEY_PREFIX_ADMIN=chatone:admin
# ai
QWEN_API_KEY=
QWEN_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
DEEPSEEK_API_KEY=
VOLC_API_KEY=
# ai route
AI_ROUTE_RETRY_TIMES=1
AI_ROUTE_TIMEOUT_MS=45000
```
安全要求:
- `.env` 仅服务器本地保存,不入仓库。
- 定期轮换密钥,变更后执行 `pm2 reload chat-one-service --update-env`
## 6. 首次部署流程
以下命令以 `chatone` 用户执行:
```bash
set -e
APP_ROOT=/srv/chat-one-service
RELEASE="$APP_ROOT/releases/$(date +%Y%m%d_%H%M%S)"
mkdir -p "$RELEASE"
git clone <your-repo-url> "$RELEASE"
cd "$RELEASE"
yarn install --frozen-lockfile
yarn build
npx prisma migrate deploy
ln -sfn "$RELEASE" "$APP_ROOT/current"
```
启动:
```bash
cd /srv/chat-one-service/current
pm2 start ecosystem.config.js --env production
pm2 save
pm2 startup
```
## 7. 日常发布流程(零停机)
```bash
set -e
APP_ROOT=/srv/chat-one-service
RELEASE="$APP_ROOT/releases/$(date +%Y%m%d_%H%M%S)"
mkdir -p "$RELEASE"
git clone <your-repo-url> "$RELEASE"
cd "$RELEASE"
yarn install --frozen-lockfile
yarn build
npx prisma migrate deploy
ln -sfn "$RELEASE" "$APP_ROOT/current"
pm2 reload chat-one-service --update-env
```
发布后验证:
```bash
curl -fsS http://127.0.0.1:3000/api/docs >/dev/null
curl -fsS https://api.example.com/api/docs >/dev/null
```
如需 SSE 冒烟测试,调用:
- `POST /api/client/v1/chat/completions/stream`
## 8. Nginx 配置(含 SSE
参考文件:`deploy/nginx/chat-one-service.conf`
生效步骤:
```bash
sudo cp deploy/nginx/chat-one-service.conf /etc/nginx/sites-available/chat-one-service.conf
sudo ln -sfn /etc/nginx/sites-available/chat-one-service.conf /etc/nginx/sites-enabled/chat-one-service.conf
sudo nginx -t
sudo systemctl reload nginx
```
申请 HTTPS
```bash
sudo certbot --nginx -d api.example.com
```
## 9. 回滚策略
### 9.1 代码回滚(快速)
```bash
APP_ROOT=/srv/chat-one-service
ls -1dt "$APP_ROOT"/releases/* | sed -n '1,2p' # 找到上一个版本
ln -sfn <previous-release-path> "$APP_ROOT/current"
pm2 reload chat-one-service --update-env
```
### 9.2 数据回滚(高风险)
- 仅在迁移引发严重问题时执行。
- 使用最近一次全量备份恢复(建议维护停机窗口)。
## 10. 备份与监控最小集
### 10.1 PostgreSQL 备份
每日定时cron
```bash
pg_dump "$DATABASE_URL" | gzip > /data/backup/chat_one_$(date +%F).sql.gz
```
建议:
- 保留 7-14 天
- 同步到对象存储(异地)
### 10.2 应用观测
- PM2重启次数、内存、CPU
- Nginx`4xx/5xx` 比率、延迟
- Redis连接数与内存
- 日志:按天滚动,至少保留 7 天
## 11. 常用排障命令
```bash
pm2 ls
pm2 logs chat-one-service --lines 200
pm2 describe chat-one-service
sudo systemctl status nginx
sudo tail -n 200 /var/log/nginx/error.log
curl -i http://127.0.0.1:3000/api/docs
```
## 12. 安全加固建议
- 安全组白名单限制 SSH 来源
- 开启 UFW仅放行 `22/80/443`
- 禁止将 `.env`、备份明文文件提交到 Git
- 配置 fail2ban可选