Skip to content

Commit ca1d093

Browse files
committed
✨ additional flags
modified: README.md; modified: charts/kube-reqsizer/Chart.yaml; modified: charts/kube-reqsizer/templates/deployment.yaml; modified: charts/kube-reqsizer/values.yaml; modified: controllers/pod_controller.go; modified: controllers/pod_controller_functions.go; modified: controllers/pod_controller_types.go; modified: main.go
1 parent 78c633a commit ca1d093

File tree

8 files changed

+125
-51
lines changed

8 files changed

+125
-51
lines changed

README.md

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,20 @@ helm install kube-reqsizer/kube-reqsizer
1717
```yaml
1818
sampleSize: 1
1919
minSeconds: 1
20+
enableIncrease: true
21+
enableReduce: true
22+
maxMemory: 0
23+
minMemory: 0
24+
maxCPU: 0
25+
minCPU: 0
2026
enabledAnnotation: true
2127
logLevel: info
2228
```
2329
## Description
2430
25-
**kube-reqsizer** has three primary custom flags:
31+
**kube-reqsizer** has primary custom flags:
2632
27-
```
33+
```bash
2834
--annotation-filter bool (default true)
2935

3036
Enable a annotation filter for pod scraping.
@@ -43,6 +49,24 @@ logLevel: info
4349
Minimum seconds between pod restart.
4450
This ensures the controller will not restart a pod if the minimum time
4551
has not passed since it has started sampling it.
52+
53+
--enable-increase (default true)
54+
Enables the controller to increase pod requests
55+
56+
--enable-reduce (default true)
57+
Enables the controller to reduce pod requests
58+
59+
--max-cpu int (default 0)
60+
Maximum CPU in (m) that the controller can set a pod request to. 0 is infinite
61+
62+
--max-memory int (default 0)
63+
Maximum memory in (Mi) that the controller can set a pod request to. 0 is infinite
64+
65+
--min-cpu int (default 0)
66+
Minimum CPU in (m) that the controller can set a pod request to. 0 is infinite
67+
68+
--min-memory int (default 0)
69+
Minimum memory in (Mi) that the controller can set a pod request to. 0 is infinite
4670
```
4771

4872
Disclaimer:

charts/kube-reqsizer/Chart.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@ type: application
1313
# This is the chart version. This version number should be incremented each time you make changes
1414
# to the chart and its templates, including the app version.
1515
# Versions are expected to follow Semantic Versioning (https://semver.org/)
16-
version: 0.6.3
16+
version: 0.6.4

charts/kube-reqsizer/templates/deployment.yaml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,20 @@ spec:
2626
- --sample-size={{.Values.sampleSize}}
2727
- --min-seconds={{.Values.minSeconds}}
2828
- --zap-log-level={{.Values.logLevel}}
29+
- --enable-increase={{.Values.enableIncrease}}
30+
- --enable-reduce={{.Values.enableReduce}}
31+
- --max-cpu={{.Values.maxCPU}}
32+
- --max-memory={{.Values.maxMemory}}
33+
- --min-cpu={{.Values.minCPU}}
34+
- --min-memory={{.Values.minMemory}}
2935
resources:
3036
{{- toYaml .Values.controllerManager.manager.resources | nindent 10 }}
3137
command:
3238
- /manager
3339
env:
3440
- name: KUBERNETES_CLUSTER_DOMAIN
3541
value: {{ .Values.kubernetesClusterDomain }}
36-
image: {{ .Values.controllerManager.manager.image.repository }}:{{ .Values.controllerManager.manager.image.tag | default .Chart.AppVersion }}
42+
image: {{ .Values.controllerManager.manager.image.repository }}:{{ .Values.controllerManager.manager.image.tag }}
3743
imagePullPolicy: Always
3844
livenessProbe:
3945
httpGet:

charts/kube-reqsizer/values.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
sampleSize: 1
22
minSeconds: 1
3+
enableIncrease: true
4+
enableReduce: true
5+
maxMemory: 0
6+
minMemory: 0
7+
maxCPU: 0
8+
minCPU: 0
39
enabledAnnotation: true
410
logLevel: info
511

controllers/pod_controller.go

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,6 @@ func (r *PodReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.R
122122
}
123123
}
124124
log.Info(fmt.Sprint(SumPodRequest))
125-
log.Info(fmt.Sprint(SumPodRequest.TimeSinceFirstSample, ">", r.MinSecondsBetweenPodRestart))
126125
if (SumPodRequest.Sample >= r.SampleSize) && (SumPodRequest.TimeSinceFirstSample >= r.MinSecondsBetweenPodRestart) {
127126
log.Info("Sample Size and Minimum Time have been reached")
128127
PodChange := false
@@ -139,21 +138,21 @@ func (r *PodReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.R
139138
log.Info(fmt.Sprint("Comparing CPU: ", fmt.Sprintf("%dm", AverageUsageCPU), " <> ", fmt.Sprintf("%dm", currentC.CPU)))
140139
log.Info(fmt.Sprint("Comparing Memory: ", fmt.Sprintf("%dMi", AverageUsageMemory), " <> ", fmt.Sprintf("%dMi", currentC.Memory)))
141140
// if AverageUsageCPU < currentC.CPU {
142-
if AverageUsageCPU > 0 {
141+
if r.ValidateCPU(currentC.CPU, AverageUsageCPU) {
143142
if pod.Spec.Containers[i].Resources.Requests != nil {
144143
pod.Spec.Containers[i].Resources.Requests[v1.ResourceCPU] = resource.MustParse(fmt.Sprintf("%dm", AverageUsageCPU))
145144
PodChange = true
146145
}
147146
}
148147
// }
149-
// if AverageUsageMemory < currentC.Memory {
150-
if AverageUsageMemory > 0 {
151-
if pod.Spec.Containers[i].Resources.Requests != nil {
152-
pod.Spec.Containers[i].Resources.Requests[v1.ResourceMemory] = resource.MustParse(fmt.Sprintf("%dMi", AverageUsageMemory))
153-
PodChange = true
148+
if r.ValidateMemory(currentC.Memory, AverageUsageMemory) {
149+
if AverageUsageMemory > 0 {
150+
if pod.Spec.Containers[i].Resources.Requests != nil {
151+
pod.Spec.Containers[i].Resources.Requests[v1.ResourceMemory] = resource.MustParse(fmt.Sprintf("%dMi", AverageUsageMemory))
152+
PodChange = true
153+
}
154154
}
155155
}
156-
// }
157156
Requests = append(Requests, NewContainerRequests{Name: c.Name, Requests: pod.Spec.Containers[i].Resources})
158157
}
159158
}
@@ -170,7 +169,6 @@ func (r *PodReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.R
170169
}
171170

172171
var ownerName string
173-
174172
switch pod.OwnerReferences[0].Kind {
175173
case "ReplicaSet":
176174
replica, err := r.ClientSet.AppsV1().ReplicaSets(pod.Namespace).Get(ctx, pod.OwnerReferences[0].Name, metav1.GetOptions{})
@@ -187,7 +185,9 @@ func (r *PodReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.R
187185
log.Error(err, err.Error())
188186
return ctrl.Result{}, err
189187
}
190-
UpdatePodController(deployment, Requests, ctx)
188+
UpdatePodController(&deployment.Spec.Template.Spec, Requests, ctx)
189+
deployment.Annotations["auto.request.operator/changed"] = "true"
190+
191191
return r.UpdateKubeObject(deployment, ctx)
192192
} else {
193193
log.Info("Is Owned by Unknown CRD")
@@ -202,7 +202,8 @@ func (r *PodReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.R
202202
log.Error(err, err.Error())
203203
return ctrl.Result{}, err
204204
}
205-
UpdatePodController(deployment, Requests, ctx)
205+
UpdatePodController(&deployment.Spec.Template.Spec, Requests, ctx)
206+
deployment.Annotations["auto.request.operator/changed"] = "true"
206207
return r.UpdateKubeObject(deployment, ctx)
207208
case "StatefulSet":
208209
log.Info("Is Owned by StatefulSet")
@@ -214,7 +215,8 @@ func (r *PodReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.R
214215
return ctrl.Result{}, err
215216
}
216217

217-
UpdatePodController(deployment, Requests, ctx)
218+
UpdatePodController(&deployment.Spec.Template.Spec, Requests, ctx)
219+
deployment.Annotations["auto.request.operator/changed"] = "true"
218220
return r.UpdateKubeObject(deployment, ctx)
219221
default:
220222
fmt.Printf("Could not find resource manager for type %s\n", pod.OwnerReferences[0].Kind)

controllers/pod_controller_functions.go

Lines changed: 45 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111
"unicode/utf8"
1212

1313
"github.com/labstack/gommon/log"
14-
v1 "k8s.io/api/apps/v1"
1514
corev1 "k8s.io/api/core/v1"
1615
apierrors "k8s.io/apimachinery/pkg/api/errors"
1716
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -49,43 +48,15 @@ func (r *PodReconciler) UpdateKubeObject(pod client.Object, ctx context.Context)
4948
return ctrl.Result{RequeueAfter: 10 * time.Second}, nil
5049
}
5150

52-
func UpdatePodController(deployment interface{}, Requests []NewContainerRequests, ctx context.Context) {
53-
54-
switch v := deployment.(type) {
55-
case *v1.Deployment:
56-
for _, podContainer := range Requests {
57-
for i, depContainer := range v.Spec.Template.Spec.Containers {
58-
if depContainer.Name == podContainer.Name {
59-
log.Info(fmt.Sprint("Setting", podContainer.Requests))
60-
v.Spec.Template.Spec.Containers[i].Resources = podContainer.Requests
61-
}
51+
func UpdatePodController(podspec *corev1.PodSpec, Requests []NewContainerRequests, ctx context.Context) {
52+
for _, podContainer := range Requests {
53+
for i, depContainer := range podspec.Containers {
54+
if depContainer.Name == podContainer.Name {
55+
log.Info(fmt.Sprint("Setting", podContainer.Requests))
56+
podspec.Containers[i].Resources = podContainer.Requests
6257
}
6358
}
64-
v.Annotations["auto.request.operator/changed"] = "true"
65-
case *v1.DaemonSet:
66-
for _, podContainer := range Requests {
67-
for i, depContainer := range v.Spec.Template.Spec.Containers {
68-
if depContainer.Name == podContainer.Name {
69-
log.Info(fmt.Sprint("Setting", podContainer.Requests))
70-
v.Spec.Template.Spec.Containers[i].Resources = podContainer.Requests
71-
}
72-
}
73-
}
74-
v.Annotations["auto.request.operator/changed"] = "true"
75-
case *v1.StatefulSet:
76-
for _, podContainer := range Requests {
77-
for i, depContainer := range v.Spec.Template.Spec.Containers {
78-
if depContainer.Name == podContainer.Name {
79-
log.Info(fmt.Sprint("Setting", podContainer.Requests))
80-
v.Spec.Template.Spec.Containers[i].Resources = podContainer.Requests
81-
}
82-
}
83-
}
84-
v.Annotations["auto.request.operator/changed"] = "true"
85-
default:
86-
log.Debug("Unsupported type")
8759
}
88-
8960
}
9061

9162
// SetupWithManager sets up the controller with the Manager.
@@ -101,6 +72,45 @@ func RemoveLastChar(str string) string {
10172
}
10273
return str
10374
}
75+
76+
func (r *PodReconciler) ValidateCPU(currentCPU, AverageUsageCPU int64) bool {
77+
if AverageUsageCPU > 0 {
78+
if AverageUsageCPU > currentCPU {
79+
if r.EnableIncrease {
80+
if (AverageUsageCPU <= r.MaxCPU) || (r.MaxCPU == 0) {
81+
return true
82+
}
83+
}
84+
} else {
85+
if r.EnableReduce {
86+
if (AverageUsageCPU >= r.MinCPU) || (r.MinCPU == 0) {
87+
return true
88+
}
89+
}
90+
}
91+
}
92+
return false
93+
}
94+
95+
func (r *PodReconciler) ValidateMemory(currentMemory, AverageUsageMemory int64) bool {
96+
if AverageUsageMemory > 0 {
97+
if AverageUsageMemory > currentMemory {
98+
if r.EnableIncrease {
99+
if (AverageUsageMemory <= r.MaxMemory) || (r.MaxMemory == 0) {
100+
return true
101+
}
102+
}
103+
} else {
104+
if r.EnableReduce {
105+
if (AverageUsageMemory >= r.MinMemory) || (r.MinMemory == 0) {
106+
return true
107+
}
108+
}
109+
}
110+
}
111+
return false
112+
}
113+
104114
func GetPodRequests(pod corev1.Pod) PodRequests {
105115
containerData := []ContainerRequests{}
106116
for _, c := range pod.Spec.Containers {

controllers/pod_controller_types.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ type PodReconciler struct {
2020
SampleSize int
2121
EnableAnnotation bool
2222
MinSecondsBetweenPodRestart float64
23+
EnableIncrease bool
24+
EnableReduce bool
25+
MaxMemory int64
26+
MaxCPU int64
27+
MinMemory int64
28+
MinCPU int64
2329
}
2430

2531
type PodRequests struct {

main.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,20 @@ func main() {
5656
var probeAddr string
5757
var sampleSize int
5858
var minSecondsBetweenPodRestart float64
59+
var enableIncrease bool
60+
var enableReduce bool
61+
var maxMemory int64
62+
var maxCPU int64
63+
var minMemory int64
64+
var minCPU int64
65+
66+
flag.BoolVar(&enableIncrease, "enable-increase", true, "Enables the controller to increase pod requests")
67+
flag.BoolVar(&enableReduce, "enable-reduce", true, "Enables the controller to reduce pod requests")
68+
flag.Int64Var(&maxMemory, "max-memory", 0, "Maximum memory in (Mi) that the controller can set a pod request to. 0 is infinite")
69+
flag.Int64Var(&maxCPU, "max-cpu", 0, "Maximum CPU in (m) that the controller can set a pod request to. 0 is infinite")
70+
flag.Int64Var(&minMemory, "min-memory", 0, "Minimum memory in (Mi) that the controller can set a pod request to. 0 is infinite")
71+
flag.Int64Var(&minCPU, "min-cpu", 0, "Minimum CPU in (m) that the controller can set a pod request to. 0 is infinite")
72+
5973
flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.")
6074
flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
6175
flag.IntVar(&sampleSize, "sample-size", 1, "The sample size to create an average from when reconciling.")
@@ -112,6 +126,12 @@ func main() {
112126
SampleSize: sampleSize,
113127
EnableAnnotation: enableAnnotation,
114128
MinSecondsBetweenPodRestart: minSecondsBetweenPodRestart,
129+
EnableIncrease: enableIncrease,
130+
EnableReduce: enableReduce,
131+
MaxMemory: maxMemory,
132+
MaxCPU: maxCPU,
133+
MinMemory: minMemory,
134+
MinCPU: minCPU,
115135
}).SetupWithManager(mgr); err != nil {
116136
setupLog.Error(err, "unable to create controller", "controller", "Pod")
117137
log.Error(err, err.Error())

0 commit comments

Comments
 (0)