# services/hermes/switchyard-deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: hermes-switchyard namespace: hermes labels: app: hermes-switchyard spec: replicas: 1 revisionHistoryLimit: 2 strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 maxUnavailable: 0 selector: matchLabels: app: hermes-switchyard template: metadata: labels: app: hermes-switchyard annotations: ai.bstein.dev/config-rev: "20260815-runtime-access-boundary" prometheus.io/scrape: "true" prometheus.io/port: "9005" prometheus.io/path: /metrics vault.hashicorp.com/agent-inject: "true" vault.hashicorp.com/role: hermes-agent vault.hashicorp.com/agent-inject-secret-relay-key: kv/data/atlas/hermes/chat-telegram vault.hashicorp.com/agent-inject-template-relay-key: | {{- with secret "kv/data/atlas/hermes/chat-telegram" -}} {{ .Data.data.relay_key }} {{- end }} vault.hashicorp.com/agent-pre-populate-only: "true" vault.hashicorp.com/agent-init-first: "true" vault.hashicorp.com/agent-requests-cpu: 25m vault.hashicorp.com/agent-requests-mem: 32Mi vault.hashicorp.com/agent-limits-cpu: 100m vault.hashicorp.com/agent-limits-mem: 128Mi spec: serviceAccountName: hermes-switchyard automountServiceAccountToken: true terminationGracePeriodSeconds: 330 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-14, titan-18, titan-22, titan-24] containers: - name: switchyard image: registry.bstein.dev/bstein/hermes-switchyard@sha256:3d952d528a4e4cb8afdf84f8995272f5d6107dc127b68cc20234b1da4aff43eb imagePullPolicy: IfNotPresent command: [/bin/sh, -ec] args: - | ATLAS_BROKER_KEY="$(tr -d '\r\n' < /vault/secrets/relay-key)" export ATLAS_BROKER_KEY exec switchyard-server \ --config /etc/switchyard/routes.toml \ --host 0.0.0.0 \ --port 9005 \ --shutdown-timeout 5m \ --routing-log-file /var/lib/switchyard/routing.jsonl env: - name: RUST_LOG value: switchyard_server=info,libsy=info ports: - name: http containerPort: 9005 protocol: TCP readinessProbe: httpGet: path: /health port: http initialDelaySeconds: 3 periodSeconds: 10 timeoutSeconds: 3 livenessProbe: httpGet: path: /health port: http initialDelaySeconds: 15 periodSeconds: 30 timeoutSeconds: 5 securityContext: allowPrivilegeEscalation: false capabilities: drop: [ALL] readOnlyRootFilesystem: true runAsNonRoot: true runAsUser: 10000 runAsGroup: 10000 resources: requests: cpu: 100m memory: 128Mi limits: cpu: "2" memory: 1Gi volumeMounts: - name: config mountPath: /etc/switchyard readOnly: true - name: state mountPath: /var/lib/switchyard - name: tmp mountPath: /tmp - name: worker-route-broker image: registry.bstein.dev/bstein/hermes-switchyard-brokers@sha256:ee7e95e060ef8083da505162d7e9030daba15fdd828cc047bbcbe6aa409d2083 imagePullPolicy: IfNotPresent command: - python - /opt/coordinator/worker_route_broker.py ports: - name: worker-route containerPort: 9007 protocol: TCP env: - name: HERMES_ROUTING_CATALOG_PATH value: /routing-catalog/catalog.json readinessProbe: httpGet: path: /health port: worker-route initialDelaySeconds: 2 periodSeconds: 10 timeoutSeconds: 3 livenessProbe: httpGet: path: /health port: worker-route initialDelaySeconds: 10 periodSeconds: 30 timeoutSeconds: 5 securityContext: allowPrivilegeEscalation: false capabilities: drop: [ALL] readOnlyRootFilesystem: true runAsNonRoot: true runAsUser: 10000 runAsGroup: 10000 resources: requests: cpu: 10m memory: 24Mi limits: cpu: 100m memory: 96Mi volumeMounts: - name: coordinator mountPath: /opt/coordinator readOnly: true - name: tmp mountPath: /tmp - name: routing-catalog mountPath: /routing-catalog readOnly: true - name: classifier-broker image: registry.bstein.dev/bstein/hermes-switchyard-brokers@sha256:ee7e95e060ef8083da505162d7e9030daba15fdd828cc047bbcbe6aa409d2083 imagePullPolicy: IfNotPresent command: - python - /opt/coordinator/classifier_broker.py ports: - name: classifier containerPort: 9008 protocol: TCP env: - name: HERMES_CLASSIFIER_BROKER_UPSTREAM value: http://ollama.ai.svc.cluster.local:11434 - name: HERMES_CLASSIFIER_BROKER_READ_TIMEOUT value: "60" readinessProbe: httpGet: path: /health port: classifier initialDelaySeconds: 2 periodSeconds: 10 timeoutSeconds: 3 livenessProbe: httpGet: path: /health port: classifier initialDelaySeconds: 10 periodSeconds: 30 timeoutSeconds: 5 securityContext: allowPrivilegeEscalation: false capabilities: drop: [ALL] readOnlyRootFilesystem: true runAsNonRoot: true runAsUser: 10000 runAsGroup: 10000 resources: requests: cpu: 25m memory: 48Mi limits: cpu: 250m memory: 192Mi volumeMounts: - name: coordinator mountPath: /opt/coordinator readOnly: true - name: tmp mountPath: /tmp volumes: - name: config configMap: name: hermes-switchyard - name: coordinator configMap: name: hermes-coordinator defaultMode: 0555 - name: state persistentVolumeClaim: claimName: hermes-switchyard-state-rwx - name: routing-catalog persistentVolumeClaim: claimName: hermes-routing-catalog - name: tmp emptyDir: {}