# AWOOOI 部署契約 (Deployment Contracts) > **版本**: v1.0 > **建立日期**: 2026-03-20 > **負責人**: CIO > **強制等級**: 施工前必須遵守 --- ## 概述 此文件定義 AWOOOI 部署的「鐵律級」配置規範。 **施工前必須確認此契約,否則禁止開始基建工作。** --- ## 環境架構 (CEO 指示 #3) > ⚠️ **重要**: AWOOOI 只有兩個環境,不設 UAT | 環境 | 用途 | 域名 | K8s Namespace | 備註 | |------|------|------|---------------|------| | **Dev** | 本機開發 | `localhost:3000` | - | 開發者本機 | | **Prod** | 生產環境 | `awoooi.wooo.work` | `awoooi-prod` | 唯一線上環境 | ### 與舊系統完全隔離 | 項目 | AWOOOI (新) | Legacy (舊) | |------|-------------|-------------| | 域名 | `awoooi.wooo.work` | `aiops.wooo.work` | | Namespace | `awoooi-prod` | `wooo-aiops` | | Frontend Port | 32335 | 31235 | | API Port | 32334 | 31234 | | OpenClaw Port | 8089 | 8088 | | Redis DB | 10-15 | 0-9 | --- ## CIO-001: K8s Namespace 資源配額 > 🎯 **顧問深度討論 #3**: 防止 Memory Leak 拖垮叢集 ### ResourceQuota 配置 ```yaml # k8s/quotas/awoooi-prod-quota.yaml apiVersion: v1 kind: ResourceQuota metadata: name: awoooi-prod-quota namespace: awoooi-prod spec: hard: # 計算資源上限 (叢集 40%) requests.cpu: "4" # 4 cores requests.memory: "8Gi" # 8GB limits.cpu: "8" # 8 cores limits.memory: "16Gi" # 16GB # Pod 數量限制 pods: "50" # 儲存限制 persistentvolumeclaims: "10" requests.storage: "100Gi" ``` ### LimitRange 配置 ```yaml # k8s/quotas/awoooi-prod-limits.yaml apiVersion: v1 kind: LimitRange metadata: name: awoooi-prod-limits namespace: awoooi-prod spec: limits: # 預設容器限制 - type: Container default: cpu: "500m" memory: "512Mi" defaultRequest: cpu: "100m" memory: "128Mi" max: cpu: "2" memory: "4Gi" min: cpu: "50m" memory: "64Mi" # Pod 總限制 - type: Pod max: cpu: "4" memory: "8Gi" ``` ### 強制規則 1. **新 Deployment 必須指定 resources**: 沒有 requests/limits 將被拒絕 2. **禁止 BestEffort QoS**: 所有 Pod 必須有明確資源定義 3. **定期檢查**: 每週檢查資源使用率,超過 70% 發出告警 --- ## CIO-002: Nginx SSE 長連線配置 > 🎯 **顧問深度討論 #2**: 防止 SSE 每 60 秒斷線 ### Nginx 配置範本 ```nginx # k8s/nginx/awoooi-prod.conf # 上游服務定義 upstream awoooi-api { server awoooi-api-service:8000; keepalive 32; } upstream awoooi-web { server awoooi-web-service:3000; keepalive 16; } server { listen 443 ssl http2; server_name awoooi.wooo.work; # SSL 配置 ssl_certificate /etc/nginx/ssl/awoooi.crt; ssl_certificate_key /etc/nginx/ssl/awoooi.key; # === SSE 專用路由 (AI 思考串流) === location ~ ^/api/v1/(agent|dashboard)/stream { proxy_pass http://awoooi-api; # ⚠️ 關鍵: SSE 必要配置 proxy_buffering off; # 禁用緩衝 (打字機效果零延遲) proxy_read_timeout 3600s; # 1 小時長連線 proxy_send_timeout 3600s; proxy_connect_timeout 60s; # HTTP/1.1 長連線 proxy_http_version 1.1; proxy_set_header Connection ""; proxy_set_header X-Accel-Buffering no; # 標準 Headers 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; } # === 一般 API 路由 === location /api/ { proxy_pass http://awoooi-api; proxy_http_version 1.1; proxy_set_header Connection "keep-alive"; proxy_read_timeout 60s; proxy_send_timeout 60s; 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; } # === 前端靜態資源 === location / { proxy_pass http://awoooi-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; } # 健康檢查 (不經認證) location /health { proxy_pass http://awoooi-api/health; proxy_read_timeout 5s; } } ``` ### SSE 測試腳本 ```bash #!/bin/bash # scripts/test-sse.sh # 測試 SSE 連線是否正常 echo "Testing SSE connection to awoooi.wooo.work..." timeout 120 curl -N \ -H "Accept: text/event-stream" \ -H "Authorization: Bearer $TOKEN" \ "https://awoooi.wooo.work/api/v1/agent/stream?prompt=test" if [ $? -eq 124 ]; then echo "✅ SSE connection held for 2 minutes (test passed)" else echo "❌ SSE connection dropped unexpectedly" exit 1 fi ``` --- ## CIO-003: NetworkPolicy 零信任邊界 > 🎯 **顧問深度討論 #1**: Default Deny All 策略 ### 預設拒絕策略 ```yaml # k8s/network-policies/default-deny.yaml apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny-all namespace: awoooi-prod spec: podSelector: {} # 套用到所有 Pod policyTypes: - Ingress - Egress ``` ### 允許清單 - Ingress ```yaml # k8s/network-policies/allow-ingress.yaml apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-nginx-to-services namespace: awoooi-prod spec: podSelector: matchLabels: app: awoooi-api policyTypes: - Ingress ingress: # 只允許 Nginx Ingress Controller - from: - namespaceSelector: matchLabels: name: ingress-nginx ports: - protocol: TCP port: 8000 --- apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-nginx-to-web namespace: awoooi-prod spec: podSelector: matchLabels: app: awoooi-web policyTypes: - Ingress ingress: - from: - namespaceSelector: matchLabels: name: ingress-nginx ports: - protocol: TCP port: 3000 ``` ### 允許清單 - Egress ```yaml # k8s/network-policies/allow-egress.yaml apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-api-to-services namespace: awoooi-prod spec: podSelector: matchLabels: app: awoooi-api policyTypes: - Egress egress: # 允許訪問 PostgreSQL (192.168.0.188:5432) - to: - ipBlock: cidr: 192.168.0.188/32 ports: - protocol: TCP port: 5432 # 允許訪問 Redis DB 10-15 (192.168.0.188:6380) - to: - ipBlock: cidr: 192.168.0.188/32 ports: - protocol: TCP port: 6380 # 允許訪問 Ollama (192.168.0.188:11434) - to: - ipBlock: cidr: 192.168.0.188/32 ports: - protocol: TCP port: 11434 # 允許訪問 OpenClaw AWOOOI (192.168.0.188:8089) - to: - ipBlock: cidr: 192.168.0.188/32 ports: - protocol: TCP port: 8089 # 允許訪問 Kali Scanner (192.168.0.112:8080) - to: - ipBlock: cidr: 192.168.0.112/32 ports: - protocol: TCP port: 8080 # 允許 DNS 解析 - to: - namespaceSelector: {} podSelector: matchLabels: k8s-app: kube-dns ports: - protocol: UDP port: 53 # 允許訪問外部 AI API (雲端備援) - to: - ipBlock: cidr: 0.0.0.0/0 except: - 10.0.0.0/8 - 172.16.0.0/12 - 192.168.0.0/16 ports: - protocol: TCP port: 443 ``` ### 禁止訪問 Legacy Namespace ```yaml # k8s/network-policies/deny-legacy.yaml apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: deny-access-to-legacy namespace: awoooi-prod spec: podSelector: {} policyTypes: - Egress egress: # 明確拒絕 Legacy Namespace - to: - namespaceSelector: matchLabels: name: wooo-aiops # 沒有 ports = 全部拒絕 ``` --- ## 監控與告警配置 ### Prometheus 告警規則 ```yaml # k8s/monitoring/prometheus/awoooi-alerts.yaml groups: - name: awoooi-resource-alerts rules: # CPU 使用率告警 - alert: AWOOOIHighCPUUsage expr: | sum(rate(container_cpu_usage_seconds_total{namespace="awoooi-prod"}[5m])) / sum(kube_resourcequota{namespace="awoooi-prod", resource="limits.cpu"}) > 0.7 for: 5m labels: severity: warning annotations: summary: "AWOOOI CPU 使用率超過 70%" description: "Namespace awoooi-prod 的 CPU 使用率已達 {{ $value | humanizePercentage }}" # Memory 使用率告警 - alert: AWOOOIHighMemoryUsage expr: | sum(container_memory_working_set_bytes{namespace="awoooi-prod"}) / sum(kube_resourcequota{namespace="awoooi-prod", resource="limits.memory"}) > 0.7 for: 5m labels: severity: warning annotations: summary: "AWOOOI Memory 使用率超過 70%" # Pod 重啟告警 - alert: AWOOOIPodRestarting expr: | increase(kube_pod_container_status_restarts_total{namespace="awoooi-prod"}[1h]) > 3 for: 5m labels: severity: critical annotations: summary: "AWOOOI Pod 頻繁重啟" description: "Pod {{ $labels.pod }} 在過去 1 小時重啟超過 3 次" ``` --- ## 驗收清單 ### 施工前確認 - [ ] ResourceQuota 已套用 - [ ] LimitRange 已套用 - [ ] Default Deny NetworkPolicy 已套用 - [ ] 允許清單 NetworkPolicy 已套用 - [ ] Nginx SSE 配置已驗證 - [ ] 告警規則已部署 ### 施工後驗證 ```bash # 驗證 ResourceQuota kubectl describe quota awoooi-prod-quota -n awoooi-prod # 驗證 LimitRange kubectl describe limitrange awoooi-prod-limits -n awoooi-prod # 驗證 NetworkPolicy kubectl get networkpolicy -n awoooi-prod # 測試 SSE 連線 ./scripts/test-sse.sh # 測試 Legacy 隔離 kubectl exec -it deploy/awoooi-api -n awoooi-prod -- \ curl -s http://wooo-aiops-api.wooo-aiops:8000/health # 預期: 連線失敗 (被 NetworkPolicy 阻擋) ``` --- ## 變更記錄 | 日期 | 版本 | 變更 | 作者 | |------|------|------|------| | 2026-03-20 | v1.0 | 初版建立 | CIO | --- *此文件由 CIO 維護,基建施工前必須完整遵守。*