fix(kubernetes): wait for admin-kubeconfig before starting CP-side pods

Three Deployments in the Kubernetes app chart mount the tenant
admin-kubeconfig Secret directly as a volume: cluster-autoscaler,
kccm, and the kcsi controller. That Secret is provisioned
asynchronously by Kamaji after control-plane bootstrap, so on a fresh
install the pods used to hit FailedMount and the parent HelmRelease
ran out of its wait budget.

Mark the Secret volume optional and add a wait-for-kubeconfig
initContainer that polls the mounted path until the Secret appears.
Kubelet remounts the optional Secret within its sync period once
Kamaji publishes it, the init container exits, and the main container
starts cleanly. The Deployment becomes Available without the helm-wait
ever seeing a FailedMount.

Pins a busybox image for the init container via
images/busybox.tag (same format as the other pinned tags in this
chart).

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
This commit is contained in:
Aleksei Sviridkin 2026-04-16 20:25:42 +03:00
parent 3e26234a1c
commit ca33cc4e3c
No known key found for this signature in database
GPG key ID: 7988329FDF395282
4 changed files with 52 additions and 0 deletions

View file

@ -0,0 +1 @@
busybox:1.37.0@sha256:1487d0af5f52b4ba31c7e465126ee2123fe3f2305d638e7827681e7cf6c83d5e

View file

@ -23,6 +23,22 @@ spec:
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: "NoSchedule"
initContainers:
- name: wait-for-kubeconfig
image: "{{ $.Files.Get "images/busybox.tag" | trim }}"
command:
- sh
- -c
- |
set -eu
until [ -s /etc/kubernetes/kubeconfig/super-admin.svc ]; do
echo "waiting for admin kubeconfig to be provisioned by Kamaji..."
sleep 5
done
volumeMounts:
- name: kubeconfig
mountPath: /etc/kubernetes/kubeconfig
readOnly: true
containers:
- image: "{{ $.Files.Get "images/cluster-autoscaler.tag" | trim }}"
name: cluster-autoscaler
@ -56,6 +72,7 @@ spec:
name: cloud-config
- secret:
secretName: {{ .Release.Name }}-admin-kubeconfig
optional: true
name: kubeconfig
serviceAccountName: {{ .Release.Name }}-cluster-autoscaler
terminationGracePeriodSeconds: 10

View file

@ -24,6 +24,22 @@ spec:
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: "NoSchedule"
initContainers:
- name: wait-for-kubeconfig
image: "{{ $.Files.Get "images/busybox.tag" | trim }}"
command:
- sh
- -c
- |
set -eu
until [ -s /etc/kubernetes/kubeconfig/super-admin.svc ]; do
echo "waiting for admin kubeconfig to be provisioned by Kamaji..."
sleep 5
done
volumeMounts:
- name: kubeconfig
mountPath: /etc/kubernetes/kubeconfig
readOnly: true
containers:
- name: csi-driver
imagePullPolicy: Always
@ -234,4 +250,5 @@ spec:
emptyDir: {}
- secret:
secretName: {{ .Release.Name }}-admin-kubeconfig
optional: true
name: kubeconfig

View file

@ -22,6 +22,22 @@ spec:
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: "NoSchedule"
initContainers:
- name: wait-for-kubeconfig
image: "{{ $.Files.Get "images/busybox.tag" | trim }}"
command:
- sh
- -c
- |
set -eu
until [ -s /etc/kubernetes/kubeconfig/super-admin.svc ]; do
echo "waiting for admin kubeconfig to be provisioned by Kamaji..."
sleep 5
done
volumeMounts:
- name: kubeconfig
mountPath: /etc/kubernetes/kubeconfig
readOnly: true
containers:
- name: kubevirt-cloud-controller-manager
args:
@ -55,5 +71,6 @@ spec:
name: cloud-config
- secret:
secretName: {{ .Release.Name }}-admin-kubeconfig
optional: true
name: kubeconfig
serviceAccountName: {{ .Release.Name }}-kccm