mirror of
https://github.com/Cccc-owo/CheckInApp.git
synced 2026-06-17 05:56:29 +00:00
feat(deploy): add compose deployment
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
.git
|
||||
.gitignore
|
||||
.dockerignore
|
||||
|
||||
.venv/
|
||||
venv/
|
||||
env/
|
||||
ENV/
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*.egg-info/
|
||||
.pytest_cache/
|
||||
.ruff_cache/
|
||||
.mypy_cache/
|
||||
|
||||
apps/frontend/node_modules/
|
||||
apps/frontend/dist/
|
||||
apps/frontend/.vite/
|
||||
|
||||
data/
|
||||
sessions/
|
||||
logs/
|
||||
*.log
|
||||
*.pid
|
||||
*.lock
|
||||
!uv.lock
|
||||
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
!deploy/compose.env.example
|
||||
|
||||
debug_page_source.html
|
||||
debug_screenshot.png
|
||||
chrome-linux64/
|
||||
chrome-win64/
|
||||
chromedriver
|
||||
chromedriver.exe
|
||||
|
||||
.playwright-cli/
|
||||
output/
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
.claude/
|
||||
.codex/
|
||||
openspec/
|
||||
+6
-3
@@ -20,7 +20,8 @@ debug_page_source.html
|
||||
debug_screenshot.png
|
||||
|
||||
# 运行时文件
|
||||
sessions/
|
||||
sessions/*
|
||||
!sessions/.gitkeep
|
||||
*.lock
|
||||
!/uv.lock
|
||||
*.log
|
||||
@@ -29,14 +30,16 @@ backend.pid
|
||||
frontend.pid
|
||||
|
||||
# 数据库
|
||||
data/
|
||||
data/*
|
||||
!data/.gitkeep
|
||||
|
||||
# 配置文件
|
||||
.env
|
||||
config.ini
|
||||
|
||||
# 日志
|
||||
logs/
|
||||
logs/*
|
||||
!logs/.gitkeep
|
||||
|
||||
# IDE
|
||||
.vscode/
|
||||
|
||||
@@ -49,6 +49,18 @@ pnpm dev
|
||||
uv run python apps/backend/scripts/create_admin.py
|
||||
```
|
||||
|
||||
### Docker Compose 部署
|
||||
|
||||
生产环境推荐使用 Docker Compose。主机只需要 Docker/Compose,不需要单独安装 Python、Node.js、pnpm 或 Chromium。
|
||||
|
||||
```bash
|
||||
cp deploy/compose.env.example .env
|
||||
# 编辑 .env,至少修改 SECRET_KEY、CORS_ORIGINS、FRONTEND_URL
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
默认访问地址:<http://localhost:8080>
|
||||
|
||||
### 访问地址
|
||||
|
||||
- 前端: <http://localhost:3000>
|
||||
@@ -68,7 +80,7 @@ python main.py frontend-build
|
||||
|
||||
复制 `.env.example` 到 `.env`
|
||||
|
||||
nginx 与 systemd 的配置文件参考已给出,见 `.example`
|
||||
Docker Compose 环境变量参考 `deploy/compose.env.example`。nginx 与 systemd 的传统部署配置文件参考已给出,见 `.example`
|
||||
|
||||
## 文档
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
services:
|
||||
backend:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: deploy/docker/backend/Dockerfile
|
||||
image: checkin-app-backend:local
|
||||
container_name: checkin-backend
|
||||
env_file:
|
||||
- path: .env
|
||||
required: false
|
||||
environment:
|
||||
DATABASE_URL: ${DATABASE_URL:-sqlite:////app/data/checkin.db}
|
||||
LOG_FILE: ${LOG_FILE:-/app/logs/backend.log}
|
||||
SESSION_DIR: ${SESSION_DIR:-/app/sessions}
|
||||
BROWSER_EXECUTABLE_PATH: ${BROWSER_EXECUTABLE_PATH:-}
|
||||
volumes:
|
||||
- ./data:/app/data
|
||||
- ./sessions:/app/sessions
|
||||
- ./logs:/app/logs
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
"CMD-SHELL",
|
||||
"python -c \"import json, urllib.request; r=urllib.request.urlopen('http://127.0.0.1:8000/health', timeout=5); raise SystemExit(0 if json.load(r).get('status') == 'healthy' else 1)\"",
|
||||
]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
start_period: 40s
|
||||
|
||||
web:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: deploy/docker/web/Dockerfile
|
||||
image: checkin-app-web:local
|
||||
container_name: checkin-web
|
||||
depends_on:
|
||||
backend:
|
||||
condition: service_healthy
|
||||
ports:
|
||||
- "${CHECKIN_WEB_PORT:-8080}:80"
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1/health >/dev/null"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
start_period: 10s
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
# Copy this file to .env before running Docker Compose:
|
||||
# cp deploy/compose.env.example .env
|
||||
|
||||
# Public web port exposed by the web service.
|
||||
CHECKIN_WEB_PORT=8080
|
||||
|
||||
# ==================== Backend runtime paths ====================
|
||||
# Container-local defaults for the Compose deployment.
|
||||
DATABASE_URL=sqlite:////app/data/checkin.db
|
||||
LOG_FILE=/app/logs/backend.log
|
||||
SESSION_DIR=/app/sessions
|
||||
|
||||
# ==================== Security and public URLs ====================
|
||||
# Change this before production use.
|
||||
SECRET_KEY=change-this-to-a-long-random-secret
|
||||
|
||||
# Use the browser origins that will open the frontend.
|
||||
# Public domain + optional intranet origins.
|
||||
CORS_ORIGINS=https://checkin.example.com,http://192.168.1.10:8080,http://checkin.lan:8080
|
||||
FRONTEND_URL=https://checkin.example.com
|
||||
|
||||
# ==================== Logging ====================
|
||||
LOG_LEVEL=INFO
|
||||
|
||||
# ==================== Mail settings ====================
|
||||
SMTP_SERVER=smtp.example.com
|
||||
SMTP_PORT=465
|
||||
SMTP_SENDER_EMAIL=your-email@example.com
|
||||
SMTP_SENDER_PASSWORD=your-auth-code-here
|
||||
SMTP_USE_SSL=True
|
||||
|
||||
# ==================== Playwright browser settings ====================
|
||||
# Leave empty to use the Chromium installed in the backend image.
|
||||
BROWSER_EXECUTABLE_PATH=
|
||||
|
||||
# ==================== Scheduler settings ====================
|
||||
TOKEN_CHECK_INTERVAL_MINUTES=30
|
||||
SESSION_CLEANUP_INTERVAL_HOURS=24
|
||||
@@ -0,0 +1,23 @@
|
||||
FROM python:3.14-slim AS runtime
|
||||
|
||||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
PYTHONPATH=/app/apps \
|
||||
PLAYWRIGHT_BROWSERS_PATH=/ms-playwright \
|
||||
PATH="/app/.venv/bin:${PATH}"
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN python -m pip install --no-cache-dir --upgrade pip uv
|
||||
|
||||
COPY pyproject.toml uv.lock README.md ./
|
||||
COPY main.py ./main.py
|
||||
COPY apps ./apps
|
||||
|
||||
RUN uv sync --frozen --no-dev --extra production \
|
||||
&& playwright install --with-deps chromium \
|
||||
&& mkdir -p /app/data /app/sessions /app/logs
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
CMD ["python", "main.py", "backend", "--host", "0.0.0.0", "--port", "8000", "--no-reload", "--log-level", "info"]
|
||||
@@ -0,0 +1,18 @@
|
||||
FROM node:24-trixie-slim AS frontend-build
|
||||
|
||||
WORKDIR /app/apps/frontend
|
||||
|
||||
RUN corepack enable
|
||||
|
||||
COPY apps/frontend/package.json apps/frontend/pnpm-lock.yaml ./
|
||||
RUN pnpm install --frozen-lockfile
|
||||
|
||||
COPY apps/frontend/ ./
|
||||
RUN pnpm build
|
||||
|
||||
FROM nginx:1.27-alpine AS runtime
|
||||
|
||||
COPY deploy/docker/web/nginx.conf /etc/nginx/conf.d/default.conf
|
||||
COPY --from=frontend-build /app/apps/frontend/dist /usr/share/nginx/html
|
||||
|
||||
EXPOSE 80
|
||||
@@ -0,0 +1,47 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
client_max_body_size 10M;
|
||||
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_min_length 1024;
|
||||
gzip_types text/plain text/css application/json application/javascript application/xml image/svg+xml;
|
||||
|
||||
location /api/ {
|
||||
proxy_pass http://backend:8000/api/;
|
||||
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_set_header X-Forwarded-Host $host;
|
||||
proxy_buffering off;
|
||||
proxy_request_buffering off;
|
||||
}
|
||||
|
||||
location ~ ^/(docs|redoc|openapi.json|health)$ {
|
||||
proxy_pass http://backend:8000;
|
||||
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_set_header X-Forwarded-Host $host;
|
||||
}
|
||||
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
||||
}
|
||||
}
|
||||
+207
-102
@@ -1,6 +1,161 @@
|
||||
# 部署指南
|
||||
|
||||
## 环境准备
|
||||
## 推荐方式:Docker Compose
|
||||
|
||||
Docker Compose 是当前推荐的生产部署方式。主机只需要 Docker Engine 和 Docker Compose,Python、Node.js、pnpm、Playwright Chromium 都由镜像构建和容器运行时负责。
|
||||
|
||||
### 系统要求
|
||||
|
||||
- Linux 服务器,建议 Ubuntu 20.04+ / Debian 11+ / CentOS 7+
|
||||
- Docker Engine 24+
|
||||
- Docker Compose v2
|
||||
- 2GB+ RAM
|
||||
- 可访问外网以构建镜像和下载依赖
|
||||
|
||||
### 首次部署
|
||||
|
||||
```bash
|
||||
git clone <repository>
|
||||
cd CheckInApp
|
||||
|
||||
cp deploy/compose.env.example .env
|
||||
```
|
||||
|
||||
编辑 `.env`,至少修改:
|
||||
|
||||
- `SECRET_KEY`: 改成足够长的随机字符串。
|
||||
- `CORS_ORIGINS`: 改成浏览器实际访问的站点,例如 `https://checkin.example.com`。
|
||||
- `FRONTEND_URL`: 改成同一个公开站点,用于邮件里的链接。
|
||||
- `CHECKIN_WEB_PORT`: 默认 `8080`,按服务器端口规划调整。
|
||||
- SMTP 配置:需要邮件通知时填写真实 SMTP 参数。
|
||||
|
||||
启动:
|
||||
|
||||
```bash
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
默认访问:
|
||||
|
||||
- Web UI: `http://localhost:8080`
|
||||
- API 健康检查: `http://localhost:8080/health`
|
||||
- API 文档: `http://localhost:8080/docs`
|
||||
|
||||
### 运行结构
|
||||
|
||||
Compose 启动两个服务:
|
||||
|
||||
- `backend`: FastAPI、APScheduler、SQLAlchemy、Playwright Chromium。
|
||||
- `web`: nginx,负责前端静态资源、SPA fallback,以及代理 `/api`、`/docs`、`/redoc`、`/openapi.json`、`/health` 到 backend。
|
||||
|
||||
持久化目录:
|
||||
|
||||
- `./data:/app/data`: SQLite 数据库,默认 `data/checkin.db`。
|
||||
- `./sessions:/app/sessions`: Playwright 登录会话状态。
|
||||
- `./logs:/app/logs`: 后端日志文件。
|
||||
|
||||
容器重建或镜像更新不会删除这些目录。
|
||||
|
||||
### 创建管理员
|
||||
|
||||
先让目标用户完成一次 QQ 扫码注册,然后在容器内运行管理员脚本:
|
||||
|
||||
```bash
|
||||
docker compose exec backend uv run python apps/backend/scripts/create_admin.py
|
||||
```
|
||||
|
||||
脚本会提示输入要升级的用户别名。
|
||||
|
||||
### 常用运维命令
|
||||
|
||||
```bash
|
||||
# 查看服务状态
|
||||
docker compose ps
|
||||
|
||||
# 查看日志
|
||||
docker compose logs -f backend
|
||||
docker compose logs -f web
|
||||
|
||||
# 重启
|
||||
docker compose restart
|
||||
|
||||
# 停止
|
||||
docker compose down
|
||||
```
|
||||
|
||||
### 更新
|
||||
|
||||
```bash
|
||||
git pull
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
不要使用 `docker compose down -v`,否则会删除 Compose 管理的卷。当前默认使用项目目录 bind mount,仍应避免误删 `data/`、`sessions/`、`logs/`。
|
||||
|
||||
### 备份与恢复
|
||||
|
||||
备份 SQLite 和运行时状态:
|
||||
|
||||
```bash
|
||||
mkdir -p backups
|
||||
tar -czf backups/checkin-$(date +%Y%m%d-%H%M%S).tar.gz data sessions logs .env
|
||||
```
|
||||
|
||||
恢复:
|
||||
|
||||
```bash
|
||||
docker compose down
|
||||
tar -xzf backups/<backup-file>.tar.gz
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### 回滚
|
||||
|
||||
```bash
|
||||
git checkout <previous-tag-or-commit>
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
回滚时复用同一份 `.env`、`data/`、`sessions/`、`logs/`。如果未来版本引入数据库迁移,按对应版本说明先确认迁移是否可逆。
|
||||
|
||||
### Compose 故障排查
|
||||
|
||||
端口占用:
|
||||
|
||||
```bash
|
||||
sudo lsof -i :8080
|
||||
```
|
||||
|
||||
修改 `.env` 中的 `CHECKIN_WEB_PORT` 后重新启动:
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
后端健康检查失败:
|
||||
|
||||
```bash
|
||||
docker compose logs backend
|
||||
docker compose exec backend uv run python main.py backend --check
|
||||
```
|
||||
|
||||
Playwright 问题:
|
||||
|
||||
- Compose 部署不需要在主机安装 Chrome/Chromium。
|
||||
- 如果 QQ 登录或 payload 捕获失败,先查看 `docker compose logs backend` 和 `logs/backend.log`。
|
||||
- 重新构建镜像可刷新 Playwright 浏览器依赖:`docker compose build --no-cache backend`。
|
||||
|
||||
权限问题:
|
||||
|
||||
```bash
|
||||
mkdir -p data sessions logs
|
||||
chmod -R u+rwX data sessions logs
|
||||
docker compose restart backend
|
||||
```
|
||||
|
||||
## 备选方式:传统部署
|
||||
|
||||
传统部署适合已经有主机级 Python、Node.js、pnpm、Chromium、nginx 和 systemd 管理经验的环境。
|
||||
|
||||
### 系统要求
|
||||
|
||||
@@ -27,137 +182,127 @@ npm install -g pnpm
|
||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
```
|
||||
|
||||
## 生产部署
|
||||
|
||||
### 方式一:传统部署
|
||||
|
||||
#### 1. 后端部署
|
||||
### 后端部署
|
||||
|
||||
```bash
|
||||
# 克隆项目
|
||||
git clone <repository>
|
||||
cd CheckInApp
|
||||
|
||||
# 安装依赖
|
||||
uv sync
|
||||
|
||||
# 生产环境额外依赖
|
||||
uv sync --extra production
|
||||
|
||||
# 配置环境变量
|
||||
cp .env.example .env
|
||||
vim .env # 修改环境变量
|
||||
vim .env
|
||||
|
||||
uv run playwright install chromium
|
||||
uv run python main.py backend --no-reload
|
||||
```
|
||||
|
||||
#### 2. 前端部署
|
||||
### 前端部署
|
||||
|
||||
```bash
|
||||
cd apps/frontend
|
||||
|
||||
# 安装依赖
|
||||
pnpm install --frozen-lockfile
|
||||
|
||||
# 构建生产版本
|
||||
pnpm build
|
||||
|
||||
# 输出在 dist/ 目录
|
||||
```
|
||||
|
||||
**使用 Nginx 托管**:
|
||||
生产静态资源输出在 `apps/frontend/dist/`。
|
||||
|
||||
[示例文件](../deploy/nginx/checkin-app.conf.example)
|
||||
nginx 示例文件:[deploy/nginx/checkin-app.conf.example](../deploy/nginx/checkin-app.conf.example)
|
||||
|
||||
#### 3. 使用 Systemd 管理
|
||||
|
||||
[示例文件](../deploy/systemd/checkin-app.service.example)
|
||||
|
||||
### 方式二:Docker 部署(推荐)
|
||||
|
||||
TODO(Maybe never)
|
||||
systemd 示例文件:[deploy/systemd/checkin-app.service.example](../deploy/systemd/checkin-app.service.example)
|
||||
|
||||
## 配置优化
|
||||
|
||||
### 生产环境变量
|
||||
|
||||
[示例文件](../.env.example)
|
||||
Compose 部署参考:[deploy/compose.env.example](../deploy/compose.env.example)
|
||||
|
||||
传统部署参考:[.env.example](../.env.example)
|
||||
|
||||
### 数据库迁移到 PostgreSQL
|
||||
|
||||
当前 Compose baseline 使用 SQLite 单后端部署。需要 PostgreSQL 时,先按传统方式准备数据库并修改 `DATABASE_URL`:
|
||||
|
||||
```bash
|
||||
# 安装 PostgreSQL
|
||||
sudo apt install postgresql postgresql-contrib
|
||||
|
||||
# 创建数据库
|
||||
sudo -u postgres createdb checkin
|
||||
sudo -u postgres createuser checkin_user
|
||||
sudo -u postgres psql -c "ALTER USER checkin_user WITH PASSWORD 'password';"
|
||||
|
||||
# 修改 .env
|
||||
DATABASE_URL=postgresql://checkin_user:password@localhost/checkin
|
||||
```
|
||||
|
||||
## 安全加固
|
||||
|
||||
### 1. 防火墙配置
|
||||
### 防火墙配置
|
||||
|
||||
```bash
|
||||
sudo ufw allow 22/tcp # SSH
|
||||
sudo ufw allow 80/tcp # HTTP
|
||||
sudo ufw allow 443/tcp # HTTPS
|
||||
sudo ufw allow 22/tcp
|
||||
sudo ufw allow 80/tcp
|
||||
sudo ufw allow 443/tcp
|
||||
sudo ufw enable
|
||||
```
|
||||
|
||||
### 2. SSL 证书(Let's Encrypt)
|
||||
如果直接暴露 Compose web 端口,也需要允许 `CHECKIN_WEB_PORT` 对应端口。
|
||||
|
||||
### HTTPS
|
||||
|
||||
推荐在 Compose web 服务前放置外部反向代理或云厂商负载均衡来终止 TLS。传统 nginx 部署可以使用 Let's Encrypt:
|
||||
|
||||
```bash
|
||||
sudo apt install certbot python3-certbot-nginx
|
||||
|
||||
sudo certbot --nginx -d your-domain.com
|
||||
|
||||
# 自动续期
|
||||
sudo systemctl enable certbot.timer
|
||||
```
|
||||
|
||||
### 3. 限制访问
|
||||
### 访问限制
|
||||
|
||||
- 修改 `.env` 中的 `CORS_ORIGINS` 为实际域名
|
||||
- 在 Nginx 中配置 rate limiting
|
||||
- 使用 fail2ban 防止暴力破解
|
||||
- 生产环境必须修改默认 `SECRET_KEY`。
|
||||
- 将 `CORS_ORIGINS` 和 `FRONTEND_URL` 设置为实际公开域名。
|
||||
- 在外部反向代理中配置 rate limiting。
|
||||
- 使用 fail2ban 防止暴力破解。
|
||||
|
||||
## 监控维护
|
||||
|
||||
### 日志管理
|
||||
### 日志
|
||||
|
||||
Compose:
|
||||
|
||||
```bash
|
||||
docker compose logs -f backend
|
||||
tail -f logs/backend.log
|
||||
```
|
||||
|
||||
传统部署:
|
||||
|
||||
```bash
|
||||
# 查看后端日志
|
||||
tail -f logs/backend.log
|
||||
```
|
||||
|
||||
### 数据库备份
|
||||
|
||||
SQLite:
|
||||
|
||||
```bash
|
||||
# SQLite 备份
|
||||
cp data/checkin.db data/checkin.db.backup
|
||||
|
||||
# PostgreSQL 备份
|
||||
pg_dump checkin > backup.sql
|
||||
|
||||
# 定时备份(crontab)
|
||||
0 2 * * * /path/to/backup.sh
|
||||
```
|
||||
|
||||
### 性能监控
|
||||
PostgreSQL:
|
||||
|
||||
使用工具:
|
||||
|
||||
- Prometheus + Grafana
|
||||
- New Relic
|
||||
- Sentry(错误追踪)
|
||||
```bash
|
||||
pg_dump checkin > backup.sql
|
||||
```
|
||||
|
||||
## 扩展部署
|
||||
|
||||
### 负载均衡
|
||||
|
||||
当前应用包含内置调度器,默认 Compose baseline 只运行一个 backend 服务。多 backend 实例需要先设计调度器互斥或外部调度机制。
|
||||
|
||||
传统 nginx upstream 示例:
|
||||
|
||||
```nginx
|
||||
upstream backend {
|
||||
server 127.0.0.1:8000;
|
||||
@@ -174,50 +319,10 @@ server {
|
||||
|
||||
### Redis 缓存
|
||||
|
||||
```python
|
||||
# 安装 redis
|
||||
```bash
|
||||
uv sync --extra redis
|
||||
```
|
||||
|
||||
# 配置会话存储
|
||||
```env
|
||||
REDIS_URL=redis://localhost:6379/0
|
||||
```
|
||||
|
||||
## 故障排查
|
||||
|
||||
### 端口占用
|
||||
|
||||
```bash
|
||||
sudo lsof -i :8000
|
||||
sudo kill -9 <PID>
|
||||
```
|
||||
|
||||
### Playwright 问题
|
||||
|
||||
```bash
|
||||
# 安装浏览器
|
||||
uv run playwright install chromium
|
||||
|
||||
# 检查系统浏览器(可选)
|
||||
chromium --version
|
||||
google-chrome --version
|
||||
```
|
||||
|
||||
### 权限问题
|
||||
|
||||
```bash
|
||||
# 确保目录权限正确
|
||||
sudo chown -R www-data:www-data /path/to/CheckInApp
|
||||
sudo chmod -R 755 /path/to/CheckInApp
|
||||
```
|
||||
|
||||
## 回滚策略
|
||||
|
||||
```bash
|
||||
# 保存当前版本
|
||||
git tag -a v2.0.0 -m "Production release"
|
||||
|
||||
# 回滚到上一版本
|
||||
git checkout v1.9.0
|
||||
docker-compose down
|
||||
docker-compose up -d --build
|
||||
```
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
Reference in New Issue
Block a user