# 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: "20260811-switchyard-authority-v11" 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-anthropic-token: kv/data/atlas/hermes/agent-tokens vault.hashicorp.com/agent-inject-template-anthropic-token: | {{- with secret "kv/data/atlas/hermes/agent-tokens" -}} {{ .Data.data.anthropic_oauth_token }} {{- end }} 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: claude-oauth-broker image: registry.bstein.dev/bstein/hermes-agent@sha256:9b4c00a25fd08f0df3bcb800d755bd48576fb65af5ab0df40058fbb78a147e43 imagePullPolicy: IfNotPresent command: - /opt/hermes/.venv/bin/python - /opt/coordinator/claude_oauth_broker.py env: - name: HERMES_CLAUDE_OAUTH_TOKEN_FILE value: /vault/secrets/anthropic-token - name: HERMES_CLAUDE_BROKER_KEY_FILE value: /vault/secrets/relay-key - name: HERMES_CLAUDE_BROKER_READ_TIMEOUT value: "1800" - name: HERMES_ROUTING_CATALOG_PATH value: /routing-catalog/catalog.json ports: - name: claude containerPort: 9006 protocol: TCP readinessProbe: httpGet: path: /health port: claude initialDelaySeconds: 3 periodSeconds: 10 timeoutSeconds: 3 livenessProbe: httpGet: path: /health port: claude initialDelaySeconds: 15 periodSeconds: 30 timeoutSeconds: 5 securityContext: allowPrivilegeEscalation: false capabilities: drop: [ALL] readOnlyRootFilesystem: true runAsNonRoot: true runAsUser: 10000 runAsGroup: 10000 resources: requests: cpu: 50m memory: 96Mi limits: cpu: 500m memory: 384Mi volumeMounts: - name: coordinator mountPath: /opt/coordinator readOnly: true - name: tmp mountPath: /tmp - name: routing-catalog mountPath: /routing-catalog readOnly: true - name: worker-route-broker image: registry.bstein.dev/bstein/hermes-agent@sha256:9b4c00a25fd08f0df3bcb800d755bd48576fb65af5ab0df40058fbb78a147e43 imagePullPolicy: IfNotPresent command: - /opt/hermes/.venv/bin/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 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: {}