Files
soleprint/rig/sample-rig/rig-ui/k8s.yaml
2026-08-20 11:24:42 -03:00

109 lines
4.0 KiB
YAML

# How to plug the UI into whatever k8s you generated. THIS IS THE WHOLE THING:
# one Pod running the vite app, one Service to reach it.
#
# Optional by design. The UI complements a rig; it is not part of the end
# product, and a rig is complete and useful without it. Apply this only when you
# want the listing:
#
# kubectl apply -n <your-namespace> -f rig-ui/k8s.yaml
#
# A bare Pod, not a Deployment — this is a dev-loop convenience, not a workload
# to keep alive. If it dies you re-apply it; nothing depends on it staying up.
#
# The app and bundle.json arrive as a ConfigMap named `rig-ui`, which
# ctrl/manifest.py generates from the folder. Nothing is baked into an image, so
# editing bundle.json and re-applying is the whole update cycle.
apiVersion: v1
kind: Pod
metadata:
name: rig-ui
labels:
app: rig-ui
spec:
containers:
- name: vite
image: node:22-alpine
workingDir: /app
# npm install at start: no image to build and no registry to publish to,
# which is the point of a minimal plug-in. It needs egress to a registry —
# on a locked-down cluster point npm at the internal one, or bake an image
# instead. Nothing else here changes if you do.
command: ["sh", "-c"]
# A ConfigMap mounts flat (keys cannot contain '/'), so the files are
# placed into vite's expected layout here. bundle.json goes to public/
# because that is what vite serves at /bundle.json, which is where the
# app fetches it.
args:
- |
mkdir -p /app/src /app/public &&
cp /src/package.json /src/vite.config.js /src/index.html /app/ &&
cp /src/main.js /src/style.css /app/src/ &&
cp /src/bundle.json /app/public/ &&
npm install --no-audit --no-fund &&
npm run dev
env:
# Rendered in the heading so two rigs sharing a cluster stay
# distinguishable. Set from the namespace by ctrl/manifest.py.
- name: VITE_RIG_NAME
value: __RIG_NAME__
ports:
- name: http
containerPort: 5173
volumeMounts:
# /src is read-only from the ConfigMap; the app is copied to a writable
# /app because npm install has to create node_modules.
- name: rig-ui
mountPath: /src
- name: app
mountPath: /app
readinessProbe:
httpGet: { path: /, port: 5173 }
# npm install decides how long this takes, and it is the slow part.
initialDelaySeconds: 15
periodSeconds: 5
failureThreshold: 30
resources:
requests: { memory: 128Mi, cpu: 50m }
limits: { memory: 512Mi }
volumes:
- name: rig-ui
configMap:
name: rig-ui
- name: app
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: rig-ui
labels:
app: rig-ui
# No annotations, deliberately — see k8s/app.yaml. The target is EKS but this
# stays VPC-agnostic: no subnets, no security groups, no -scheme, no -type.
# A bare LoadBalancer is what lets one manifest work on kind and on EKS.
spec:
type: LoadBalancer
selector:
app: rig-ui
ports:
- name: http
port: 80
targetPort: 5173
protocol: TCP
# Pinned, because a LoadBalancer Service also allocates a NodePort and
# this is the only address that works everywhere.
#
# On WSL the MetalLB address is on a docker bridge INSIDE the Linux VM,
# and Windows has no route to it — the page looks broken while the
# cluster is perfectly healthy. 30080 is what rig's `hostport` ingress
# mode publishes to the host, so this is reachable at
# localhost:$HTTP_PORT from a Windows browser with nothing configured.
#
# Costs nothing elsewhere: MetalLB still assigns an external IP on Linux,
# and on EKS the load balancer targets this NodePort anyway. One Service,
# no per-environment branch.
#
# A pinned NodePort is cluster-unique, so two rigs must live in separate
# clusters — which is how they are run anyway.
nodePort: 30080