Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 26 additions & 22 deletions pkg/controllers/controllers.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,6 @@ func NewControllers(
informer.NewNodePoolController(kubeClient, cloudProvider, cluster),
informer.NewNodeClaimController(kubeClient, cloudProvider, cluster),
termination.NewController(clock, kubeClient, cloudProvider, terminator.NewTerminator(clock, kubeClient, evictionQueue, recorder), recorder),
metricspod.NewController(kubeClient, cluster),
metricsnodepool.NewController(kubeClient, cloudProvider),
metricsnode.NewController(cluster),
nodepoolreadiness.NewController(kubeClient, cloudProvider),
nodepoolregistrationhealth.NewController(kubeClient, cloudProvider),
nodepoolcounter.NewController(kubeClient, cloudProvider, cluster),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if it would make sense to include the NodePool Counter controller in this set? I could go either way - since it's just propagating information from cluster state it should be relatively cheap, but the cost does scale with the number of nodepools. It is a "cluster state observability" controller though. Did it show up at all in your performance review?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We were using a relatively small number of nodepools (~12), we didn't see significant performance impact. One thing I want to explore is how exactly the volume of metrics changes as we scale the number of nodes in the cluster

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems fine to include it for the time being, and we can re-evaluate if we see significant performance impact.

Expand All @@ -99,25 +96,32 @@ func NewControllers(
nodeclaimdisruption.NewController(clock, kubeClient, cloudProvider),
nodeclaimhydration.NewController(kubeClient, cloudProvider),
nodehydration.NewController(kubeClient, cloudProvider),
status.NewController[*v1.NodeClaim](
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these status controllers only responsible for metrics? Anything else would be missing by disabling them? (For example, looks like they also issue transition events ...)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They do also emit events for finalizers and status condition changes, but I think thats all they emit

kubeClient,
mgr.GetEventRecorderFor("karpenter"),
status.EmitDeprecatedMetrics,
status.WithHistogramBuckets(prometheus.ExponentialBuckets(0.5, 2, 15)), // 0.5, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192
status.WithLabels(append(lo.Map(cloudProvider.GetSupportedNodeClasses(), func(obj status.Object, _ int) string { return v1.NodeClassLabelKey(object.GVK(obj).GroupKind()) }), v1.NodePoolLabelKey)...),
),
status.NewController[*v1.NodePool](
kubeClient,
mgr.GetEventRecorderFor("karpenter"),
status.EmitDeprecatedMetrics,
status.WithHistogramBuckets(prometheus.ExponentialBuckets(0.5, 2, 15)), // 0.5, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192
),
status.NewGenericObjectController[*corev1.Node](
kubeClient,
mgr.GetEventRecorderFor("karpenter"),
status.WithHistogramBuckets(prometheus.ExponentialBuckets(0.5, 2, 15)), // 0.5, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192
status.WithLabels(append(lo.Map(cloudProvider.GetSupportedNodeClasses(), func(obj status.Object, _ int) string { return v1.NodeClassLabelKey(object.GVK(obj).GroupKind()) }), v1.NodePoolLabelKey, v1.NodeInitializedLabelKey)...),
),
}

if !options.FromContext(ctx).SimplifiedMetrics {
controllers = append(controllers,
metricspod.NewController(kubeClient, cluster),
metricsnodepool.NewController(kubeClient, cloudProvider),
metricsnode.NewController(cluster),
status.NewController[*v1.NodeClaim](
kubeClient,
mgr.GetEventRecorderFor("karpenter"),
status.EmitDeprecatedMetrics,
status.WithHistogramBuckets(prometheus.ExponentialBuckets(0.5, 2, 15)), // 0.5, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192
status.WithLabels(append(lo.Map(cloudProvider.GetSupportedNodeClasses(), func(obj status.Object, _ int) string { return v1.NodeClassLabelKey(object.GVK(obj).GroupKind()) }), v1.NodePoolLabelKey)...),
),
status.NewController[*v1.NodePool](
kubeClient,
mgr.GetEventRecorderFor("karpenter"),
status.EmitDeprecatedMetrics,
status.WithHistogramBuckets(prometheus.ExponentialBuckets(0.5, 2, 15)), // 0.5, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192
),
status.NewGenericObjectController[*corev1.Node](
kubeClient,
mgr.GetEventRecorderFor("karpenter"),
status.WithHistogramBuckets(prometheus.ExponentialBuckets(0.5, 2, 15)), // 0.5, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192
status.WithLabels(append(lo.Map(cloudProvider.GetSupportedNodeClasses(), func(obj status.Object, _ int) string { return v1.NodeClassLabelKey(object.GVK(obj).GroupKind()) }), v1.NodePoolLabelKey, v1.NodeInitializedLabelKey)...)),
)
}

// The cloud provider must define status conditions for the node repair controller to use to detect unhealthy nodes
Expand Down
2 changes: 2 additions & 0 deletions pkg/operator/options/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ type Options struct {
minValuesPolicyRaw string
MinValuesPolicy MinValuesPolicy
FeatureGates FeatureGates
SimplifiedMetrics bool
}

type FlagSet struct {
Expand Down Expand Up @@ -124,6 +125,7 @@ func (o *Options) AddFlags(fs *FlagSet) {
fs.StringVar(&o.preferencePolicyRaw, "preference-policy", env.WithDefaultString("PREFERENCE_POLICY", string(PreferencePolicyRespect)), "How the Karpenter scheduler should treat preferences. Preferences include preferredDuringSchedulingIgnoreDuringExecution node and pod affinities/anti-affinities and ScheduleAnyways topologySpreadConstraints. Can be one of 'Ignore' and 'Respect'")
fs.StringVar(&o.minValuesPolicyRaw, "min-values-policy", env.WithDefaultString("MIN_VALUES_POLICY", string(MinValuesPolicyStrict)), "Min values policy for scheduling. Options include 'Strict' for existing behavior where min values are strictly enforced or 'BestEffort' where Karpenter relaxes min values when it isn't satisfied.")
fs.StringVar(&o.FeatureGates.inputStr, "feature-gates", env.WithDefaultString("FEATURE_GATES", "NodeRepair=false,ReservedCapacity=true,SpotToSpotConsolidation=false,NodeOverlay=false"), "Optional features can be enabled / disabled using feature gates. Current options are: NodeRepair, ReservedCapacity, and SpotToSpotConsolidation.")
fs.BoolVarWithEnv(&o.SimplifiedMetrics, "simplified-metrics", "SIMPLIFIED_METRICS", false, "Optionally disable generic cluster state metrics")
}

func (o *Options) Parse(fs *FlagSet, args ...string) error {
Expand Down
Loading