diff --git a/pkg/apis/eksctl.io/v1alpha5/assets/schema.json b/pkg/apis/eksctl.io/v1alpha5/assets/schema.json index c6e41046c6..d7bb7aa919 100755 --- a/pkg/apis/eksctl.io/v1alpha5/assets/schema.json +++ b/pkg/apis/eksctl.io/v1alpha5/assets/schema.json @@ -1656,10 +1656,16 @@ "$ref": "#/definitions/HorizontalPodAutoscalerControllerConfig", "description": "specifies the horizontal pod autoscaler controller configuration.", "x-intellij-html-description": "specifies the horizontal pod autoscaler controller configuration." + }, + "podGCControllerConfig": { + "$ref": "#/definitions/PodGCControllerConfig", + "description": "specifies the pod garbage collector controller configuration.", + "x-intellij-html-description": "specifies the pod garbage collector controller configuration." } }, "preferredOrder": [ - "horizontalPodAutoscalerControllerConfig" + "horizontalPodAutoscalerControllerConfig", + "podGCControllerConfig" ], "additionalProperties": false, "description": "holds the kube-controller-manager configuration.", @@ -2981,6 +2987,21 @@ "description": "specifies placement group information", "x-intellij-html-description": "specifies placement group information" }, + "PodGCControllerConfig": { + "properties": { + "terminatedPodGCThreshold": { + "type": "integer", + "description": "specifies the number of terminated pods that can exist before the pod garbage collector starts deleting terminated pods.", + "x-intellij-html-description": "specifies the number of terminated pods that can exist before the pod garbage collector starts deleting terminated pods." + } + }, + "preferredOrder": [ + "terminatedPodGCThreshold" + ], + "additionalProperties": false, + "description": "holds the pod garbage collector controller configuration.", + "x-intellij-html-description": "holds the pod garbage collector controller configuration." + }, "PodIdentityAssociation": { "properties": { "createServiceAccount": { diff --git a/pkg/apis/eksctl.io/v1alpha5/types.go b/pkg/apis/eksctl.io/v1alpha5/types.go index 56f8105156..279bc1f80b 100644 --- a/pkg/apis/eksctl.io/v1alpha5/types.go +++ b/pkg/apis/eksctl.io/v1alpha5/types.go @@ -1222,6 +1222,10 @@ type KubeControllerManagerConfig struct { // controller configuration. // +optional HorizontalPodAutoscalerControllerConfig *HorizontalPodAutoscalerControllerConfig `json:"horizontalPodAutoscalerControllerConfig,omitempty"` + + // PodGCControllerConfig specifies the pod garbage collector controller configuration. + // +optional + PodGCControllerConfig *PodGCControllerConfig `json:"podGCControllerConfig,omitempty"` } // HorizontalPodAutoscalerControllerConfig holds the horizontal pod autoscaler controller configuration. @@ -1232,6 +1236,14 @@ type HorizontalPodAutoscalerControllerConfig struct { HorizontalPodAutoscalerSyncPeriod *string `json:"horizontalPodAutoscalerSyncPeriod,omitempty"` } +// PodGCControllerConfig holds the pod garbage collector controller configuration. +type PodGCControllerConfig struct { + // TerminatedPodGCThreshold specifies the number of terminated pods that can exist + // before the pod garbage collector starts deleting terminated pods. + // +optional + TerminatedPodGCThreshold *int `json:"terminatedPodGCThreshold,omitempty"` +} + // OutpostInfo describes the Outpost info. type OutpostInfo interface { // IsControlPlaneOnOutposts returns true if the control plane is on Outposts. diff --git a/pkg/apis/eksctl.io/v1alpha5/zz_generated.deepcopy.go b/pkg/apis/eksctl.io/v1alpha5/zz_generated.deepcopy.go index 02793615c1..6059f176a3 100644 --- a/pkg/apis/eksctl.io/v1alpha5/zz_generated.deepcopy.go +++ b/pkg/apis/eksctl.io/v1alpha5/zz_generated.deepcopy.go @@ -1654,6 +1654,11 @@ func (in *KubeControllerManagerConfig) DeepCopyInto(out *KubeControllerManagerCo *out = new(HorizontalPodAutoscalerControllerConfig) (*in).DeepCopyInto(*out) } + if in.PodGCControllerConfig != nil { + in, out := &in.PodGCControllerConfig, &out.PodGCControllerConfig + *out = new(PodGCControllerConfig) + (*in).DeepCopyInto(*out) + } return } @@ -2519,6 +2524,27 @@ func (in *Placement) DeepCopy() *Placement { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodGCControllerConfig) DeepCopyInto(out *PodGCControllerConfig) { + *out = *in + if in.TerminatedPodGCThreshold != nil { + in, out := &in.TerminatedPodGCThreshold, &out.TerminatedPodGCThreshold + *out = new(int) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodGCControllerConfig. +func (in *PodGCControllerConfig) DeepCopy() *PodGCControllerConfig { + if in == nil { + return nil + } + out := new(PodGCControllerConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PodIdentityAssociation) DeepCopyInto(out *PodIdentityAssociation) { *out = *in @@ -2718,6 +2744,32 @@ func (in *RemoteNodesIAM) DeepCopy() *RemoteNodesIAM { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ResourceWeight) DeepCopyInto(out *ResourceWeight) { + *out = *in + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(string) + **out = **in + } + if in.Weight != nil { + in, out := &in.Weight, &out.Weight + *out = new(int) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceWeight. +func (in *ResourceWeight) DeepCopy() *ResourceWeight { + if in == nil { + return nil + } + out := new(ResourceWeight) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RollbackConfig) DeepCopyInto(out *RollbackConfig) { *out = *in @@ -2786,32 +2838,6 @@ func (in *ScalingConfig) DeepCopy() *ScalingConfig { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ResourceWeight) DeepCopyInto(out *ResourceWeight) { - *out = *in - if in.Name != nil { - in, out := &in.Name, &out.Name - *out = new(string) - **out = **in - } - if in.Weight != nil { - in, out := &in.Weight, &out.Weight - *out = new(int) - **out = **in - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceWeight. -func (in *ResourceWeight) DeepCopy() *ResourceWeight { - if in == nil { - return nil - } - out := new(ResourceWeight) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ScoringStrategy) DeepCopyInto(out *ScoringStrategy) { *out = *in diff --git a/pkg/cfn/builder/cluster.go b/pkg/cfn/builder/cluster.go index 48b19b1f4b..914864f98d 100644 --- a/pkg/cfn/builder/cluster.go +++ b/pkg/cfn/builder/cluster.go @@ -706,16 +706,25 @@ func makeKubeSchedulerConfig(config *api.KubeSchedulerConfig) *gfneks.Cluster_Ku // CloudFormation representation. It returns nil if no values are set, so that the property // is omitted from the template entirely. func makeKubeControllerManagerConfig(config *api.KubeControllerManagerConfig) *gfneks.Cluster_KubeControllerManagerConfig { - if config == nil || config.HorizontalPodAutoscalerControllerConfig == nil { - return nil - } - hpaConfig := config.HorizontalPodAutoscalerControllerConfig - if hpaConfig.HorizontalPodAutoscalerSyncPeriod == nil { + if config == nil { return nil } - return &gfneks.Cluster_KubeControllerManagerConfig{ - HorizontalPodAutoscalerControllerConfig: &gfneks.Cluster_HorizontalPodAutoscalerControllerConfig{ + result := &gfneks.Cluster_KubeControllerManagerConfig{} + set := false + if hpaConfig := config.HorizontalPodAutoscalerControllerConfig; hpaConfig != nil && hpaConfig.HorizontalPodAutoscalerSyncPeriod != nil { + result.HorizontalPodAutoscalerControllerConfig = &gfneks.Cluster_HorizontalPodAutoscalerControllerConfig{ HorizontalPodAutoscalerSyncPeriod: gfnt.NewString(*hpaConfig.HorizontalPodAutoscalerSyncPeriod), - }, + } + set = true + } + if podGCConfig := config.PodGCControllerConfig; podGCConfig != nil && podGCConfig.TerminatedPodGCThreshold != nil { + result.PodGcControllerConfig = &gfneks.Cluster_PodGcControllerConfig{ + TerminatedPodGcThreshold: gfnt.NewInteger(*podGCConfig.TerminatedPodGCThreshold), + } + set = true + } + if !set { + return nil } + return result } diff --git a/pkg/cfn/builder/cluster_component_config_test.go b/pkg/cfn/builder/cluster_component_config_test.go index b3766c4a3f..192876dbb4 100644 --- a/pkg/cfn/builder/cluster_component_config_test.go +++ b/pkg/cfn/builder/cluster_component_config_test.go @@ -282,6 +282,42 @@ var _ = Describe("control plane component config template properties", func() { }, }, }), + Entry("empty pod GC config is omitted", entry{ + config: &api.KubeControllerManagerConfig{ + PodGCControllerConfig: &api.PodGCControllerConfig{}, + }, + expected: nil, + }), + Entry("terminated pod GC threshold set", entry{ + config: &api.KubeControllerManagerConfig{ + PodGCControllerConfig: &api.PodGCControllerConfig{ + TerminatedPodGCThreshold: aws.Int(12000), + }, + }, + expected: &gfneks.Cluster_KubeControllerManagerConfig{ + PodGcControllerConfig: &gfneks.Cluster_PodGcControllerConfig{ + TerminatedPodGcThreshold: gfnt.NewInteger(12000), + }, + }, + }), + Entry("both sync period and terminated pod GC threshold set", entry{ + config: &api.KubeControllerManagerConfig{ + HorizontalPodAutoscalerControllerConfig: &api.HorizontalPodAutoscalerControllerConfig{ + HorizontalPodAutoscalerSyncPeriod: aws.String("15s"), + }, + PodGCControllerConfig: &api.PodGCControllerConfig{ + TerminatedPodGCThreshold: aws.Int(12000), + }, + }, + expected: &gfneks.Cluster_KubeControllerManagerConfig{ + HorizontalPodAutoscalerControllerConfig: &gfneks.Cluster_HorizontalPodAutoscalerControllerConfig{ + HorizontalPodAutoscalerSyncPeriod: gfnt.NewString("15s"), + }, + PodGcControllerConfig: &gfneks.Cluster_PodGcControllerConfig{ + TerminatedPodGcThreshold: gfnt.NewInteger(12000), + }, + }, + }), ) }) }) diff --git a/pkg/ctl/utils/update_control_plane_component_config.go b/pkg/ctl/utils/update_control_plane_component_config.go index f2cedf7d74..b0d9acd5e8 100644 --- a/pkg/ctl/utils/update_control_plane_component_config.go +++ b/pkg/ctl/utils/update_control_plane_component_config.go @@ -151,16 +151,25 @@ func makeKubeSchedulerConfigRequest(config *api.KubeSchedulerConfig) *ekstypes.K // component is omitted from the request entirely and left unchanged. // It mirrors makeKubeControllerManagerConfig in pkg/cfn/builder/cluster.go. func makeKubeControllerManagerConfigRequest(config *api.KubeControllerManagerConfig) *ekstypes.KubeControllerManagerConfigRequest { - if config == nil || config.HorizontalPodAutoscalerControllerConfig == nil { - return nil - } - hpaConfig := config.HorizontalPodAutoscalerControllerConfig - if hpaConfig.HorizontalPodAutoscalerSyncPeriod == nil { + if config == nil { return nil } - return &ekstypes.KubeControllerManagerConfigRequest{ - HorizontalPodAutoscalerControllerConfig: &ekstypes.HorizontalPodAutoscalerControllerConfigRequest{ + result := &ekstypes.KubeControllerManagerConfigRequest{} + set := false + if hpaConfig := config.HorizontalPodAutoscalerControllerConfig; hpaConfig != nil && hpaConfig.HorizontalPodAutoscalerSyncPeriod != nil { + result.HorizontalPodAutoscalerControllerConfig = &ekstypes.HorizontalPodAutoscalerControllerConfigRequest{ HorizontalPodAutoscalerSyncPeriod: hpaConfig.HorizontalPodAutoscalerSyncPeriod, - }, + } + set = true + } + if podGCConfig := config.PodGCControllerConfig; podGCConfig != nil && podGCConfig.TerminatedPodGCThreshold != nil { + result.PodGcControllerConfig = &ekstypes.PodGcControllerConfigRequest{ + TerminatedPodGcThreshold: aws.Int32(int32(*podGCConfig.TerminatedPodGCThreshold)), + } + set = true + } + if !set { + return nil } + return result } diff --git a/pkg/ctl/utils/update_control_plane_component_config_request_test.go b/pkg/ctl/utils/update_control_plane_component_config_request_test.go index 8a022e7b60..2af76f298c 100644 --- a/pkg/ctl/utils/update_control_plane_component_config_request_test.go +++ b/pkg/ctl/utils/update_control_plane_component_config_request_test.go @@ -250,6 +250,42 @@ var _ = Describe("control plane component config update requests", func() { }, }, }), + Entry("empty pod GC config is not sent", entry{ + config: &api.KubeControllerManagerConfig{ + PodGCControllerConfig: &api.PodGCControllerConfig{}, + }, + expected: nil, + }), + Entry("terminated pod GC threshold set", entry{ + config: &api.KubeControllerManagerConfig{ + PodGCControllerConfig: &api.PodGCControllerConfig{ + TerminatedPodGCThreshold: aws.Int(12000), + }, + }, + expected: &ekstypes.KubeControllerManagerConfigRequest{ + PodGcControllerConfig: &ekstypes.PodGcControllerConfigRequest{ + TerminatedPodGcThreshold: aws.Int32(12000), + }, + }, + }), + Entry("both sync period and terminated pod GC threshold set", entry{ + config: &api.KubeControllerManagerConfig{ + HorizontalPodAutoscalerControllerConfig: &api.HorizontalPodAutoscalerControllerConfig{ + HorizontalPodAutoscalerSyncPeriod: aws.String("15s"), + }, + PodGCControllerConfig: &api.PodGCControllerConfig{ + TerminatedPodGCThreshold: aws.Int(12000), + }, + }, + expected: &ekstypes.KubeControllerManagerConfigRequest{ + HorizontalPodAutoscalerControllerConfig: &ekstypes.HorizontalPodAutoscalerControllerConfigRequest{ + HorizontalPodAutoscalerSyncPeriod: aws.String("15s"), + }, + PodGcControllerConfig: &ekstypes.PodGcControllerConfigRequest{ + TerminatedPodGcThreshold: aws.Int32(12000), + }, + }, + }), ) }) }) diff --git a/pkg/goformation/cloudformation/eks/aws-eks-cluster_kubecontrollermanagerconfig.go b/pkg/goformation/cloudformation/eks/aws-eks-cluster_kubecontrollermanagerconfig.go index feb3c323d7..ed9da6739c 100644 --- a/pkg/goformation/cloudformation/eks/aws-eks-cluster_kubecontrollermanagerconfig.go +++ b/pkg/goformation/cloudformation/eks/aws-eks-cluster_kubecontrollermanagerconfig.go @@ -13,6 +13,11 @@ type Cluster_KubeControllerManagerConfig struct { // See: https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-properties-eks-cluster-kubecontrollermanagerconfig.html#cfn-eks-cluster-kubecontrollermanagerconfig-horizontalpodautoscalercontrollerconfig HorizontalPodAutoscalerControllerConfig *Cluster_HorizontalPodAutoscalerControllerConfig `json:"HorizontalPodAutoscalerControllerConfig,omitempty"` + // PodGcControllerConfig AWS CloudFormation Property + // Required: false + // See: https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-properties-eks-cluster-kubecontrollermanagerconfig.html#cfn-eks-cluster-kubecontrollermanagerconfig-podgccontrollerconfig + PodGcControllerConfig *Cluster_PodGcControllerConfig `json:"PodGcControllerConfig,omitempty"` + // AWSCloudFormationDeletionPolicy represents a CloudFormation DeletionPolicy AWSCloudFormationDeletionPolicy policies.DeletionPolicy `json:"-"` diff --git a/pkg/goformation/cloudformation/eks/aws-eks-cluster_podgccontrollerconfig.go b/pkg/goformation/cloudformation/eks/aws-eks-cluster_podgccontrollerconfig.go new file mode 100644 index 0000000000..76b1180e13 --- /dev/null +++ b/pkg/goformation/cloudformation/eks/aws-eks-cluster_podgccontrollerconfig.go @@ -0,0 +1,36 @@ +package eks + +import ( + "github.com/weaveworks/eksctl/pkg/goformation/cloudformation/policies" + "github.com/weaveworks/eksctl/pkg/goformation/cloudformation/types" +) + +// Cluster_PodGcControllerConfig AWS CloudFormation Resource (AWS::EKS::Cluster.PodGcControllerConfig) +// See: https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-properties-eks-cluster-podgccontrollerconfig.html +type Cluster_PodGcControllerConfig struct { + + // TerminatedPodGcThreshold AWS CloudFormation Property + // Required: false + // See: https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-properties-eks-cluster-podgccontrollerconfig.html#cfn-eks-cluster-podgccontrollerconfig-terminatedpodgcthreshold + TerminatedPodGcThreshold *types.Value `json:"TerminatedPodGcThreshold,omitempty"` + + // AWSCloudFormationDeletionPolicy represents a CloudFormation DeletionPolicy + AWSCloudFormationDeletionPolicy policies.DeletionPolicy `json:"-"` + + // AWSCloudFormationUpdateReplacePolicy represents a CloudFormation UpdateReplacePolicy + AWSCloudFormationUpdateReplacePolicy policies.UpdateReplacePolicy `json:"-"` + + // AWSCloudFormationDependsOn stores the logical ID of the resources to be created before this resource + AWSCloudFormationDependsOn []string `json:"-"` + + // AWSCloudFormationMetadata stores structured data associated with this resource + AWSCloudFormationMetadata map[string]interface{} `json:"-"` + + // AWSCloudFormationCondition stores the logical ID of the condition that must be satisfied for this resource to be created + AWSCloudFormationCondition string `json:"-"` +} + +// AWSCloudFormationType returns the AWS CloudFormation resource type +func (r *Cluster_PodGcControllerConfig) AWSCloudFormationType() string { + return "AWS::EKS::Cluster.PodGcControllerConfig" +} diff --git a/userdocs/src/usage/control-plane-component-config.md b/userdocs/src/usage/control-plane-component-config.md index 645ab72804..7d2c3aa747 100644 --- a/userdocs/src/usage/control-plane-component-config.md +++ b/userdocs/src/usage/control-plane-component-config.md @@ -38,6 +38,8 @@ kubeSchedulerConfig: kubeControllerManagerConfig: horizontalPodAutoscalerControllerConfig: horizontalPodAutoscalerSyncPeriod: 15s + podGCControllerConfig: + terminatedPodGCThreshold: 12000 ``` ```shell @@ -98,11 +100,18 @@ look after a pod is placed on them. kubeControllerManagerConfig: horizontalPodAutoscalerControllerConfig: horizontalPodAutoscalerSyncPeriod: 15s + podGCControllerConfig: + terminatedPodGCThreshold: 12000 ``` - `horizontalPodAutoscalerSyncPeriod` — the interval between horizontal pod autoscaler syncs, as a duration string such as `15s`. Shorter intervals make autoscaling more responsive at the cost of more frequent - metric queries. + metric queries. Only configurable on provisioned control plane (PCP) scaling tiers (for example `tier-xl`); + on the Standard tier it is fixed at the default (15s). +- `terminatedPodGCThreshold` — the number of terminated pods that can accumulate before the pod garbage + collector starts deleting them. Lower values reclaim resources sooner; higher values keep more terminated + pods around for inspection. Only configurable on provisioned control plane (PCP) scaling tiers (for example + `tier-xl`); on the Standard tier it is fixed at the default (12500). ## Notes