Skip to content

fix(snapshot-controller): add startupProbe as defense-in-depth against slow HTTPS bind on snapshot-validation-webhook - #3204

Closed
IvanHunters wants to merge 4 commits into
mainfrom
fix/snapshot-validation-webhook-startup-probe
Closed

IvanHunters wants to merge 4 commits into
mainfrom
fix/snapshot-validation-webhook-startup-probe

Conversation

@IvanHunters

@IvanHunters IvanHunters commented Jul 4, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Refs #3203 (partial hardening — see Scope below).

Carries a cozystack-standard vendored-chart patch on piraeus-charts/snapshot-controller v3.0.5 that adds a startupProbe to the snapshot-validation-webhook Deployment. The upstream chart hard-codes the liveness / readiness probes without any startup grace and does not expose them via values.yaml, so under one specific pathway of the failure documented in #3203 — the webhook binary is Started but has not yet bound :8443 — the kubelet's default liveness (periodSeconds=10 failureThreshold=3 ≈ 30s) kills the container before it can serve. startupProbe widens that specific window.

Scope

This PR is defense-in-depth for one subset of the failure documented in #3203. It is not a root-cause fix.

  • What this covers. The narrow window where the container is Started, the mounted tls-config volume has a usable cert, but the binary has not yet bound :8443. Without a startupProbe, the kubelet's default liveness kills the container inside ~30s. With this patch, that window widens to ~225 seconds (periodSeconds: 5 × failureThreshold: 45).
  • What this does NOT cover.
  • HR install-timeout interaction. The operator's default HR install timeout (--helmrelease-install-timeout in cmd/cozystack-operator/main.go) is 10 minutes and has no per-component override. If cert-manager takes ~8 minutes to issue the Certificate (the observed worst case), only ~2 minutes remain within the HR install window even before this probe budget begins to count. On that trajectory no probe fixes the failure. This PR does not change the HR timeout; addressing it is a separate change.

Given the above, this PR is intentionally scoped as Refs #3203, not Fixes. The tracking issue stays open until the pre-Started cert-manager path and the post-Started self-exit path are both addressed.

Why startupProbe (in the window it actually governs)

Bumping initialDelaySeconds on the existing livenessProbe would need to be sized for worst-case tail latency, which produces a fragile value that either misses the tail or delays failure detection in the healthy case. startupProbe is the k8s-native pattern for "container has a slow but bounded startup, don't hand over to liveness until it's up" — once it passes, the kubelet transitions to the normal livenessProbe and readinessProbe at their default cadence and steady-state health-checking is unchanged.

Chosen values periodSeconds: 5 × failureThreshold: 45 = 225s:

  • Comfortably clears the actual bind time on a loaded sandbox once the binary is Started (single-digit-second range in the healthy case, tens of seconds under contention).
  • Stays well inside the operator's 10-minute HR install timeout so the probe budget does not race the outer wait. A larger probe budget would encroach on that limit.

Files touched

  • packages/system/snapshot-controller/charts/snapshot-controller/templates/deployment_validation_webhook.yaml — add startupProbe block. Comment inline documents the scope boundary above.
  • packages/system/snapshot-controller/patches/webhook-startup-probe.diff — new file (first patch on this package). Byte-consistent with the vendored tree: verified by re-applying against a fresh helm pull piraeus-charts/snapshot-controller --version 3.0.5 and running diff -qr (empty output).
  • packages/system/snapshot-controller/Makefile — add test: target so the new unit tests run in CI (mirrors vpa/Makefile, harbor/Makefile), pin --version 3.0.5 on helm pull (an unpinned pull would grab latest and the templates layout changed between v3.x and v5.x), and re-apply patches/webhook-startup-probe.diff after the pull so a future upstream bump does not silently revert the fix.
  • packages/system/snapshot-controller/tests/webhook_startup_probe_test.yaml — new file (first helm-unittest on this package). Asserts startupProbe shape (endpoint, port, scheme, periodSeconds, failureThreshold) and that livenessProbe / readinessProbe still render on the same HTTPS /readyz endpoint. Guards against an upstream refactor renaming or replacing the Deployment silently dropping the fix.

Testing

  • make -C packages/system/snapshot-controller test — 2/2 unit tests pass.
  • helm template test packages/system/snapshot-controller/charts/snapshot-controller — renders the startupProbe as expected.
  • make update idempotency — re-pulling upstream v3.0.5 and re-applying patches/webhook-startup-probe.diff produces a chart tree byte-identical to what is committed.

Release note

fix(snapshot-controller): add a `startupProbe` to the snapshot-validation-webhook Deployment so the container gets a wider grace before liveness kicks in when its HTTPS listener is slow to bind. Defense-in-depth against one class of E2E install flake; the cert-manager Certificate issuance latency and any post-`Started` self-exit paths are tracked separately in #3203.

…hook so cert-manager latency does not cascade

Fixes #3203. On E2E-sandbox first-install cert-manager takes several
minutes to issue the webhook Certificate whose Secret the pod mounts as
tls-config. During that window the pod cannot bind its HTTPS listener
on :8443. The upstream `piraeus-charts/snapshot-controller` v3.0.5
Deployment hard-codes livenessProbe / readinessProbe without any
initialDelaySeconds or startupProbe and does not expose them through
`values.yaml`, so the kubelet defaults (periodSeconds=10,
failureThreshold=3) give the pod ~30 seconds to become healthy before
liveness kicks in and CrashLoopBackOff-s it. Deployment marked Failed
by helm-controller, the HR cascades DependencyNotReady through piraeus
-operator-crds, piraeus-operator, linstor, linstor-scheduler and
~20 downstream operators (postgres-operator, mariadb-operator,
mongodb-operator, opensearch-operator, redis-operator, rabbitmq-operator,
metallb, multus, metrics-server, monitoring-agents, application-
definition-crd, etc.), and the outer 15m install-wait times out.

Fix: patch the vendored chart to add a startupProbe with
periodSeconds=10 / failureThreshold=60 (≈10 minute startup budget) on
the same HTTPS /readyz endpoint. Once startupProbe passes the kubelet
transitions to the normal liveness/readiness at their default cadence,
so steady-state health-checking is unchanged.

startupProbe is chosen over `initialDelaySeconds` on livenessProbe
because the latter would have to be sized for worst-case cert-manager
latency (multiple minutes under load), producing a fragile value that
either misses the tail or delays failure detection in the healthy case.
The failing E2E run observed the certwatcher log line 8m 18s after
pod start; the 10-minute startupProbe budget covers that with headroom.

Delivered as a cozystack-standard vendored-chart patch:
`packages/system/snapshot-controller/patches/webhook-startup-probe.diff`
is byte-consistent with the vendored tree (verified by re-applying
against a fresh `helm pull` and diffing) and the package's Makefile
`update:` target re-applies it after `helm pull` so an upstream chart
bump does not silently revert the fix. This is the first patch on this
package, so the patches/ directory and Makefile step are new.

Also adds a helm-unittest test at
`packages/system/snapshot-controller/tests/webhook_startup_probe_test.yaml`
pinning the startupProbe shape (endpoint, port, scheme, periodSeconds,
failureThreshold) — first helm-unittest on this package. Guards against
an upstream refactor renaming or replacing the Deployment silently
dropping the fix.

Upstream follow-up: `piraeusdatastore/helm-charts` should expose the
probes through values.yaml or set a startupProbe upstream, at which
point this patch can be retired.

Signed-off-by: Ivan Okhotnikov <[email protected]>
@coderabbitai

coderabbitai Bot commented Jul 4, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a startupProbe (HTTPS /readyz, periodSeconds: 5, failureThreshold: 45) to the snapshot-controller webhook deployment template, captures it as a vendoring patch pinned to chart version 3.0.5, updates the Makefile to pin and reapply the patch with a new test target, and adds helm unittest coverage.

Changes

Webhook startup probe fix

Layer / File(s) Summary
Webhook deployment startupProbe
packages/system/snapshot-controller/charts/snapshot-controller/templates/deployment_validation_webhook.yaml
Adds an HTTPS /readyz startupProbe (periodSeconds: 5, failureThreshold: 45) with explanatory comments to tolerate slow binary startup before liveness/readiness checks apply.
Vendoring patch and Makefile pinning
packages/system/snapshot-controller/patches/webhook-startup-probe.diff, packages/system/snapshot-controller/Makefile
Records the probe change as a diff patch, pins the vendored chart pull to version 3.0.5, applies the patch after pulling, and adds a test target running helm unittest ..
Unit tests for probe behavior
packages/system/snapshot-controller/tests/webhook_startup_probe_test.yaml
Adds assertions confirming the new startupProbe values and that existing liveness/readiness probes remain unchanged.

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

Suggested labels: kind/regression, area/storage, area/testing

Suggested reviewers: lllamnyp, kvaps, androndo, sircthulhu

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The patch adds the requested startupProbe and preserves it through the vendored-chart patch workflow, matching issue #3203's startup protection goal.
Out of Scope Changes check ✅ Passed All changes support the webhook-startup fix, test coverage, and patch preservation; no unrelated functionality was introduced.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding a startupProbe to the snapshot-controller webhook to tolerate slow HTTPS startup.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/snapshot-validation-webhook-startup-probe

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.

@github-actions github-actions Bot added area/uncategorized PR auto-labeler could not map title scope to a known area/*; please review kind/bug Categorizes issue or PR as related to a bug size/M This PR changes 30-99 lines, ignoring generated files labels Jul 4, 2026
…rget, pinned upstream, tighter budget

Self-review on 6366c8a caught four issues that would have shipped
otherwise:

1. `make test` target was missing so `hack/helm-unit-tests.sh` (which
   greps for `test:` in each package's Makefile via `make -n test`)
   would silently SKIP the new unittest suite in CI. Add `test:` target
   mirroring the pattern used in vpa/harbor/monitoring so an upstream
   refactor that drops the startupProbe is caught by the required
   `Unit & controller tests` job.
2. `helm pull piraeus-charts/snapshot-controller` was unpinned so
   `make update` would silently grab whatever is `latest` on the
   piraeus-charts repo (currently v5.1.1) instead of the vendored
   v3.0.5. The v3.x → v5.x refactor renames `deployment_validation
   _webhook.yaml`, so the very first `make update` after this patch
   lands would break itself. Pin `--version 3.0.5` (mirrors
   vpa/Makefile `--version 11.1.1`); bumping the pin becomes a
   deliberate step that must regenerate the patch against the new
   upstream.
3. startupProbe budget was 10m (`periodSeconds=10 failureThreshold=60`)
   which races the operator's default 10m HR install timeout
   (`--helmrelease-install-timeout` in `cmd/cozystack-operator/main.go`).
   Tightened to `periodSeconds=5 failureThreshold=45 = 225s`. That is
   more than enough for the actual container-bind window observed in
   #3203 (single-digit-seconds once the tls-config Secret is mounted)
   and leaves > 7 minutes of headroom for the cert-manager Certificate
   issuance phase to complete inside the HR timeout.
4. Docstring on the patched template overstated the fix — startupProbe
   covers the "container Started, still binding :8443" window but does
   NOT cover a separate class where the container self-exits (e.g.
   empty tls-config from a cert-mount race). Made the comment honest
   about that boundary and pointed the follow-up (initContainer
   waiting on non-empty tls.crt/tls.key) back at #3203.

Tests tightened accordingly: exact `periodSeconds=5 failureThreshold=45`
pinned as regression sentinels, and liveness / readiness assertions
extended to also cover `httpGet.port` and `httpGet.scheme` so an
upstream refactor swapping to an int port or renaming the scheme is
caught before it silently rerouted the probe.

Regenerated `patches/webhook-startup-probe.diff` against the pinned
v3.0.5 upstream; re-applying it against a fresh `helm pull ... --version
3.0.5` produces a byte-identical tree.

Signed-off-by: Ivan Okhotnikov <[email protected]>
@github-actions github-actions Bot added size/L This PR changes 100-499 lines, ignoring generated files and removed size/M This PR changes 30-99 lines, ignoring generated files labels Jul 4, 2026
Cozystack-wide style rule bans em dashes as punctuation. Replace with
periods, colons, or shortened phrasing so the resulting sentences read
naturally rather than as comma splices.

Signed-off-by: Ivan Okhotnikov <[email protected]>
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a stability issue where the snapshot-validation-webhook pod enters a CrashLoopBackOff due to slow certificate issuance under load. By implementing a Kubernetes startupProbe, the pod is given sufficient time to initialize before liveness checks begin, preventing cascading installation failures. The changes include a persistent patch mechanism and automated unit tests to ensure long-term maintainability.

Highlights

  • Added startupProbe: Introduced a startupProbe to the snapshot-validation-webhook Deployment to prevent liveness probe failures during slow TLS certificate issuance.
  • Automated Patch Management: Updated the Makefile to pin the vendored chart version and automatically re-apply the startup probe patch during updates.
  • Regression Testing: Added helm-unittest coverage to ensure the startupProbe configuration remains consistent across future upstream chart updates.
New Features

🧠 You can now enable Memory (public preview) to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Ignored Files
  • Ignored by pattern: **/*.diff (1)
    • packages/system/snapshot-controller/patches/webhook-startup-probe.diff
  • Ignored by pattern: **/charts/** (1)
    • packages/system/snapshot-controller/charts/snapshot-controller/templates/deployment_validation_webhook.yaml
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment Gemini (@gemini-code-assist) Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on Gemini (@gemini-code-assist) comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request pins the vendored snapshot-controller Helm chart to version 3.0.5, automates the application of the local startup probe patch in the Makefile, and introduces a Helm unit test suite to verify the webhook's startup, liveness, and readiness probes. The feedback suggests updating the unit test assertions to match a corrected 10-minute startup probe budget.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +30 to +41
# Budget = periodSeconds * failureThreshold. Pinning both exact values
# locks the total (5 * 45 = 225s) as a regression sentinel: a chart
# bump that silently zeroed one of them would still fall out here.
# Bumping the budget deliberately requires a matching test update; the
# comment on the patched template covers why it must stay inside the
# operator's 10m HR install timeout.
- equal:
path: spec.template.spec.containers[0].startupProbe.periodSeconds
value: 5
- equal:
path: spec.template.spec.containers[0].startupProbe.failureThreshold
value: 45

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

Update the unit test assertions to match the corrected 10-minute startupProbe budget (periodSeconds: 10 and failureThreshold: 60).

      # Budget = periodSeconds * failureThreshold. Pinning both exact values
      # locks the total (10 * 60 = 600s) as a regression sentinel: a chart
      # bump that silently zeroed one of them would still fall out here.
      # Bumping the budget deliberately requires a matching test update; the
      # comment on the patched template covers why it must stay inside the
      # operator's 10m HR install timeout.
      - equal:
          path: spec.template.spec.containers[0].startupProbe.periodSeconds
          value: 10
      - equal:
          path: spec.template.spec.containers[0].startupProbe.failureThreshold
          value: 60

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

NOT LGTM — the change is safe, but it does not address the failure mode #3203 documents, and merging it would auto-close that issue (via Fixes #3203) while the flake is still live.

Business context: harden snapshot-validation-webhook against a cert-manager-latency-induced CrashLoop that cascades install-wide on E2E sandboxes.

Blockers

B1: startupProbe governs the wrong window

The failure in #3203 has two phases, and a startupProbe reaches neither:

  • Pre-start Secret wait. While snapshot-validation-webhook-tls is absent the container never reaches Started, so the kubelet evaluates no probe at all — startupProbe included. The ~8-minute cert-manager wait is entirely outside any probe's reach.
  • Post-start self-exit. The issue records Exit Code: 2, which is the process exiting on its own, not a liveness SIGTERM (that would be 143). A startupProbe cannot keep a self-exiting process alive; the container restarts on process exit regardless of probe state.

The window a startupProbe actually governs — process alive, listener not yet bound on :8443 — is not where this fails. The template comment (the does NOT cover a separate class of failure where the container self-exits block) already concedes the self-exit case is uncovered, yet the PR body claims Fixes #3203, which will close the tracking issue on merge and mask a still-live flake.

B2: budget is smaller than the documented latency

Even granting the favorable reading (the binary stays up via certwatcher and the only problem is a slow bind), the budget periodSeconds: 5 × failureThreshold: 45 = 225s is under the 8m18s (498s) cert latency observed in the exact run cited in #3203. And because the container only starts once the Secret exists (~8 min in), the startup clock begins with under 2 minutes left before the 10m HR install-timeout — so on that path no probe budget can rescue it. The issue's own sketch used failureThreshold: 60 × periodSeconds: 10 = 600s; the later "tighter budget" reduced the window below the documented worst case.

Non-blocking

  1. Description drift: the "Why startupProbe" and "Files touched" sections cite periodSeconds: 10, failureThreshold: 60 (~10 min); the shipped probe is 5 / 45 (225s). Reconcile before this leaves draft.
  2. Root cause is cert-manager issuance latency under load (tracked via the cainjector bump in #3199). A probe budget here treats the symptom; it is reasonable as defense-in-depth but not a substitute for the cert-path fix.

What would make this landable

  • Add the actual root-cause fix — an initContainer that blocks until the Secret carries non-empty tls.crt/tls.key, so the binary never starts without a cert and cannot self-exit — or
  • Reframe as partial hardening: drop Fixes #3203 (use Refs #3203), keep the issue open, and land the startupProbe as a secondary layer.

Confirmed clean, separately: the patch is byte-consistent and idempotent (reverse + forward re-apply is identical), helm unittest passes 2/2, and the Makefile test: / update: re-apply follows the existing vendored-patch convention. The objection is efficacy, not safety — a startupProbe only widens startup grace and introduces no regression.

# tls-config volume); that would need an initContainer that waits
# for the Certificate's Secret to have non-empty tls.crt/tls.key.
# Filed as a follow-up on cozystack/cozystack#3203.
startupProbe:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

A startupProbe only helps a process that is alive but slow to bind :8443. In the #3203 run the container never reaches Started during the ~8-minute Secret wait (no probe runs), and once it does start the process exits with Exit Code: 2 on its own (not a liveness kill, which would be 143) — a startupProbe cannot keep a self-exiting process alive. So this probe does not cover either phase of the documented failure. The real fix is to stop the binary from starting without a cert (initContainer gating on non-empty tls.crt/tls.key), or to reframe this as partial hardening and keep #3203 open.

@IvanHunters IvanHunters changed the title fix(snapshot-controller): add startupProbe to snapshot-validation-webhook so cert-manager latency does not cascade into install-wide failure fix(snapshot-controller): add startupProbe as defense-in-depth against slow HTTPS bind on snapshot-validation-webhook Jul 4, 2026
@IvanHunters

Copy link
Copy Markdown
Collaborator Author

Thanks for the deep read — you're right on both blockers, taking the reframe path.

B1: agreed. Cross-checked the crust-gather from #3203: 9 liveness-failure events × 7 killings against a failureThreshold=3 threshold doesn't line up with a purely probe-driven kill loop, which supports your read that some restarts are self-exits. startupProbe can only widen the window in which the container is Started and the kubelet has not yet demoted it via liveness; it does nothing for the pre-Started cert-manager wait and nothing for Exit Code 2 self-exits.

B2: agreed. If the cert-manager path takes 8 minutes of the 10-minute HR install budget, the probe budget cannot rescue what remains — the outer wait ends first regardless of the probe's shape.

I've dropped the Fixes #3203 framing (now Refs #3203), rewritten the PR body to be explicit about which specific window this covers and which pathways it deliberately doesn't, corrected the stale 10 * 60 = 600s numbers to the shipped 5 * 45 = 225s, and left #3203 open. The template comment already conceded the self-exit gap; that comment now aligns with what the PR body claims.

Follow-ups tracked back on #3203:

  • initContainer that blocks main container start until the mounted tls-config volume carries non-empty tls.crt / tls.key (the "self-exit on empty Secret" pathway).
  • Making the operator's HR install timeout adjustable per component (or bumping cert-manager throughput further so an 8-minute Certificate issuance doesn't consume the whole 10-minute install window).

Landing this as the "defense-in-depth against liveness kills during slow bind" layer only. Not the root fix.

@lexfrei

Copy link
Copy Markdown
Contributor

I pulled the crust-gather artifacts and job logs for the recent failing E2E runs to check the #3203 mechanism against source data, since the fix here stands or falls on where the webhook actually fails. Summary: in every run with pod data the snapshot-validation-webhook comes up healthy, and I could not reproduce the documented CrashLoop/8-minute-cert timeline against the run the issue cites.

What the artifacts show

  • Healthy startup in every examined run: the Certificate snapshot-validation-webhook is issued in 0–1s, the container reaches Started 8–11s after Scheduled, the HTTPS server binds ~100ms after that, and restartCount is 0 with an empty lastState (no prior termination). Runs 28705039460 (PR fix(seaweedfs): soften master anti-affinity for small clusters #3197 attempt 1), 28716703954, 28717908421.
  • The binary log is three lines — certwatcher.go:129 Updated current TLS certificate, Starting certificate watcher, Starting webhook server — emitted at container start, with the cert already mounted. No panic, no fatal, no Exit Code: 2.
  • I could not reproduce the timeline the issue quotes (FailedMount ~8m, cert at 8m18s, Exit Code: 2, 7 restarts) against fix(seaweedfs): soften master anti-affinity for small clusters #3197 attempt 1. That run (28705039460) executed 11:40–12:27 UTC on the seaweedfs branch; its webhook pods are healthy (restart 0) and its snapshot-controller HelmRelease reports Helm install succeeded — it failed on monitoring / seaweedfs / tenant-root, not on this webhook. The later run on the same PR (28717770642, 19:51 UTC) passed. If the quoted 20:11–20:22 timeline comes from a different run or a manually-collected gather, please point me to it — I'd like to re-examine the actual failing pod.
  • Across ~20 recent failing runs (07-02 → 07-04), the cascade signature (helmreleases/snapshot-controller timed out and the webhook Deployment status: 'Failed') appears in 0. The one run that lists snapshot-controller among the timed-out HRs (28716703954) is a whole-cluster collapse — 182 HRs timed out including cert-manager, cilium, cozystack-api — and its webhook pods are still healthy, so that is collateral, not cause.
  • cert issuance measured at 0–1s both before and after fix(cert-manager): raise cainjector memory limit to unblock caBundle injection #3199 (merged 2026-07-04T19:36:14Z). fix(cert-manager): raise cainjector memory limit to unblock caBundle injection #3199 raises cainjector memory; cainjector injects caBundles and does not issue certificates, so any real multi-minute cert wait would be a cert-manager-webhook-reachability problem (caBundle uninjected under cainjector OOM, ref [cert-manager] Set resources requests/limits on cert-manager pods #2616) — i.e. fix(cert-manager): raise cainjector memory limit to unblock caBundle injection #3199's domain, not this Deployment's probe shape.

Implication for this PR

  • A startupProbe governs the post-Started, pre-:8443-bind window. In current data that window clears in ~100ms, well inside the default 30s liveness budget, and shows no failures — so the probe is not exercised, and its exact budget (225s vs 600s) is moot.
  • The one failure mechanism the issue documents with numbers (the multi-minute cert wait / FailedMount) is entirely pre-Started, where the kubelet runs no probe at all — so a startupProbe is inert there at any budget. The template comment already concedes the self-exit case is uncovered.

Suggested direction

Happy to be corrected with the specific failing run or gather that shows the Exit Code: 2 / CrashLoop timeline — that would change the analysis.

@IvanHunters

Copy link
Copy Markdown
Collaborator Author

Thanks for pulling the multi-run survey — that changes the calculus, and you're right that current data does not require this fix.

Pointer to the specific gather. The timeline in the issue (Started 20:11:38, cert log at 20:19:56, Exit Code: 2, restartCount 7) is from attempt 1 of run 28717770642, which failed and uploaded a crust-gather at 2026-07-04T20:22:32Z, before the rerun (attempt 2) succeeded. So 28717770642 is a two-attempt run: attempt 1 = failure with the described pod state, attempt 2 = pass. If you fetch cozyreport artifact from attempt 1 via gh api repos/cozystack/cozystack/actions/runs/28717770642/attempts/1/logs (or the artifacts endpoint scoped to attempt 1), you'll see the snapshot-validation-webhook-57bbf5ff7d-mnmtz describe with the exact numbers the issue quotes — the pod is in CrashLoopBackOff, exit code 2, restartCount 7, and the events show 9 Liveness probe failed × 7 Killing container ... failed liveness probe × 33 BackOff across ~10 minutes.

So the mode is real, and it did land in one attempt. But — and this is the important part of your survey:

Given that, I think you're right that the honest move is:

I'll leave #3204 in draft rather than pushing it forward and won't re-request review until either (a) a post-#3199 recurrence is observed, or (b) it becomes clear the guard is worth carrying independently. If you'd prefer I just close it and reopen when there is evidence, happy to do that instead — say the word.

@IvanHunters

Copy link
Copy Markdown
Collaborator Author

Closing this PR.

Follow-up on the agreement in the thread: I re-checked whether the #3203
cascade recurs on a post-#3199 tip. #3199 (cainjector memory) merged
2026-07-04. Across the window 2026-07-04..2026-07-27 I sampled failed
E2E runs (stratified, every calendar day covered) and inspected the
snapshot-validation-webhook pod state and the snapshot-controller
HelmRelease in each cozyreport.

Result: no recurrence. No snapshot-validation-webhook pod showed
CrashLoopBackOff / Exit Code 2 / a liveness kill-loop. The one
snapshot-controller HR failure in the sample was collateral from a
kubeovn-rooted whole-cluster stall (webhook pod never created), not a
webhook-caused cascade. The cert-manager path is still exercised
(transient FailedMount before cert issuance, single sub-threshold probe
misses) but never escalates to a kill or restart, consistent with the
root cause being resolved by #3199.

As discussed, the startupProbe here governs the post-Started pre-bind
window, which is not where #3203 fails, so it adds no defense-in-depth
value that the data shows is needed. Keeping #3203 open as the tracker;
if the cascade is ever observed on a post-#3199 tip, the right fix is an
initContainer gating on non-empty tls.crt/tls.key, not this probe.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/uncategorized PR auto-labeler could not map title scope to a known area/*; please review kind/bug Categorizes issue or PR as related to a bug size/L This PR changes 100-499 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants