Files
awoooi/k8s/awoooi-prod/06-deployment-api.yaml
OG T 77f2da9264
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
fix(k8s): Bug #11+#12 — SSH egress 白名單 + repair-ssh-key 讀取權限
Bug #11 (NetworkPolicy): allow-required-egress 缺少 192.168.0.110:22
  - K8s Pod 到 110 的 SSH port 22 被 default-deny-all 封鎖
  - 自動修復的 SSH_COMMAND Playbook 必然 Connection refused
  - 修正: 加入 port 22 到 110 的 egress 白名單

Bug #12 (Deployment): repair-ssh-key Secret defaultMode=0400 (root-only)
  - Pod 以 appuser(UID 1000) 跑,無法讀取 root-owned 的 SSH key
  - ssh 報錯: "Load key: Permission denied"
  - 修正: 加入 securityContext.fsGroup=1000,讓 appuser 透過 group read 存取
  - 已驗證: Pod 內 ssh → repair-bot-110 → REPAIR_OK:sentry 

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 14:50:49 +08:00

150 lines
4.6 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 Backend (FastAPI) Deployment
# 負責人: CIO
# 版本: v1.1
# 日期: 2026-03-20
# 更新: 2026-03-28 - 新增 startupProbe + revisionHistoryLimit:3 (Phase K0.5/K0.7)
apiVersion: apps/v1
kind: Deployment
metadata:
name: awoooi-api
namespace: awoooi-prod
labels:
app: awoooi-api
system: awoooi
environment: prod
spec:
replicas: 2
revisionHistoryLimit: 3
selector:
matchLabels:
app: awoooi-api
environment: prod
system: awoooi
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app: awoooi-api
system: awoooi
environment: prod
spec:
# Phase 7: 使用 RBAC ServiceAccount (最小權限)
serviceAccountName: awoooi-executor
automountServiceAccountToken: true
# 2026-04-09 Claude Sonnet 4.6 Asia/Taipei: Bug #12 修正
# fsGroup=1000 讓 appuser(1000) 可讀取 defaultMode=0400 的 repair-ssh-key Secret
# SSH 要求 key 必須是 owner-only (0400/0600)0444 會被拒絕
securityContext:
fsGroup: 1000
containers:
- name: api
# 映像標籤由 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
ports:
- containerPort: 8000
name: http
envFrom:
- configMapRef:
name: awoooi-config
- secretRef:
name: awoooi-secrets
# 2026-04-05 Claude Code: Sprint 3 — 掛載 SSH key 供 HostRepairAgent 使用
volumeMounts:
- name: repair-ssh-key
mountPath: /etc/repair-ssh
readOnly: true
# 2026-04-06 Claude Code: Sprint 3 Security Fix A1 — known_hosts
# 掛到獨立目錄,避免與 repair-ssh-key 的 mountPath 衝突
- name: repair-known-hosts
mountPath: /etc/repair-known-hosts
readOnly: true
# 2026-04-08 Claude Sonnet 4.6: Sprint 5.1 Guardrail — service registry YAML
# 掛載到 /app/ops/config/ 讓 _find_registry_path() 可找到
- name: service-registry
mountPath: /app/ops/config/service-registry.yaml
subPath: service-registry.yaml
readOnly: true
resources:
requests:
cpu: "200m"
memory: "512Mi"
limits:
cpu: "1"
memory: "1Gi"
livenessProbe:
httpGet:
path: /api/v1/health
port: 8000
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /api/v1/health
port: 8000
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
# Phase K0.5: Startup Probe (允許最多 60 秒啟動時間)
startupProbe:
httpGet:
path: /api/v1/health
port: 8000
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 5
failureThreshold: 12
# 反親和性 - 分散到不同節點
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app: awoooi-api
topologyKey: kubernetes.io/hostname
# 2026-04-05 Claude Code: Sprint 3 — repair SSH key (defaultMode 0400)
volumes:
- name: repair-ssh-key
secret:
secretName: awoooi-repair-ssh-key
defaultMode: 0400 # 八進位 0400 = 十進位 256 = r-------- (owner read-only)
# 2026-04-06 Claude Code: Sprint 3 Security Fix A1
# optional: true — CD 首次跑時建立 secretPod 不阻塞等待
- name: repair-known-hosts
secret:
secretName: awoooi-repair-known-hosts
optional: true
# 2026-04-08 Claude Sonnet 4.6: Sprint 5.1 Guardrail — service registry
- name: service-registry
configMap:
name: service-registry
---
apiVersion: v1
kind: Service
metadata:
name: awoooi-api-svc
namespace: awoooi-prod
labels:
app: awoooi-api
spec:
type: NodePort
selector:
app: awoooi-api
ports:
- port: 8000
targetPort: 8000
nodePort: 32334
name: http