12 KiB
12 KiB
部署与运维设计文档
一、部署方式
1.1 Docker Compose(推荐)
一键部署,适合中小团队。
docker compose up -d
包含的服务:
| 服务 | 镜像 | 端口 | 说明 |
|---|---|---|---|
| light-sentry-api | 自建 (Node.js) | 9000 | API 服务 + 管理后台 |
| loki | grafana/loki | 3100 | 日志存储 |
| promtail | grafana/promtail | - | 日志收集(容器日志) |
| grafana | grafana/grafana | 3000 | 数据可视化 |
| dozzle | amir20/dozzle | 8080 | 容器日志查看 |
| nginx | (系统已有) | 80/443 | 反向代理 + SSL |
1.2 二进制部署
适合对 Docker 不熟悉的场景:
- 安装 Node.js 18+
- 安装 Loki(单二进制)
- 安装 Grafana
- 配置 Nginx
- 启动 API 服务(pm2 守护)
1.3 Kubernetes 部署
适合大规模、多租户场景:
- Helm Chart 部署
- HPA 自动扩缩容
- Loki 分布式模式
- MySQL / PostgreSQL 集群
二、资源需求
2.1 最小配置(测试/个人用)
| 资源 | 配置 | 说明 |
|---|---|---|
| CPU | 1 核 | 低流量下足够 |
| 内存 | 1GB | 紧张,可能需要调小 Loki 缓存 |
| 磁盘 | 20GB | 存 7 天日志(每天 ~2GB) |
| 网络 | 1Mbps | 上报流量不大 |
承载能力:
- 10 个项目以内
- 每天 1 万事件以内
2.2 推荐配置(小团队)
| 资源 | 配置 | 说明 |
|---|---|---|
| CPU | 2 核 | 应对突发流量 |
| 内存 | 4GB | Loki + API + Grafana 都够 |
| 磁盘 | 100GB SSD | 存 30 天日志 |
| 网络 | 5Mbps | 足够 |
承载能力:
- 50 个项目以内
- 每天 100 万事件以内
2.3 生产配置(中大型团队)
| 资源 | 配置 | 说明 |
|---|---|---|
| CPU | 4 核以上 | 高并发上报 |
| 内存 | 8GB 以上 | Loki 内存索引 |
| 磁盘 | 500GB+ SSD | 大量日志存储 |
| 网络 | 10Mbps+ | 大流量上报 |
承载能力:
- 200 个项目以内
- 每天 1000 万事件以内
三、Docker Compose 配置详解
3.1 完整配置说明
version: '3.8'
services:
# API 服务 + 管理后台
light-sentry-api:
build: .
container_name: light-sentry-api
network_mode: host
environment:
- NODE_ENV=production
- PORT=9000
- LOKI_URL=http://127.0.0.1:3100
- DATA_DIR=/app/data
volumes:
- ./data:/app/data
restart: unless-stopped
depends_on:
- loki
# Loki - 日志存储
loki:
image: grafana/loki:2.9.4
container_name: light-sentry-loki
network_mode: host
command: -config.file=/etc/loki/local-config.yaml
volumes:
- ./loki/config:/etc/loki
- loki-data:/loki
restart: unless-stopped
# Promtail - 收集容器日志
promtail:
image: grafana/promtail:2.9.4
container_name: light-sentry-promtail
network_mode: host
volumes:
- ./promtail/config:/etc/promtail
- /var/lib/docker/containers:/var/lib/docker/containers:ro
restart: unless-stopped
depends_on:
- loki
# Grafana - 可视化
grafana:
image: grafana/grafana:10.2.0
container_name: light-sentry-grafana
network_mode: host
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin123
volumes:
- grafana-data:/var/lib/grafana
restart: unless-stopped
# Dozzle - 容器日志查看
dozzle:
image: amir20/dozzle:latest
container_name: light-sentry-dozzle
network_mode: host
volumes:
- /var/run/docker.sock:/var/run/docker.sock
restart: unless-stopped
volumes:
loki-data:
grafana-data:
3.2 Loki 配置
loki/config/local-config.yaml
auth_enabled: false
server:
http_listen_port: 3100
ingester:
lifecycler:
ring:
kvstore:
store: inmemory
replication_factor: 1
chunk_idle_period: 30m
chunk_retain_period: 1m
max_transfer_retries: 0
schema_config:
configs:
- from: 2024-01-01
store: boltdb-shipper
object_store: filesystem
schema: v12
index:
prefix: index_
period: 24h
storage_config:
boltdb_shipper:
active_index_directory: /loki/index
cache_location: /loki/index_cache
shared_store: filesystem
filesystem:
directory: /loki/chunks
limits_config:
retention_period: 168h # 7 天
per_stream_rate_limit: 10MB
ingestion_rate_mb: 50
ingestion_burst_size_mb: 100
max_streams_per_user: 10000
max_chunks_per_query: 2000000
max_query_series: 5000
table_manager:
retention_deletes_enabled: true
retention_period: 168h # 7 天
四、Nginx 配置
4.1 反向代理配置
server {
listen 443 ssl http2;
server_name log.example.com;
# SSL 配置
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
# API 服务(Sentry 上报 + 管理后台 API)
location /api/ {
proxy_pass http://127.0.0.1:9000/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_read_timeout 30s;
proxy_connect_timeout 10s;
proxy_send_timeout 30s;
# CORS(SDK 上报需要)
add_header Access-Control-Allow-Origin * always;
add_header Access-Control-Allow-Methods GET,POST,OPTIONS always;
add_header Access-Control-Allow-Headers Content-Type,X-Sentry-Auth always;
if ($request_method = OPTIONS) {
return 204;
}
}
# 管理后台
location /manage/ {
proxy_pass http://127.0.0.1:9000/manage/;
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;
}
# Grafana
location /grafana/ {
proxy_pass http://127.0.0.1:3000/;
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;
}
# Dozzle
location /dozzle/ {
proxy_pass http://127.0.0.1:8080/;
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;
# WebSocket 支持
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# Loki(可选,直接暴露给 Grafana 用,一般不需要外部访问)
location /loki/ {
proxy_pass http://127.0.0.1:3100/;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
deny all; # 禁止外部访问,只允许内网
}
# 根路径重定向到管理后台
location = / {
return 301 /manage/;
}
}
4.2 限流配置
# 定义限流 zone
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=100r/s;
location /api/ {
limit_req zone=api_limit burst=200 nodelay;
# ... 其他配置
}
五、CI/CD 部署
5.1 Gitea Actions 示例
name: Deploy Light-Sentry
on:
push:
branches: [ main ]
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy via SSH
uses: appleboy/ssh-action@v1.0.0
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd ~/light-sentry
git pull
docker compose build light-sentry-api
docker compose up -d
echo "Deploy completed"
5.2 智能重启(只重启变更的服务)
检测变更的文件,只重启相关服务,减少停机时间:
src/**→ 重启 API 服务loki/**→ 重启 Lokigrafana/**→ 重启 Grafanadocker-compose.yml→ 全部重启nginx/**→ reload Nginx
六、监控与告警
6.1 自身监控
Light-Sentry 自己也要监控自己:
| 监控项 | 方式 | 告警阈值 |
|---|---|---|
| API 服务存活 | 健康检查接口 + Prometheus | 502 持续 1 分钟 |
| Loki 服务存活 | Grafana 内置监控 | 连接失败 |
| 磁盘使用率 | Node Exporter | > 80% 告警 |
| 内存使用率 | Node Exporter | > 85% 告警 |
| CPU 使用率 | Node Exporter | > 90% 告警 |
| 事件上报量 | Loki 查询 | 突增 200% |
| 错误率 | Loki 查询 | > 5% |
6.2 健康检查
GET /health
{
"status": "ok",
"timestamp": "2024-01-01T00:00:00Z",
"uptime": 86400,
"queue_size": 123,
"loki": "connected",
"mysql": "connected"
}
七、备份与恢复
7.1 需要备份的数据
| 数据 | 位置 | 备份频率 | 保留时间 |
|---|---|---|---|
| 项目配置 | data/projects.json | 每天 | 30 天 |
| Loki 数据 | loki-data 卷 | 每周 | 4 周 |
| Grafana 配置 | grafana-data 卷 | 每天 | 30 天 |
| 告警规则 | MySQL | 每天 | 永久 |
| 错误聚合 | MySQL | 每天 | 永久 |
7.2 备份脚本
#!/bin/bash
# backup.sh - Light-Sentry 备份脚本
BACKUP_DIR="/backup/light-sentry"
DATE=$(date +%Y%m%d_%H%M%S)
# 创建备份目录
mkdir -p $BACKUP_DIR
# 备份配置文件
tar czf $BACKUP_DIR/config_$DATE.tar.gz /opt/light-sentry/data/
# 备份 Loki 数据(可选,量大)
# docker run --rm -v loki-data:/data -v $BACKUP_DIR:/backup \
# alpine tar czf /backup/loki_$DATE.tar.gz -C /data .
# 备份 Grafana
docker run --rm -v grafana-data:/data -v $BACKUP_DIR:/backup \
alpine tar czf /backup/grafana_$DATE.tar.gz -C /data .
# 清理 30 天前的备份
find $BACKUP_DIR -name "*.tar.gz" -mtime +30 -delete
echo "Backup completed: $DATE"
7.3 恢复流程
# 1. 停止服务
docker compose down
# 2. 恢复配置
tar xzf backup/config_20240101_000000.tar.gz -C /opt/light-sentry/
# 3. 恢复 Grafana
docker run --rm -v grafana-data:/data -v /backup:/backup \
alpine tar xzf /backup/grafana_20240101_000000.tar.gz -C /data
# 4. 启动服务
docker compose up -d
八、性能优化
8.1 API 服务优化
- Node.js 集群模式:利用多核 CPU
- 内存队列调优:根据流量调整队列大小和刷盘频率
- 连接池:数据库连接池、HTTP 连接池
- 缓存:项目配置缓存,不用每次查存储
8.2 Loki 优化
- 调整保留时间:从 7 天调整到实际需要的时间
- 降低索引基数:减少 label 数量
- 批量写入:增加 chunk 大小,减少写入次数
- 内存调优:根据实际数据量调整内存
8.3 Nginx 优化
- 启用 gzip 压缩:减少传输体积
- 启用缓存:静态文件缓存
- TCP 参数调优:增加连接数限制
九、安全加固
9.1 网络安全
- 管理后台加访问密码(HTTP Basic Auth 或登录)
- Loki 不对外暴露(只允许 Grafana 访问)
- Dozzle 加访问密码
- 只开放必要端口(80/443)
9.2 数据安全
- SDK 上报接口 CORS 限制域名(可选)
- 项目 DSN 泄露后可重置 publicKey
- 敏感数据自动脱敏
- 定期备份,异地存储
9.3 依赖安全
- 定期更新依赖
- 镜像扫描漏洞
- 最小权限运行
十、常见问题排查
10.1 事件上报失败
- 检查网络是否通:
curl -I https://log.example.com/api/1001/envelope/ - 检查 DSN 是否正确:publicKey 和 projectId 对应
- 查看 API 日志:
docker logs light-sentry-api - 查看 Nginx 日志:
tail -f /var/log/nginx/access.log
10.2 Grafana 查不到数据
- 检查 Loki 数据源是否配置正确
- 检查时间范围是否正确
- 检查 label 拼写是否正确
- 查看 Loki 日志:
docker logs light-sentry-loki
10.3 服务无法启动
- 检查端口是否被占用:
netstat -tlnp | grep 9000 - 查看容器日志:
docker logs light-sentry-api - 检查配置文件格式:JSON / YAML 语法
- 检查磁盘空间:
df -h
十一、升级策略
11.1 版本升级
# 拉取最新代码
git pull
# 重新构建并启动
docker compose build light-sentry-api
docker compose up -d
# 验证
curl https://log.example.com/health
11.2 数据迁移
- 配置向后兼容,新版本能读旧版本数据
- 启动时自动检测并执行数据迁移
- 迁移前自动备份