Reconcile all kustomizations #5229
-
Hello My team and are are developing a kubernetes cluster and we have a local setup using kind which is based on the same approach as flux-local-dev. We often need to push new changes to the local registry and trigger a flux reconcile, and there doesnt seem to be a command in the flux cli that reconciles all kustomizations as soon as possible. We started with a loop to just start reconciling each kustomization, but that ended up being the wrong order (in terms of dependencies, i.e. spec.dependsOn) and therefore very slow. We then used a topological sort based on the kustomization dependencies which was better. But it runs in bash and we did not want to go through the effort of making it multi threaded in bash so it was single threaded and therefore also not great. Now we have a go program which runs package main
import (
"encoding/json"
"flag"
"log"
"os/exec"
"sync"
)
type KustomizationJson struct {
Metadata struct {
Name string `json:"name"`
Namespace string `json:"namespace"`
} `json:"metadata"`
Spec struct {
DependsOn []struct {
Name string `json:"name"`
} `json:"dependsOn"`
} `json:"spec"`
}
type KustomizationJsonList struct {
Items []KustomizationJson `json:"items"`
}
type FQN struct {
Namespace string
Name string
}
type Kustomization struct {
Name string
Namespace string
DependsOn []*Kustomization
IsDependedOnBy []*Kustomization
InDegree int
}
var (
wg sync.WaitGroup
reconcileTimeout = flag.String("timeout", "10m0s", "Flux reconcile timeout")
kubeContext = flag.String("context", "", "Kubernetes context")
)
func main() {
flag.Parse()
// Get all kustomizations
out, err := exec.Command("kubectl", "get", "kustomizations", "--context", *kubeContext, "-A", "-o", "json").Output()
if err != nil {
log.Fatalf("Error calling kubectl: %v", err)
}
var kustomizationsJson KustomizationJsonList
if err := json.Unmarshal(out, &kustomizationsJson); err != nil {
log.Fatalf("Failed to parse JSON: %v", err)
}
// Create kustomization objects
kustomizations := make(map[FQN]*Kustomization)
for _, k := range kustomizationsJson.Items {
FQN := FQN{
Namespace: k.Metadata.Namespace,
Name: k.Metadata.Name,
}
kustomizations[FQN] = &Kustomization{
Name: k.Metadata.Name,
Namespace: k.Metadata.Namespace,
DependsOn: []*Kustomization{},
IsDependedOnBy: []*Kustomization{},
InDegree: len(k.Spec.DependsOn),
}
}
// Populate dependencies
for _, k := range kustomizationsJson.Items {
dependsOn := []*Kustomization{}
for _, dep := range k.Spec.DependsOn {
FQN := FQN{
Namespace: k.Metadata.Namespace,
Name: dep.Name,
}
dependsOn = append(dependsOn, kustomizations[FQN])
}
FQN := FQN{
Namespace: k.Metadata.Namespace,
Name: k.Metadata.Name,
}
kustomizations[FQN].DependsOn = dependsOn
kustomizations[FQN].InDegree = len(k.Spec.DependsOn)
}
for _, kustomization := range kustomizations {
for _, dep := range kustomization.DependsOn {
dep.IsDependedOnBy = append(dep.IsDependedOnBy, kustomization)
}
}
// Start reconciling
for _, kustomization := range kustomizations {
if kustomization.InDegree == 0 {
wg.Add(1)
go reconcile(kustomization)
}
}
wg.Wait()
}
func reconcile(k *Kustomization) {
defer wg.Done()
log.Printf("[START] Reconcile: %s/%s\n", k.Namespace, k.Name)
// Reconcile kustomization
cmd := exec.Command(
"flux", "reconcile", "kustomization",
k.Name,
"--context", *kubeContext,
"--namespace", k.Namespace,
"--timeout", *reconcileTimeout,
)
out, err := cmd.CombinedOutput()
if err != nil {
log.Fatalf("[ERROR] flux reconcile failed for %s: %v\nOutput:\n%s\n", k.Name, err, out)
}
log.Printf("[DONE] Reconcile: %s/%s\n", k.Namespace, k.Name)
// Update in-degree of kustomizations that depend on this one
for _, dep := range k.IsDependedOnBy {
dep.InDegree--
if dep.InDegree == 0 {
wg.Add(1)
go reconcile(dep)
}
}
} |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 7 replies
-
You can use the Receiver API to have a list of kustomizations to reconcile, then if you set https://fluxcd.io/flux/components/notification/receivers/#resources To run the |
Beta Was this translation helpful? Give feedback.
Not really, when blocked by dependencies the retry interval is another one, configured at the controller level with a flag of the binary,
--requeue-dependency
:https://github.com/fluxcd/kustomize-controller/blob/dc0e5853c06df506de22ce1bb0b9303389d90942/internal/controller/kustomization_controller.go#L277
Docs: https://fluxcd.io/flux/components/kustomize/options/#flags
You can set this to, say,
5s
.