feat: embed k3s to run soul-demo as self-healing k8s pods #13
@@ -211,6 +211,7 @@ jobs:
|
||||
--image "$IMAGE" \
|
||||
--region us-central1 \
|
||||
--project neuron-785695 \
|
||||
--execution-environment gen2 \
|
||||
--service-account neuron-marketing-sa@neuron-785695.iam.gserviceaccount.com \
|
||||
--update-env-vars "NODE_ENV=production,STRIPE_PUBLISHABLE_KEY=pk_test_51TPoHnJg9Fv1D3AUp1FEMcy4MGlKRZqs4scW66kjQFQjWofmNc2rottzXzDaXekHvuw1OQpyp2WCIsc7O5fXIG0G00HQQrkdGX,GCS_SHARE_BUCKET=neuron-shares-prod,SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Im9jb2pzZ2hhb25sdHVuaWRrenB3Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3Nzc2NDIxNjgsImV4cCI6MjA5MzIxODE2OH0.e0FVFw1aahnrBVvnkR5R8a-RxCx095U8o_gsk7Quq3E,NEURON_LLM_0_FORMAT=anthropic,NEURON_LLM_0_MODEL=claude-sonnet-4-5,NEURON_LLM_0_URL=https://api.anthropic.com/v1/messages" \
|
||||
--update-secrets "SUPABASE_SERVICE_KEY=supabase-service-key:latest,NEURON_LLM_0_KEY=anthropic-api-key:latest,ANTHROPIC_API_KEY=anthropic-api-key:latest,STRIPE_SECRET_KEY=stripe-secret-key-stage:latest,STRIPE_WEBHOOK_SECRET=stripe-webhook-secret-stage:latest,STRIPE_PRICE_PROFESSIONAL=stripe-price-professional-stage:latest,STRIPE_PRICE_FOUNDING=stripe-price-founding-stage:latest,STRIPE_PRICE_FAMILY_CHILD=stripe-price-family-child:latest,RESEND_API_KEY=resend-api-key:latest,DOCUSEAL_WEBHOOK_TOKEN=docuseal-webhook-token:latest" \
|
||||
@@ -228,6 +229,7 @@ jobs:
|
||||
|
||||
gcloud run services update marketing-stage \
|
||||
--region us-central1 --project neuron-785695 \
|
||||
--execution-environment gen2 \
|
||||
--update-env-vars "NEURON_ORIGIN=${STAGE_URL}" \
|
||||
--quiet
|
||||
|
||||
@@ -265,6 +267,7 @@ jobs:
|
||||
--image "$IMAGE" \
|
||||
--region "$region" \
|
||||
--project neuron-785695 \
|
||||
--execution-environment gen2 \
|
||||
--quiet
|
||||
}
|
||||
deploy us-central1 marketing-prod-us &
|
||||
|
||||
@@ -31,3 +31,10 @@ src/assets/js/
|
||||
!dist/elhtml_impl.c
|
||||
!dist/entrypoint.sh
|
||||
!dist/engram-snapshot.json
|
||||
!dist/Dockerfile.soul-demo
|
||||
!dist/k3s-soul-demo.yaml
|
||||
|
||||
# Build artifacts produced by the soul-demo packaging step in build-stage.sh
|
||||
dist/soul-demo
|
||||
dist/soul-demo-snapshot.json
|
||||
dist/soul-demo-image.tar
|
||||
|
||||
+23
-2
@@ -17,6 +17,7 @@ FROM debian:bookworm-slim AS builder
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
build-essential \
|
||||
curl \
|
||||
libcurl4-openssl-dev \
|
||||
libssl-dev \
|
||||
ca-certificates \
|
||||
@@ -41,6 +42,10 @@ RUN cc -O2 -rdynamic \
|
||||
soul-demo.c vessel_stubs.c el_runtime.o \
|
||||
-lcurl -lpthread -ldl -lm -lssl -lcrypto
|
||||
|
||||
# ── Download k3s binary ───────────────────────────────────────────────────────
|
||||
RUN curl -fL https://github.com/k3s-io/k3s/releases/download/v1.32.4%2Bk3s1/k3s -o /usr/local/bin/k3s \
|
||||
&& chmod +x /usr/local/bin/k3s
|
||||
|
||||
# ── Stage 2: runtime image ────────────────────────────────────────────────────
|
||||
FROM debian:bookworm-slim
|
||||
|
||||
@@ -53,7 +58,9 @@ RUN apt-get update \
|
||||
&& groupadd -r landing && useradd -r -g landing landing \
|
||||
&& mkdir -p /srv/landing/assets /srv/landing/js /srv/landing/shares \
|
||||
&& mkdir -p /srv/soul/engram-demo \
|
||||
&& chown -R landing:landing /srv/landing /srv/soul
|
||||
&& chown -R landing:landing /srv/landing /srv/soul \
|
||||
&& mkdir -p /var/lib/rancher/k3s /tmp/k3s \
|
||||
&& chown -R landing:landing /var/lib/rancher /tmp/k3s
|
||||
|
||||
# neuron-web binary — produced by `elb build` in CI (linux/amd64)
|
||||
COPY dist/neuron-landing /usr/local/bin/neuron-web
|
||||
@@ -61,6 +68,17 @@ RUN chmod +x /usr/local/bin/neuron-web
|
||||
|
||||
COPY --from=builder /build/soul-demo /usr/local/bin/soul-demo
|
||||
|
||||
# k3s binary
|
||||
COPY --from=builder /usr/local/bin/k3s /usr/local/bin/k3s
|
||||
|
||||
# soul-demo OCI image tar — k3s imports this at startup (no registry needed)
|
||||
RUN mkdir -p /var/lib/rancher/k3s/agent/images
|
||||
COPY dist/soul-demo-image.tar /var/lib/rancher/k3s/agent/images/soul-demo.tar
|
||||
|
||||
# k3s manifests — auto-applied when k3s starts
|
||||
RUN mkdir -p /var/lib/rancher/k3s/server/manifests
|
||||
COPY dist/k3s-soul-demo.yaml /var/lib/rancher/k3s/server/manifests/soul-demo.yaml
|
||||
|
||||
# Engram snapshot — baked in so soul has memory from cold start
|
||||
COPY dist/engram-snapshot.json /srv/soul/engram-demo/snapshot.json
|
||||
|
||||
@@ -83,8 +101,11 @@ ENV LANDING_ROOT=/srv/landing
|
||||
ENV PORT=8080
|
||||
ENV NEURON_HOME=/srv/soul/engram-demo
|
||||
ENV NEURON_PORT=7772
|
||||
ENV K3S_DATA_DIR=/var/lib/rancher/k3s
|
||||
ENV KUBECONFIG=/var/lib/rancher/k3s/server/cred/admin.kubeconfig
|
||||
|
||||
USER landing
|
||||
# k3s requires root to create network namespaces and mount cgroups.
|
||||
# Cloud Run gen2 sandbox is the security boundary here.
|
||||
EXPOSE 8080
|
||||
|
||||
CMD ["/usr/local/bin/entrypoint.sh"]
|
||||
|
||||
@@ -43,4 +43,22 @@ docker build \
|
||||
-t "marketing:${TAG}" \
|
||||
.
|
||||
|
||||
# Extract soul-demo binary and engram snapshot from built image
|
||||
echo "==> Packaging soul-demo:local image for k3s..."
|
||||
CONTAINER_ID=$(docker create "marketing:${TAG}")
|
||||
docker cp "${CONTAINER_ID}:/usr/local/bin/soul-demo" dist/soul-demo
|
||||
docker cp "${CONTAINER_ID}:/srv/soul/engram-demo/snapshot.json" dist/soul-demo-snapshot.json 2>/dev/null || true
|
||||
docker rm "${CONTAINER_ID}"
|
||||
|
||||
# Build minimal soul-demo container image
|
||||
cp dist/soul-demo-snapshot.json dist/engram-snapshot.json 2>/dev/null || true
|
||||
docker build \
|
||||
-f dist/Dockerfile.soul-demo \
|
||||
-t soul-demo:local \
|
||||
dist/
|
||||
|
||||
# Save as OCI tar for k3s to import at startup
|
||||
docker save soul-demo:local -o dist/soul-demo-image.tar
|
||||
echo "==> soul-demo:local image saved ($(du -sh dist/soul-demo-image.tar | cut -f1))"
|
||||
|
||||
echo "==> Done. marketing:${TAG} built."
|
||||
|
||||
Vendored
+13
@@ -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"]
|
||||
Vendored
+29
-15
@@ -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
|
||||
|
||||
Vendored
+90
@@ -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: 80
|
||||
Reference in New Issue
Block a user