How do you configure Flux health checks and readiness gates for reliable reconciliation?
Quick Answer
Flux health checks use the spec.healthChecks field on Kustomizations and HelmReleases to define explicit resource readiness criteria, combined with spec.wait and spec.timeout to control how long Flux waits for resources to become healthy before marking a reconciliation as successful or failed.
Detailed Answer
Think of Flux health checks like the preflight checklist a pilot completes before takeoff. The pilot does not simply submit the flight plan (apply manifests) and immediately declare the plane ready to fly. Instead, they systematically verify each system — engines running at proper RPM (Deployment replicas ready), fuel pressure within tolerance (StatefulSet volumes bound), navigation systems online (Service endpoints populated) — and only when every item on the checklist passes does the pilot declare ready for takeoff (Kustomization status set to Ready). If any check fails within the allowed time window (timeout), the pilot aborts the departure and reports the failure. Flux health checks work exactly the same way, ensuring that applied resources are genuinely operational, not just submitted to the Kubernetes API.
Flux provides two mechanisms for health assessment: the implicit spec.wait field and the explicit spec.healthChecks field. When spec.wait is set to true on a Kustomization, the kustomize-controller waits for all resources applied by that Kustomization to become ready using Flux's built-in health assessment logic. For Deployments, readiness means all replicas are available and the rollout is complete. For StatefulSets, all replicas must be in the Ready state. For Jobs, the Job must complete successfully. For custom resources, Flux looks for standard status conditions — specifically the Ready condition or the Available condition — to determine health. The spec.timeout field controls how long the controller waits before declaring the reconciliation failed, defaulting to five minutes. If any resource does not become healthy within the timeout period, the Kustomization status is set to False with a detailed message identifying which resources failed their health assessment.
The explicit spec.healthChecks field provides more granular control by allowing you to specify exactly which resources to health check, including resources that may not be directly managed by the Kustomization. Each health check entry specifies the apiVersion, kind, name, and namespace of the resource to monitor. This is particularly useful when your Kustomization deploys a custom resource like a PostgreSQL cluster CR, and you want Flux to wait for the operator-created StatefulSet (which the Kustomization did not directly create) to become healthy. You can also health check resources in different namespaces, enabling cross-component readiness validation. The health checks are evaluated in parallel — all specified resources must become healthy within the timeout period for the reconciliation to be considered successful.
In production environments deploying services like user-auth-service, the health check configuration typically includes checks for the primary Deployment to ensure all replicas are rolled out, checks for any CronJob-created Jobs to verify background tasks are functional, and checks for Ingress resources to confirm external accessibility. For HelmReleases, the spec.test field provides an additional layer by running Helm test hooks after the release is installed or upgraded, which execute Pod-based tests that validate the application's internal health beyond just Kubernetes resource status. A common pattern is to combine spec.wait with explicit healthChecks for operator-managed resources: spec.wait handles the directly deployed resources while healthChecks monitor the derived resources created by operators or controllers.
A critical production gotcha is setting the timeout too low for resources that legitimately take a long time to start. Database StatefulSets pulling large images, services requiring initial data migration, or applications with slow readiness probes can easily exceed the default five-minute timeout, causing Flux to report false failures and potentially trigger unnecessary alerts. Teams should analyze the actual startup time of their heaviest services and set timeouts with a comfortable buffer — typically two to three times the observed startup time. Another common mistake is not configuring health checks at all and relying solely on the apply-and-forget approach, which means Flux reports success as soon as manifests are submitted to the API server, regardless of whether Pods crash-loop or Services have no endpoints. This gives a false sense of confidence in the deployment pipeline. Additionally, for custom resources managed by operators, the operator must set standard status conditions (Ready or Available) for Flux to assess health correctly — if the operator does not follow this convention, Flux will treat the resource as healthy immediately after creation, bypassing the intended readiness gate.