Skip to content

feat(k8s): migrate pipelines to prod EKS as a private service - #31

Merged
sumit-badsara merged 3 commits into
mainfrom
feat/eks-migration
Jul 13, 2026
Merged

feat(k8s): migrate pipelines to prod EKS as a private service#31
sumit-badsara merged 3 commits into
mainfrom
feat/eks-migration

Conversation

@sumit-badsara

@sumit-badsara sumit-badsara commented Jul 10, 2026

Copy link
Copy Markdown

Migrates the Open WebUI Pipelines filter service off Porter onto the self-managed prod EKS cluster (hub-and-spoke ArgoCD), mirroring the skillshield backend pattern.

Private by design

Pipelines is called only in-cluster by ai-gateway / ai-gateway-data at /v1/perform_filters, and it is an arbitrary-code plugin runtime — so it deploys PRIVATE: ClusterIP service, no ingress, no DNS.

What's here

  • k8s/chart/ — Deployment + Service (ClusterIP:8080, targetPort http) + HPA (min1/max2, CPU/mem 75) + ExternalSecret (ESO prod/pipelines<release>-secrets, injected via envFrom). Ingress template kept but gated enabled: false.
    • Stateless — no DB/redis/migrations, so no migrate Job (unlike skillshield).
    • Probes hit GET / (get_status → unauthenticated 200 {"status": true}); generous startup window for cold model load.
    • PIPELINES_API_KEY comes from Secrets Manager, never the app's insecure 0p3n-w3bu! default.
    • image: …/k8s/pipelines:prod, pullPolicy: Always; strategy: RollingUpdate maxSurge 1 maxUnavailable 0; revisionHistoryLimit: 3.
  • k8s/prod/values.yaml — prod overlay (tag prod, ingress disabled, prod/pipelines, autoscaling min1/max2, env PORT/HOST/PIPELINES_DIR).
  • .github/workflows/deploy-eks.yml — SHA-pinned actions. PR = build-only; push main = push :sha only; dispatch = advance :prod + rollout (fail-fast). Migrate step removed (stateless).
  • .github/workflows/chart-validate.yml — helm lint + template on k8s/**.

Notable deltas from the existing chart

  • ExternalSecret target renamed <release>-env<release>-secrets (skillshield/envFrom convention).
  • Dropped the securityContext (mirrors skillshield; the image runs as root and writes to PIPELINES_DIR at runtime — non-root uid 1000 would break pip installs / plugin writes).
  • Dropped the unused configMap template and the hardcoded DD_AGENT_HOST env (neither in skillshield; pipelines ships no gateway plugin config).

Validation

  • helm lint k8s/chart -f k8s/prod/values.yaml
  • helm template pipelines-prod k8s/chart -f k8s/prod/values.yaml → Deployment, Service (ClusterIP:8080), ExternalSecret, HPA (min1/max2); no Ingress
  • Workflows parse as valid YAML ✅

Companion unbound-infra PR wires ArgoCD + the repo secret + OIDC trust. The gateway keeps calling Porter pipelines until the later cutover.

🤖 Generated with Claude Code


Note

Medium Risk
Privileged CI (OIDC → ECR/EKS) and dispatch-only :prod tagging affect prod rollout; chart changes harden secrets and network exposure but the workload remains a root plugin runtime executing arbitrary code.

Overview
Adds prod EKS packaging for Pipelines (private ClusterIP, ArgoCD-managed manifests) plus CI that separates image build from prod rollout.

Helm chart is reshaped for the skillshield-style deploy: drops ConfigMap/DD_AGENT_HOST, renames ExternalSecret output to <release>-secrets, switches ESO from dataFrom extract to pinned secretKeys (so missing PIPELINES_API_KEY fails sync instead of falling back to the app default), moves non-secret config into env, and uses values-driven seccomp/cap-drop hardening without runAsNonRoot. Adds k8s/prod/values.yaml (tag :prod, prod/pipelines, ingress off, HPA 1–2); dev overlay scales to 0 with HPA off.

.github/workflows/deploy-eks.yml builds/pushes immutable :sha on main; :prod advances only on workflow_dispatch (then rollout restart with 15m fail-fast). .github/workflows/chart-validate.yml runs helm lint + helm template on k8s/** so chart-only changes still get CI. k8s/README.md documents private in-cluster cutover prerequisites.

Reviewed by Cursor Bugbot for commit 0fed160. Bugbot is set up for automated code reviews on this repo. Configure here.

Greptile Summary

This PR moves the Pipelines service onto the private prod EKS path. The main changes are:

  • Adds Helm chart validation for Kubernetes changes.
  • Adds an EKS build and deploy workflow with ECR image promotion.
  • Updates the Helm chart for a private ClusterIP service with ExternalSecret-backed configuration.
  • Adds prod and dev values for the new deployment shape.
  • Documents EKS prerequisites, soak checks, and gateway cutover.

Confidence Score: 5/5

This looks safe to merge.

  • No blocking issues found in the changed code.

Important Files Changed

Filename Overview
.github/workflows/chart-validate.yml Adds Helm lint and template checks for Kubernetes chart changes.
.github/workflows/deploy-eks.yml Adds the EKS image build, ECR promotion, and rollout workflow.
k8s/chart/templates/deployment.yaml Updates the Deployment for secret injection, image validation, probes, and container hardening.
k8s/chart/templates/external-secret.yaml Renames the generated secret and pins the required secret property.
k8s/chart/values.yaml Sets the base chart defaults for image, ExternalSecret, env, autoscaling, probes, and hardening.
k8s/prod/values.yaml Adds the production values for the private Pipelines service.
k8s/dev/values.yaml Keeps dev scaled down while configuring the dev secret source.

Reviews (3): Last reviewed commit: "fix(chart,ci): round 2 review — enforce ..." | Re-trigger Greptile

Context used:

  • Rule used - Ensure that the confidence score is always within ... (source)

Learned From
websentry-ai/ai-gateway-data#448

Deploy the Open WebUI Pipelines filter service onto the self-managed prod
EKS cluster (hub-and-spoke ArgoCD), mirroring the skillshield backend
pattern. Pipelines is called only in-cluster by ai-gateway /
ai-gateway-data at /v1/perform_filters, so it deploys PRIVATE: ClusterIP
service, no ingress, no DNS. It is an arbitrary-code plugin runtime, so
private is required.

Chart (k8s/chart): Deployment + Service (ClusterIP:8080) + HPA (min1/max2)
+ ExternalSecret (ESO, prod/pipelines -> {{ .Release.Name }}-secrets via
envFrom). No migrate Job (stateless — no DB/redis/migrations). No
securityContext (mirrors skillshield; the image runs as root and writes to
PIPELINES_DIR at runtime). Probes hit GET / (get_status -> unauthenticated
200), with a generous startup window for cold model load. PIPELINES_API_KEY
comes from Secrets Manager, never the app's insecure default.

prod overlay (k8s/prod/values.yaml): image :prod, ingress disabled,
externalSecret prod/pipelines, autoscaling min1/max2.

CI: deploy-eks.yml (SHA-pinned actions; PR=build-only, push main=push :sha,
dispatch=advance :prod + rollout with fail-fast; no migrate step) and
chart-validate.yml (helm lint + template on k8s/** changes).

Removed the unused configMap template (skillshield has none; pipelines ships
no gateway plugin config). Left dev/staging overlays untouched. The gateway
keeps calling Porter pipelines until the later cutover.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread k8s/chart/templates/deployment.yaml
Comment thread k8s/chart/templates/external-secret.yaml Outdated
Comment thread k8s/chart/templates/deployment.yaml
Comment thread k8s/chart/templates/deployment.yaml Outdated
Comment thread .github/workflows/deploy-eks.yml
Comment thread .github/workflows/deploy-eks.yml Outdated
Comment thread k8s/chart/templates/deployment.yaml
Comment thread k8s/chart/values.yaml
Comment thread .github/workflows/deploy-eks.yml Outdated
Comment thread .github/workflows/deploy-eks.yml Outdated
…imeouts

- Container securityContext: drop ALL caps + allowPrivilegeEscalation:false +
  seccomp RuntimeDefault (NOT runAsNonRoot — image runs as root and writes
  PIPELINES_DIR). Restores hardening for the plugin-execution service
  (greptile + cursor HIGH).
- externalSecret.enabled defaults TRUE — pod always gets PIPELINES_API_KEY from
  SM, never the 0p3n-w3bu! fallback (greptile). `required` guard on remoteKey
  (greptile "empty key renders") and on image.repository (greptile "empty image").
- id-token:write scoped to the build-and-deploy job, not workflow-global — PR
  runs / the resolve job never receive it (cursor HIGH: PR-branch cred theft).
- dev overlay autoscaling.enabled=false so the held-off dev (PR #30, replicas 0)
  doesn't get scaled back up by the now-default HPA (cursor).
- rollout status timeout 10m->15m and job timeout 30->60m for the heavy
  torch/transformers image + ML cold starts (cursor x2).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread k8s/chart/values.yaml
Comment thread .github/workflows/deploy-eks.yml

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit ee59818. Configure here.

Comment thread k8s/dev/values.yaml
Comment thread k8s/chart/values.yaml

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Comment thread .github/workflows/deploy-eks.yml Outdated
…leak

- ExternalSecret uses an explicit `data` mapping keyed on secretKeys
  ([PIPELINES_API_KEY]) via remoteRef.property, so a missing key FAILS the ESO
  sync (pod won't start) instead of silently letting the app use its
  0p3n-w3bu! default (cursor HIGH).
- dev overlay adds replicaCount: 0 (not just HPA off) so the held-off env stays
  at zero pods (cursor).
- rollout-failure diagnostics no longer stream pod logs into the Actions log —
  this service handles LLM/guardrail content that may be sensitive; describe +
  events + pod status suffice (cursor MEDIUM). Also corrected the 10m->15m text.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@sumit-badsara
sumit-badsara merged commit f7aea7a into main Jul 13, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants