# Config Drift Detection CronJob - Phase 25 P2 # 每小時掃描 awoooi-prod namespace 的配置漂移 # # 建立時間: 2026-04-04 (台北時區) # 建立者: Claude Code (Phase 25 P2) # 關聯設計: docs/superpowers/specs/2026-04-04-nemotron-active-defense-design.md 方向三 # 關聯 ADR: 待起草 ADR-057 # # 部署: kubectl apply -f k8s/drift-cronjob.yaml -n awoooi-prod # 手動觸發: kubectl create job --from=cronjob/drift-scanner drift-scan-manual -n awoooi-prod # 查看 log: kubectl logs -l job-name=drift-scanner -n awoooi-prod apiVersion: batch/v1 kind: CronJob metadata: name: drift-scanner namespace: awoooi-prod labels: app: awoooi component: drift-scanner phase: "25" annotations: # 2026-04-04 ogt: Phase 25 P2 — Config Drift Detection description: "每小時掃描 K8s 配置漂移,由 Nemotron 做意圖分析" spec: # 每小時整點執行(台北時間 = UTC+8,schedule 用 UTC) schedule: "0 * * * *" concurrencyPolicy: Forbid # 禁止並發:上次未完成則跳過 successfulJobsHistoryLimit: 3 failedJobsHistoryLimit: 5 startingDeadlineSeconds: 60 # 錯過時間窗口超過 60s 則跳過 jobTemplate: spec: backoffLimit: 0 # 失敗不重試(漂移掃描冪等,下次 cron 自動補掃) activeDeadlineSeconds: 300 # 最長 5 分鐘 template: metadata: labels: app: awoooi component: drift-scanner spec: restartPolicy: Never # 2026-04-09 Claude Sonnet 4.6: awoooi-api SA 不存在,改用 default(只需呼叫內部 API,不需 K8s 權限) serviceAccountName: default containers: - name: drift-scanner # 使用 awoooi-api 鏡像(含 kubectl + Python 環境) # 2026-04-09 Claude Sonnet 4.6: 改用內網 registry + 固定 SHA tag (禁止 latest) image: 192.168.0.110:5000/awoooi/api:21567a7a6dbee7db2c0f59c265f80713ff5e6fe4 imagePullPolicy: Always command: - python - -c - | import asyncio, httpx, os API_URL = os.environ.get("INTERNAL_API_URL", "http://awoooi-api:8000") async def run(): async with httpx.AsyncClient(timeout=240) as c: r = await c.post(f"{API_URL}/api/v1/drift/internal/scan") print(f"status={r.status_code} body={r.text[:200]}") asyncio.run(run()) env: # 2026-04-09 Claude Sonnet 4.6: ClusterIP 和 DNS 在 Job Pod 均不可達 # 改用 NodePort 直連 K3s worker node(同 K8s_API_SERVER_URL 解法) - name: INTERNAL_API_URL value: "http://192.168.0.121:32334" - name: DRIFT_SCAN_NAMESPACES value: "awoooi-prod" resources: requests: cpu: "50m" memory: "64Mi" limits: cpu: "200m" memory: "256Mi"