feat(k8s): Kubernetes manifests for the three runtimes - #25
Merged
Conversation
Deployments for api, scheduler and worker, plus Service, Ingress, migration Job, ConfigMap and a documented secret example. The worker Deployment declares no replicas: a KEDA ScaledObject scales it on BullMQ queue depth, which is the signal that actually tracks its load. CPU does not, because the worker blocks on network I/O against slow feeds while the backlog grows. Liveness probes never touch Postgres or Redis, so a dependency outage removes pods from the Service instead of restarting them against a broken dependency. Refs #17, #18, #19, #20
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
5 tasks
Two jobs: kubeconform over both overlays, then an end-to-end run that builds the image, applies the CI overlay to a kind cluster and drives it until the three runtimes are ready, migrations have completed and both probes answer. Also fixes the KEDA trigger address. It resolved Redis through addressFromEnv: REDIS_ADDRESS, but the worker exposes REDIS_URL (a full URL) rather than a host:port pair, so the scaler would never have connected. Refs #19, #22
The overlay disabled ENABLE_AUTH, which env.schema.ts rejects outright under NODE_ENV=production: disabling auth resolves every request to the shared legacy tenant. The guard was right and the overlay was wrong. Switches AUTH_PROVIDER to api_key so no Clerk credentials are needed, and seeds BOOTSTRAP_API_KEY for the migration to install.
The connection is opened by the KEDA operator, which runs in the keda namespace. Short service names only resolve within the caller's own namespace, so 'redis:6379' failed with 'server misbehaving' and the HPA was never created. Found by the kind end-to-end job.
Replaces the 'never applied to a cluster' caveat with the CI that now applies them, and records the two bugs the end-to-end job caught.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds
k8s/with the manifests to run FeedPulse's three runtimes on Kubernetes, and the CI that proves they work.What is here
k8s/base— Deployments forapi,schedulerandworker, plus Service, PDB, Ingress, migration Job, ConfigMap and a documented (non-applied) secret examplek8s/overlays/ci— Postgres, Redis and CI-only secrets, so the manifests can be exercised end to endk8s/keda— ScaledObject autoscaling the worker on BullMQ queue depthk8s/monitoring— ServiceMonitor and PodMonitor for kube-prometheus-stack.github/workflows/k8s.yml— schema validation + a real kind clusterk8s/README.md— the decisions and their reasoningVerified, not asserted
Both jobs are green. The end-to-end job builds the image, side-loads it into kind, applies the overlay, runs migrations, waits for all three runtimes, curls
/healthand/ready, restarts the worker to exercise graceful shutdown, then installs KEDA and waits for the ScaledObject to reportReady=True— which is what proves the HPA was actually created rather than merely accepted by the webhook.Two bugs CI caught that review would not have
The KEDA Redis address was wrong twice. First
addressFromEnv: REDIS_ADDRESS, but the worker exposesREDIS_URL— a URL, nothost:port. Then the short nameredis:6379, which fails withserver misbehaving: the connection is opened by the KEDA operator in thekedanamespace, and short service names only resolve within the caller's own namespace.The CI overlay disabled
ENABLE_AUTH.env.schema.tsrejects that underNODE_ENV=productionbecause it resolves every request to the shared legacy tenant. The guard was right, the overlay was wrong. CI now runs with auth on, as production does.Decisions worth reviewing
Scheduler is a Deployment, not a CronJob. It owns its own loop via
SCHEDULER_TICK_MS(default 15s) and holds warm connections.strategy: Recreateso two never tick at once.Liveness never touches a dependency.
/healthis process-only,/readyresolves the base schema. A dependency check in liveness turns a Postgres blip into a cluster-wide CrashLoopBackOff.Worker declares no
replicas— KEDA owns that field.terminationGracePeriodSeconds(60s) exceedsSHUTDOWN_TIMEOUT_MS(30s) so in-flight jobs drain instead of being SIGKILLed.Known limitations, stated rather than hidden
Refs #17, #18, #19, #20, #22