Skip to content

Infra/106 advanced devops - #123

Merged
raphael-frank merged 6 commits into
mainfrom
infra/106-advanced-devops
Jul 9, 2026
Merged

Infra/106 advanced devops#123
raphael-frank merged 6 commits into
mainfrom
infra/106-advanced-devops

Conversation

@raphael-frank

@raphael-frank raphael-frank commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

This adds advanced devops steategies like horizontal pod scaling and autohealing.

Closes #106

Summary by CodeRabbit

  • New Features

    • Added per-service autoscaling support for several backend services, including CPU-based scaling limits.
    • Improved rollout behavior for select web services with safer rolling updates.
  • Bug Fixes

    • Prevented autoscaling from being overridden during deployments.
    • Added a short shutdown delay to help avoid dropped requests during pod termination.
  • Documentation

    • Expanded Helm and web client setup docs with autoscaling, mock data, and local development guidance.

api-docs was the only service without a health: path, so it fell back to
a TCP-only readiness probe with no liveness/startup probe at all -- a
hung-but-alive container never got restarted. swagger-ui serves an HTML
root, so / works the same way every other service's health check does.
Enables CPU-based autoscaling (min 1 / max 2) for all 9 app services --
metrics-server is already live on the cluster and every service already
declares resources.requests, so HPA is viable with no other prerequisites.
Postgres, Keycloak, Ollama and the monitoring stack keep their own
templates and stay fixed-replica; they're stateful/singleton and
shouldn't scale out.

deployment.yaml now omits spec.replicas for autoscaled services --
otherwise every helm upgrade (which runs on every push to main) would
reset it back to 1 and fight the HPA's own scaling decisions.

The namespace ResourceQuota is nearly fully committed already (verified
live: ~90%+ of both limits.cpu and limits.memory used just running one
replica of everything), so in practice most scale-up attempts will sit
Pending rather than actually schedule -- documented in the helm README
along with how to tell the difference between Pending-on-quota and
metrics-server not being reachable.
strategy: is now overridable per service (same pattern as resources:).
web-client and api-docs (80Mi/80m each) get maxSurge: 1 / maxUnavailable: 0
-- cheap enough to fit the namespace's remaining quota slack, so these two
get a genuine zero-downtime rolling deploy. Every other service keeps the
existing maxSurge: 0 default, since surging a second replica of any of
them would exceed the namespace's CPU quota and break the rollout.

Also adds a preStop sleep hook + explicit terminationGracePeriodSeconds
to every service's pod template, at no extra resource cost: it gives the
endpoints controller time to drain a pod out of Service routing before
SIGTERM, shrinking the request-drop window that maxSurge: 0 rollouts
otherwise have for the rest of the services (old pod is killed before
readiness on the new one even starts).
The frontend only ever saw mock data because .env.development.example
defaulted VITE_USE_MOCKS to true -- every deployed environment already
runs live (the var is never set in web-client/Dockerfile, in either
docker-compose build config, or in the CD workflow's build_args, and
.dockerignore excludes .env* from the build context entirely), so this
was purely a local pnpm dev default, not a deployment gap.

Verified end-to-end against a fresh docker compose stack: every feature
(organization, members, events, payments, letters, feedback, helper,
profile) renders real backend data through Traefik with zero console
errors. The mock path (VITE_USE_MOCKS=true, persona switching) still
works unchanged -- nothing in src/mocks/** touched.

Also documents a known limitation: pnpm dev's dev-proxy strips cookies
and never routes the initial page load through Traefik, so it can't
satisfy the forward-auth session cookie every backend route requires --
live-mode API calls from pnpm dev itself will fail. This doesn't affect
any real deployment (docker-compose/VM/Kubernetes all go through Traefik
end-to-end already); for local iteration against real data, browse the
docker-compose stack directly at http://localhost/ instead of pnpm dev.
@raphael-frank
raphael-frank requested a review from f-s-h July 9, 2026 08:58
@raphael-frank raphael-frank self-assigned this Jul 9, 2026
@raphael-frank raphael-frank added the infra Issue regarding the infrastructure or CICD pipeline label Jul 9, 2026
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@raphael-frank, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 32 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8414188b-b49e-4a55-b2dd-44e8275f405c

📥 Commits

Reviewing files that changed from the base of the PR and between 3df1b0c and 65afb65.

📒 Files selected for processing (1)
  • infra/helm/team-devoops/values.yaml
📝 Walkthrough

Walkthrough

This PR adds per-service Kubernetes HorizontalPodAutoscaler support via a new Helm template, updates the Deployment template to conditionally omit replicas under autoscaling and add a preStop lifecycle hook, configures autoscaling/strategy values for several services, documents these changes in the infra README, and updates web-client environment defaults and documentation for mock data usage.

Changes

Helm Autoscaling and Self-Healing

Layer / File(s) Summary
HPA template and Deployment autoscaling wiring
infra/helm/team-devoops/templates/hpa.yaml, infra/helm/team-devoops/templates/deployment.yaml
New per-service HorizontalPodAutoscaler template targets Deployments by name with CPU-based scaling; Deployment template conditionally omits replicas when autoscaling.enabled and adds a 5-second preStop sleep hook.
Per-service autoscaling and strategy values
infra/helm/team-devoops/values.yaml
Adds autoscaling blocks (min/max replicas, target CPU) to multiple services and RollingUpdate strategy overrides (maxSurge: 1, maxUnavailable: 0) for web-client and api-docs, plus a comment on per-service strategy overrides.
Autoscaling and self-healing documentation
infra/helm/README.md
Documents the new hpa.yaml template, autoscaling behavior, ResourceQuota caveats, and Kubernetes self-healing/rollback behavior.

Web-client Dev Environment and Mock Data Docs

Layer / File(s) Summary
Default env config for backend-first development
web-client/.env.development.example
Switches VITE_USE_MOCKS default to false and updates documentation on fixture usage and persona selection.
README updates for local dev and mock data
web-client/README.md
Updates local dev setup commands and Vite dev server URL, and adds a Mock data section covering VITE_USE_MOCKS, VITE_MOCK_PERSONA, and a forward-auth known limitation.

Estimated code review effort: 2 (Simple) | ~12 minutes

Suggested labels: enhancement

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The web-client .env and README updates are unrelated to the devops objectives and appear to be extra scope. Split the web-client docs/env changes into a separate PR unless they are required for the linked issue and can be justified there.
Title check ❓ Inconclusive The title is related to the PR, but it's generic and doesn't clearly describe the autoscaling/self-healing changes. Rename it to mention the main change, e.g. 'Add HPA, probes, and rolling update improvements for team-devoops.'
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed The PR covers the requested autoscaling, self-healing, and advanced deployment strategy work with HPAs, probes, and rollout tuning.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch infra/106-advanced-devops

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
infra/helm/team-devoops/templates/hpa.yaml (1)

16-22: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider adding a behavior block for scale-down stabilization.

The HPA template omits the optional behavior field, so Kubernetes defaults apply (300s scale-down stabilization, 0s scale-up). This is acceptable for maxReplicas: 2, but explicitly defining a behavior block makes the scaling policy self-documenting and prevents surprises if cluster defaults change.

♻️ Optional: add behavior block
   minReplicas: {{ $svc.autoscaling.minReplicas }}
   maxReplicas: {{ $svc.autoscaling.maxReplicas }}
+  behavior:
+    scaleDown:
+      stabilizationWindowSeconds: 300
+      policies:
+        - type: Percent
+          value: 100
+          periodSeconds: 15
+    scaleUp:
+      stabilizationWindowSeconds: 0
+      policies:
+        - type: Percent
+          value: 100
+          periodSeconds: 15
   metrics:
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@infra/helm/team-devoops/templates/hpa.yaml` around lines 16 - 22, The HPA
template in the autoscaling manifest is missing an explicit behavior policy, so
add a `behavior` block to the same template that renders the `metrics` section
and `targetCPUUtilizationPercentage`. Keep the existing scaling logic intact,
and define scale-down stabilization (and any scale-up policy you want to
preserve) directly in the HPA spec so the behavior is explicit and stable if
cluster defaults change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@infra/helm/team-devoops/values.yaml`:
- Around line 399-403: The py-genai-helper autoscaling settings conflict with
its RWO persistence, since the service’s PVC is only safe with a single replica.
Update the autoscaling block for this service in values.yaml so it cannot scale
beyond one pod, or disable autoscaling entirely if that is the intended
behavior. Keep the fix aligned with the existing persistence configuration
around the py-genai-helper service and its autoscaling.enabled/maxReplicas
settings.

---

Nitpick comments:
In `@infra/helm/team-devoops/templates/hpa.yaml`:
- Around line 16-22: The HPA template in the autoscaling manifest is missing an
explicit behavior policy, so add a `behavior` block to the same template that
renders the `metrics` section and `targetCPUUtilizationPercentage`. Keep the
existing scaling logic intact, and define scale-down stabilization (and any
scale-up policy you want to preserve) directly in the HPA spec so the behavior
is explicit and stable if cluster defaults change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 10f326c4-000d-4709-a145-887f2db6cdc2

📥 Commits

Reviewing files that changed from the base of the PR and between 9d23abe and 3df1b0c.

📒 Files selected for processing (6)
  • infra/helm/README.md
  • infra/helm/team-devoops/templates/deployment.yaml
  • infra/helm/team-devoops/templates/hpa.yaml
  • infra/helm/team-devoops/values.yaml
  • web-client/.env.development.example
  • web-client/README.md

Comment thread infra/helm/team-devoops/values.yaml Outdated
Its vector-store PVC is ReadWriteOnce (see the persistence block just
below), which can only mount to one node at a time -- the chart's own
service catalogue doc already says persistence is "only safe with a
single replica." A second HPA-spawned replica wouldn't fail cleanly, it'd
sit stuck on a Multi-Attach error indefinitely. Dropping the autoscaling
block entirely rather than pinning maxReplicas: 1, since a min=max=1 HPA
is a no-op object with nothing to show for it -- this service now joins
Postgres/Keycloak/Ollama/monitoring as intentionally not autoscaled.

Found via CodeRabbit review.
The manual CD run on 3df1b0c failed: api-docs' new pod's startup probe
got a 404 on GET / and was killed/restarted in a loop until
progressDeadlineSeconds, so helm --rollback-on-failure reverted the
release. Confirmed live via kubectl describe rs (Warning Unhealthy:
"HTTP probe failed with statuscode: 404") and a port-forward straight
to the pod: GET / -> 404, GET /docs/ -> 200.

Root cause: api/Dockerfile bakes BASE_URL=/docs into the image, so
swagger-ui serves its UI under /docs, not root -- I assumed root when
adding this service's health path in df9ddb4. The namespace's tight
ResourceQuota was a red herring here; this pod scheduled, pulled, and
started fine, it just never passed its own health check.
@raphael-frank

Copy link
Copy Markdown
Collaborator Author

CD runs through without problems now.

@f-s-h f-s-h left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

lgtm

@raphael-frank
raphael-frank merged commit bc356ac into main Jul 9, 2026
29 checks passed
@raphael-frank
raphael-frank deleted the infra/106-advanced-devops branch July 9, 2026 15:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

infra Issue regarding the infrastructure or CICD pipeline

Projects

None yet

Development

Successfully merging this pull request may close these issues.

infra: advanced devops

2 participants