# EwoooC 運維與自動化手冊 (DevOps Handbook) ## 🌐 伺服器連線 | 環境 | 主機 | 指令 | |---|-|---| | **正式 (EwoooC)** | 192.168.0.188 | `ssh -J wooo@192.168.0.110 ollama@192.168.0.188` | | **周邊 (UAT)** | 192.168.0.110 | `ssh wooo@192.168.0.110` | | **安全 (Kali)** | 192.168.0.112 | `ssh kali@192.168.0.112` | --- ## 🐋 Docker & Docker Compose 指令 (188 主機) 執行路徑:`/home/ollama/momo-pro` ### 常用操作 - **查看狀態**: `docker ps | grep momo` - **查看日誌**: `docker logs -f momo-pro-system --tail 100` - **熱重載主應用**: `docker kill -s HUP momo-pro-system` - **精準重建應用容器**: `docker compose up -d --no-deps --force-recreate momo-app` - **精準重建排程/Telegram**: `docker compose up -d --no-deps --force-recreate scheduler telegram-bot` - **全面啟動**: `docker compose up -d` - **進入資料庫**: `docker exec -it momo-db psql -U momo` 紅線: - 禁止使用 `docker compose down` 或 `--remove-orphans`。 - 禁止 stop/remove/recreate `momo-db`;資料庫生命週期需另走明確維護流程。 ### 影像管理 - **重建影像**: `docker compose build --no-cache momo-app` - **清理過期資源**: `docker system prune -f` --- ## 🌐 Nginx 反向代理 (110 主機) 配置路徑:`/etc/nginx/sites-enabled/momo` - **重新載入**: `sudo systemctl reload nginx` - **語法檢查**: `sudo nginx -t` --- ## 🤖 n8n 工作流程管理 (188 主機) - **進入容器**: `docker exec -it n8n /bin/sh` - **手動執行 Workflow**: `docker exec n8n n8n execute --id=` - **列出 Workflow**: `docker exec n8n n8n list:workflow` --- ## ❄️ K8s / K3s 狀態 已撤除。EwoooC 正式 runtime 是 188 主機的 Docker Compose,110 只作為 Gateway / Nginx / Gitea 等周邊服務主機。 若看到舊文件提到 Pod、Deployment、PVC 或叢集操作,先以 `docs/adr/ADR-008-actual-runtime-on-188.md` 與 `docs/adr/ADR-011-cross-project-resource-isolation.md` 為準,不要照抄舊叢集命令。 --- ## 🏥 健康檢查與自動修復 **監控腳本**: `/home/wooo/scripts/domain-health-monitor.sh` (於 110 執行) **頻率**: 每 5 分鐘 - `https://mo.wooo.work/health` -> 200 - `https://monitor.wooo.work/` -> 200 - `https://registry.wooo.work/v2/` -> 401 --- ## 🆘 故障排除 (Troubleshooting) - 2026-04-28 實戰總結 ### 0. 110 → 188 SCP 報 `Host key verification failed` - **原因**: 110 的 `~/.ssh/known_hosts` 保留了 188 的舊 host key 或缺少目前 key,導致部署檔案傳輸被 SSH 安全檢查擋下。 - **修復**: 在 110 執行 `ssh-keygen -R 192.168.0.188 && ssh-keyscan -H 192.168.0.188 >> ~/.ssh/known_hosts`。 - **驗證**: 先把 `/tmp/momo_scp_smoke.txt` 從 110 傳到 188 的 `/tmp`,再用 `ssh ollama@192.168.0.188 'cat /tmp/momo_scp_smoke.txt'` 確認可讀,最後刪除 smoke 檔。 - **紅線**: 不要把正式部署指令改成長期 `StrictHostKeyChecking=no`;遇到 key 問題要修 known_hosts,而不是關閉驗證。 ### 1. 網站 502 Bad Gateway (Nginx 找不到後端) - **原因**: 110 與 188 之間的 SSH 隧道中斷。 - **檢查**: 在 110 執行 `curl -I http://127.0.0.1:5003/health`。 - **修復**: 在 110 執行 `ssh -fN -L 5003:127.0.0.1:5003 ollama@192.168.0.188` 重啟隧道。 - **CD 判斷**: 先確認 188 內部 `docker exec momo-pro-system curl http://127.0.0.1:80/health`,再看外部 `https://mo.wooo.work/health`;若 internal 已 200 但 external 502,多半是 Nginx/tunnel 短暫延遲。 ### 2. CI/CD 報錯 `parent snapshot ... not found` - **原因**: Docker Buildx 快取損壞。 - **修復**: 在 `.gitea/workflows/cd.yaml` 中使用 `docker compose build --no-cache`。 ### 3. CI/CD 報錯 `No such container: momo-pro-system` - **原因**: Sync 模式使用硬編碼容器名,但容器可能已被重建或改名。 - **修復**: 先 `docker compose up -d --no-deps momo-app scheduler telegram-bot` 確保容器存在,再 `docker compose restart momo-app scheduler telegram-bot` 讓 bind-mounted Python 檔案重新載入。 ### 4. Telegram Bot 代碼更新無效 (幽靈容器) - **原因**: `docker-compose.yml` 遺漏了 `/app/routes` 的 Volume 掛載。 - **檢查**: `docker inspect momo-telegram-bot | jq '.[0].Mounts'`。 - **修復**: 確保 `volumes` 段落包含 `- ./routes:/app/routes:ro`。 ### 5. Gunicorn 設定更新後仍吃舊版 image 內容 - **原因**: `gunicorn.conf.py` 若沒有 bind mount,容器 restart 會使用 image 內建檔案;host 上新版設定不會自動進入 `/app/gunicorn.conf.py`。 - **檢查**: `docker inspect momo-pro-system | jq '.[0].Mounts'`,確認有 `/app/gunicorn.conf.py`。 - **修復**: `docker-compose.yml` 的 `momo-app.volumes` 必須包含 `- ./gunicorn.conf.py:/app/gunicorn.conf.py:ro`,再走 CD rebuild 或精準 recreate app/scheduler/bot。 ### 6. `/metrics` 持續出現 realtime_sales_monthly 欄位不存在 warning - **原因**: 線上表 schema 可能比 ORM 窄,ORM count 會包子查詢並引用不存在欄位。 - **修復**: metrics 只需要總筆數時使用 `SELECT COUNT(*) FROM realtime_sales_monthly`,不要透過 `session.query(RealtimeSalesMonthly).count()`。 ### 7. Rebuild 模式造成長時間 502 - **原因**: CD 若先 `docker stop/rm` 再 `docker compose build --no-cache`,build 耗時會全部變成服務中斷時間。 - **修復**: rebuild 模式必須先 `docker compose build --no-cache momo-app` 成功,才短暫 stop/rm/recreate `momo-app scheduler telegram-bot`。 - **救急**: 若 build 已經在跑且三應用容器已被移除,可精準執行 `docker compose up -d --no-deps momo-app scheduler telegram-bot` 先恢復服務;禁止使用 `--remove-orphans`。 ### 8. ElephantAlpha NIM 回 404 - **原因**: NVIDIA `/v1/models` 可能列出模型,但帳號未必可呼叫該 hosted function;production 曾對 Ultra 253B 回 `Function ... Not found for account`。 - **檢查**: 在容器內用 `NVIDIA_API_KEY` 呼叫 `https://integrate.api.nvidia.com/v1/models`,再用低 `max_tokens` 測試目標 model。 - **修復**: `ELEPHANT_ALPHA_MODEL` 預設使用 `nvidia/llama-3.3-nemotron-super-49b-v1.5`,並保留 `ELEPHANT_ALPHA_FALLBACK_MODELS`。 ### 9. PostgreSQL 連線數快速升高 - **原因**: Flask routes 會頻繁建立 `DatabaseManager()`,若每次都產生新 engine/pool,Gunicorn 多 worker 會快速吃滿 PostgreSQL clients。 - **修復**: `DatabaseManager` 以 `(DATABASE_TYPE, DATABASE_PATH)` 重用 engine/session,且 PostgreSQL pool 收斂為 `pool_size=2/max_overflow=3`。 - **檢查**: app log 應出現 `使用 PostgreSQL 資料庫 (連線池已收斂)`,Gunicorn `post_fork` 仍需 dispose inherited engines。 ### 10. OpenClaw embedding timeout - **原因**: Hermes/Ollama 負載高或舊 `/api/embeddings` endpoint 慢,會讓 embedding worker 累加 retry。 - **檢查**: 看 `embedding_retry_queue` 的 `pending/processing/failed` 分布,並測 `http://192.168.0.111:11434/api/embed`。 - **修復**: client 預設使用官方 `/api/embed`;若舊節點 404/405 才 fallback `/api/embeddings`。必要時調整 `EMBEDDING_TIMEOUT`。 ### 11. `/health` 偶發 000 或容器 unhealthy,但 app log 仍有 200 - **原因**: Blackbox 或外部探測打 Dashboard 首頁 `/`,會觸發商品看板與 PChome 比價重型查詢;少量 sync worker 被長請求佔滿時,輕量 `/health` 也會排隊逾時。 - **檢查**: `docker logs momo-pro-system --since 20m | grep 'Blackbox-Exporter'` 應只看到 `GET /health`;`docker stats momo-db` 若接近多核心滿載,需同步看 `pg_stat_activity` 的 `latest_momo` 類查詢。 - **修復**: 188 的 `monitoring/prometheus.yml` 與 110 的 `/home/wooo/monitoring/prometheus.yml` blackbox HTTP targets 必須使用 `/health`;Gunicorn 保持 `worker_class=gthread`、`GUNICORN_THREADS=4`、`preload_app=False`。