Files
awoooi/docs/runbooks/ANSIBLE-OPERATING-MODEL.md
Your Name cfb866d055
Some checks failed
Ansible Lint / lint (push) Successful in 35s
CD Pipeline / tests (push) Failing after 13s
CD Pipeline / build-and-deploy (push) Has been skipped
CD Pipeline / post-deploy-checks (push) Has been skipped
Code Review / ai-code-review (push) Failing after 11s
feat(governance): add agent market automation surfaces
2026-06-04 21:50:55 +08:00

207 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AWOOOI Ansible 運作模型
> 最後更新2026-05-12台北時間
> 範圍:說明 Ansible 在 110 / 120 / 121 / 188 的運維、冷啟動恢復、監控與部署安全中扮演的角色。
## 產品架構定位
Ansible 是主機狀態收斂層,負責 Kubernetes 與 Docker 映像之外的主機狀態包括檔案、套件、systemd units、cron、nginx 設定、node-exporter textfile monitor以及主機層資源護欄。
Ansible 不取代下列系統:
- `k8s/` 之下的 Kubernetes manifests
- 各服務目錄自己管理的 Docker Compose application 定義
- 資料庫恢復決策
- AI 自動修復執行
- 緊急 console fsck
目標控制流程是:
```text
Git repo
-> Ansible 驗證並收斂主機狀態
-> Prometheus 觀測 host/app gate
-> Alertmanager 發出告警
-> AWOOOI/AwoooP AI 進行診斷與分流
-> 涉及有狀態或高風險修復時交由人工批准
```
## 目前納管範圍
| 範圍 | 事實來源 | Runtime 目標 |
|---|---|---|
| 主機 inventory | `infra/ansible/inventory/hosts.yml` | 記錄 110 / 120 / 121 / 188 / 112 |
| 188 public nginx routes | `infra/ansible/roles/nginx/templates/*` + `playbooks/nginx-sync.yml` | `/etc/nginx/sites-enabled/*` |
| 110 Ollama proxy | `110-ollama-proxy.conf.j2` | `/etc/nginx/sites-enabled/110-ollama-proxy.conf` |
| 110 cold-start monitor | `roles/cold-start-monitor` | `/home/wooo/scripts`、cron、node-exporter textfile |
| 110 runner guardrails | `roles/runner-guardrails` | `actions.runner.*` systemd drop-ins |
| 110/188 Docker/systemd/storage/backup textfile exporters | `roles/host-textfile-exporters` | `/home/*/node_exporter_textfiles/docker_stats.prom``storage_health.prom``backup_health.prom`、110 `systemd_units.prom` |
| 110 Sentry backup / integrity drill | `110-devops.yml --tags backup_jobs` | `/backup/scripts/backup-sentry.sh``check-backup-integrity.sh`、weekly/monthly cron |
| 主機健康描述 | `110-devops.yml``188-ai-web.yml` | 只讀檢查與有限度主機狀態修復 |
## 必要流程
相關檔案變更後Gitea workflow `.gitea/workflows/ansible-lint.yml` 會在 self-hosted runner 上執行 `scripts/ops/ansible-validate.sh``ansible-lint`。本地仍需先跑驗證,避免把明顯壞掉的 Ansible 變更推進 CI。
### 1. 本地驗證
任何 Ansible 變更前先執行:
```bash
bash scripts/ops/bootstrap-ansible-validation-env.sh --recreate
PATH="${ANSIBLE_VALIDATION_VENV:-/tmp/awoooi-ansible-venv}/bin:$PATH" \
bash scripts/ops/ansible-validate.sh
```
`bootstrap-ansible-validation-env.sh` 會建立 pinned 驗證工具鏈:`ansible-core==2.17.14``ansible-lint==24.12.2`。如果本機沒有 `ansible-playbook``ansible-validate.sh` 仍會驗證 YAML 與 shell syntax並明確提示已跳過 Ansible syntax-check但重開機 SOP、CI 與接手稽核應使用 bootstrap venv避免只做半套驗證。
若要稽核整個重開機恢復包是否齊全:
```bash
bash scripts/reboot-recovery/reboot-recovery-readiness-audit.sh --live --no-color
```
若要確認是否可以釋放 P3 高負載工作:
```bash
bash scripts/reboot-recovery/p3-controlled-release-gate.sh --no-color
```
### 2. 演練(`--check`
從 repo root 執行:
```bash
ansible-playbook -i infra/ansible/inventory/hosts.yml infra/ansible/playbooks/site.yml --check
```
針對單一變更時:
```bash
ansible-playbook -i infra/ansible/inventory/hosts.yml infra/ansible/playbooks/nginx-sync.yml --tags 188 --check
ansible-playbook -i infra/ansible/inventory/hosts.yml infra/ansible/playbooks/110-devops.yml --tags cold_start_monitor --check
ansible-playbook -i infra/ansible/inventory/hosts.yml infra/ansible/playbooks/110-devops.yml --tags runner_guardrails --check
ansible-playbook -i infra/ansible/inventory/hosts.yml infra/ansible/playbooks/110-devops.yml --tags textfile_exporters --check
ansible-playbook -i infra/ansible/inventory/hosts.yml infra/ansible/playbooks/110-devops.yml --tags backup_jobs --check
ansible-playbook -i infra/ansible/inventory/hosts.yml infra/ansible/playbooks/188-ai-web.yml --tags textfile_exporters --check
```
### 3. 套用
只套用最小必要 tag
```bash
ansible-playbook -i infra/ansible/inventory/hosts.yml infra/ansible/playbooks/nginx-sync.yml --tags 188
ansible-playbook -i infra/ansible/inventory/hosts.yml infra/ansible/playbooks/110-devops.yml --tags cold_start_monitor
ansible-playbook -i infra/ansible/inventory/hosts.yml infra/ansible/playbooks/110-devops.yml --tags runner_guardrails
ansible-playbook -i infra/ansible/inventory/hosts.yml infra/ansible/playbooks/110-devops.yml --tags textfile_exporters
ansible-playbook -i infra/ansible/inventory/hosts.yml infra/ansible/playbooks/110-devops.yml --tags backup_jobs
ansible-playbook -i infra/ansible/inventory/hosts.yml infra/ansible/playbooks/188-ai-web.yml --tags textfile_exporters
```
### 4. 事後驗證
Ansible apply 不等於完成runtime gate 變綠才算完成:
```bash
SSH_BATCH_MODE=yes bash scripts/reboot-recovery/full-stack-cold-start-check.sh --send-alert-test
curl -kLsS -o /dev/null -w '%{http_code}\n' https://awoooi.wooo.work/api/v1/health
curl -kLsS -o /dev/null -w '%{http_code}\n' https://mo.wooo.work/health
```
## 冷啟動整合
重開機恢復時:
1. 主機卡在 initramfs 時,先用 console/fsck 讓主機乾淨開機。
2. 只在必要時人工恢復依賴鏈188 data layer、110 registry/observability、K3s、public routes。
3. Stack 可達後,用 Ansible 把 live state 收回 repo/IaC。
4. 執行 cold-start gate。
5. Gate 變綠前AI auto-repair 維持 observe-only。
Cold-start monitor 由下列 role/playbook 管理:
```text
infra/ansible/roles/cold-start-monitor
infra/ansible/playbooks/110-devops.yml --tags cold_start_monitor
```
它會寫入:
```text
/home/wooo/node_exporter_textfiles/cold_start_recovery.prom
/home/wooo/reboot-recovery/cold-start-last.log
```
## Dirty Reboot 與檔案系統防線
110 與 188 曾在重開機後停在 initramfs manual fsck這一類問題不能只靠網站健康檢查發現。`roles/host-textfile-exporters` 現在也會部署 `storage-health-textfile-exporter.py`,每分鐘輸出:
```text
/home/wooo/node_exporter_textfiles/storage_health.prom
/home/ollama/node_exporter_textfiles/storage_health.prom
```
這個 exporter 只讀取 `/proc/mounts``/proc/stat``journalctl -k` 與 fsck logs不會修復、不會重啟、不會寫資料庫。它提供 root filesystem 是否 read-only、目前 boot 是否有 storage/kernel error、上一個 boot 是否留下 dirty reboot/fsck 證據。Prometheus 的 `host_storage_health_alerts` 只告警與阻擋放量,所有 fsck/資料恢復仍需人工批准。
## 備份健康與設定檔備份
`roles/host-textfile-exporters` 也管理 `backup-health-textfile-exporter.py`。它每 10 分鐘輸出:
```text
/home/wooo/node_exporter_textfiles/backup_health.prom
/home/ollama/node_exporter_textfiles/backup_health.prom
```
這個 exporter 只讀取 cron、script path、restic snapshot metadata 與既有 textfile不會執行備份或還原。它用來確認
- 110 的 `/backup/scripts/backup-all.sh`、AWOOOI 高頻備份、`/backup/configs` 設定檔備份都存在且新鮮。
- 110 的 `/backup/sentry` 專屬資料層備份新鮮,並且 weekly `restic check` / monthly restore drill 有成功證據。
- 188 的 `backup-from-110` 與 momo PostgreSQL daily backup 都新鮮。
- 120 的 Velero schedule、latest Completed backup、`backup-restore-test` CronJob/Job 狀態可查。
- 預期 script 不缺、cron 不缺、最近 aggregate backup 沒有失敗項目。
設定檔備份由 `/backup/scripts/backup-configs.sh` 負責,納入每日 `backup-all.sh`。它會把 nginx、systemd、cron、Docker Compose、K3s manifests、K8s Secret/ConfigMap/RBAC、certs 與 runtime scripts 放進加密 restic repo `/backup/configs`。Secrets 只允許進加密備份,不得出現在 repo、log、Prometheus label 或告警訊息。
Sentry 資料層備份由 `/backup/scripts/backup-sentry.sh` 負責,納入每日 `backup-all.sh`。它會輸出 Sentry Postgres logical dump並把 ClickHouse、Kafka、Redis、SeaweedFS、Taskbroker、Vroom、Symbolicator 等必要 state 放入加密 restic repo `/backup/sentry`。這是備份行為,不做 restore也不停止 production stack。
備份可用性由 `/backup/scripts/check-backup-integrity.sh` 負責:
- 每週 `--mode check`:對預期 restic repos 執行 `restic check --read-data-subset=1%`
- 每月 `--mode restore-drill`:從每個 repo 抽一個小檔案 `restic dump latest <sample>` 到 0700 暫存目錄,驗證 snapshot 可讀。
- 執行狀態寫入 `/backup/integrity/check.status``/backup/integrity/restore-drill.status`,由 `backup-health-textfile-exporter.py` 轉成 Prometheus metrics。
## 下一批納入 Ansible 的項目
| 優先級 | 項目 | 原因 |
|---|---|---|
| P0 | 110 runner guardrails | `roles/runner-guardrails` 已建立;下一步是在有 Ansible 的 ops host 做 live dry-run/apply 與 CI syntax-check |
| P0 | Sentry 專屬備份與 restic integrity drill | `backup_jobs` 已納入 110 playbook下一步累積 nightly/weekly/monthly 成功證據 |
| P0 | 188 nginx HTTPS route ownership | 避免 public tool routes 在事故後或同步後再次漂移 |
| P1 | certbot/snap certbot 標準化 | 目前 apt certbot/OpenSSL 路徑脆弱renewal 需要統一路徑 |
| P1 | 110/188 Docker/systemd/storage/backup textfile exporters | `roles/host-textfile-exporters` 已建立;下一步是在 ops host 上 dry-run/apply並確認 `docker_stats.prom` / `storage_health.prom` / `backup_health.prom` / `systemd_units.prom` freshness |
| P1 | node-exporter/cAdvisor caps | 監控元件本身不能變成負載來源 |
| P2 | K3s diagnostic-only host tasks | 只驗證 containerd/kubelet 狀態,不做破壞性修復 |
| P2 | 112 Kali inventory only | 先記錄,不掃描、不修復 |
## 安全規則
- 預設先跑 `--check`
- 用 tags 控制範圍;事故中避免直接套用完整 `site.yml`
- 不把密碼寫進 repo、cron、inventory 或 group vars。
- 不讓 Ansible 執行 DB/ClickHouse/Kafka 的破壞性恢復。
- Ansible 只做可預期的主機狀態收斂,不處理未知資料修復。
- 任何有狀態 restart 或 quarantine 仍需人工批准。
- Runner guardrail role 預設不重啟 units只有在計畫維護窗才設定 `runner_guardrails_restart_units=true`
## 完成定義
Ansible 管理的變更必須全部符合下列條件,才算完成:
- `scripts/ops/ansible-validate.sh` 通過。
- 目標 playbook dry run 成功,或有文件化原因說明為何略過 dry run。
- 目標 apply 成功。
- 影響 runtime 的變更,`full-stack-cold-start-check.sh --send-alert-test` 必須變綠。
- 相關 public routes 或 service health endpoints 通過。
- `docs/LOGBOOK.md` 記錄套用範圍與驗證結果。