Hermes Agent + Obsidian 打造第二大脑(三):Docker 部署详解——从零到生产环境的完整实战指南!

🎯 博主简介

CSDN 「新星创作者」 人工智能技术领域博主,码龄5年 ,累计发布 180+篇原创 文章,博客总访问量 24万+浏览!

🚀 持续更新AI前沿实战知识,专注于 AI 技术实战,多个专栏详细解析,包括:

📱: 安逸Ai--- 每天一点AI:资料、笔记、工具、趋势,一起进步。


📑 目录

  • [1. Docker 部署概述](#1. Docker 部署概述)
    • [1.1 为什么选择 Docker](#1.1 为什么选择 Docker)
    • [1.2 部署架构总览](#1.2 部署架构总览)
    • [1.3 组件通信原理](#1.3 组件通信原理)
  • [2. 完整部署流程](#2. 完整部署流程)
    • [2.1 获取源码](#2.1 获取源码)
    • [2.2 环境配置](#2.2 环境配置)
    • [2.3 启动服务](#2.3 启动服务)
    • [2.4 验证部署](#2.4 验证部署)
  • [3. Obsidian 目录挂载](#3. Obsidian 目录挂载)
    • [3.1 创建挂载目录](#3.1 创建挂载目录)
    • [3.2 配置权限](#3.2 配置权限)
    • [3.3 验证同步](#3.3 验证同步)
    • [3.4 双向同步原理](#3.4 双向同步原理)
  • [4. 生产环境配置](#4. 生产环境配置)
    • [4.1 HTTPS 配置](#4.1 HTTPS 配置)
    • [4.2 域名配置](#4.2 域名配置)
    • [4.3 反向代理配置](#4.3 反向代理配置)
    • [4.4 SSL 证书自动续期](#4.4 SSL 证书自动续期)
  • [5. 运维管理](#5. 运维管理)
    • [5.1 日志查看](#5.1 日志查看)
    • [5.2 监控配置](#5.2 监控配置)
    • [5.3 定时任务](#5.3 定时任务)
  • [6. 扩容方案](#6. 扩容方案)
    • [6.1 水平扩容](#6.1 水平扩容)
    • [6.2 垂直扩容](#6.2 垂直扩容)
    • [6.3 Kubernetes 部署方案](#6.3 Kubernetes 部署方案)
  • [7. 故障排查](#7. 故障排查)
    • [7.1 常见问题](#7.1 常见问题)
    • [7.2 排查命令](#7.2 排查命令)
    • [7.3 日志分析](#7.3 日志分析)
  • [8. 迁移指南](#8. 迁移指南)
    • [8.1 同服务器迁移](#8.1 同服务器迁移)
    • [8.2 跨服务器迁移](#8.2 跨服务器迁移)
    • [8.3 从开发环境到生产环境](#8.3 从开发环境到生产环境)
  • [9. 监控与告警](#9. 监控与告警)
    • [9.1 Prometheus + Grafana 监控](#9.1 Prometheus + Grafana 监控)
    • [9.2 日志收集 ELK 方案](#9.2 日志收集 ELK 方案)
    • [9.3 告警规则配置](#9.3 告警规则配置)
  • [10. 常见问题 FAQ](#10. 常见问题 FAQ)
  • [11. 总结](#11. 总结)

1. Docker 部署概述

1.1 为什么选择 Docker

Docker 是部署 Hermes Agent 的推荐方式,原因如下:

维度 传统部署 Docker 部署
环境依赖 手动安装 Python、Node、PostgreSQL 一键搞定
环境一致性 "在我机器上能跑"问题 跨环境完全一致
版本管理 升级困难 docker compose pull 即可
资源隔离 互相影响 独立容器,互不干扰
清理卸载 残留文件难以清除 docker compose down 干净卸载
水平扩展 复杂 Docker Swarm / K8s 原生支持
快速回滚 困难 版本标签,原生支持
复制代码
┌─────────────────────────────────────────────────────────────────┐
│                    Docker 部署优势图解                           │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   传统部署                  Docker 部署                          │
│                                                                 │
│   ┌─────────┐              ┌─────────┐                          │
│   │ Python  │              │  Container  │                       │
│   │ Node.js │              │  hermes-api │                      │
│   │ Postgres│   =====>    │  hermes-web │                      │
│   │  Redis  │              │  hermes-worker│                    │
│   │   ...   │              │   postgres   │                     │
│   └─────────┘              │   redis      │                     │
│       │                    └──────────────┘                       │
│       ▼                            │                              │
│   环境冲突                   环境隔离                             │
│   版本冲突                   版本固定                             │
│   配置复杂                   配置简单                             │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

1.2 部署架构总览

复制代码
┌────────────────────────────────────────────────────────────────────────────┐
│                         Hermes Agent 部署架构                               │
├────────────────────────────────────────────────────────────────────────────┤
│                                                                            │
│                         用户浏览器/应用                                     │
│                               │                                            │
│                               ▼                                            │
│                    ┌─────────────────────┐                                 │
│                    │   反向代理 (Nginx)  │ ← HTTPS + 域名                  │
│                    │   端口: 80/443      │                                 │
│                    └──────────┬──────────┘                                 │
│                               │                                            │
│                    ┌──────────▼──────────┐                                 │
│                    │   Docker Network    │                                 │
│                    │   hermes-network    │                                 │
│                    └──────────┬──────────┘                                 │
│                               │                                            │
│          ┌───────────────────┼───────────────────┐                        │
│          │                   │                   │                        │
│          ▼                   ▼                   ▼                        │
│    ┌───────────┐       ┌───────────┐       ┌───────────┐                │
│    │    Web    │       │    API    │       │   Worker  │                │
│    │   :3000   │       │   :8080   │       │  (队列)   │                │
│    └───────────┘       └─────┬─────┘       └───────────┘                │
│                               │                                      │
│          ┌───────────────────┼───────────────────┐                      │
│          │                   │                   │                      │
│          ▼                   ▼                   ▼                      │
│    ┌───────────┐       ┌───────────┐       ┌───────────┐              │
│    │ Postgres  │       │   Redis   │       │   Vault   │              │
│    │  :5432   │       │  :6379   │       │ /data/*   │              │
│    └───────────┘       └───────────┘       └───────────┘              │
│                                                                            │
│   外部服务                                                                │
│   ┌─────────────┐     ┌─────────────┐     ┌─────────────┐             │
│   │   OpenAI    │     │  Anthropic  │     │   Ollama    │             │
│   │     API     │     │     API     │     │ (本地模型)  │             │
│   └─────────────┘     └─────────────┘     └─────────────┘             │
│                                                                            │
└────────────────────────────────────────────────────────────────────────────┘

1.3 组件通信原理

复制代码
┌─────────────────────────────────────────────────────────────────┐
│                    组件间通信流程图                                │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  1. 用户请求流程                                                 │
│                                                                 │
│  用户 ──▶ Nginx ──▶ Web (:3000) ──▶ API (:8080)               │
│                                         │                        │
│                                         ▼                        │
│                                   ┌─────────┐                   │
│                                   │ Worker  │                   │
│                                   │ (异步)  │                   │
│                                   └────┬────┘                   │
│                                        │                        │
│  2. 数据写入流程                                                │
│                                                                 │
│  API ──▶ PostgreSQL (:5432)                                    │
│  API ──▶ Redis (:6379)                                         │
│  API ──▶ Vault (文件系统)                                      │
│  API ──▶ LLM Provider (外部 API)                               │
│                                                                 │
│  3. 任务队列流程                                                │
│                                                                 │
│  API ──入队──▶ Redis Queue ──出队──▶ Worker                   │
│                                         │                        │
│                                         ▼                        │
│                                   ┌─────────┐                   │
│                                   │ 处理任务 │                   │
│                                   │ (搜索索引│                   │
│                                   │  等)    │                   │
│                                   └─────────┘                   │
│                                                                 │
│  4. Web 与 API 通信                                            │
│                                                                 │
│  Web ──HTTP──▶ API (REST)                                      │
│  Web ◀──SSE─── API (实时推送)                                  │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

端口与协议对应表

源容器 目标容器 目标端口 协议 用途
web api 8080 HTTP REST API 调用
api postgres 5432 PostgreSQL 数据读写
api redis 6379 Redis 缓存/队列
api vault - 文件系统 文件读写
api llm 外部 HTTPS LLM API 调用
worker postgres 5432 PostgreSQL 数据读写
worker redis 6379 Redis 队列消费
worker vault - 文件系统 文件读写

2. 完整部署流程

2.1 获取源码

bash 复制代码
# 创建工作目录
mkdir -p ~/hermes-agent && cd ~/hermes-agent

# 克隆官方源码(如果有公开仓库)
git clone https://github.com/hermes-agent/hermes-agent.git .

# 或者手动创建 docker-compose.yml 和配置文件
# 参考 02 篇的完整配置

# 查看目录结构
ls -la

完整目录结构

复制代码
hermes-agent/
├── docker-compose.yml          # 容器编排配置(核心)
├── docker-compose.override.yml # 开发环境覆盖配置
├── docker-compose.prod.yml     # 生产环境配置
├── .env                      # 环境变量(不提交 Git)
├── .env.example              # 环境变量模板
├── .env.production           # 生产环境变量模板
├── .gitignore                # Git 忽略配置
├── data/                     # 数据目录
│   ├── vault/              # Obsidian Vault 挂载点
│   ├── postgres/           # PostgreSQL 数据持久化
│   ├── redis/              # Redis 数据持久化
│   └── backups/            # 备份目录
├── logs/                   # 日志目录
├── scripts/                 # 运维脚本
│   ├── backup.sh          # 备份脚本
│   ├── restore.sh         # 恢复脚本
│   ├── healthcheck.sh     # 健康检查脚本
│   ├── migrate.sh         # 数据迁移脚本
│   └── ssl-renew.sh       # SSL 证书续期脚本
├── nginx/                   # Nginx 配置
│   ├── nginx.conf         # 主配置
│   └── conf.d/            # 额外配置
│       └── hermes.conf    # Hermes 站点配置
├── prometheus/             # Prometheus 配置
│   └── prometheus.yml
├── grafana/                # Grafana 配置
│   └── provisioning/
├── README.md               # 项目说明
├── CHANGELOG.md            # 变更日志
└── LICENSE                 # 许可证

2.2 环境配置

复制环境变量模板

bash 复制代码
cp .env.example .env

编辑 .env 文件

bash 复制代码
nano .env  # 或使用 VS Code: code .env

关键配置项详解

bash 复制代码
# ============================================
# 必须配置
# ============================================

# LLM API Key(从 OpenAI/Anthropic 获取)
OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxx

# 或者使用 Anthropic
# ANTHROPIC_API_KEY=sk-ant-xxxxxxxxxxxxxxxx

# 安全密钥(生成随机字符串)
JWT_SECRET=your-jwt-secret-change-this-min-32-chars
API_SECRET_KEY=your-api-secret-change-this-min-32-chars

# Obsidian Vault 路径
OBSIDIAN_VAULT_PATH=/data/vault

# ============================================
# 可选配置(按需调整)
# ============================================

# LLM 提供商选择
LLM_PROVIDER=openai  # openai | anthropic | ollama | azure

# 模型配置
OPENAI_MODEL=gpt-4o
OPENAI_API_BASE=https://api.openai.com/v1
OPENAI_MAX_TOKENS=4096
OPENAI_TEMPERATURE=0.7

# Anthropic 模型
ANTHROPIC_MODEL=claude-3-5-sonnet-20241022
ANTHROPIC_MAX_TOKENS=4096

# Ollama 本地模型(需要本地部署)
OLLAMA_BASE_URL=http://localhost:11434
OLLAMA_MODEL=llama3:70b

# Azure OpenAI(企业用户)
AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com
AZURE_OPENAI_KEY=your-azure-key
AZURE_OPENAI_DEPLOYMENT=gpt-4o

# ============================================
# 端口配置(一般不需要修改)
# ============================================
WEB_PORT=3000
API_PORT=8080

# ============================================
# 数据库配置(生产环境务必修改密码)
# ============================================
POSTGRES_DB=hermes
POSTGRES_USER=hermes
POSTGRES_PASSWORD=your-secure-db-password-here
POSTGRES_HOST=postgres
POSTGRES_PORT=5432
POSTGRES_MAX_CONNECTIONS=200

# ============================================
# Redis 配置(生产环境务必修改密码)
# ============================================
REDIS_HOST=redis
REDIS_PORT=6379
REDIS_PASSWORD=your-secure-redis-password-here
REDIS_DB=0

# ============================================
# 同步配置
# ============================================
SYNC_INTERVAL=30           # 同步间隔(秒)
SYNC_STRATEGY=keep_both    # 同步策略
ENABLE_FILE_LOCK=true
LOCK_TIMEOUT=30

# ============================================
# Worker 配置
# ============================================
WORKER_CONCURRENCY=5       # 并发 worker 数量
WORKER_QUEUE=hermes_tasks  # 任务队列名称
WORKER_RETRY_ATTEMPTS=3    # 重试次数
WORKER_RETRY_DELAY=60      # 重试延迟(秒)

# ============================================
# 日志配置
# ============================================
LOG_LEVEL=info             # debug | info | warn | error
LOG_FORMAT=json            # json | text
LOG_MAX_SIZE=50m          # 单个日志文件大小
LOG_MAX_FILES=5           # 保留日志文件数量

# ============================================
# 性能配置
# ============================================
DB_POOL_SIZE=20            # 数据库连接池大小
DB_POOL_TIMEOUT=30         # 连接池超时(秒)
CACHE_TTL=3600             # 缓存 TTL(秒)

# ============================================
# 安全配置
# ============================================
CORS_ORIGINS=http://localhost:3000,https://your-domain.com
RATE_LIMIT_ENABLED=true
RATE_LIMIT_REQUESTS_PER_MINUTE=60

# ============================================
# 备份配置
# ============================================
BACKUP_ENABLED=true
BACKUP_DIR=/data/backups
BACKUP_RETENTION_DAYS=30

# ============================================
# 国际化
# ============================================
LANGUAGE=zh-CN
TIMEZONE=Asia/Shanghai

生成安全密钥

bash 复制代码
# 方法1: OpenSSL(推荐)
# JWT 密钥(32 字节随机)
openssl rand -base64 32
# 输出示例: Xk9mPqR2sT3vUw5yBz7Jh4Nu6Lc8Df1Eg0OoP3aQbM=

# API 密钥(64 字节十六进制)
openssl rand -hex 32
# 输出示例: a1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456

# 方法2: Python
python3 -c "import secrets; print('JWT_SECRET=' + secrets.token_urlsafe(32))"
python3 -c "import secrets; print('API_SECRET_KEY=' + secrets.token_hex(32))"

# 方法3: macOS
cat /dev/urandom | base64 | head -c 32 | pbcopy

2.3 启动服务

Step 1: 配置 Docker 镜像加速(国内用户)

bash 复制代码
# 编辑 Docker 配置文件
sudo tee /etc/docker/daemon.json << 'EOF'
{
  "registry-mirrors": [
    "https://docker.mirrors.ustc.edu.cn",
    "https://hub-mirror.c.163.com",
    "https://mirror.baidubce.com",
    "https://docker.nju.edu.cn"
  ],
  "builder": {
    "gc": {
      "enabled": true,
      "defaultKeepStorage": "20GB"
    }
  },
  "experimental": false,
  "features": {
    "buildkit": true
  }
}
EOF

# 重启 Docker
sudo systemctl restart docker

# 验证镜像加速
docker info | grep -A 5 "Registry Mirrors"

Step 2: 拉取镜像

bash 复制代码
# 拉取所有镜像(可能需要几分钟)
docker compose pull

# 或者只拉取特定镜像
docker compose pull api worker web postgres redis

# 查看已拉取的镜像
docker images | grep hermes

Step 3: 创建数据目录

bash 复制代码
# 创建数据目录
mkdir -p data/vault data/postgres data/redis data/backups logs

# 设置权限(Docker 容器内用户需要写入权限)
chmod -R 755 data/
chmod -R 755 logs/

# 如果遇到权限问题,尝试
sudo chown -R 1000:1000 data/

Step 4: 启动服务

bash 复制代码
# 后台启动所有服务
docker compose up -d

# 如果需要重新创建容器
docker compose up -d --force-recreate

# 查看启动进度
docker compose logs -f

Step 5: 查看状态

bash 复制代码
# 查看所有容器状态
docker compose ps

# 查看资源使用
docker stats

# 查看网络
docker network ls | grep hermes

预期输出

复制代码
$ docker compose ps
NAME                STATUS          PORTS                     HEALTH
hermes-web        Up (healthy)   0.0.0.0:3000->3000/tcp   healthy
hermes-api        Up (healthy)   0.0.0.0:8080->8080/tcp   healthy
hermes-worker     Up             0.0.0.0:8080              -     
hermes-postgres   Up (healthy)   5432/tcp                  healthy
hermes-redis      Up (healthy)   6379/tcp                  healthy

2.4 验证部署

健康检查 API

bash 复制代码
# API 健康检查
curl http://localhost:8080/health

# 预期输出
{
  "status": "ok",
  "version": "1.0.0",
  "uptime": 1234,
  "services": {
    "database": "connected",
    "redis": "connected",
    "vault": "accessible"
  }
}

# 详细状态检查
curl http://localhost:8080/health/detailed

# 预期输出
{
  "status": "ok",
  "components": {
    "api": {"status": "healthy", "responseTime": "5ms"},
    "web": {"status": "healthy", "responseTime": "10ms"},
    "postgres": {"status": "healthy", "latency": "1ms"},
    "redis": {"status": "healthy", "latency": "0ms"},
    "vault": {"status": "healthy", "path": "/data/vault"}
  },
  "llm": {
    "provider": "openai",
    "status": "configured",
    "daily_usage": {"prompt_tokens": 1500, "completion_tokens": 3200}
  }
}

访问 Web UI

复制代码
浏览器打开: http://localhost:3000

首次访问时需要创建管理员账号:

json 复制代码
{
  "email": "admin@example.com",
  "password": "YourSecurePassword123!",
  "name": "Admin"
}

API 文档

复制代码
访问: http://localhost:8080/api/docs

Swagger UI 会自动加载,显示所有可用 API 端点。

WebSocket 连接测试

bash 复制代码
# 测试 WebSocket 连接
curl -i -N \
  -H "Connection: Upgrade" \
  -H "Upgrade: websocket" \
  -H "Sec-WebSocket-Version: 13" \
  -H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" \
  http://localhost:8080/api/ws

3. Obsidian 目录挂载

3.1 创建挂载目录

bash 复制代码
# 在宿主机创建 Obsidian Vault 目录
mkdir -p ~/Obsidian\ Vault

# 创建基础文件夹结构
cd ~/Obsidian\ Vault
mkdir -p "0_临时" "1_日志" "2_项目" "3_知识"

# 创建 .obsidian 配置目录
mkdir -p .obsidian

# 创建模板目录
mkdir -p templates

Obsidian Vault 完整结构

复制代码
Obsidian Vault/
├── 📁 0_临时/           # 收集箱,临时想法
│   ├── 📝 inbox.md     # 收件箱入口
│   └── 📝 临时笔记/
├── 📁 1_日志/           # 每日日志
│   ├── 📁 每日/         # 每日笔记
│   ├── 📁 周报/         # 周报
│   └── 📁 月报/         # 月报
├── 📁 2_项目/           # 项目笔记
│   ├── 📁 进行中/       # 正在进行的项目
│   ├── 📁 已完成/       # 已完成的项目
│   └── 📁 已归档/       # 已归档的项目
├── 📁 3_知识/           # 知识沉淀
│   ├── 📁 技术/         # 技术文档
│   ├── 📁 产品/         # 产品知识
│   ├── 📁 运营/         # 运营知识
│   └── 📁 设计/         # 设计知识
├── 📁 4_归档/           # 归档资料
├── 📁 templates/        # 模板文件
│   ├── 📝 daily.md      # 每日模板
│   ├── 📝 weekly.md     # 周报模板
│   └── 📝 project.md    # 项目模板
└── 📁 .obsidian/        # Obsidian 配置
    ├── 📝 workspace.json
    └── 📝 community-plugins.json

3.2 配置权限

bash 复制代码
# Docker 容器以特定用户运行,需要配置权限
# 查看容器运行用户
docker compose exec api id
# 输出示例: uid=1000(hermes) gid=1000(hermes) groups=1000(hermes)

# 设置 Vault 目录权限
sudo chown -R 1000:1000 ~/Obsidian\ Vault

# 设置读写权限
chmod -R 755 ~/Obsidian\ Vault
chmod -R 777 ~/Obsidian\ Vault/.obsidian

# 如果使用 WSL2 或 macOS
chmod -R 777 ~/Obsidian\ Vault

权限问题排查流程

复制代码
┌─────────────────────────────────────────────────────────────────┐
│                    权限问题排查流程                              │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  1. 检查目录所有者                                               │
│     ls -la ~/Obsidian\ Vault                                    │
│                                                                 │
│  2. 检查 Docker 容器用户                                         │
│     docker compose exec api id                                  │
│                                                                 │
│  3. 匹配权限                                                    │
│     sudo chown -R 1000:1000 ~/Obsidian\ Vault                  │
│                                                                 │
│  4. 测试写入                                                    │
│     docker compose exec api touch /data/vault/test.md          │
│                                                                 │
│  5. 从容器内删除测试文件                                         │
│     docker compose exec api rm /data/vault/test.md             │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

3.3 验证同步

bash 复制代码
# 在宿主机 Vault 中创建测试文件
echo "# 测试文件" > ~/Obsidian\ Vault/test-sync.md

# 在容器内检查文件是否存在
docker compose exec api ls -la /data/vault/

# 应该看到 test-sync.md

# 通过 Hermes API 触发同步
curl -X POST http://localhost:8080/api/v1/sync/trigger \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $API_TOKEN"

# 预期输出
{
  "status": "success",
  "message": "Sync triggered",
  "files_processed": 1,
  "sync_id": "sync_20260426_123456"
}

# 检查 Obsidian 是否能检测到新文件
# 打开 Obsidian,应该能在 vault 中看到 test-sync.md

3.4 双向同步原理

复制代码
┌─────────────────────────────────────────────────────────────────┐
│                    双向同步原理图                                 │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  Obsidian (本地)                          Hermes (服务器)        │
│  ┌─────────────────┐                    ┌─────────────────┐     │
│  │  用户编辑笔记   │                    │                 │     │
│  │    ↓           │                    │                 │     │
│  │  文件系统变化   │ ──同步──▶          │   接收变化     │     │
│  │    ↓           │                    │   ↓            │     │
│  │  Hermes Watcher│                    │   写入 Vault   │     │
│  │               │                    │   ↓            │     │
│  │  ◀──通知──    │                    │   更新索引     │     │
│  │               │                    │                 │     │
│  └───────────────┘                    └─────────────────┘     │
│          ↑                                      │                │
│          │                                      │                │
│          └──◀─── Hermes 推送变化 ◀─────────────┘                │
│                                                                 │
│  同步冲突处理:                                                   │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                         │    │
│  │   本地版本          服务器版本         合并策略         │    │
│  │   ─────────         ─────────         ─────────         │    │
│  │   keep_both   →    A.md              A.md              │    │
│  │                   A_conflict_20260426.md               │    │
│  │                                                         │    │
│  │   newest_wins →    比较时间戳        保留最新           │    │
│  │                                                         │    │
│  │   manual      →    标记冲突          需手动解决         │    │
│  │                                                         │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

4. 生产环境配置

4.1 HTTPS 配置

使用 Let's Encrypt 免费证书

bash 复制代码
# 安装 certbot
sudo apt update
sudo apt install certbot python3-certbot-nginx

# 停止 Nginx(如果正在运行)
sudo systemctl stop nginx

# 生成证书(standalone 模式)
sudo certbot certonly --standalone -d your-domain.com

# 或者 nginx 模式(需要 Nginx 已配置好)
sudo certbot --nginx -d your-domain.com

# 查看证书位置
sudo ls -la /etc/letsencrypt/live/your-domain.com/

# 证书包含:
# - fullchain.pem  (证书链)
# - privkey.pem    (私钥)
# - cert.pem       (服务器证书)

4.2 域名配置

DNS 记录设置

记录类型 主机名 TTL
A @ 你的服务器 IP 300
A www 你的服务器 IP 300
A api 你的服务器 IP 300
CNAME * @ 300
bash 复制代码
# 验证 DNS 解析
dig your-domain.com
nslookup your-domain.com

# 测试 API 子域名
dig api.your-domain.com

4.3 反向代理配置

完整 Nginx 配置

nginx 复制代码
# /etc/nginx/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
    worker_connections 1024;
    use epoll;
    multi_accept on;
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    # 日志格式
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for" '
                    'rt=$request_time uct="$upstream_connect_time" '
                    'uht="$upstream_header_time" urt="$upstream_response_time"';

    access_log /var/log/nginx/access.log main;

    # 性能优化
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;

    # Gzip 压缩
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types text/plain text/css text/xml application/json application/javascript 
               application/xml application/xml+rss text/javascript application/x-javascript;

    # 限制请求
    limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;

    # 上游服务器
    upstream hermes_api {
        least_conn;
        server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
        keepalive 32;
    }

    upstream hermes_web {
        server 127.0.0.1:3000;
        keepalive 32;
    }

    # HTTP 服务器(重定向到 HTTPS)
    server {
        listen 80;
        server_name your-domain.com api.your-domain.com;

        # Let's Encrypt 验证
        location /.well-known/acme-challenge/ {
            root /var/www/certbot;
            try_files $uri =404;
        }

        # 强制跳转到 HTTPS
        location / {
            return 301 https://$host$request_uri;
        }
    }

    # HTTPS 主站点
    server {
        listen 443 ssl http2;
        server_name your-domain.com;

        # SSL 证书
        ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
        
        # SSL 安全配置
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
        ssl_prefer_server_ciphers off;
        ssl_session_cache shared:SSL:10m;
        ssl_session_timeout 1d;
        ssl_session_tickets off;

        # HSTS(可选,启用后浏览器会强制使用 HTTPS)
        # add_header Strict-Transport-Security "max-age=63072000" always;

        # 安全头
        add_header X-Frame-Options "SAMEORIGIN" always;
        add_header X-Content-Type-Options "nosniff" always;
        add_header X-XSS-Protection "1; mode=block" always;
        add_header Referrer-Policy "strict-origin-when-cross-origin" always;

        # 上传大小限制
        client_max_body_size 100M;
        client_body_timeout 300s;
        proxy_read_timeout 300s;

        # Web UI
        location / {
            proxy_pass http://hermes_web;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            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_cache_bypass $http_upgrade;
            proxy_buffering off;
        }

        # API 请求
        location /api/ {
            proxy_pass http://hermes_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;
            
            # 限流
            limit_req zone=api_limit burst=20 nodelay;
            
            # 超时设置
            proxy_connect_timeout 60s;
            proxy_send_timeout 300s;
            proxy_read_timeout 300s;
        }

        # WebSocket 支持
        location /ws/ {
            proxy_pass http://hermes_api;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            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_read_timeout 86400;
        }

        # 静态资源(如果有)
        location /static/ {
            alias /var/www/hermes/static/;
            expires 30d;
            add_header Cache-Control "public, immutable";
        }

        # 健康检查(无需认证)
        location /health {
            proxy_pass http://hermes_api;
            proxy_http_version 1.1;
            proxy_set_header Host $host;
            access_log off;
        }

        # 错误页面
        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
            root /usr/share/nginx/html;
        }
    }

    # API 专用子域名
    server {
        listen 443 ssl http2;
        server_name api.your-domain.com;

        ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
        ssl_protocols TLSv1.2 TLSv1.3;

        location / {
            proxy_pass http://hermes_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;
        }
    }
}

启用配置并测试

bash 复制代码
# 测试配置语法
sudo nginx -t

# 重载 Nginx
sudo systemctl reload nginx

# 查看 Nginx 状态
sudo systemctl status nginx

4.4 SSL 证书自动续期

创建续期脚本

bash 复制代码
cat > ~/Scripts/ssl-renew.sh << 'EOF'
#!/bin/bash

# 停止 Nginx
sudo systemctl stop nginx

# 续期证书
sudo certbot renew --standalone --pre-hook "sudo systemctl stop nginx" \
                    --post-hook "sudo systemctl start nginx" \
                    --deploy-hook "sudo systemctl reload nginx"

# 如果只想测试续期(不实际执行)
# sudo certbot renew --dry-run

# 查看证书过期时间
sudo certbot certificates
EOF

chmod +x ~/Scripts/ssl-renew.sh

添加到 crontab

bash 复制代码
# 编辑 crontab
crontab -e

# 添加以下行(每天凌晨 2 点检查续期)
0 2 * * * ~/Scripts/ssl-renew.sh >> ~/logs/ssl-renew.log 2>&1

5. 运维管理

5.1 日志查看

bash 复制代码
# 实时查看所有日志
docker compose logs -f

# 查看特定服务日志
docker compose logs -f api
docker compose logs -f web
docker compose logs -f worker
docker compose logs -f postgres
docker compose logs -f redis

# 查看最近 100 行日志
docker compose logs --tail 100

# 保存日志到文件
docker compose logs > hermes_logs_$(date +%Y%m%d).txt

# 搜索日志中的错误
docker compose logs | grep -i error
docker compose logs | grep -i "failed\|timeout\|exception"

# 查看特定时间范围的日志
docker compose logs --since "2026-04-26T10:00:00"
docker compose logs --until "2026-04-26T12:00:00"

# 实时查看多个服务的日志
docker compose logs -f api worker

日志级别说明

级别 含义 使用场景
DEBUG 详细调试信息 排查问题时
INFO 一般信息 正常运行日志
WARN 警告信息 需要关注但不紧急
ERROR 错误信息 需要立即处理
FATAL 致命错误 服务不可用

5.2 监控配置

Docker Stats 实时监控

bash 复制代码
# 查看资源使用(实时刷新)
docker stats

# 查看特定容器资源使用
docker stats hermes-api hermes-worker hermes-web

# 持续监控(每秒刷新)
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}" --no-stream

# 格式化输出示例
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}\t{{.NetIO}}\t{{.BlockIO}}" --no-stream

Prometheus + Grafana 监控方案

yaml 复制代码
# docker-compose.yml 添加监控服务
services:
  prometheus:
    image: prom/prometheus:latest
    container_name: hermes-prometheus
    restart: unless-stopped
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus-data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--web.console.libraries=/etc/prometheus/console_libraries'
      - '--web.console.templates=/etc/prometheus/consoles'
      - '--storage.tsdb.retention.time=30d'
    networks:
      - hermes-network

  grafana:
    image: grafana/grafana:latest
    container_name: hermes-grafana
    restart: unless-stopped
    ports:
      - "3001:3000"
    environment:
      - GF_SECURITY_ADMIN_USER=admin
      - GF_SECURITY_ADMIN_PASSWORD=change-me-in-production
      - GF_USERS_ALLOW_SIGN_UP=false
    volumes:
      - ./grafana/provisioning:/etc/grafana/provisioning
      - grafana-data:/var/lib/grafana
    depends_on:
      - prometheus
    networks:
      - hermes-network

volumes:
  prometheus-data:
  grafana-data:

prometheus.yml 配置

yaml 复制代码
global:
  scrape_interval: 15s
  evaluation_interval: 15s

alerting:
  alertmanagers:
    - static_configs:
        - targets: []

rule_files: []

scrape_configs:
  # Prometheus 自身监控
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

  # Hermes API 监控
  - job_name: 'hermes-api'
    static_configs:
      - targets: ['api:8080']
    metrics_path: '/metrics'
    scrape_interval: 10s

  # Hermes Web 监控
  - job_name: 'hermes-web'
    static_configs:
      - targets: ['web:3000']
    metrics_path: '/metrics'

  # Docker 容器监控
  - job_name: 'cadvisor'
    static_configs:
      - targets: ['cadvisor:8080']

  # PostgreSQL 监控
  - job_name: 'postgres'
    static_configs:
      - targets: ['postgres-exporter:9187']

  # Redis 监控
  - job_name: 'redis'
    static_configs:
      - targets: ['redis-exporter:9121']

5.3 定时任务

自动备份脚本

bash 复制代码
cat > ~/Scripts/hermes-backup.sh << 'EOF'
#!/bin/bash

# ============================================
# Hermes Agent 备份脚本
# ============================================

set -euo pipefail

# 配置
BACKUP_DIR=~/backup/hermes
DATE=$(date +%Y%m%d_%H%M%S)
RETENTION_DAYS=30
LOG_FILE=~/logs/backup.log

# 日志函数
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}

# 创建备份目录
mkdir -p "$BACKUP_DIR"
mkdir -p ~/logs

log "========== 开始备份 =========="

# 1. 备份 Obsidian Vault (Git)
log "备份 Vault (Git)..."
cd ~/Obsidian\ Vault
git add . 2>/dev/null || true
git commit -m "Auto backup $DATE" 2>/dev/null || true
git push origin main 2>/dev/null || log "警告: Git 推送失败"
log "Vault 备份完成"

# 2. 备份 PostgreSQL
log "备份 PostgreSQL..."
docker compose exec -T postgres pg_dump -U "${POSTGRES_USER:-hermes}" "${POSTGRES_DB:-hermes}" > "$BACKUP_DIR/postgres_$DATE.sql"
gzip "$BACKUP_DIR/postgres_$DATE.sql"
log "PostgreSQL 备份完成: postgres_$DATE.sql.gz"

# 3. 备份 Redis
log "备份 Redis..."
docker compose exec redis redis-cli -a "${REDIS_PASSWORD:-}" SAVE 2>/dev/null
docker cp $(docker compose ps -q redis):/data/dump.rdb "$BACKUP_DIR/redis_$DATE.rdb" 2>/dev/null || true
log "Redis 备份完成"

# 4. 备份 Docker 卷
log "备份 Docker 卷..."
tar -czf "$BACKUP_DIR/vault_$DATE.tar.gz" -C ~/ hermes-agent/data/vault 2>/dev/null || true
log "Vault 归档备份完成"

# 5. 清理旧备份
log "清理超过 $RETENTION_DAYS 天的备份..."
find "$BACKUP_DIR" -name "*.sql.gz" -mtime +$RETENTION_DAYS -delete 2>/dev/null || true
find "$BACKUP_DIR" -name "*.rdb" -mtime +$RETENTION_DAYS -delete 2>/dev/null || true
find "$BACKUP_DIR" -name "*.tar.gz" -mtime +$RETENTION_DAYS -delete 2>/dev/null || true
log "旧备份清理完成"

# 6. 显示备份统计
log "========== 备份统计 =========="
log "备份目录: $BACKUP_DIR"
log "最新备份:"
ls -lh "$BACKUP_DIR" | tail -5
log "磁盘使用:"
du -sh "$BACKUP_DIR"

log "========== 备份完成 =========="
EOF

chmod +x ~/Scripts/hermes-backup.sh

# 添加到 crontab
(crontab -l 2>/dev/null; echo "0 3 * * * ~/Scripts/hermes-backup.sh >> ~/logs/backup.log 2>&1") | crontab -

# 手动执行测试
~/Scripts/hermes-backup.sh

自动更新脚本

bash 复制代码
cat > ~/Scripts/hermes-update.sh << 'EOF'
#!/bin/bash

set -euo pipefail

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}

cd ~/hermes-agent

log "========== 开始更新 =========="

# 1. 备份当前状态
log "备份 docker-compose.yml..."
cp docker-compose.yml docker-compose.yml.backup

# 2. 拉取最新镜像
log "拉取最新镜像..."
docker compose pull

# 3. 重启服务
log "重启服务..."
docker compose up -d

# 4. 检查服务状态
sleep 10
docker compose ps

# 5. 检查健康状态
log "检查健康状态..."
curl -sf http://localhost:8080/health > /dev/null && log "API 健康检查通过" || log "警告: API 健康检查失败"
curl -sf http://localhost:3000/health > /dev/null && log "Web 健康检查通过" || log "警告: Web 健康检查失败"

log "========== 更新完成 =========="
EOF

chmod +x ~/Scripts/hermes-update.sh

# 每周日凌晨 4 点更新
(crontab -l 2>/dev/null; echo "0 4 * * 0 ~/Scripts/hermes-update.sh >> ~/logs/update.log 2>&1") | crontab -

6. 扩容方案

6.1 水平扩容

多副本部署架构

复制代码
┌─────────────────────────────────────────────────────────────────┐
│                    水平扩容架构图                                 │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│                        用户请求                                  │
│                           │                                     │
│                           ▼                                     │
│                    ┌─────────────┐                              │
│                    │  Nginx LB   │                              │
│                    │ (负载均衡)  │                              │
│                    └──────┬──────┘                              │
│                           │                                     │
│         ┌─────────────────┼─────────────────┐                   │
│         │                 │                 │                   │
│         ▼                 ▼                 ▼                   │
│    ┌─────────┐       ┌─────────┐       ┌─────────┐            │
│    │ API #1  │       │ API #2  │       │ API #3  │            │
│    │ :8080   │       │ :8081   │       │ :8082   │            │
│    └────┬────┘       └────┬────┘       └────┬────┘            │
│         │                 │                 │                   │
│         └─────────────────┴─────────────────┘                   │
│                           │                                     │
│                           ▼                                     │
│    ┌─────────┐       ┌─────────┐       ┌─────────┐            │
│    │ Worker#1│       │Worker#2 │       │Worker#3 │            │
│    └─────────┘       └─────────┘       └─────────┘            │
│                           │                                     │
│                           ▼                                     │
│                    ┌─────────────┐                              │
│                    │  PostgreSQL │ ← 主库                       │
│                    │  (读写分离)  │                              │
│                    └─────────────┘                              │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

docker-compose.yml 多副本配置

yaml 复制代码
services:
  api:
    deploy:
      replicas: 3  # 3 个副本
    ports:
      - "8080-8082:8080"  # 端口映射范围

  worker:
    deploy:
      replicas: 3  # 3 个副本

Nginx 负载均衡配置

nginx 复制代码
upstream hermes_api {
    least_conn;  # 最少连接算法
    server 127.0.0.1:8080 weight=1 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:8081 weight=1 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:8082 weight=1 max_fails=3 fail_timeout=30s;
    keepalive 32;
}

6.2 垂直扩容

资源配置调整

yaml 复制代码
services:
  api:
    deploy:
      resources:
        limits:
          memory: 4G      # 增加到 4GB
          cpus: '4'       # 增加到 4 核
        reservations:
          memory: 2G
          cpus: '2'
    
  worker:
    deploy:
      resources:
        limits:
          memory: 2G
          cpus: '2'
        reservations:
          memory: 1G

  postgres:
    deploy:
      resources:
        limits:
          memory: 4G
          cpus: '2'
    command: >
      postgres
      -c max_connections=500
      -c shared_buffers=1GB
      -c effective_cache_size=2GB
      -c maintenance_work_mem=256MB
      -c work_mem=16MB

6.3 Kubernetes 部署方案

K8s 部署架构

复制代码
┌─────────────────────────────────────────────────────────────────┐
│                    Kubernetes 架构图                             │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐  │
│   │                    K8s Cluster                          │  │
│   │                                                         │  │
│   │   ┌─────────────────────────────────────────────────┐   │  │
│   │   │              Namespace: hermes                  │   │  │
│   │   │                                                 │   │  │
│   │   │   ┌───────────┐    ┌───────────┐               │   │  │
│   │   │   │  Service  │    │  Service  │               │   │  │
│   │   │   │   web     │    │   api     │               │   │  │
│   │   │   └─────┬─────┘    └─────┬─────┘               │   │  │
│   │   │         │                │                      │   │  │
│   │   │   ┌─────┴─────┐    ┌─────┴─────┐               │   │  │
│   │   │   │ Deployment│    │ Deployment│               │   │  │
│   │   │   │  replicas │    │  replicas │               │   │  │
│   │   │   │    = 3    │    │    = 3    │               │   │  │
│   │   │   └───────────┘    └───────────┘               │   │  │
│   │   │         │                │                      │   │  │
│   │   │         └────────┬───────┘                      │   │  │
│   │   │                  │                              │   │  │
│   │   │   ┌─────────────┴─────────────┐               │   │  │
│   │   │   │       Ingress             │               │   │  │
│   │   │   │   (Nginx Controller)     │               │   │  │
│   │   │   └───────────────────────────┘               │   │  │
│   │   │                                                 │   │  │
│   │   └─────────────────────────────────────────────────┘   │  │
│   │                                                         │  │
│   │   ┌───────────┐    ┌───────────┐    ┌───────────┐     │  │
│   │   │  ConfigMap│    │  Secret   │    │    PVC    │     │  │
│   │   │   env     │    │  api-key  │    │   vault   │     │  │
│   │   └───────────┘    └───────────┘    └───────────┘     │  │
│   │                                                         │  │
│   └─────────────────────────────────────────────────────────┘  │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

K8s 部署清单

yaml 复制代码
# hermes-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hermes-api
  namespace: hermes
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hermes-api
  template:
    metadata:
      labels:
        app: hermes-api
    spec:
      containers:
        - name: api
          image: hermes/hermes-api:latest
          ports:
            - containerPort: 8080
          envFrom:
            - configMapRef:
                name: hermes-config
            - secretRef:
                name: hermes-secrets
          resources:
            requests:
              memory: "512Mi"
              cpu: "250m"
            limits:
              memory: "2Gi"
              cpu: "1000m"
          livenessProbe:
            httpGet:
              path: /health
              port: 8080
            initialDelaySeconds: 30
            periodSeconds: 10
          readinessProbe:
            httpGet:
              path: /health
              port: 8080
            initialDelaySeconds: 5
            periodSeconds: 5
      volumes:
        - name: vault
          persistentVolumeClaim:
            claimName: hermes-vault

---
apiVersion: v1
kind: Service
metadata:
  name: hermes-api
  namespace: hermes
spec:
  selector:
    app: hermes-api
  ports:
    - port: 8080
      targetPort: 8080
  type: ClusterIP

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hermes-worker
  namespace: hermes
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hermes-worker
  template:
    metadata:
      labels:
        app: hermes-worker
    spec:
      containers:
        - name: worker
          image: hermes/hermes-worker:latest
          envFrom:
            - configMapRef:
                name: hermes-config
            - secretRef:
                name: hermes-secrets
          resources:
            requests:
              memory: "256Mi"
              cpu: "100m"
            limits:
              memory: "1Gi"
              cpu: "500m"

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: hermes-vault
  namespace: hermes
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: nfs
  resources:
    requests:
      storage: 50Gi

7. 故障排查

7.1 常见问题

问题 原因 解决方案
容器启动后立即退出 配置错误/端口占用 docker compose logs 查看原因
数据库连接失败 启动顺序问题 添加 depends_on + condition: service_healthy
API 返回 401 Key 配置错误 检查 .env 配置
页面加载慢 资源不足 增加内存/CPU 限制
同步失败 权限问题 chmod 777 Vault 目录
WebSocket 断开 Nginx 未配置 ws 支持 添加 proxy_set_header Upgrade
SSL 证书过期 未配置自动续期 设置 certbot cron 任务

7.2 排查命令

bash 复制代码
# 查看所有容器状态
docker compose ps

# 查看容器详细信息
docker inspect hermes-api

# 查看容器进程
docker top hermes-api

# 进入容器调试
docker compose exec api /bin/sh
docker compose exec postgres psql -U hermes

# 测试网络连通性
docker compose exec api ping postgres
docker compose exec api nc -zv postgres 5432

# 查看资源限制
docker inspect hermes-api | grep -A 20 "HostConfig"

# 查看容器日志
docker compose logs --tail 100 hermes-api

# 查看网络
docker network inspect hermes-network

# 查看卷
docker volume ls
docker volume inspect hermes_vault-data

7.3 日志分析

常见错误代码

错误代码 含义 排查方法
500 服务器内部错误 查看 API 日志 docker compose logs api
502 网关错误 检查上游服务是否运行
503 服务不可用 检查容器健康状态
504 网关超时 增加 proxy_read_timeout
401 未授权 检查 JWT/API Key 配置
403 禁止访问 检查 CORS 和权限配置
404 未找到 检查路由配置
429 请求过多 启用/调整限流配置

日志分析脚本

bash 复制代码
cat > ~/Scripts/analyze-logs.sh << 'EOF'
#!/bin/bash

echo "========== Hermes 日志分析 =========="
echo ""

# 错误统计
echo "错误统计:"
docker compose logs --tail=1000 2>&1 | grep -i error | wc -l
echo "个错误"
echo ""

# 错误类型分布
echo "错误类型分布:"
docker compose logs --tail=1000 2>&1 | grep -i error | sed 's/.*\(ERROR\|error\).*//' | sort | uniq -c | sort -rn | head -10
echo ""

# 最近 20 条错误
echo "最近 20 条错误:"
docker compose logs --tail=100 --since "10m" 2>&1 | grep -i error | tail -20
echo ""

# 警告统计
echo "警告统计:"
docker compose logs --tail=1000 2>&1 | grep -i warn | wc -l
echo "个警告"
echo ""

# 慢查询(PostgreSQL)
echo "PostgreSQL 慢查询:"
docker compose logs postgres --since "1h" 2>&1 | grep -i "slow\|duration" | tail -10
EOF

chmod +x ~/Scripts/analyze-logs.sh

8. 迁移指南

8.1 同服务器迁移

bash 复制代码
# 1. 停止服务
cd ~/hermes-agent
docker compose down

# 2. 备份数据
cp -r data data.backup.$(date +%Y%m%d)
cp docker-compose.yml docker-compose.yml.backup
cp .env .env.backup

# 3. 迁移目录
mv ~/hermes-agent ~/hermes-agent-new

# 4. 启动服务
cd ~/hermes-agent-new
docker compose up -d

# 5. 验证
curl http://localhost:8080/health

8.2 跨服务器迁移

bash 复制代码
# ===== 在旧服务器上执行 =====

# 1. 停止服务
cd ~/hermes-agent
docker compose down

# 2. 备份所有数据
docker compose exec postgres pg_dump -U hermes hermes > hermes_db.sql
tar -czf vault_backup.tar.gz ~/Obsidian\ Vault
tar -czf data_backup.tar.gz data/

# 3. 传输文件到新服务器
scp hermes_db.sql user@new-server:~/hermes-agent/
scp vault_backup.tar.gz user@new-server:~/hermes-agent/
scp data_backup.tar.gz user@new-server:~/hermes-agent/
scp .env user@new-server:~/hermes-agent/

# 4. 传输 docker-compose.yml
scp docker-compose.yml user@new-server:~/hermes-agent/

# ===== 在新服务器上执行 =====

# 1. 安装 Docker(如果未安装)
curl -fsSL https://get.docker.com | sh

# 2. 创建目录
mkdir -p ~/hermes-agent
cd ~/hermes-agent

# 3. 恢复数据
tar -xzf vault_backup.tar.gz
tar -xzf data_backup.tar.gz
mv hermes_db.sql data/postgres/

# 4. 启动服务
docker compose up -d

# 5. 恢复数据库
docker compose exec -T postgres psql -U hermes -d hermes < data/postgres/hermes_db.sql

# 6. 验证
curl http://localhost:8080/health
docker compose ps

8.3 从开发环境到生产环境

bash 复制代码
# 1. 在生产服务器创建目录
mkdir -p ~/hermes-agent && cd ~/hermes-agent

# 2. 复制配置文件
scp user@dev-server:~/hermes-agent/docker-compose.prod.yml ~/hermes-agent/
scp user@dev-server:~/hermes-agent/.env.production ~/hermes-agent/.env

# 3. 编辑 .env,更新生产配置
nano .env
# - 更新 API Keys(使用生产密钥)
# - 更新域名配置
# - 更新数据库密码

# 4. 拉取生产镜像
docker compose -f docker-compose.prod.yml pull

# 5. 启动服务
docker compose -f docker-compose.prod.yml up -d

# 6. 配置 Nginx(生产域名)
sudo cp nginx/hermes.prod.conf /etc/nginx/sites-available/hermes
sudo ln -s /etc/nginx/sites-available/hermes /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

9. 监控与告警

9.1 Prometheus + Grafana 监控

Grafana 仪表盘配置

json 复制代码
{
  "dashboard": {
    "title": "Hermes Agent 监控",
    "tags": ["hermes", "agent"],
    "timezone": "Asia/Shanghai",
    "panels": [
      {
        "title": "API 请求率",
        "type": "graph",
        "targets": [
          {
            "expr": "rate(http_requests_total{service=\"api\"}[5m])",
            "legendFormat": "{{method}} {{path}}"
          }
        ]
      },
      {
        "title": "API 响应时间",
        "type": "graph",
        "targets": [
          {
            "expr": "histogram_quantile(0.95, rate(http_request_duration_seconds_bucket{service=\"api\"}[5m]))",
            "legendFormat": "p95"
          },
          {
            "expr": "histogram_quantile(0.99, rate(http_request_duration_seconds_bucket{service=\"api\"}[5m]))",
            "legendFormat": "p99"
          }
        ]
      },
      {
        "title": "容器 CPU 使用率",
        "type": "graph",
        "targets": [
          {
            "expr": "rate(container_cpu_usage_seconds_total{name=~\"hermes.*\"}[5m]) * 100",
            "legendFormat": "{{name}}"
          }
        ]
      },
      {
        "title": "容器内存使用",
        "type": "graph",
        "targets": [
          {
            "expr": "container_memory_usage_bytes{name=~\"hermes.*\"}",
            "legendFormat": "{{name}}"
          }
        ]
      },
      {
        "title": "任务队列长度",
        "type": "gauge",
        "targets": [
          {
            "expr": "redis_queue_length{queue=\"hermes_tasks\"}",
            "legendFormat": "待处理任务"
          }
        ]
      },
      {
        "title": "数据库连接数",
        "type": "graph",
        "targets": [
          {
            "expr": "pg_stat_database_numbackends{datname=\"hermes\"}",
            "legendFormat": "活动连接"
          },
          {
            "expr": "pg_stat_database_max_connections",
            "legendFormat": "最大连接"
          }
        ]
      }
    ]
  }
}

9.2 日志收集 ELK 方案

复制代码
┌─────────────────────────────────────────────────────────────────┐
│                    ELK 日志收集架构                              │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌─────────┐    ┌─────────┐    ┌─────────┐    ┌─────────┐     │
│  │ Docker  │───▶│ Filebeat│───▶│Logstash │───▶│Elastic  │     │
│  │  Logs   │    │         │    │         │    │search   │     │
│  └─────────┘    └─────────┘    └─────────┘    └────┬────┘     │
│                                                     │           │
│                                                     ▼           │
│                                              ┌─────────┐        │
│                                              │ Grafana │        │
│                                              │ Kibana  │        │
│                                              └─────────┘        │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

9.3 告警规则配置

yaml 复制代码
# alertmanager.yml
global:
  smtp_smarthost: 'smtp.gmail.com:587'
  smtp_from: 'hermes-alerts@gmail.com'
  smtp_auth_username: 'your-email@gmail.com'
  smtp_auth_password: 'your-app-password'

route:
  group_by: ['alertname']
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 4h
  receiver: 'email'

receivers:
  - name: 'email'
    email_configs:
      - to: 'your-email@gmail.com'
        send_resolved: true

# prometheus/rules/hermes-alerts.yml
groups:
  - name: hermes
    rules:
      # 服务宕机告警
      - alert: HermesServiceDown
        expr: up{job="hermes-api"} == 0
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "Hermes API 服务不可用"
          description: "Hermes API 已停止运行超过 1 分钟"

      # 内存使用过高
      - alert: HermesHighMemory
        expr: (container_memory_usage_bytes{name=~"hermes.*"} / container_spec_memory_limit_bytes{name=~"hermes.*"}) > 0.9
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Hermes 内存使用率过高"
          description: "内存使用率超过 90%"

      # CPU 使用过高
      - alert: HermesHighCPU
        expr: rate(container_cpu_usage_seconds_total{name=~"hermes.*"}[5m]) > 0.8
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "Hermes CPU 使用率过高"
          description: "CPU 使用率持续超过 80%"

      # 磁盘空间不足
      - alert: DiskSpaceLow
        expr: (node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}) < 0.1
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "服务器磁盘空间不足"
          description: "磁盘剩余空间少于 10%"

      # API 错误率过高
      - alert: HermesHighErrorRate
        expr: rate(http_requests_total{service="api",status=~"5.."}[5m]) > 0.05
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "Hermes API 错误率过高"
          description: "5xx 错误率超过 5%"

      # 任务队列积压
      - alert: TaskQueueBacklog
        expr: redis_queue_length{queue="hermes_tasks"} > 100
        for: 15m
        labels:
          severity: warning
        annotations:
          summary: "Hermes 任务队列积压"
          description: "待处理任务超过 100 个"

10. 常见问题 FAQ

Q1: 如何完全重启所有服务?

bash 复制代码
docker compose down
docker compose up -d

Q2: 如何查看容器内部进程?

bash 复制代码
# 进入容器 bash
docker compose exec api /bin/bash

# 进入 PostgreSQL
docker compose exec postgres psql -U hermes -d hermes

# 进入 Redis
docker compose exec redis redis-cli -a $REDIS_PASSWORD

Q3: 如何修改已运行容器的配置?

bash 复制代码
# 修改 .env 文件后,重启服务
docker compose up -d

# 如果需要重新创建容器
docker compose up -d --force-recreate

# 只重启特定服务
docker compose restart api

Q4: 如何更新到新版本?

bash 复制代码
# 拉取最新镜像
docker compose pull

# 重启服务
docker compose up -d

# 如果有数据库迁移
docker compose run --rm api migrate

Q5: 如何完全卸载?

bash 复制代码
# 停止服务
docker compose down

# 删除数据(谨慎!)
docker compose down -v

# 删除镜像
docker compose down --rmi all

# 删除残留文件和配置
rm -rf ~/hermes-agent

Q6: 容器间网络不通怎么办?

bash 复制代码
# 检查网络
docker network inspect hermes-network

# 重新创建网络
docker network rm hermes-network
docker compose up -d

# 在容器内测试连通性
docker compose exec api ping postgres
docker compose exec api nc -zv postgres 5432

Q7: 如何限制外部访问?

yaml 复制代码
# 只允许本地访问
services:
  web:
    ports:
      - "127.0.0.1:3000:3000"  # 只有本地能访问

Q8: 如何配置多个环境(开发/测试/生产)?

bash 复制代码
# 开发环境
docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d

# 测试环境
docker compose -f docker-compose.yml -f docker-compose.test.yml up -d

# 生产环境
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

Q9: 如何排查 PostgreSQL 连接问题?

bash 复制代码
# 检查 PostgreSQL 状态
docker compose ps postgres

# 查看日志
docker compose logs postgres | tail -50

# 测试连接
docker compose exec api nc -zv postgres 5432

# 进入 PostgreSQL
docker compose exec postgres psql -U hermes -d hermes

# 执行 SQL 测试
SELECT version();
SELECT 1;

Q10: 如何配置 API 限流?

yaml 复制代码
# docker-compose.yml
api:
  environment:
    - RATE_LIMIT_ENABLED=true
    - RATE_LIMIT_REQUESTS_PER_MINUTE=60
    - RATE_LIMIT_BURST=10

Q11: 如何备份和恢复 Obsidian Vault?

bash 复制代码
# 备份
tar -czf vault_backup_$(date +%Y%m%d).tar.gz ~/Obsidian\ Vault

# 恢复
tar -xzf vault_backup_20260426.tar.gz -C ~/

# 或使用 Git
cd ~/Obsidian\ Vault
git pull origin main

Q12: 如何升级 PostgreSQL 版本?

bash 复制代码
# 1. 备份数据
docker compose exec postgres pg_dump -U hermes hermes > backup.sql

# 2. 修改 docker-compose.yml 中的 PostgreSQL 版本
# postgres:
#   image: postgres:16-alpine  # 改为 postgres:17-alpine

# 3. 停止服务
docker compose down

# 4. 拉取新镜像
docker compose pull postgres

# 5. 启动服务
docker compose up -d

# 6. 验证数据
docker compose exec postgres psql -U hermes -d hermes -c "SELECT version();"

Q13: 如何排查 Worker 任务不执行的问题?

bash 复制代码
# 查看 worker 日志
docker compose logs worker

# 检查队列状态
docker compose exec redis redis-cli -a $REDIS_PASSWORD LLEN hermes_tasks

# 查看所有 key
docker compose exec redis redis-cli -a $REDIS_PASSWORD KEYS "*"

# 手动触发任务
curl -X POST http://localhost:8080/api/v1/tasks/test

# 重启 worker
docker compose restart worker

Q14: 如何配置外部存储(如 NFS)?

yaml 复制代码
# docker-compose.yml
volumes:
  vault-data:
    driver: local
    driver_opts:
      type: nfs
      o: addr=192.168.1.100,rw
      device: ":/data/hermes-vault"

Q15: 如何查看容器的实时资源使用?

bash 复制代码
# 实时资源监控
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}\t{{.BlockIO}}" --no-stream

# 查看特定容器
docker stats hermes-api hermes-worker

# 每 5 秒刷新一次
docker stats --interval 5s

11. 总结

Docker 部署要点

复制代码
┌─────────────────────────────────────────────────────────────────┐
│                 Docker 部署核心要点                             │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ✅ 使用 docker compose 管理所有服务                             │
│  ✅ 配置 .env 管理敏感信息(不提交 Git)                         │
│  ✅ 使用 healthcheck 确保启动顺序                               │
│  ✅ 配置资源限制防止 OOM                                        │
│  ✅ 设置自动备份(Vault + 数据库)                              │
│  ✅ 生产环境必须使用 HTTPS                                       │
│  ✅ 配置日志轮转,防止磁盘爆满                                   │
│  ✅ 使用监控和告警,及时发现和处理问题                           │
│  ✅ 定期测试备份恢复流程                                         │
│  ✅ 记录部署配置和变更,便于排查问题                             │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

推荐生产配置

配置项 推荐值 说明
CPU 4+ 核 API 和 Worker 需要
内存 16GB+ PostgreSQL + Redis + 各服务
存储 100GB+ SSD 数据库 + Vault
网络 100Mbps+ API 响应和文件同步
副本 2-3 个 API 和 Worker 多副本

后续优化方向

  1. 配置读写分离的 PostgreSQL 集群
  2. 使用 Redis Sentinel 或 Cluster 提高可用性
  3. 迁移到 Kubernetes 进行容器编排
  4. 配置 CDN 加速静态资源
  5. 实现灰度发布和回滚机制

相关推荐
byoass1 小时前
自动化任务系列之二:批量建目录树——Excel模板驱动千人项目初始化
运维·网络·安全·自动化·云计算
脆皮炸鸡7551 小时前
Linux~~基础IO
linux·运维·服务器·经验分享·算法·学习方法
喜欢吃燃面2 小时前
Linux 信号保存机制深度解析:从内核数据结构到进程状态管理
linux·运维·数据结构·学习
IMPYLH2 小时前
Linux 的 stdbuf 命令
linux·运维·服务器·bash
Elastic 中国社区官方博客2 小时前
Elasticsearch 多年来的演进 —— LogsDB 如何在不影响吞吐量的情况下将索引大小减少高达 75%
大数据·运维·elasticsearch·搜索引擎·全文检索·可用性测试
keyipatience2 小时前
12.GDB调试技巧与计算机体系结构解析
linux·运维·服务器
小熊吃保安2 小时前
Excel下载变成了ZIP?Docker 容器里的 Content-Type 离奇失踪案
docker·go
小夏子_riotous2 小时前
Docker学习路径——9、Docker 网络深度解析:从默认网络到自定义网络实战
linux·运维·网络·docker·容器·centos·云计算
峥无2 小时前
《read/write的秘密:文件描述符、重定向与用户态缓冲区》
linux·运维·服务器·进程