excluding controller node pods by default.
This commit is contained in:
parent
1688aa6dea
commit
891fdc990c
@ -8,17 +8,19 @@ import (
|
|||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/client-go/kubernetes"
|
"k8s.io/client-go/kubernetes"
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Fetcher struct {
|
type Fetcher struct {
|
||||||
KubernetesNamespace string
|
KubernetesNamespace string
|
||||||
SocketPath string
|
SocketPath string
|
||||||
ContainerdNamespace string
|
ContainerdNamespace string
|
||||||
Nodename string
|
Nodename string
|
||||||
ReadyDuration time.Duration
|
ReadyDuration time.Duration
|
||||||
|
includeControllerNodes bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fetcher *Fetcher) canonicalizeImageName(image string) string {
|
func (fetcher *Fetcher) canonicalizeImageName(image string) string {
|
||||||
@ -72,8 +74,14 @@ func (fetcher *Fetcher) canonicalizeImageName(image string) string {
|
|||||||
return fullimage
|
return fullimage
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fetcher *Fetcher) isReadyForSomeTime(pod *v1.Pod) bool {
|
func (fetcher *Fetcher) isReadyForSomeTime(pod *v1.Pod, controllers map[string]bool) bool {
|
||||||
ready := false
|
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 {
|
for _, condition := range pod.Status.Conditions {
|
||||||
if condition.Type == corev1.PodReady && condition.Status == corev1.ConditionTrue {
|
if condition.Type == corev1.PodReady && condition.Status == corev1.ConditionTrue {
|
||||||
if time.Now().Sub(condition.LastTransitionTime.Time) > fetcher.ReadyDuration {
|
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 {
|
func (fetcher *Fetcher) getContainers(clientset *kubernetes.Clientset) map[string]bool {
|
||||||
|
|
||||||
|
controllers := fetcher.getControllerNames(clientset)
|
||||||
|
|
||||||
pods, err := clientset.CoreV1().Pods(fetcher.KubernetesNamespace).List(context.Background(),
|
pods, err := clientset.CoreV1().Pods(fetcher.KubernetesNamespace).List(context.Background(),
|
||||||
metav1.ListOptions{})
|
metav1.ListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -104,7 +115,7 @@ func (fetcher *Fetcher) getContainers(clientset *kubernetes.Clientset) map[strin
|
|||||||
if pod.Spec.NodeName == fetcher.Nodename {
|
if pod.Spec.NodeName == fetcher.Nodename {
|
||||||
containersOnCurrentNode[fetcher.canonicalizeImageName(container.Image)] = true
|
containersOnCurrentNode[fetcher.canonicalizeImageName(container.Image)] = true
|
||||||
} else {
|
} else {
|
||||||
if fetcher.isReadyForSomeTime(&pod) {
|
if fetcher.isReadyForSomeTime(&pod, controllers) {
|
||||||
containers[fetcher.canonicalizeImageName(container.Image)] = true
|
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 {
|
if pod.Spec.NodeName == fetcher.Nodename {
|
||||||
containersOnCurrentNode[fetcher.canonicalizeImageName(container.Image)] = true
|
containersOnCurrentNode[fetcher.canonicalizeImageName(container.Image)] = true
|
||||||
} else {
|
} else {
|
||||||
if fetcher.isReadyForSomeTime(&pod) {
|
if fetcher.isReadyForSomeTime(&pod, controllers) {
|
||||||
containers[fetcher.canonicalizeImageName(container.Image)] = true
|
containers[fetcher.canonicalizeImageName(container.Image)] = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -187,6 +198,21 @@ func (fetcher *Fetcher) pullAndPin() error {
|
|||||||
return nil
|
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
|
// TODO
|
||||||
// 1. periodic pull and pin, configurable time interval
|
// 1. periodic pull and pin, configurable time interval
|
||||||
// 2. logging summary results of each pull and pin
|
// 2. logging summary results of each pull and pin
|
||||||
|
@ -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")
|
"Kubernetes node name the fetcher is running on, it will only fetch images running on other nodes")
|
||||||
cmd.PersistentFlags().DurationVar(&fetcher.ReadyDuration, "ready-duration",
|
cmd.PersistentFlags().DurationVar(&fetcher.ReadyDuration, "ready-duration",
|
||||||
1*time.Hour, "Time a pod must be ready before its image will be fetched")
|
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)
|
cmd.Flags().AddGoFlagSet(klogFlags)
|
||||||
|
|
||||||
err := cmd.Execute()
|
err := cmd.Execute()
|
||||||
|
Loading…
Reference in New Issue
Block a user