Files
awoooi/k8s/awoooi-prod/08-deployment-worker.yaml
2026-07-14 12:16:37 +08:00

259 lines
10 KiB
YAML
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 Signal Worker Deployment
# 負責人: CTO
# 版本: v1.3
# 日期: 2026-03-22
# 更新: 2026-03-28 v1.1 - 新增 startupProbe + revisionHistoryLimit:3 (Phase K0.5/K0.7)
# 更新: 2026-03-28 v1.2 - liveness 改為 mtime 檢查 (心跳機制長期方案)
# 更新: 2026-03-29 v1.3 - ADR-038/039 terminationGracePeriodSeconds:90 (Graceful Shutdown)
#
# Phase 6.5: Redis Streams 消費者
# 職責: 消費 awoooi:signals 串流,觸發 Incident Engine
apiVersion: apps/v1
kind: Deployment
metadata:
name: awoooi-worker
namespace: awoooi-prod
labels:
app: awoooi-worker
system: awoooi
environment: prod
component: signal-processor
spec:
# Phase 8: Worker 啟用 - 處理 Redis Streams 訊號
replicas: 1
revisionHistoryLimit: 3
selector:
matchLabels:
app: awoooi-worker
environment: prod
system: awoooi
strategy:
type: RollingUpdate
rollingUpdate:
# 2026-07-01 Codex: DB role `awoooi` is capped at two connections and
# worker imports the same API DB stack. Do not run old+new worker pods
# during rollout until the DB role/pool budget is raised and verified.
maxSurge: 0
maxUnavailable: 1
template:
metadata:
labels:
app: awoooi-worker
system: awoooi
environment: prod
component: signal-processor
spec:
# 2026-07-01 Codex: keep hostname spread as a preference, not a hard
# scheduler blocker, so reboot recovery and GitOps rollouts do not deadlock.
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app: awoooi-worker
environment: prod
system: awoooi
# ADR-038/039: Graceful Shutdown (Worker 需要 75 秒完成清理)
# Signal correlation and candidate production are read-only. Runtime
# side effects belong exclusively to awoooi-executor-broker.
serviceAccountName: awoooi-worker
automountServiceAccountToken: true
terminationGracePeriodSeconds: 90
containers:
- name: worker
# 映像標籤由 CI/CD 動態注入 (格式: {sha}-{run_id})
# Harbor 金庫: 110 主機 (192.168.0.110:5000)
image: 192.168.0.110:5000/library/api:IMAGE_TAG_PLACEHOLDER
imagePullPolicy: Always
lifecycle:
preStop:
exec:
command: ["/bin/sh", "-c", "sleep 5"]
# Worker 模式啟動 (非 HTTP 服務)
command: ["python", "-m", "src.workers.signal_worker"]
envFrom:
- configMapRef:
name: awoooi-config
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: awoooi-worker-db
key: DATABASE_URL
- name: REDIS_URL
valueFrom:
secretKeyRef: {name: awoooi-secrets, key: REDIS_URL, optional: true}
- name: GEMINI_API_KEY
valueFrom:
secretKeyRef: {name: awoooi-secrets, key: GEMINI_API_KEY, optional: true}
- name: CLAUDE_API_KEY
valueFrom:
secretKeyRef: {name: awoooi-secrets, key: CLAUDE_API_KEY, optional: true}
- name: ANTHROPIC_API_KEY
valueFrom:
secretKeyRef: {name: awoooi-secrets, key: ANTHROPIC_API_KEY, optional: true}
- name: NVIDIA_API_KEY
valueFrom:
secretKeyRef: {name: awoooi-secrets, key: NVIDIA_API_KEY, optional: true}
- name: OPENCLAW_TG_BOT_TOKEN
valueFrom:
secretKeyRef: {name: awoooi-secrets, key: OPENCLAW_TG_BOT_TOKEN, optional: true}
- name: OPENCLAW_TG_CHAT_ID
valueFrom:
secretKeyRef: {name: awoooi-secrets, key: OPENCLAW_TG_CHAT_ID, optional: true}
- name: OPENCLAW_TG_USER_WHITELIST
valueFrom:
secretKeyRef: {name: awoooi-secrets, key: OPENCLAW_TG_USER_WHITELIST, optional: true}
- name: SRE_GROUP_CHAT_ID
valueFrom:
secretKeyRef: {name: awoooi-secrets, key: SRE_GROUP_CHAT_ID, optional: true}
- name: AGENT99_SRE_ALERT_RELAY_TOKEN
valueFrom:
secretKeyRef: {name: awoooi-secrets, key: AGENT99_SRE_ALERT_RELAY_TOKEN, optional: true}
- name: WEBHOOK_HMAC_SECRET
valueFrom:
secretKeyRef: {name: awoooi-secrets, key: WEBHOOK_HMAC_SECRET, optional: true}
- name: AWOOOP_OPERATOR_API_KEY
valueFrom:
secretKeyRef: {name: awoooi-secrets, key: AWOOOP_OPERATOR_API_KEY, optional: true}
- name: JWT_SECRET
valueFrom:
secretKeyRef: {name: awoooi-secrets, key: JWT_SECRET, optional: true}
- name: JWT_ALGORITHM
valueFrom:
secretKeyRef: {name: awoooi-secrets, key: JWT_ALGORITHM, optional: true}
- name: LANGFUSE_PUBLIC_KEY
valueFrom:
secretKeyRef: {name: awoooi-secrets, key: LANGFUSE_PUBLIC_KEY, optional: true}
- name: LANGFUSE_SECRET_KEY
valueFrom:
secretKeyRef: {name: awoooi-secrets, key: LANGFUSE_SECRET_KEY, optional: true}
- name: SENTRY_DSN
valueFrom:
secretKeyRef: {name: awoooi-secrets, key: SENTRY_DSN, optional: true}
- name: SENTRY_AUTH_TOKEN
valueFrom:
secretKeyRef: {name: awoooi-secrets, key: SENTRY_AUTH_TOKEN, optional: true}
- name: ARGOCD_API_TOKEN
valueFrom:
secretKeyRef: {name: awoooi-secrets, key: ARGOCD_API_TOKEN, optional: true}
- name: GITEA_API_TOKEN
valueFrom:
secretKeyRef: {name: awoooi-secrets, key: GITEA_API_TOKEN, optional: true}
- name: GITEA_WEBHOOK_SECRET
valueFrom:
secretKeyRef: {name: awoooi-secrets, key: GITEA_WEBHOOK_SECRET, optional: true}
- name: NEMOTRON_BOT_TOKEN
valueFrom:
secretKeyRef: {name: awoooi-secrets, key: NEMOTRON_BOT_TOKEN, optional: true}
- name: OPENCLAW_BOT_TOKEN
valueFrom:
secretKeyRef: {name: awoooi-secrets, key: OPENCLAW_BOT_TOKEN, optional: true}
- name: SMTP_HOST
valueFrom:
secretKeyRef: {name: awoooi-secrets, key: SMTP_HOST, optional: true}
- name: WORKER_MODE
value: "true"
- name: CONSUMER_GROUP
value: "awoooi-workers"
- name: CONSUMER_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: DATABASE_POOL_SIZE
# 2026-07-01 Codex: keep worker DB usage inside the current
# production role connection budget during reboot rollouts.
value: "1"
- name: DATABASE_MAX_OVERFLOW
value: "0"
- name: DATABASE_NULL_POOL
value: "true"
- name: DATABASE_BOOTSTRAP_DDL_ENABLED
value: "false"
- name: AWOOOI_BUILD_COMMIT_SHA
value: "afe15662f339660db9c8fc9270e27217358df311"
- name: ENABLE_AWOOOP_ANSIBLE_CANDIDATE_BACKFILL_WORKER
value: "true"
- name: ENABLE_SECURITY_CONTROL_PLANE_MAINTENANCE_WORKER
value: "true"
- name: AWOOOP_ANSIBLE_CANDIDATE_BACKFILL_INTERVAL_SECONDS
value: "600"
- name: AWOOOP_ANSIBLE_CANDIDATE_BACKFILL_BATCH_LIMIT
value: "2"
- name: AWOOOP_ANSIBLE_CANDIDATE_BACKFILL_WINDOW_HOURS
value: "24"
- name: AWOOOP_ANSIBLE_CANDIDATE_BACKFILL_STARTUP_SLEEP_SECONDS
value: "10"
- name: ENABLE_AWOOOP_ANSIBLE_CHECK_MODE_WORKER
value: "false"
- name: ENABLE_AWOOOP_ANSIBLE_CONTROLLED_APPLY
value: "false"
- name: ENABLE_IWOOOS_WAZUH_MANAGER_POSTURE_EXECUTOR
value: "true"
- name: IWOOOS_WAZUH_MANAGER_POSTURE_FRESHNESS_HOURS
value: "6"
- name: AWOOOP_ANSIBLE_CONTROLLED_APPLY_ALLOWED_RISK_LEVELS
value: "low,medium,high"
- name: AWOOOP_ANSIBLE_CHECK_MODE_INTERVAL_SECONDS
value: "300"
- name: AWOOOP_ANSIBLE_CHECK_MODE_BATCH_LIMIT
value: "1"
- name: AWOOOP_ANSIBLE_CHECK_MODE_TIMEOUT_SECONDS
value: "180"
- name: AWOOOP_ANSIBLE_CHECK_MODE_STARTUP_SLEEP_SECONDS
value: "30"
resources:
requests:
cpu: "100m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
# Worker 健康檢查 (mtime 時間戳檢查 - 長期解決方案)
# 心跳機制Worker 每 30 秒 touch 健康文件
# 探針檢查:文件 mtime 必須在 60 秒內
livenessProbe:
exec:
command:
- /bin/sh
- -c
- |
[ -f /tmp/worker-healthy ] && \
[ "$(find /tmp/worker-healthy -mmin -1 2>/dev/null)" ] && exit 0
exit 1
initialDelaySeconds: 30
periodSeconds: 15
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
exec:
command:
- cat
- /tmp/worker-ready
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
# Phase K0.5: Startup Probe (允許最多 60 秒啟動時間)
startupProbe:
exec:
command:
- cat
- /tmp/worker-ready
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 5
failureThreshold: 12
# 反親和性 - 分散到不同節點
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app: awoooi-worker
topologyKey: kubernetes.io/hostname