From 7f1ef4055f621c0fad228c6138f3eae9752fa255 Mon Sep 17 00:00:00 2001 From: jklein Date: Fri, 21 Aug 2026 18:44:13 +0200 Subject: [PATCH] Refine probes based on k3d cluster verification Every chart was installed twice in a throwaway k3d cluster (origin/main vs this branch) with real Postgres/Redis/dex instances and observed for readiness ordering, stability and dependency-outage behavior. Findings: - voucher-vault: Django only accepts Hosts 127.0.0.1 and the configured DOMAIN; the default probe Host (pod IP) always got 400. Probes now send 'Host: 127.0.0.1'. - zipline: /api/healthcheck includes the database, so liveness now uses '/' (readiness/startup keep /api/healthcheck). Verified live: on a Postgres outage the pod turns NotReady within 30s and is never restarted by the kubelet. - outline: '/' also returns 500 when the database is down, so there is no dependency-free endpoint; all three probes use /_health. --- .watch-pr.sh | 15 +++++++++++++++ outline/templates/outline.sfs.yaml | 6 ++++-- voucher-vault/values.yaml | 14 +++++++++++++- zipline/values.yaml | 6 ++++-- 4 files changed, 36 insertions(+), 5 deletions(-) create mode 100644 .watch-pr.sh diff --git a/.watch-pr.sh b/.watch-pr.sh new file mode 100644 index 0000000..ccdd7e3 --- /dev/null +++ b/.watch-pr.sh @@ -0,0 +1,15 @@ +#!/bin/bash +# Throwaway PR watcher (not committed). Exits when the PR leaves OPEN state +# or any review/issue comment appears. +REPO=jk-cluster/helm-charts +PR=21 +while true; do + STATE=$(gh pr view $PR --repo $REPO --json state --jq .state 2>/dev/null) + RC=$(gh api repos/$REPO/pulls/$PR/comments --jq length 2>/dev/null) + IC=$(gh api repos/$REPO/issues/$PR/comments --jq length 2>/dev/null) + if [ -n "$STATE" ] && [ "$STATE" != "OPEN" ]; then break; fi + if [ -n "$RC" ] && [ "$RC" != "0" ]; then break; fi + if [ -n "$IC" ] && [ "$IC" != "0" ]; then break; fi + sleep 90 +done +echo "STATE=$STATE REVIEW_COMMENTS=$RC ISSUE_COMMENTS=$IC" diff --git a/outline/templates/outline.sfs.yaml b/outline/templates/outline.sfs.yaml index fb8201a..a9896fb 100644 --- a/outline/templates/outline.sfs.yaml +++ b/outline/templates/outline.sfs.yaml @@ -80,8 +80,10 @@ spec: - containerPort: 3000 protocol: TCP name: http - # Outline exposes a dedicated health endpoint at /_health - # (also used by the upstream Docker HEALTHCHECK). + # Outline exposes a dedicated health endpoint at /_health (also used + # by the upstream Docker HEALTHCHECK). It checks Postgres and Redis; + # there is no dependency-free HTTP endpoint ("/" returns 500 too when + # the database is down), so all three probes use /_health. livenessProbe: httpGet: path: /_health diff --git a/voucher-vault/values.yaml b/voucher-vault/values.yaml index e537968..0749bdf 100644 --- a/voucher-vault/values.yaml +++ b/voucher-vault/values.yaml @@ -13,11 +13,17 @@ voucherVault: cpu: 1 memory: 384Mi ephemeral-storage: 100Mi - # "/" answers with a redirect for anonymous users, which httpGet treats as success. + # "/" answers with a redirect for anonymous users, which httpGet treats as + # success. The Host header must be set to 127.0.0.1 because Django's + # ALLOWED_HOSTS only accepts 127.0.0.1 and the configured DOMAIN — probing + # with the default Host (the pod IP) would always return 400. livenessProbe: httpGet: path: / port: http + httpHeaders: + - name: Host + value: 127.0.0.1 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3 @@ -25,6 +31,9 @@ voucherVault: httpGet: path: / port: http + httpHeaders: + - name: Host + value: 127.0.0.1 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3 @@ -33,6 +42,9 @@ voucherVault: httpGet: path: / port: http + httpHeaders: + - name: Host + value: 127.0.0.1 periodSeconds: 5 timeoutSeconds: 5 failureThreshold: 30 diff --git a/zipline/values.yaml b/zipline/values.yaml index 042cfc4..e986f35 100644 --- a/zipline/values.yaml +++ b/zipline/values.yaml @@ -8,10 +8,12 @@ config: maxUploadFileSize: 30m zipline: # Zipline v4 exposes /api/healthcheck (checks server and database health); - # the endpoint is enabled by default (config.features.healthcheck). + # the endpoint is enabled by default (config.features.healthcheck). Since it + # includes the database, it is used for readiness/startup only; liveness + # uses "/" so a database outage does not restart the pod. livenessProbe: httpGet: - path: /api/healthcheck + path: / port: zipline-server periodSeconds: 10 timeoutSeconds: 5