Files
k8s-manifests/shortsmith/deployment.yaml
T

144 lines
5.2 KiB
YAML

---
apiVersion: v1
kind: Namespace
metadata:
name: shortsmith
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
annotations:
# Never let ArgoCD prune this PVC: it holds the job store and the rendered videos.
argocd.argoproj.io/sync-options: Prune=false
name: shortsmith-data
namespace: shortsmith
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: shortsmith
namespace: shortsmith
labels:
app: shortsmith
spec:
replicas: 1
# Single replica on a RWO local-path volume holding a SQLite job store in WAL mode:
# Recreate keeps two pods from opening /data/shortsmith.db during a roll. The queue
# is per-process anyway, so a second replica would not share work, only the file.
strategy:
type: Recreate
selector:
matchLabels:
app: shortsmith
template:
metadata:
labels:
app: shortsmith
spec:
containers:
- name: shortsmith
image: git.chemavx.xyz/chemavx/shortsmith:171dc544
imagePullPolicy: Always
ports:
- name: http
containerPort: 8080
env:
- name: SHORTSMITH_DATA_DIR
value: "/data"
volumeMounts:
- name: data
mountPath: /data
# Measured on chemavx-k8 under `systemd-run --scope -p CPUQuota=300%`,
# sampling the cgroup's memory.stat anon every 20 ms — the figure that
# cannot be reclaimed. Rendering is this service's normal mode, not a
# burst, so the request comes from the peak and not from the resting 22 MB.
#
# at rest (imports + FastAPI app) 22 MB
# frames, 3 workers, 1260 of them 147 MB
# audio synthesis and WAV 71 MB
# encode, -threads 3 480 MB <- the whole cost
# full render of examples/jal1628.json 522 MB, 32 s
# the same at the spec's 180 s ceiling 511 MB, 138 s
#
# The peak is the encode's and does not grow with duration: at 5400 frames
# anon is unchanged and only the page cache grows (64 -> 275 MB), which is
# reclaimable. That is why these are sized against anon and not against
# memory.current, which reaches 808 MB at the ceiling.
#
# 512Mi does survive the reference render, but only by evicting page cache
# to sit exactly on the cap with no margin. 640Mi covers the measured peak
# with ~20% headroom; the 1Gi limit lets the page cache stay cached instead
# of being re-read during the encode.
#
# The CPU limit is what sizes the worker pool, not the request — the code
# reads cpu.max, since cpu_count() reports the node's 16. At limits.cpu 3
# that is 3 workers, verified in a real cgroup (300%->3, 200%->2, 100%->1).
# 3 CPUs render in 32 s against 48 s at 2, for 22 MB less, so the third is
# worth more than the extra worker costs.
#
# Consequence, deliberate: under sustained contention the pod runs 3 workers
# on the 1 CPU it is guaranteed and a render takes about 3x longer. That is
# benign here — POST /render returns a job id, the queue runs at concurrency
# 1 and the caller polls, so a slow render is a later `done`, never a
# timeout. Do not "fix" it by sizing the pool from the request: that would
# trade an occasional slowdown for a permanent 3x on every render, including
# the ones on an idle node, which is the common case.
resources:
requests:
cpu: "1"
memory: "640Mi"
limits:
cpu: "3"
memory: "1Gi"
# The render runs off the event loop (asyncio.to_thread, and the frame
# workers are separate processes), so /healthz answers while a job is in
# flight. A probe timing out means the process is actually wedged.
readinessProbe:
httpGet:
path: /healthz
port: http
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /healthz
port: http
initialDelaySeconds: 15
periodSeconds: 30
failureThreshold: 3
volumes:
- name: data
persistentVolumeClaim:
claimName: shortsmith-data
imagePullSecrets:
- name: gitea-registry-infisical
---
apiVersion: v1
kind: Service
metadata:
# Must end in -svc. researchowl hit this: a Service named `searxng` collided with
# the SEARXNG_* env vars k8s injects into every pod in the namespace and returned
# 403s until it was renamed.
name: shortsmith-svc
namespace: shortsmith
spec:
selector:
app: shortsmith
ports:
- name: http
port: 8080
targetPort: http
# No Ingress on purpose: this is an internal API with no authentication, reached at
# shortsmith-svc.shortsmith.svc.cluster.local:8080 from inside the cluster. Ollama was
# exposed without auth once and had to be retrofitted with Authentik forward-auth.