Skip to content

Commit ce9919c

Browse files
committed
♻️ add min seconds
modified: README.md; modified: charts/kube-reqsizer/Chart.yaml; modified: controllers/pod_controller.go; modified: controllers/pod_controller_functions.go; modified: controllers/pod_controller_types.go; modified: main.go
1 parent e134f6f commit ce9919c

File tree

6 files changed

+56
-35
lines changed

6 files changed

+56
-35
lines changed

README.md

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,33 @@
88
Kube-reqsizer has two primary custom flags:
99

1010
```
11-
-annotation-filter bool
11+
--annotation-filter bool
1212
1313
Enable a annotation filter for pod scraping.
1414
Enabling this will ensure that the controller
1515
only sets requests of controllers of which pods have the annotation.
16-
(auto.request.operator/optimize=true)
1716
18-
-sample-size int
17+
auto.request.operator/optimize=true
1918
20-
The sample size to create an average from when reconciling. (default 1)
19+
--sample-size int (default 1)
20+
21+
The sample size to create an average from when reconciling.
22+
23+
--min-seconds int (default 1)
24+
25+
Minimum seconds between pod restart.
26+
This ensures the controller will not restart a pod if the minimum time
27+
has not passed since it has started sampling it.
2128
```
2229

23-
Sample size is the amount of data-points the controller will store in cache before constructing an average for the pod. After a requests resizing, the cache will clean itself and a new average will be calculated based on the sample size.
30+
Disclaimer:
31+
32+
`sample-size` is the amount of data-points the controller will store in cache before constructing an average for the pod. After a requests resizing, the cache will clean itself and a new average will be calculated based on the sample size. If `min-seconds` has not yet passed since the pod has last been supposed to be sample-reconciled, the controller will keep sampling the pod until `min-seconds` have been reached and only then zero the sample and restart from cache.
2433

2534
## Deploy - Helm
2635

2736
```bash
28-
helm install https://github.com/jatalocks/kube-reqsizer/releases/download/kube-reqsizer-0.1.0/kube-reqsizer-0.1.0.tgz
37+
helm install https://github.com/jatalocks/kube-reqsizer/releases/download/kube-reqsizer-0.2.0/kube-reqsizer-0.2.0.tgz
2938
```
3039
# Development
3140
## Getting Started

charts/kube-reqsizer/Chart.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ 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.1.0
16+
version: 0.2.0
1717
# This is the version number of the application being deployed. This version number should be
1818
# incremented each time you make changes to the application. Versions are not expected to
1919
# follow Semantic Versioning. They should reflect the version the application is using.
2020
# It is recommended to use it with quotes.
21-
appVersion: "0.1.0"
21+
appVersion: "0.2.0"

controllers/pod_controller.go

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -92,12 +92,16 @@ func (r *PodReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.R
9292
LatestPodRequest, err := fetchFromCache(cacheStore, pod.Name)
9393
if err != nil {
9494
SumPodRequest.Sample = 0
95+
SumPodRequest.TimeSinceFirstSample = 0
96+
SumPodRequest.Timestamp = time.Now()
9597
addToCache(cacheStore, SumPodRequest)
9698
} else {
9799
if err != nil {
98100
log.Error(err, err.Error())
99101
} else {
100102
SumPodRequest.Sample = LatestPodRequest.Sample + 1
103+
SumPodRequest.TimeSinceFirstSample = int(time.Since(LatestPodRequest.Timestamp).Seconds())
104+
SumPodRequest.Timestamp = time.Now()
101105
for _, sumC := range SumPodRequest.ContainerRequests {
102106
for _, latestC := range LatestPodRequest.ContainerRequests {
103107
if latestC.Name == sumC.Name {
@@ -118,7 +122,7 @@ func (r *PodReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.R
118122
}
119123
}
120124

121-
if SumPodRequest.Sample == r.SampleSize {
125+
if (SumPodRequest.Sample >= r.SampleSize) && (SumPodRequest.TimeSinceFirstSample >= r.MinSecondsBetweenPodRestart) {
122126
PodChange := false
123127
Requests := []NewContainerRequests{}
124128
log.Info(fmt.Sprint(SumPodRequest))
@@ -133,18 +137,18 @@ func (r *PodReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.R
133137
log.Info(c.Name)
134138
log.Info(fmt.Sprint("Comparing CPU: ", fmt.Sprintf("%dm", AverageUsageCPU), " < ", fmt.Sprintf("%dm", currentC.CPU)))
135139
log.Info(fmt.Sprint("Comparing Memory: ", fmt.Sprintf("%dMi", AverageUsageMemory), " < ", fmt.Sprintf("%dMi", currentC.Memory)))
136-
if AverageUsageCPU < currentC.CPU {
137-
if AverageUsageCPU > 0 {
138-
pod.Spec.Containers[i].Resources.Requests[v1.ResourceCPU] = resource.MustParse(fmt.Sprintf("%dm", AverageUsageCPU))
139-
PodChange = true
140-
}
140+
// if AverageUsageCPU < currentC.CPU {
141+
if AverageUsageCPU > 0 {
142+
pod.Spec.Containers[i].Resources.Requests[v1.ResourceCPU] = resource.MustParse(fmt.Sprintf("%dm", AverageUsageCPU))
143+
PodChange = true
141144
}
142-
if AverageUsageMemory < currentC.Memory {
143-
if AverageUsageMemory > 0 {
144-
pod.Spec.Containers[i].Resources.Requests[v1.ResourceMemory] = resource.MustParse(fmt.Sprintf("%dMi", AverageUsageMemory))
145-
PodChange = true
146-
}
145+
// }
146+
// if AverageUsageMemory < currentC.Memory {
147+
if AverageUsageMemory > 0 {
148+
pod.Spec.Containers[i].Resources.Requests[v1.ResourceMemory] = resource.MustParse(fmt.Sprintf("%dMi", AverageUsageMemory))
149+
PodChange = true
147150
}
151+
// }
148152
Requests = append(Requests, NewContainerRequests{Name: c.Name, Requests: pod.Spec.Containers[i].Resources})
149153
}
150154
}

controllers/pod_controller_functions.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"fmt"
88
"strconv"
99
"strings"
10+
"time"
1011
"unicode/utf8"
1112

1213
"github.com/labstack/gommon/log"
@@ -119,7 +120,7 @@ func GetPodRequests(pod corev1.Pod) PodRequests {
119120
}
120121
containerData = append(containerData, ContainerRequests{Name: c.Name, CPU: int64(nanoCores), Memory: int64(miMemory)})
121122
}
122-
return PodRequests{pod.Name, containerData, 0}
123+
return PodRequests{pod.Name, containerData, 0, 0, time.Now()}
123124
}
124125

125126
func addToCache(cacheStore cache.Store, object PodRequests) error {
@@ -159,5 +160,5 @@ func GeneratePodRequestsObjectFromRestData(restData []byte) PodRequests {
159160
kiMemory, _ := strconv.Atoi(strings.ReplaceAll(c.Usage.Memory, "Ki", ""))
160161
containerData = append(containerData, ContainerRequests{Name: c.Name, CPU: int64(nanoCores / 1000000), Memory: int64(kiMemory / 1000)})
161162
}
162-
return PodRequests{data.Metadata.Name, containerData, 0}
163+
return PodRequests{data.Metadata.Name, containerData, 0, 0, time.Now()}
163164
}

controllers/pod_controller_types.go

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,20 @@ import (
1414
// PodReconciler reconciles a Pod object
1515
type PodReconciler struct {
1616
client.Client
17-
Log logr.Logger
18-
Scheme *runtime.Scheme
19-
ClientSet *kubernetes.Clientset
20-
SampleSize int
21-
EnableAnnotation bool
17+
Log logr.Logger
18+
Scheme *runtime.Scheme
19+
ClientSet *kubernetes.Clientset
20+
SampleSize int
21+
EnableAnnotation bool
22+
MinSecondsBetweenPodRestart int
2223
}
2324

2425
type PodRequests struct {
25-
Name string
26-
ContainerRequests []ContainerRequests
27-
Sample int
26+
Name string
27+
ContainerRequests []ContainerRequests
28+
Sample int
29+
TimeSinceFirstSample int
30+
Timestamp time.Time
2831
}
2932

3033
type ContainerRequests struct {

main.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,12 @@ func main() {
5555
var enableAnnotation bool
5656
var probeAddr string
5757
var sampleSize int
58+
var minSecondsBetweenPodRestart int
5859
flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.")
5960
flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
6061
flag.IntVar(&sampleSize, "sample-size", 1, "The sample size to create an average from when reconciling.")
62+
flag.IntVar(&sampleSize, "min-seconds", 1, "Minimum seconds between pod restart. "+
63+
"This ensures the controller will not restart a pod if the minimum time has not passed since it has started sampling it.")
6164
flag.BoolVar(&enableLeaderElection, "leader-elect", false,
6265
"Enable leader election for controller manager. "+
6366
"Enabling this will ensure there is only one active controller manager.")
@@ -103,12 +106,13 @@ func main() {
103106
}
104107

105108
if err = (&controllers.PodReconciler{
106-
Client: mgr.GetClient(),
107-
Log: ctrl.Log.WithName("controllers").WithName("Pod"),
108-
Scheme: mgr.GetScheme(),
109-
ClientSet: clientset,
110-
SampleSize: sampleSize,
111-
EnableAnnotation: enableAnnotation,
109+
Client: mgr.GetClient(),
110+
Log: ctrl.Log.WithName("controllers").WithName("Pod"),
111+
Scheme: mgr.GetScheme(),
112+
ClientSet: clientset,
113+
SampleSize: sampleSize,
114+
EnableAnnotation: enableAnnotation,
115+
MinSecondsBetweenPodRestart: minSecondsBetweenPodRestart,
112116
}).SetupWithManager(mgr); err != nil {
113117
setupLog.Error(err, "unable to create controller", "controller", "Pod")
114118
log.Error(err, err.Error())

0 commit comments

Comments
 (0)