feat: embed k3s in neuron-web image to run soul-demo as managed pods

soul-demo now runs as a k3s Deployment with HPA (1–8 replicas, 60% CPU
target) instead of a bare background process. k3s starts first in
entrypoint.sh, imports the soul-demo:local OCI tar from
/var/lib/rancher/k3s/agent/images, and auto-applies the Deployment,
NodePort Service, and HPA from the server/manifests dir. neuron-web
starts only after the soul-demo pod is Running. Cloud Run gen2 execution
environment required for k3s (provides /dev/kmsg and Linux capabilities).
This commit is contained in:
2026-05-07 00:57:06 -05:00
parent a9bc933867
commit ddbb568f1d
7 changed files with 181 additions and 16 deletions
+13
View File
@@ -0,0 +1,13 @@
FROM debian:bookworm-slim
RUN apt-get update \
&& apt-get install -y --no-install-recommends libcurl4 libssl3 ca-certificates \
&& rm -rf /var/lib/apt/lists/* \
&& groupadd -r landing && useradd -r -g landing landing \
&& mkdir -p /srv/soul/engram-demo \
&& chown -R landing:landing /srv/soul
COPY soul-demo /usr/local/bin/soul-demo
COPY engram-snapshot.json /srv/soul/engram-demo/snapshot.json
ENV NEURON_HOME=/srv/soul/engram-demo
ENV NEURON_PORT=7772
USER landing
CMD ["/usr/local/bin/soul-demo"]
+29 -15
View File
@@ -1,21 +1,35 @@
#!/usr/bin/env bash
# entrypoint.sh — Start soul-demo then neuron-web in the same container.
#
# soul-demo runs in the background on :7772 (localhost only, not exposed).
# neuron-web runs in the foreground on :8080 (Cloud Run health checks this).
# If neuron-web exits, the container exits. Soul crashing is non-fatal —
# chat will return "demo soul not responding" but the page stays up.
#!/bin/sh
set -e
set -euo pipefail
echo "[entrypoint] Starting k3s server (embedded soul-demo orchestrator)..."
echo "[entrypoint] starting soul-demo on :7772"
/usr/local/bin/soul-demo &
SOUL_PID=$!
# k3s server — single-node mode, disable unused components
# --disable traefik,servicelb: we don't need an ingress or LB
# --disable metrics-server: saves ~50MB RAM
# --write-kubeconfig-mode=644: allow non-root reads
# --data-dir: use the pre-chowned dir
k3s server \
--disable traefik \
--disable servicelb \
--disable metrics-server \
--write-kubeconfig-mode=644 \
--data-dir /var/lib/rancher/k3s \
--node-name soul-node &
# Give the soul a few seconds to load its engram and seed safety nodes
sleep 4
K3S_PID=$!
echo "[entrypoint] soul-demo started (pid=$SOUL_PID)"
echo "[entrypoint] starting neuron-web on :${PORT:-8080}"
echo "[entrypoint] Waiting for k3s to become ready..."
until k3s kubectl get nodes --no-headers 2>/dev/null | grep -q "Ready"; do
sleep 2
done
echo "[entrypoint] k3s ready. soul-demo Deployment will be applied automatically from manifests."
# Wait for soul-demo pod to be Running before starting neuron-web
echo "[entrypoint] Waiting for soul-demo pod..."
until k3s kubectl get pods -l app=soul-demo --no-headers 2>/dev/null | grep -q "Running"; do
sleep 3
done
echo "[entrypoint] soul-demo is running."
echo "[entrypoint] Starting neuron-web on port ${PORT:-8080}..."
exec /usr/local/bin/neuron-web
+90
View File
@@ -0,0 +1,90 @@
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: soul-demo
namespace: default
labels:
app: soul-demo
spec:
replicas: 1
selector:
matchLabels:
app: soul-demo
template:
metadata:
labels:
app: soul-demo
spec:
containers:
- name: soul-demo
image: soul-demo:local
imagePullPolicy: Never
ports:
- containerPort: 7772
env:
- name: NEURON_HOME
value: /srv/soul/engram-demo
- name: NEURON_PORT
value: "7772"
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: 1000m
memory: 512Mi
livenessProbe:
httpGet:
path: /healthz
port: 7772
initialDelaySeconds: 10
periodSeconds: 15
failureThreshold: 3
readinessProbe:
httpGet:
path: /healthz
port: 7772
initialDelaySeconds: 5
periodSeconds: 10
volumeMounts:
- name: engram-data
mountPath: /srv/soul/engram-demo
volumes:
- name: engram-data
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: soul-demo
namespace: default
spec:
type: NodePort
selector:
app: soul-demo
ports:
- port: 7772
targetPort: 7772
nodePort: 7772
protocol: TCP
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: soul-demo
namespace: default
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: soul-demo
minReplicas: 1
maxReplicas: 8
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60