# Momentry 服務添加規範 v2.0 ## 一、概述 本文檔定義在 Momentry 系統中添加新服務的標準流程和規範。 **重要原則**: - 使用 `launchctl` 管理服務,勿使用 `brew services` - 所有服務使用 `com.momentry.*` 作為 plist Label - 數據存放於 `/Users/accusys/momentry/` 目錄 - 每個服務需提供完整的監控腳本 - 所有服務 Plist 存放於 `/Library/LaunchDaemons/` - 所有服務以 `accusys` 用戶運行,確保 accusys 可以管理 --- ## 二、服務運行方式 ### 2.1 運行分類 | 類型 | 說明 | 示例 | |------|------|------| | **開機自動運行** | 電腦開機後立即自動啟動 | PostgreSQL, Redis, n8n, Caddy 等核心服務 | | **登入時運行** | 用戶登入後才啟動 | 開發工具、臨時服務 | **當前所有服務**:均為開機自動運行 ### 2.2 Plist 存放位置 所有 Momentry 服務統一存放於: ``` /Library/LaunchDaemons/com.momentry.{service_name}.plist ``` --- ## 三、服務命名規範 ### 3.1 Plist 文件命名 ``` com.momentry.{service_name}.plist ``` 示例: - `com.momentry.redis.plist` - `com.momentry.n8n.main.plist` - `com.momentry.rustdesk.hbbs.plist` ### 3.2 目錄命名 服務相關目錄統一放置於: ``` /Users/accusys/momentry/ ├── var/{service_name}/ # 服務數據 ├── etc/{service_name}/ # 服務配置 ├── log/{service_name}.log # 服務日誌 (stdout) └── log/{service_name}.error.log # 錯誤日誌 (stderr) ``` --- ## 四、Plist 文件模板 ### 4.1 標準服務模板 ```xml Label com.momentry.{service_name} UserName accusys WorkingDirectory /Users/accusys/momentry/var/{service_name} ProgramArguments /path/to/executable --arg1 value1 EnvironmentVariables PATH /opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin RunAtLoad KeepAlive StandardOutPath /Users/accusys/momentry/log/{service_name}.log StandardErrorPath /Users/accusys/momentry/log/{service_name}.error.log ``` ### 4.2 日誌文件規範 每個服務必須創建兩個日誌文件: | 文件 | 說明 | 路徑 | |------|------|------| | StandardOutPath | 標準輸出日誌 | `/Users/accusys/momentry/log/{service_name}.log` | | StandardErrorPath | 錯誤輸出日誌 | `/Users/accusys/momentry/log/{service_name}.error.log` | **創建日誌文件**: ```bash touch /Users/accusys/momentry/log/{service_name}.log touch /Users/accusys/momentry/log/{service_name}.error.log chmod 644 /Users/accusys/momentry/log/{service_name}.log chmod 644 /Users/accusys/momentry/log/{service_name}.error.log ``` --- ## 五、添加服務步驟 ### 步驟 1:創建目錄結構 ```bash # 創建服務目錄 mkdir -p /Users/accusys/momentry/var/{service_name} mkdir -p /Users/accusys/momentry/etc/{service_name} # 創建日誌文件 touch /Users/accusys/momentry/log/{service_name}.log touch /Users/accusys/momentry/log/{service_name}.error.log ``` ### 步驟 2:創建 Plist 文件 ```bash # 複製模板並編輯 cp /Users/accusys/momentry_core_0.1/momentry_runtime/plist/template.service.plist \ /Users/accusys/momentry_core_0.1/momentry_runtime/plist/com.momentry.{service_name}.plist # 編輯 plist 文件 vim /Users/accusys/momentry_core_0.1/momentry_runtime/plist/com.momentry.{service_name}.plist ``` ### 步驟 3:複製到系統 LaunchDaemons ```bash # 複製到 /Library/LaunchDaemons/ sudo cp /Users/accusys/momentry_core_0.1/momentry_runtime/plist/com.momentry.{service_name}.plist \ /Library/LaunchDaemons/ ``` ### 步驟 4:載入服務 ```bash # 載入服務 sudo launchctl load /Library/LaunchDaemons/com.momentry.{service_name}.plist # 驗證服務狀態 launchctl list | grep momentry ``` ### 步驟 5:添加監控 在 `monitor/config/monitor_config.yaml` 中添加服務配置: ```yaml service: services: - name: "{service_name}" type: "http" # 或 "process", "tcp" port: {port_number} host: "localhost" check_url: "http://localhost:{port}/health" timeout: 5 enabled: true ``` ### 步驟 6:添加文檔 在 `docs/INSTALL_{SERVICE_NAME}.md` 中記錄: - 安裝步驟 - 配置說明 - 健康檢查命令 - 故障排除 --- ## 六、服務分類 ### 按功能分類 | 類別 | 服務 | |------|------| | 資料庫 | PostgreSQL, Redis, MariaDB, MongoDB | | 應用 | n8n, Gitea, SFTPGo | | 網頁 | Caddy, PHP-FPM | | AI/ML | Ollama, Qdrant | | 遠程 | RustDesk | ### 按運行方式分類 | 運行方式 | 數量 | 服務 | |----------|------|------| | 開機自動運行 | 15 | PostgreSQL, Redis, n8n, Caddy, Gitea, SFTPGo, Ollama, Qdrant, MariaDB, PHP-FPM, RustDesk, MongoDB, Agent | | 登入時運行 | 0 | (暫無) | --- ## 七、監控要求 每個服務必須提供: ### 7.1 健康檢查 在 `monitor/service/health_check.sh` 中添加檢查函數: ```bash check_{service_name}() { local start=$(date +%s%N) if nc -z localhost {port} > /dev/null 2>&1; then local end=$(date +%s%N) local ms=$(( (end - start) / 1000000 )) echo -e "${GREEN}✓${NC} {service_name} ({port}) - ${ms}ms" record_service "{service_name}" "up" "$ms" "" return 0 else echo -e "${RED}✗${NC} {service_name} ({port}) - Down" record_service "{service_name}" "down" "0" "Connection failed" return 1 fi } ``` ### 7.2 數據庫記錄 ```sql -- 添加服務監控記錄函數 record_service() { local service=$1 local status=$2 local response_time=$3 local error_msg=$4 psql -U accusys -h localhost -d momentry << EOF INSERT INTO monitor_services (service_name, service_type, status, response_time_ms, error_message, checked_at) VALUES ('$service', 'service', '$status', $response_time, '$error_msg', NOW()); EOF } ``` --- ## 八、服務管理命令 ### 8.1 基本操作 ```bash # 啟動服務 sudo launchctl load /Library/LaunchDaemons/com.momentry.{service}.plist # 停止服務 sudo launchctl unload /Library/LaunchDaemons/com.momentry.{service}.plist # 重啟服務 sudo launchctl unload /Library/LaunchDaemons/com.momentry.{service}.plist sudo launchctl load /Library/LaunchDaemons/com.momentry.{service}.plist # 查看服務狀態 launchctl list | grep momentry # 查看服務日誌 tail -f /Users/accusys/momentry/log/{service}.log tail -f /Users/accusys/momentry/log/{service}.error.log ``` ### 8.2 故障排除 ```bash # 檢查服務是否運行 pgrep -f "{service_process_name}" # 檢查端口是否監聽 lsof -i :{port} # 檢查錯誤日誌 tail -100 /Users/accusys/momentry/log/{service}.error.log ``` --- ## 九、服務備份作業 ### 9.1 備份內容 每個服務需要備份的內容: | 類別 | 路徑 | 說明 | |------|------|------| | 數據 | `/Users/accusys/momentry/var/{service}/` | 服務運行數據 | | 配置 | `/Users/accusys/momentry/etc/{service}/` | 服務配置文件 | | Plist | `/Library/LaunchDaemons/com.momentry.{service}.plist` | 啟動配置 | | 日誌 | `/Users/accusys/momentry/log/{service}.log` | 運行日誌 | ### 9.2 備份命名規範 **格式**: `{service}_{type}_{YYYYMMDD}_{HHMMSS}[_{suffix}].{ext}` **組成部分**: | 位置 | 說明 | 範例 | |------|------|------| | `{service}` | 服務名稱 (小寫) | `postgresql`, `redis`, `n8n` | | `{type}` | 備份類型 | `full`, `db`, `cfg`, `data` | | `{YYYYMMDD}` | 備份日期 | `20260315` | | `{HHMMSS}` | 備份時間 (24小時制) | `030000` | | `{suffix}` | 可選標記 | `incremental`, `verified` | | `{ext}` | 檔案擴展名 | `sql.gz`, `tar.gz`, `rdb`, `zip` | **類型說明**: | 類型 | 說明 | 包含內容 | |------|------|---------| | `full` | 完整備份 | 數據 + 配置 + 日誌 | | `db` | 數據庫備份 | 資料庫導出 (sql, rdb) | | `cfg` | 配置備份 | 配置文件 | | `data` | 數據備份 | var 目錄 | **範例**: ``` postgresql_db_20260315_030000.sql.gz # PostgreSQL 完整資料庫 (壓縮) redis_rdb_20260315_030000.rdb # Redis RDB 快照 n8n_full_20260315_030000.tar.gz # n8n 完整備份 mariadb_db_wordpress_20260315_030000.sql.gz # MariaDB WP 資料庫 gitea_full_20260315_030000.zip # Gitea 完整備份 qdrant_snapshot_20260315_030000.tar.gz # Qdrant 向量庫 ollama_cfg_20260315_030000.tar.gz # Ollama 配置 caddy_cfg_20260315_030000.tar.gz # Caddy 配置 ``` **可信斷點標記**: - 檔名本身即為可信時間點 - 還原時直接使用檔名中的時間戳 - 建議配合 `backup_registry` 資料庫記錄完整元數據 **校驗和命名**: ``` postgresql_db_20260315_030000.sql.gz.sha256 ``` ### 9.3 備份腳本 ```bash #!/bin/bash # 標準化備份腳本範本 # 遵循命名規範: {service}_{type}_{YYYYMMDD}_{HHMMSS}.{ext} set -e SERVICE_NAME="{service_name}" BACKUP_TYPE="{type}" # full, db, cfg, data TIMESTAMP=$(date +%Y%m%d_%H%M%S) BACKUP_DIR="/Users/accusys/momentry/backup/${SERVICE_NAME}" mkdir -p "$BACKUP_DIR" # 根據類型執行備份 case "$BACKUP_TYPE" in full) echo "[$TIMESTAMP] 執行 $SERVICE_NAME 完整備份..." tar -czf "$BACKUP_DIR/${SERVICE_NAME}_full_${TIMESTAMP}.tar.gz" \ /Users/accusys/momentry/var/${SERVICE_NAME}/ \ /Users/accusys/momentry/etc/${SERVICE_NAME}/ 2>/dev/null ;; db) echo "[$TIMESTAMP] 執行 $SERVICE_NAME 資料庫備份..." if [ "$SERVICE_NAME" = "postgresql" ]; then pg_dump -U accusys ${SERVICE_NAME} | gzip > \ "$BACKUP_DIR/${SERVICE_NAME}_db_${TIMESTAMP}.sql.gz" elif [ "$SERVICE_NAME" = "mariadb" ]; then mysqldump -u root -p --all-databases | gzip > \ "$BACKUP_DIR/${SERVICE_NAME}_db_${TIMESTAMP}.sql.gz" elif [ "$SERVICE_NAME" = "redis" ]; then redis-cli -a accusys SAVE cp /opt/homebrew/var/db/redis/dump.rdb \ "$BACKUP_DIR/${SERVICE_NAME}_rdb_${TIMESTAMP}.rdb" fi ;; cfg) echo "[$TIMESTAMP] 執行 $SERVICE_NAME 配置備份..." tar -czf "$BACKUP_DIR/${SERVICE_NAME}_cfg_${TIMESTAMP}.tar.gz" \ /Users/accusys/momentry/etc/${SERVICE_NAME}/ 2>/dev/null ;; data) echo "[$TIMESTAMP] 執行 $SERVICE_NAME 數據備份..." tar -czf "$BACKUP_DIR/${SERVICE_NAME}_data_${TIMESTAMP}.tar.gz" \ /Users/accusys/momentry/var/${SERVICE_NAME}/ 2>/dev/null ;; esac # 生成校驗和 if [ -f "$BACKUP_DIR/${SERVICE_NAME}_${BACKUP_TYPE}_${TIMESTAMP}"* ]; then sha256sum "$BACKUP_DIR/${SERVICE_NAME}_${BACKUP_TYPE}_${TIMESTAMP}"* > \ "$BACKUP_DIR/${SERVICE_NAME}_${BACKUP_TYPE}_${TIMESTAMP}.sha256" fi # 清理舊備份 (保留 30 天) find "$BACKUP_DIR" -name "*_${TIMESTAMP%%_*}_*.tar.gz" -mtime +30 -delete 2>/dev/null find "$BACKUP_DIR" -name "*_${TIMESTAMP%%_*}_*.sql.gz" -mtime +30 -delete 2>/dev/null find "$BACKUP_DIR" -name "*_${TIMESTAMP%%_*}_*.rdb" -mtime +30 -delete 2>/dev/null find "$BACKUP_DIR" -name "*.sha256" -mtime +30 -delete 2>/dev/null echo "備份完成: ${SERVICE_NAME}_${BACKUP_TYPE}_${TIMESTAMP}" ``` ### 9.4 備份排程 建議使用 cron 進行自動備份: ```bash # 編輯 crontab crontab -e # 添加備份任務 (每天凌晨 3 點) 0 3 * * * /Users/accusys/momentry/scripts/backup_{service}.sh >> /Users/accusys/momentry/log/backup.log 2>&1 # 每週日凌晨 3 點執行完整備份 0 3 * * 0 /Users/accusys/momentry/scripts/backup_{service}.sh full >> /Users/accusys/momentry/log/backup.log 2>&1 ``` ### 9.5 備份驗證 ```bash # 查看備份列表 (按時間排序) ls -lt /Users/accusys/momentry/backup/{service}/ # 驗證備份完整性 # 1. 檢查校驗和 sha256sum -c /Users/accusys/momentry/backup/{service}/*.sha256 # 2. 驗證 tar 壓縮 tar -tzf /Users/accusys/momentry/backup/{service}/{service}_full_20260315_030000.tar.gz # 3. 驗證 SQL 備份 zcat /Users/accusys/momentry/backup/{service}/{service}_db_20260315_030000.sql.gz | head -5 # 驗證備份完整性 tar -tzf /Users/accusys/momentry/backup/{service}/{service}_var_20260315.tar.gz ``` --- ## 十、服務完整刪除作業 ### 10.1 刪除前確認 **警告**:此操作不可逆,請確保已完成備份! - [ ] 確認服務已停止運行 - [ ] 確認數據已備份 - [ ] 確認無其他服務依賴此服務 ### 10.2 刪除步驟 **步驟 1:停止服務** ```bash # 停止服務 sudo launchctl unload /Library/LaunchDaemons/com.momentry.{service}.plist # 驗證服務已停止 launchctl list | grep momentry.{service} ``` **步驟 2:刪除 Plist** ```bash # 刪除系統 Plist sudo rm /Library/LaunchDaemons/com.momentry.{service}.plist # 刪除專案 Plist rm /Users/accusys/momentry_core_0.1/momentry_runtime/plist/com.momentry.{service}.plist ``` **步驟 3:刪除數據和配置** ```bash # 刪除數據目錄 sudo rm -rf /Users/accusys/momentry/var/{service}/ # 刪除配置目錄 sudo rm -rf /Users/accusys/momentry/etc/{service}/ # 刪除日誌 rm -f /Users/accusys/momentry/log/{service}.log rm -f /Users/accusys/momentry/log/{service}.error.log ``` **步驟 4:清理監控配置** ```bash # 從監控配置中移除服務 vim /Users/accusys/momentry_core_0.1/monitor/config/monitor_config.yaml # 刪除該服務的監控配置 # 從監控腳本中移除 vim /Users/accusys/momentry_core_0.1/monitor/service/health_check.sh # 移除該服務的檢查函數 ``` **步驟 5:清理監控數據(可選)** ```bash # 保留歷史數據還是刪除? # 刪除監控數據 psql -U accusys -h localhost -d momentry -c " DELETE FROM monitor_services WHERE service_name = '{service}'; " ``` ### 10.3 驗證刪除 ```bash # 確認服務已停止 launchctl list | grep momentry.{service} # 確認目錄已刪除 ls /Users/accusys/momentry/var/{service}/ 2>/dev/null || echo "已刪除" # 確認 Plist 已刪除 ls /Library/LaunchDaemons/com.momentry.{service}.plist 2>/dev/null || echo "已刪除" ``` ### 10.4 完整刪除腳本 ```bash #!/bin/bash SERVICE_NAME="{service_name}" echo "========== 服務完整刪除 ==========" echo "服務: $SERVICE_NAME" echo "警告:此操作不可逆!" read -p "確認繼續 (yes/no): " confirm if [ "$confirm" != "yes" ]; then echo "取消刪除" exit 0 fi # 停止服務 echo "[1/6] 停止服務..." sudo launchctl unload /Library/LaunchDaemons/com.momentry.${SERVICE_NAME}.plist 2>/dev/null # 刪除 Plist echo "[2/6] 刪除 Plist..." sudo rm -f /Library/LaunchDaemons/com.momentry.${SERVICE_NAME}.plist rm -f /Users/accusys/momentry_core_0.1/momentry_runtime/plist/com.momentry.${SERVICE_NAME}.plist # 刪除數據 echo "[3/6] 刪除數據..." sudo rm -rf /Users/accusys/momentry/var/${SERVICE_NAME}/ # 刪除配置 echo "[4/6] 刪除配置..." sudo rm -rf /Users/accusys/momentry/etc/${SERVICE_NAME}/ # 刪除日誌 echo "[5/6] 刪除日誌..." rm -f /Users/accusys/momentry/log/${SERVICE_NAME}.log rm -f /Users/accusys/momentry/log/${SERVICE_NAME}.error.log # 清理監控數據 echo "[6/6] 清理監控數據..." psql -U accusys -h localhost -d momentry -c " DELETE FROM monitor_services WHERE service_name = '${SERVICE_NAME}'; " 2>/dev/null echo "========== 刪除完成 ==========" ``` --- ## 十一、檢查清單 添加新服務時,請確認以下項目: - [ ] 創建服務目錄 (`var/`, `etc/`) - [ ] 配置日誌文件 (`.log` + `.error.log`) - [ ] 創建 plist 文件,UserName 設為 `accusys` - [ ] 複製到 `/Library/LaunchDaemons/` - [ ] 使用 launchctl 載入服務 - [ ] 驗證服務運行 - [ ] 添加監控配置 - [ ] 測試監控腳本 - [ ] 創建安裝文檔 - [ ] 更新 SERVICES.md 服務清單 - [ ] 更新 MOMENTRY_INTEGRATION_GUIDE.md --- ## 十二、模板文件 ### Plist 模板位置 ``` /Users/accusys/momentry_core_0.1/momentry_runtime/plist/ ├── template.service.plist # 服務模板 ├── com.momentry.redis.plist # 服務示例 └── com.momentry.n8n.main.plist # 複雜服務示例 ``` ### 創建模板命令 ```bash # 創建服務模板 cat > /Users/accusys/momentry_core_0.1/momentry_runtime/plist/template.service.plist << 'EOF' Label com.momentry.SERVICE_NAME UserName accusys WorkingDirectory /Users/accusys/momentry/var/SERVICE_NAME ProgramArguments /path/to/executable RunAtLoad KeepAlive StandardOutPath /Users/accusys/momentry/log/SERVICE_NAME.log StandardErrorPath /Users/accusys/momentry/log/SERVICE_NAME.error.log EOF ``` --- ## 十一、版本歷史 | 版本 | 日期 | 內容 | |------|------|------| | 1.0 | 2026-03-15 | 初始版本 | | 2.0 | 2026-03-15 | 統一 Plist 位置、移除 root/用戶區分、加入運行方式分類 | | 2.1 | 2026-03-15 | 新增服務備份作業、服務完整刪除作業 |