222 lines
7.0 KiB
YAML
222 lines
7.0 KiB
YAML
# All Hermes state: config.yaml, .env (keys entered in the dashboard), auth.json
|
|
# (the Anthropic OAuth login), sessions, memories, skills, cron. Mounted at
|
|
# /opt/data, the image's HERMES_HOME.
|
|
apiVersion: v1
|
|
kind: PersistentVolumeClaim
|
|
metadata:
|
|
name: hermes-data
|
|
namespace: hermes
|
|
spec:
|
|
accessModes:
|
|
- ReadWriteOnce
|
|
storageClassName: ceph-block
|
|
resources:
|
|
requests:
|
|
storage: 10Gi
|
|
---
|
|
# Hermes Agent: the gateway (messaging platforms, cron, API server on 8642) and
|
|
# the dashboard (9119, also the Hermes Desktop remote-gateway backend), both
|
|
# supervised by the image's s6-overlay. s6 must be PID 1 and starts as root,
|
|
# remapping and dropping to the `hermes` user (10000).
|
|
#
|
|
# One replica, Recreate: two gateways must never share one data directory.
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: hermes
|
|
namespace: hermes
|
|
labels:
|
|
app.kubernetes.io/name: hermes
|
|
spec:
|
|
replicas: 1
|
|
strategy:
|
|
type: Recreate
|
|
selector:
|
|
matchLabels:
|
|
app.kubernetes.io/name: hermes
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app.kubernetes.io/name: hermes
|
|
spec:
|
|
serviceAccountName: hermes
|
|
securityContext:
|
|
fsGroup: 10000
|
|
seccompProfile:
|
|
type: RuntimeDefault
|
|
initContainers:
|
|
# The dashboard trusts X-Forwarded-* only from listed peers; Traefik
|
|
# connects from the pod network. No env equivalent exists, so it is
|
|
# set in config.yaml on every start (idempotent).
|
|
- name: config
|
|
image: gitea.renner.uno/konairius/hermes:build.FIRST_BUILD_TS # {"$imagepolicy": "flux-system:hermes"}
|
|
command:
|
|
- /opt/hermes/.venv/bin/hermes
|
|
- config
|
|
- set
|
|
- dashboard.trusted_proxies
|
|
- '["10.244.0.0/16","fd10:244::/48"]'
|
|
env:
|
|
- name: HERMES_HOME
|
|
value: /opt/data
|
|
- name: HOME
|
|
value: /opt/data
|
|
securityContext:
|
|
runAsUser: 10000
|
|
runAsGroup: 10000
|
|
runAsNonRoot: true
|
|
allowPrivilegeEscalation: false
|
|
capabilities:
|
|
drop: ["ALL"]
|
|
volumeMounts:
|
|
- name: data
|
|
mountPath: /opt/data
|
|
# Skills from git (ConfigMap hermes-skills) beside the PVC's skills/.
|
|
- name: skills-config
|
|
image: gitea.renner.uno/konairius/hermes:build.FIRST_BUILD_TS # {"$imagepolicy": "flux-system:hermes"}
|
|
command:
|
|
- /opt/hermes/.venv/bin/hermes
|
|
- config
|
|
- set
|
|
- skills.external_dirs
|
|
- '["/opt/hermes-skills"]'
|
|
env:
|
|
- name: HERMES_HOME
|
|
value: /opt/data
|
|
- name: HOME
|
|
value: /opt/data
|
|
securityContext:
|
|
runAsUser: 10000
|
|
runAsGroup: 10000
|
|
runAsNonRoot: true
|
|
allowPrivilegeEscalation: false
|
|
capabilities:
|
|
drop: ["ALL"]
|
|
volumeMounts:
|
|
- name: data
|
|
mountPath: /opt/data
|
|
containers:
|
|
- name: hermes
|
|
image: gitea.renner.uno/konairius/hermes:build.FIRST_BUILD_TS # {"$imagepolicy": "flux-system:hermes"}
|
|
args: ["gateway", "run"]
|
|
env:
|
|
- name: HERMES_DASHBOARD
|
|
value: "1"
|
|
- name: HERMES_DASHBOARD_PUBLIC_URL
|
|
value: https://hermes.renner.uno
|
|
# Dashboard login: Authentik OIDC, public PKCE client (blueprint
|
|
# in apps/authentik/blueprints-configmap.yaml, group Hermes Users).
|
|
- name: HERMES_DASHBOARD_OIDC_ISSUER
|
|
value: https://auth.renner.uno/application/o/hermes/
|
|
- name: HERMES_DASHBOARD_OIDC_CLIENT_ID
|
|
value: hermes-dashboard
|
|
- name: API_SERVER_ENABLED
|
|
value: "true"
|
|
- name: API_SERVER_HOST
|
|
value: 0.0.0.0
|
|
# git as hermes-bot: the credential helper reads the mounted token.
|
|
- name: GIT_CONFIG_COUNT
|
|
value: "3"
|
|
- name: GIT_CONFIG_KEY_0
|
|
value: credential.https://gitea.renner.uno.helper
|
|
- name: GIT_CONFIG_VALUE_0
|
|
value: '!f() { test "$1" = get && echo username=hermes-bot && echo "password=$(cat /var/run/secrets/gitea/api-token)"; }; f'
|
|
- name: GIT_CONFIG_KEY_1
|
|
value: user.name
|
|
- name: GIT_CONFIG_VALUE_1
|
|
value: hermes-bot
|
|
- name: GIT_CONFIG_KEY_2
|
|
value: user.email
|
|
- name: GIT_CONFIG_VALUE_2
|
|
value: hermes-bot@konstantin-renner.de
|
|
envFrom:
|
|
- secretRef:
|
|
name: hermes-api-key
|
|
ports:
|
|
- name: dashboard
|
|
containerPort: 9119
|
|
- name: api
|
|
containerPort: 8642
|
|
# The dashboard is the user-facing surface; /api/status is public.
|
|
startupProbe:
|
|
httpGet:
|
|
path: /api/status
|
|
port: dashboard
|
|
periodSeconds: 10
|
|
failureThreshold: 30
|
|
readinessProbe:
|
|
httpGet:
|
|
path: /api/status
|
|
port: dashboard
|
|
periodSeconds: 15
|
|
livenessProbe:
|
|
httpGet:
|
|
path: /api/status
|
|
port: dashboard
|
|
periodSeconds: 60
|
|
timeoutSeconds: 10
|
|
failureThreshold: 3
|
|
resources:
|
|
requests:
|
|
cpu: 100m
|
|
memory: 512Mi
|
|
limits:
|
|
memory: 4Gi
|
|
volumeMounts:
|
|
- name: data
|
|
mountPath: /opt/data
|
|
# Identity and house rules from git (SOUL.md beside this file).
|
|
- name: soul
|
|
mountPath: /opt/data/SOUL.md
|
|
subPath: SOUL.md
|
|
readOnly: true
|
|
- name: skills
|
|
mountPath: /opt/hermes-skills
|
|
readOnly: true
|
|
- name: wiki-key
|
|
mountPath: /var/run/secrets/wiki
|
|
readOnly: true
|
|
- name: gitea-token
|
|
mountPath: /var/run/secrets/gitea
|
|
readOnly: true
|
|
volumes:
|
|
- name: data
|
|
persistentVolumeClaim:
|
|
claimName: hermes-data
|
|
- name: soul
|
|
configMap:
|
|
name: hermes-soul
|
|
- name: skills
|
|
configMap:
|
|
name: hermes-skills
|
|
items:
|
|
- key: homelab-wiki-SKILL.md
|
|
path: homelab-wiki/SKILL.md
|
|
- key: homelab-wiki-wiki.py
|
|
path: homelab-wiki/scripts/wiki.py
|
|
- name: wiki-key
|
|
secret:
|
|
secretName: hermes-wiki
|
|
optional: true
|
|
- name: gitea-token
|
|
secret:
|
|
secretName: hermes-gitea
|
|
---
|
|
apiVersion: v1
|
|
kind: Service
|
|
metadata:
|
|
name: hermes
|
|
namespace: hermes
|
|
labels:
|
|
app.kubernetes.io/name: hermes
|
|
spec:
|
|
selector:
|
|
app.kubernetes.io/name: hermes
|
|
ports:
|
|
- name: dashboard
|
|
port: 9119
|
|
targetPort: dashboard
|
|
- name: api
|
|
port: 8642
|
|
targetPort: api
|