- RED_ZONES.md: Tier 3/2 紅區清單 - setup-hooks.sh: Git Hook 安裝腳本 - infrastructure docs: 部署拓撲更新 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
481 lines
11 KiB
Markdown
481 lines
11 KiB
Markdown
# 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 維護,基建施工前必須完整遵守。*
|