109 lines
4.0 KiB
YAML
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
|