# services/hermes/chat-router.yaml apiVersion: apps/v1 kind: Deployment metadata: name: hermes-chat-router namespace: hermes labels: app: hermes-chat-router spec: replicas: 1 revisionHistoryLimit: 2 strategy: type: Recreate selector: matchLabels: app: hermes-chat-router template: metadata: labels: app: hermes-chat-router annotations: ai.bstein.dev/role: privacy-preserving-chat-tenant-router ai.bstein.dev/config-rev: "20260815-runtime-access-boundary" vault.hashicorp.com/agent-inject: "true" vault.hashicorp.com/agent-pre-populate-only: "true" vault.hashicorp.com/agent-init-first: "true" vault.hashicorp.com/role: hermes-chat vault.hashicorp.com/agent-inject-secret-telegram-config: kv/data/atlas/hermes/chat-telegram vault.hashicorp.com/agent-inject-template-telegram-config: | {{- with secret "kv/data/atlas/hermes/chat-telegram" -}} bot_token={{ .Data.data.bot_token }} relay_key={{ .Data.data.relay_key }} {{- end }} spec: serviceAccountName: hermes-chat automountServiceAccountToken: true securityContext: fsGroup: 10000 fsGroupChangePolicy: OnRootMismatch seccompProfile: type: RuntimeDefault affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/arch operator: In values: [arm64] - key: node-role.kubernetes.io/worker operator: In values: ["true"] - key: kubernetes.io/hostname operator: NotIn values: [titan-13, titan-15, titan-17, titan-18, titan-19] preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 preference: matchExpressions: - key: hardware operator: In values: [rpi5] containers: - name: router image: registry.bstein.dev/bstein/hermes-chat-router@sha256:6744cb7b87c6050f1b97c0675cd280b8295b3b5826ba1d6d92e37aee6fd0b8c4 # {"$imagepolicy": "hermes:hermes-chat-router-release"} imagePullPolicy: IfNotPresent ports: - {name: http, containerPort: 8080, protocol: TCP} env: - {name: TENANT_SLOTS, value: "8"} - {name: TENANT_STATE_PATH, value: /state/tenants.json} - {name: TELEGRAM_CONFIG_PATH, value: /vault/secrets/telegram-config} readinessProbe: httpGet: {path: /healthz, port: http} initialDelaySeconds: 2 periodSeconds: 10 livenessProbe: httpGet: {path: /healthz, port: http} initialDelaySeconds: 10 periodSeconds: 20 securityContext: allowPrivilegeEscalation: false capabilities: drop: [ALL] readOnlyRootFilesystem: true runAsUser: 10000 runAsGroup: 10000 seccompProfile: type: RuntimeDefault volumeMounts: - {name: state, mountPath: /state} - {name: tmp, mountPath: /tmp} resources: requests: {cpu: 25m, memory: 32Mi} limits: {cpu: 250m, memory: 128Mi} volumes: - name: state persistentVolumeClaim: claimName: hermes-chat-router-state - name: tmp emptyDir: sizeLimit: 128Mi