elb-openapi in-cluster kubeconfig (/v1/ready 503 fix)¶
Motivation¶
The elb-openapi service /v1/ready endpoint returned HTTP 503 with
k8s_unreachable even when the target AKS cluster (elb-cluster-02) was fully
Running/Succeeded. The error detail was:
The command "kubectl get --raw /readyz --request-timeout=1s" returned with exit code 1
The connection to the server localhost:8080 was refused - did you specify the right host or port?
Root cause (confirmed via live pod inspection)¶
The /v1/ready probe shells out to kubectl get --raw /readyz. The kubectl
CLI does not auto-load in-cluster configuration the way the client-go
InClusterConfig() helper does. The pod had:
- the in-cluster env vars present (
KUBERNETES_SERVICE_HOST,KUBERNETES_SERVICE_PORT), - the projected ServiceAccount token mounted at
/var/run/secrets/kubernetes.io/serviceaccount/{token,ca.crt,namespace}, - valid
elb-openapi-saRBAC,
but no ~/.kube/config and an empty KUBECONFIG, so kubectl fell back to
its default localhost:8080 and every cluster call failed with
"connection refused".
Validated live that writing a tokenFile-based in-cluster kubeconfig and
pointing KUBECONFIG at it makes the exact probe command succeed:
User-facing change¶
/v1/ready now returns 200 (cluster reachable) instead of 503
k8s_unreachable once the elb-openapi Deployment is re-applied with the new
manifest. No SPA code change required.
API / IaC diff summary¶
api/tasks/openapi/manifests.py (build_manifests):
- New
ConfigMapelb-openapi-kubeconfigholding an in-cluster kubeconfig. It usestokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token(auto-rotated),certificate-authority: .../ca.crt, andserver: https://kubernetes.default.svc(the standard in-cluster API endpoint, always present in the API server certificate SAN). - New container env
KUBECONFIG=/etc/elb/kube/config(added toopenapi_env). - New volume
incluster-kubeconfig(ConfigMap-backed) mounted read-only at/etc/elb/kubeon theopenapicontainer. - ConfigMap appended to the multi-document output (between RBAC and Deployment).
The fix lives entirely in the dashboard-owned manifest — no sibling
elastic-blast-azure image change is needed. The default projected
ServiceAccount token mount is relied upon (automountServiceAccountToken
remains the default true).
Validation evidence¶
uv run ruff check api/tasks/openapi/manifests.py— clean.uv run pytest -q api/tests/test_smoke.py api/tests/test_openapi_task.py— 91 passed. Existing tests look up documents bykind, so the additional ConfigMap document is non-breaking.- Live proof that the kubeconfig approach works (IP-based variant):
kubectl get --raw /readyz→ok,kubectl get deploy elb-openapi→2 readyReplicas.
Rollout¶
This changes the elb-openapi Kubernetes manifest (not ordinary api/web code),
so a redeploy of the api sidecar followed by the dashboard
"Deploy elb-openapi" action (POST /api/aks/openapi/deploy) is the sanctioned
path to apply the new ConfigMap + volume and recreate the pods.