Skip to content

Commit

Permalink
feat: expand VPA to all GMP components
Browse files Browse the repository at this point in the history
  • Loading branch information
bernot-dev committed Jan 14, 2025
1 parent 584732e commit b8427b4
Show file tree
Hide file tree
Showing 6 changed files with 217 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,7 @@ spec:
properties:
enabled:
description: |-
Enabled configures whether the operator configures Vertical Pod Autoscaling for the collector pods.
Enabled configures whether the operator configures Vertical Pod Autoscaling for GMP workloads.
In GKE, installing Vertical Pod Autoscaling requires a cluster restart, and therefore it also results in an operator restart.
In other environments, the operator may need to be restarted to enable VPA to run the following check again and watch for the objects.
type: boolean
Expand Down
2 changes: 1 addition & 1 deletion doc/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -3479,7 +3479,7 @@ bool
</em>
</td>
<td>
<p>Enabled configures whether the operator configures Vertical Pod Autoscaling for the collector pods.
<p>Enabled configures whether the operator configures Vertical Pod Autoscaling for GMP workloads.
In GKE, installing Vertical Pod Autoscaling requires a cluster restart, and therefore it also results in an operator restart.
In other environments, the operator may need to be restarted to enable VPA to run the following check again and watch for the objects.</p>
</td>
Expand Down
2 changes: 1 addition & 1 deletion manifests/setup.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2154,7 +2154,7 @@ spec:
properties:
enabled:
description: |-
Enabled configures whether the operator configures Vertical Pod Autoscaling for the collector pods.
Enabled configures whether the operator configures Vertical Pod Autoscaling for GMP workloads.
In GKE, installing Vertical Pod Autoscaling requires a cluster restart, and therefore it also results in an operator restart.
In other environments, the operator may need to be restarted to enable VPA to run the following check again and watch for the objects.
type: boolean
Expand Down
2 changes: 1 addition & 1 deletion pkg/operator/apis/monitoring/v1/operator_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ type ScalingSpec struct {

// VPASpec defines configuration options for vertical pod autoscaling.
type VPASpec struct {
// Enabled configures whether the operator configures Vertical Pod Autoscaling for the collector pods.
// Enabled configures whether the operator configures Vertical Pod Autoscaling for GMP workloads.
// In GKE, installing Vertical Pod Autoscaling requires a cluster restart, and therefore it also results in an operator restart.
// In other environments, the operator may need to be restarted to enable VPA to run the following check again and watch for the objects.
Enabled bool `json:"enabled,omitempty"`
Expand Down
161 changes: 155 additions & 6 deletions pkg/operator/scaling.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ import (
)

const (
collectorVPAName = "collector"
alertmanagerVPAName = "alertmanager"
collectorVPAName = "collector"
operatorVPAName = "gmp-operator"
ruleEvaluatorVPAName = "rule-evaluator"
)

type scalingReconciler struct {
Expand Down Expand Up @@ -96,14 +99,53 @@ func (r *scalingReconciler) Reconcile(ctx context.Context, req reconcile.Request
}

func applyVPA(ctx context.Context, c client.Client, namespace string) error {
vpa := autoscalingv1.VerticalPodAutoscaler{
alertmanagerVPA := autoscalingv1.VerticalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Namespace: namespace,
Name: alertmanagerVPAName,
},
}
if _, err := controllerutil.CreateOrUpdate(ctx, c, &alertmanagerVPA, func() error {
alertmanagerVPA.Spec = autoscalingv1.VerticalPodAutoscalerSpec{
TargetRef: &autoscaling.CrossVersionObjectReference{
APIVersion: "apps/v1",
Kind: "StatefulSet",
Name: alertmanagerVPAName,
},
UpdatePolicy: &autoscalingv1.PodUpdatePolicy{
MinReplicas: ptr.To(int32(1)),
UpdateMode: ptr.To(autoscalingv1.UpdateModeAuto),
},
ResourcePolicy: &autoscalingv1.PodResourcePolicy{
ContainerPolicies: []autoscalingv1.ContainerResourcePolicy{
{
ContainerName: "alertmanager",
Mode: ptr.To(autoscalingv1.ContainerScalingModeAuto),
MinAllowed: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("1m"),
corev1.ResourceMemory: resource.MustParse("16Mi"),
},
},
{
ContainerName: "config-reloader",
Mode: ptr.To(autoscalingv1.ContainerScalingModeOff),
},
},
},
}
return nil
}); err != nil {
return err
}

collectorVPA := autoscalingv1.VerticalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Namespace: namespace,
Name: collectorVPAName,
},
}
if _, err := controllerutil.CreateOrUpdate(ctx, c, &vpa, func() error {
vpa.Spec = autoscalingv1.VerticalPodAutoscalerSpec{
if _, err := controllerutil.CreateOrUpdate(ctx, c, &collectorVPA, func() error {
collectorVPA.Spec = autoscalingv1.VerticalPodAutoscalerSpec{
TargetRef: &autoscaling.CrossVersionObjectReference{
APIVersion: "apps/v1",
Kind: "DaemonSet",
Expand All @@ -118,6 +160,7 @@ func applyVPA(ctx context.Context, c client.Client, namespace string) error {
ContainerName: "prometheus",
Mode: ptr.To(autoscalingv1.ContainerScalingModeAuto),
MinAllowed: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("4m"),
corev1.ResourceMemory: resource.MustParse("32Mi"),
},
},
Expand All @@ -132,18 +175,124 @@ func applyVPA(ctx context.Context, c client.Client, namespace string) error {
}); err != nil {
return err
}

operatorVPA := autoscalingv1.VerticalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Namespace: namespace,
Name: operatorVPAName,
},
}
if _, err := controllerutil.CreateOrUpdate(ctx, c, &operatorVPA, func() error {
collectorVPA.Spec = autoscalingv1.VerticalPodAutoscalerSpec{
TargetRef: &autoscaling.CrossVersionObjectReference{
APIVersion: "apps/v1",
Kind: "Deployment",
Name: operatorVPAName,
},
UpdatePolicy: &autoscalingv1.PodUpdatePolicy{
MinReplicas: ptr.To(int32(1)),
UpdateMode: ptr.To(autoscalingv1.UpdateModeAuto),
},
ResourcePolicy: &autoscalingv1.PodResourcePolicy{
ContainerPolicies: []autoscalingv1.ContainerResourcePolicy{
{
ContainerName: "operator",
Mode: ptr.To(autoscalingv1.ContainerScalingModeAuto),
MinAllowed: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("1m"),
corev1.ResourceMemory: resource.MustParse("16Mi"),
},
},
},
},
}
return nil
}); err != nil {
return err
}

ruleEvaluatorVPA := autoscalingv1.VerticalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Namespace: namespace,
Name: ruleEvaluatorVPAName,
},
}
if _, err := controllerutil.CreateOrUpdate(ctx, c, &ruleEvaluatorVPA, func() error {
collectorVPA.Spec = autoscalingv1.VerticalPodAutoscalerSpec{
TargetRef: &autoscaling.CrossVersionObjectReference{
APIVersion: "apps/v1",
Kind: "Deployment",
Name: ruleEvaluatorVPAName,
},
UpdatePolicy: &autoscalingv1.PodUpdatePolicy{
MinReplicas: ptr.To(int32(1)),
UpdateMode: ptr.To(autoscalingv1.UpdateModeAuto),
},
ResourcePolicy: &autoscalingv1.PodResourcePolicy{
ContainerPolicies: []autoscalingv1.ContainerResourcePolicy{
{
ContainerName: "evaluator",
Mode: ptr.To(autoscalingv1.ContainerScalingModeAuto),
MinAllowed: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("1m"),
corev1.ResourceMemory: resource.MustParse("16Mi"),
},
},
{
ContainerName: "config-reloader",
Mode: ptr.To(autoscalingv1.ContainerScalingModeOff),
},
},
},
}
return nil
}); err != nil {
return err
}

return nil
}

func deleteVPA(ctx context.Context, c client.Writer, namespace string) error {
vpa := autoscalingv1.VerticalPodAutoscaler{
alertmanagerVPA := autoscalingv1.VerticalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: alertmanagerVPAName,
Namespace: namespace,
},
}
if err := c.Delete(ctx, &alertmanagerVPA); client.IgnoreNotFound(err) != nil {
return err
}

collectorVPA := autoscalingv1.VerticalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: collectorVPAName,
Namespace: namespace,
},
}
if err := c.Delete(ctx, &vpa); client.IgnoreNotFound(err) != nil {
if err := c.Delete(ctx, &collectorVPA); client.IgnoreNotFound(err) != nil {
return err
}

operatorVPA := autoscalingv1.VerticalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: operatorVPAName,
Namespace: namespace,
},
}
if err := c.Delete(ctx, &operatorVPA); client.IgnoreNotFound(err) != nil {
return err
}

ruleEvaluatorVPA := autoscalingv1.VerticalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: ruleEvaluatorVPAName,
Namespace: namespace,
},
}
if err := c.Delete(ctx, &ruleEvaluatorVPA); client.IgnoreNotFound(err) != nil {
return err
}

return nil
}
64 changes: 58 additions & 6 deletions pkg/operator/scaling_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,26 @@ import (
)

func TestApplyVPA(t *testing.T) {
vpa := autoscalingv1.VerticalPodAutoscaler{
alertmanagerVPA := autoscalingv1.VerticalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: alertmanagerVPAName,
},
}
collectorVPA := autoscalingv1.VerticalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: collectorVPAName,
},
}
operatorVPA := autoscalingv1.VerticalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: operatorVPAName,
},
}
ruleEvaluatorVPA := autoscalingv1.VerticalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: ruleEvaluatorVPAName,
},
}

scheme, err := NewScheme()
if err != nil {
Expand All @@ -59,7 +74,7 @@ func TestApplyVPA(t *testing.T) {
wantErr: true,
},
"update": {
c: fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(&vpa).Build(),
c: fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(&alertmanagerVPA, &collectorVPA, &operatorVPA, &ruleEvaluatorVPA).Build(),
},
}

Expand All @@ -74,18 +89,44 @@ func TestApplyVPA(t *testing.T) {
case err != nil && tc.wantErr:
// Ok
case err == nil && !tc.wantErr:
// Ok
if err := tc.c.Get(context.TODO(), client.ObjectKey{Name: alertmanagerVPAName}, &autoscalingv1.VerticalPodAutoscaler{}); err != nil {
t.Error(err)
}
if err := tc.c.Get(context.TODO(), client.ObjectKey{Name: collectorVPAName}, &autoscalingv1.VerticalPodAutoscaler{}); err != nil {
t.Error(err)
}
if err := tc.c.Get(context.TODO(), client.ObjectKey{Name: operatorVPAName}, &autoscalingv1.VerticalPodAutoscaler{}); err != nil {
t.Error(err)
}
if err := tc.c.Get(context.TODO(), client.ObjectKey{Name: ruleEvaluatorVPAName}, &autoscalingv1.VerticalPodAutoscaler{}); err != nil {
t.Error(err)
}
}
})
}
}

func TestDeleteVPA(t *testing.T) {
vpa := autoscalingv1.VerticalPodAutoscaler{
alertmanagerVPA := autoscalingv1.VerticalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: alertmanagerVPAName,
},
}
collectorVPA := autoscalingv1.VerticalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: collectorVPAName,
},
}
operatorVPA := autoscalingv1.VerticalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: operatorVPAName,
},
}
ruleEvaluatorVPA := autoscalingv1.VerticalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: ruleEvaluatorVPAName,
},
}

scheme, err := NewScheme()
if err != nil {
Expand Down Expand Up @@ -113,7 +154,7 @@ func TestDeleteVPA(t *testing.T) {
c: fake.NewClientBuilder().WithScheme(scheme).WithInterceptorFuncs(deleteInterceptorWithNotFoundError).Build(),
},
"ok": {
c: fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(&vpa).Build(),
c: fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(&alertmanagerVPA, &collectorVPA, &operatorVPA, &ruleEvaluatorVPA).Build(),
},
"err": {
c: fake.NewClientBuilder().WithScheme(scheme).WithInterceptorFuncs(deleteInterceptorWithError).Build(),
Expand All @@ -132,7 +173,18 @@ func TestDeleteVPA(t *testing.T) {
case err != nil && tc.wantErr:
// Ok
case err == nil && !tc.wantErr:
// Ok
if err := tc.c.Get(context.TODO(), client.ObjectKey{Name: alertmanagerVPAName}, &autoscalingv1.VerticalPodAutoscaler{}); !apierrors.IsNotFound(err) {
t.Errorf("expected not found, got %s", err)
}
if err := tc.c.Get(context.TODO(), client.ObjectKey{Name: collectorVPAName}, &autoscalingv1.VerticalPodAutoscaler{}); !apierrors.IsNotFound(err) {
t.Errorf("expected not found, got %s", err)
}
if err := tc.c.Get(context.TODO(), client.ObjectKey{Name: operatorVPAName}, &autoscalingv1.VerticalPodAutoscaler{}); !apierrors.IsNotFound(err) {
t.Errorf("expected not found, got %s", err)
}
if err := tc.c.Get(context.TODO(), client.ObjectKey{Name: ruleEvaluatorVPAName}, &autoscalingv1.VerticalPodAutoscaler{}); !apierrors.IsNotFound(err) {
t.Errorf("expected not found, got %s", err)
}
}
})
}
Expand Down

0 comments on commit b8427b4

Please sign in to comment.