Commit 0539086f authored by Michael Taufen's avatar Michael Taufen

add a flag to control the cap on images reported in node status

While I normally try to avoid adding flags, this is a short term scalability fix for v1.11, and there are other long-term solutions in the works, so we shouldn't commit to this in the v1beta1 Kubelet config. Flags are our escape hatch.
parent f3d54f3f
...@@ -169,6 +169,9 @@ type KubeletFlags struct { ...@@ -169,6 +169,9 @@ type KubeletFlags struct {
// bootstrapCheckpointPath is the path to the directory containing pod checkpoints to // bootstrapCheckpointPath is the path to the directory containing pod checkpoints to
// run on restore // run on restore
BootstrapCheckpointPath string BootstrapCheckpointPath string
// NodeStatusMaxImages caps the number of images reported in Node.Status.Images.
// This is an experimental, short-term flag to help with node scalability.
NodeStatusMaxImages int32
// DEPRECATED FLAGS // DEPRECATED FLAGS
// minimumGCAge is the minimum age for a finished container before it is // minimumGCAge is the minimum age for a finished container before it is
...@@ -244,6 +247,8 @@ func NewKubeletFlags() *KubeletFlags { ...@@ -244,6 +247,8 @@ func NewKubeletFlags() *KubeletFlags {
CAdvisorPort: 0, CAdvisorPort: 0,
// TODO(#58010:v1.13.0): Remove --allow-privileged, it is deprecated // TODO(#58010:v1.13.0): Remove --allow-privileged, it is deprecated
AllowPrivileged: true, AllowPrivileged: true,
// prior to the introduction of this flag, there was a hardcoded cap of 50 images
NodeStatusMaxImages: 50,
} }
} }
...@@ -255,6 +260,9 @@ func ValidateKubeletFlags(f *KubeletFlags) error { ...@@ -255,6 +260,9 @@ func ValidateKubeletFlags(f *KubeletFlags) error {
if f.CAdvisorPort != 0 && utilvalidation.IsValidPortNum(int(f.CAdvisorPort)) != nil { if f.CAdvisorPort != 0 && utilvalidation.IsValidPortNum(int(f.CAdvisorPort)) != nil {
return fmt.Errorf("invalid configuration: CAdvisorPort (--cadvisor-port) %v must be between 0 and 65535, inclusive", f.CAdvisorPort) return fmt.Errorf("invalid configuration: CAdvisorPort (--cadvisor-port) %v must be between 0 and 65535, inclusive", f.CAdvisorPort)
} }
if f.NodeStatusMaxImages < -1 {
return fmt.Errorf("invalid configuration: NodeStatusMaxImages (--node-status-max-images) must be -1 or greater")
}
return nil return nil
} }
...@@ -392,6 +400,7 @@ func (f *KubeletFlags) AddFlags(mainfs *pflag.FlagSet) { ...@@ -392,6 +400,7 @@ func (f *KubeletFlags) AddFlags(mainfs *pflag.FlagSet) {
fs.BoolVar(&f.ExitOnLockContention, "exit-on-lock-contention", f.ExitOnLockContention, "Whether kubelet should exit upon lock-file contention.") fs.BoolVar(&f.ExitOnLockContention, "exit-on-lock-contention", f.ExitOnLockContention, "Whether kubelet should exit upon lock-file contention.")
fs.StringVar(&f.SeccompProfileRoot, "seccomp-profile-root", f.SeccompProfileRoot, "<Warning: Alpha feature> Directory path for seccomp profiles.") fs.StringVar(&f.SeccompProfileRoot, "seccomp-profile-root", f.SeccompProfileRoot, "<Warning: Alpha feature> Directory path for seccomp profiles.")
fs.StringVar(&f.BootstrapCheckpointPath, "bootstrap-checkpoint-path", f.BootstrapCheckpointPath, "<Warning: Alpha feature> Path to to the directory where the checkpoints are stored") fs.StringVar(&f.BootstrapCheckpointPath, "bootstrap-checkpoint-path", f.BootstrapCheckpointPath, "<Warning: Alpha feature> Path to to the directory where the checkpoints are stored")
fs.Int32Var(&f.NodeStatusMaxImages, "node-status-max-images", f.NodeStatusMaxImages, "<Warning: Alpha feature> The maximum number of images to report in Node.Status.Images. If -1 is specified, no cap will be applied. Default: 50")
// DEPRECATED FLAGS // DEPRECATED FLAGS
fs.StringVar(&f.BootstrapKubeconfig, "experimental-bootstrap-kubeconfig", f.BootstrapKubeconfig, "") fs.StringVar(&f.BootstrapKubeconfig, "experimental-bootstrap-kubeconfig", f.BootstrapKubeconfig, "")
......
...@@ -958,6 +958,7 @@ func RunKubelet(kubeFlags *options.KubeletFlags, kubeCfg *kubeletconfiginternal. ...@@ -958,6 +958,7 @@ func RunKubelet(kubeFlags *options.KubeletFlags, kubeCfg *kubeletconfiginternal.
kubeFlags.NodeLabels, kubeFlags.NodeLabels,
kubeFlags.SeccompProfileRoot, kubeFlags.SeccompProfileRoot,
kubeFlags.BootstrapCheckpointPath, kubeFlags.BootstrapCheckpointPath,
kubeFlags.NodeStatusMaxImages,
stopCh) stopCh)
if err != nil { if err != nil {
return fmt.Errorf("failed to create kubelet: %v", err) return fmt.Errorf("failed to create kubelet: %v", err)
...@@ -1043,6 +1044,7 @@ func CreateAndInitKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration, ...@@ -1043,6 +1044,7 @@ func CreateAndInitKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration,
nodeLabels map[string]string, nodeLabels map[string]string,
seccompProfileRoot string, seccompProfileRoot string,
bootstrapCheckpointPath string, bootstrapCheckpointPath string,
nodeStatusMaxImages int32,
stopCh <-chan struct{}) (k kubelet.Bootstrap, err error) { stopCh <-chan struct{}) (k kubelet.Bootstrap, err error) {
// TODO: block until all sources have delivered at least one update to the channel, or break the sync loop // TODO: block until all sources have delivered at least one update to the channel, or break the sync loop
// up into "per source" synchronizations // up into "per source" synchronizations
...@@ -1077,6 +1079,7 @@ func CreateAndInitKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration, ...@@ -1077,6 +1079,7 @@ func CreateAndInitKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration,
nodeLabels, nodeLabels,
seccompProfileRoot, seccompProfileRoot,
bootstrapCheckpointPath, bootstrapCheckpointPath,
nodeStatusMaxImages,
stopCh) stopCh)
if err != nil { if err != nil {
return nil, err return nil, err
......
...@@ -219,7 +219,9 @@ type Builder func(kubeCfg *kubeletconfiginternal.KubeletConfiguration, ...@@ -219,7 +219,9 @@ type Builder func(kubeCfg *kubeletconfiginternal.KubeletConfiguration,
keepTerminatedPodVolumes bool, keepTerminatedPodVolumes bool,
nodeLabels map[string]string, nodeLabels map[string]string,
seccompProfileRoot string, seccompProfileRoot string,
bootstrapCheckpointPath string) (Bootstrap, error) bootstrapCheckpointPath string,
nodeStatusMaxImages int32,
stopCh <-chan struct{}) (Bootstrap, error)
// Dependencies is a bin for things we might consider "injected dependencies" -- objects constructed // Dependencies is a bin for things we might consider "injected dependencies" -- objects constructed
// at runtime that are necessary for running the Kubelet. This is a temporary solution for grouping // at runtime that are necessary for running the Kubelet. This is a temporary solution for grouping
...@@ -345,6 +347,7 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration, ...@@ -345,6 +347,7 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration,
nodeLabels map[string]string, nodeLabels map[string]string,
seccompProfileRoot string, seccompProfileRoot string,
bootstrapCheckpointPath string, bootstrapCheckpointPath string,
nodeStatusMaxImages int32,
stopCh <-chan struct{}) (*Kubelet, error) { stopCh <-chan struct{}) (*Kubelet, error) {
if rootDirectory == "" { if rootDirectory == "" {
return nil, fmt.Errorf("invalid root directory %q", rootDirectory) return nil, fmt.Errorf("invalid root directory %q", rootDirectory)
...@@ -535,6 +538,7 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration, ...@@ -535,6 +538,7 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration,
iptablesDropBit: int(kubeCfg.IPTablesDropBit), iptablesDropBit: int(kubeCfg.IPTablesDropBit),
experimentalHostUserNamespaceDefaulting: utilfeature.DefaultFeatureGate.Enabled(features.ExperimentalHostUserNamespaceDefaultingGate), experimentalHostUserNamespaceDefaulting: utilfeature.DefaultFeatureGate.Enabled(features.ExperimentalHostUserNamespaceDefaultingGate),
keepTerminatedPodVolumes: keepTerminatedPodVolumes, keepTerminatedPodVolumes: keepTerminatedPodVolumes,
nodeStatusMaxImages: nodeStatusMaxImages,
} }
if klet.cloud != nil { if klet.cloud != nil {
...@@ -1157,6 +1161,9 @@ type Kubelet struct { ...@@ -1157,6 +1161,9 @@ type Kubelet struct {
// such as device plugins or CSI plugins. It discovers plugins by monitoring inotify events under the // such as device plugins or CSI plugins. It discovers plugins by monitoring inotify events under the
// directory returned by kubelet.getPluginsDir() // directory returned by kubelet.getPluginsDir()
pluginWatcher pluginwatcher.Watcher pluginWatcher pluginwatcher.Watcher
// This flag sets a maximum number of images to report in the node status.
nodeStatusMaxImages int32
} }
func allGlobalUnicastIPs() ([]net.IP, error) { func allGlobalUnicastIPs() ([]net.IP, error) {
......
...@@ -49,9 +49,6 @@ import ( ...@@ -49,9 +49,6 @@ import (
) )
const ( const (
// maxImagesInNodeStatus is the number of max images we store in image status.
maxImagesInNodeStatus = 50
// maxNamesPerImageInNodeStatus is max number of names per image stored in // maxNamesPerImageInNodeStatus is max number of names per image stored in
// the node status. // the node status.
maxNamesPerImageInNodeStatus = 5 maxNamesPerImageInNodeStatus = 5
...@@ -721,8 +718,9 @@ func (kl *Kubelet) setNodeStatusImages(node *v1.Node) { ...@@ -721,8 +718,9 @@ func (kl *Kubelet) setNodeStatusImages(node *v1.Node) {
return return
} }
// sort the images from max to min, and only set top N images into the node status. // sort the images from max to min, and only set top N images into the node status.
if maxImagesInNodeStatus < len(containerImages) { if int(kl.nodeStatusMaxImages) > -1 &&
containerImages = containerImages[0:maxImagesInNodeStatus] int(kl.nodeStatusMaxImages) < len(containerImages) {
containerImages = containerImages[0:kl.nodeStatusMaxImages]
} }
for _, image := range containerImages { for _, image := range containerImages {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment