Some checks failed
Code Review / ai-code-review (push) Successful in 10s
run-migration / migrate (push) Successful in 7s
CD Pipeline / build-and-deploy (push) Has been cancelled
CD Pipeline / post-deploy-checks (push) Has been cancelled
CD Pipeline / tests (push) Has been cancelled
80 lines
3.4 KiB
YAML
80 lines
3.4 KiB
YAML
# 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
|
||
# 2026-04-14 Claude Sonnet 4.6: 補 system=awoooi — allow-required-egress 以此篩選
|
||
# 缺此 label 導致 default-deny-all 封鎖所有 egress(系統沉默 9.4h 根因)
|
||
system: awoooi
|
||
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-05-05 Codex: call the in-cluster Service instead of a
|
||
# fixed worker NodePort. After reboot, 121 can be unavailable
|
||
# while the Service and VIP are already healthy.
|
||
- name: INTERNAL_API_URL
|
||
value: "http://awoooi-api-svc.awoooi-prod.svc.cluster.local:8000"
|
||
- name: DRIFT_SCAN_NAMESPACES
|
||
value: "awoooi-prod"
|
||
resources:
|
||
requests:
|
||
cpu: "50m"
|
||
memory: "64Mi"
|
||
limits:
|
||
cpu: "200m"
|
||
memory: "256Mi"
|