excluding controller node pods by default.

This commit is contained in:
Erik Brakkee 2025-03-02 17:18:13 +01:00
parent 1688aa6dea
commit 891fdc990c
2 changed files with 36 additions and 8 deletions

View File

@ -8,17 +8,19 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/klog/v2"
"os"
"regexp"
"strings"
"time"
)
type Fetcher struct {
KubernetesNamespace string
SocketPath string
ContainerdNamespace string
Nodename string
ReadyDuration time.Duration
KubernetesNamespace string
SocketPath string
ContainerdNamespace string
Nodename string
ReadyDuration time.Duration
includeControllerNodes bool
}
func (fetcher *Fetcher) canonicalizeImageName(image string) string {
@ -72,8 +74,14 @@ func (fetcher *Fetcher) canonicalizeImageName(image string) string {
return fullimage
}
func (fetcher *Fetcher) isReadyForSomeTime(pod *v1.Pod) bool {
func (fetcher *Fetcher) isReadyForSomeTime(pod *v1.Pod, controllers map[string]bool) bool {
ready := false
if !fetcher.includeControllerNodes {
klog.Infof("Checking %s (%s)", pod.Name, pod.Spec.NodeName)
if _, ok := controllers[pod.Spec.NodeName]; ok {
return false
}
}
for _, condition := range pod.Status.Conditions {
if condition.Type == corev1.PodReady && condition.Status == corev1.ConditionTrue {
if time.Now().Sub(condition.LastTransitionTime.Time) > fetcher.ReadyDuration {
@ -88,6 +96,9 @@ func (fetcher *Fetcher) isReadyForSomeTime(pod *v1.Pod) bool {
}
func (fetcher *Fetcher) getContainers(clientset *kubernetes.Clientset) map[string]bool {
controllers := fetcher.getControllerNames(clientset)
pods, err := clientset.CoreV1().Pods(fetcher.KubernetesNamespace).List(context.Background(),
metav1.ListOptions{})
if err != nil {
@ -104,7 +115,7 @@ func (fetcher *Fetcher) getContainers(clientset *kubernetes.Clientset) map[strin
if pod.Spec.NodeName == fetcher.Nodename {
containersOnCurrentNode[fetcher.canonicalizeImageName(container.Image)] = true
} else {
if fetcher.isReadyForSomeTime(&pod) {
if fetcher.isReadyForSomeTime(&pod, controllers) {
containers[fetcher.canonicalizeImageName(container.Image)] = true
}
}
@ -114,7 +125,7 @@ func (fetcher *Fetcher) getContainers(clientset *kubernetes.Clientset) map[strin
if pod.Spec.NodeName == fetcher.Nodename {
containersOnCurrentNode[fetcher.canonicalizeImageName(container.Image)] = true
} else {
if fetcher.isReadyForSomeTime(&pod) {
if fetcher.isReadyForSomeTime(&pod, controllers) {
containers[fetcher.canonicalizeImageName(container.Image)] = true
}
}
@ -187,6 +198,21 @@ func (fetcher *Fetcher) pullAndPin() error {
return nil
}
func (fetcher *Fetcher) getControllerNames(clientset *kubernetes.Clientset) map[string]bool {
nodes, err := clientset.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{
LabelSelector: "node-role.kubernetes.io/control-plane=,!node-role.kubernetes.io/master",
})
if err != nil {
fmt.Printf("Error listing nodes: %v\n", err)
os.Exit(1)
}
nodeset := make(map[string]bool)
for _, node := range nodes.Items {
nodeset[node.Name] = true
}
return nodeset
}
// TODO
// 1. periodic pull and pin, configurable time interval
// 2. logging summary results of each pull and pin

View File

@ -37,6 +37,8 @@ so they don't get garbage collected'`,
"Kubernetes node name the fetcher is running on, it will only fetch images running on other nodes")
cmd.PersistentFlags().DurationVar(&fetcher.ReadyDuration, "ready-duration",
1*time.Hour, "Time a pod must be ready before its image will be fetched")
cmd.PersistentFlags().BoolVar(&fetcher.includeControllerNodes, "include-controllers",
false, "Include controller nodes")
cmd.Flags().AddGoFlagSet(klogFlags)
err := cmd.Execute()