forked from kubernetes/autoscaler
/
recommender.go
125 lines (110 loc) · 4.72 KB
/
recommender.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"time"
"github.com/golang/glog"
vpa_types "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/apis/poc.autoscaling.k8s.io/v1alpha1"
vpa_clientset "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/client/clientset/versioned"
vpa_api "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/client/clientset/versioned/typed/poc.autoscaling.k8s.io/v1alpha1"
vpa_api_util "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/utils/vpa"
"k8s.io/autoscaler/vertical-pod-autoscaler/recommender/input"
"k8s.io/autoscaler/vertical-pod-autoscaler/recommender/input/history"
"k8s.io/autoscaler/vertical-pod-autoscaler/recommender/logic"
"k8s.io/autoscaler/vertical-pod-autoscaler/recommender/model"
"k8s.io/autoscaler/vertical-pod-autoscaler/recommender/output"
"k8s.io/client-go/rest"
)
// Recommender recommend resources for certain containers, based on utilization periodically got from metrics api.
type Recommender interface {
Run()
}
type recommender struct {
clusterState *model.ClusterState
clusterStateFeeder input.ClusterStateFeeder
checkpointWriter output.CheckpointWriter
metricsFetchingInterval time.Duration
vpaClient vpa_api.VerticalPodAutoscalersGetter
podResourceRecommender logic.PodResourceRecommender
useCheckpoints bool
}
// Updates VPA CRD objects' statuses.
func (r *recommender) updateVPAs() {
for key, vpa := range r.clusterState.Vpas {
glog.V(3).Infof("VPA to update #%v: %+v", key, vpa)
vpa.Conditions.Set(vpa_types.Configured, true, "", "")
resources := r.podResourceRecommender.GetRecommendedPodResources(vpa)
containerResources := make([]vpa_types.RecommendedContainerResources, 0, len(resources))
for containerID, res := range resources {
containerResources = append(containerResources, vpa_types.RecommendedContainerResources{
Name: containerID,
Target: model.ResourcesAsResourceList(res.Target),
MinRecommended: model.ResourcesAsResourceList(res.MinRecommended),
MaxRecommended: model.ResourcesAsResourceList(res.MaxRecommended),
})
}
vpa.Recommendation = &vpa_types.RecommendedPodResources{containerResources}
vpa.Conditions.Set(vpa_types.RecommendationProvided, true, "", "")
_, err := vpa_api_util.UpdateVpaStatus(
r.vpaClient.VerticalPodAutoscalers(vpa.ID.Namespace), vpa)
if err != nil {
glog.Errorf(
"Cannot update VPA %v object. Reason: %+v", vpa.ID.VpaName, err)
}
}
}
// Currently it just prints out current utilization to the console.
// It will be soon replaced by something more useful.
func (r *recommender) runOnce() {
glog.V(3).Infof("Recommender Run")
r.clusterStateFeeder.LoadVPAs()
r.clusterStateFeeder.LoadPods()
r.clusterStateFeeder.LoadRealTimeMetrics()
r.updateVPAs()
glog.V(3).Infof("ClusterState is tracking %v PodStates and %v VPAs", len(r.clusterState.Pods), len(r.clusterState.Vpas))
if r.useCheckpoints {
r.checkpointWriter.StoreCheckpoints()
}
}
func (r *recommender) Run() {
if r.useCheckpoints {
r.clusterStateFeeder.InitFromCheckpoints()
} else {
r.clusterStateFeeder.InitFromHistoryProvider()
}
for {
select {
case <-time.After(r.metricsFetchingInterval):
{
r.runOnce()
}
}
}
}
// NewRecommender creates a new recommender instance,
// which can be run in order to provide continuous resource recommendations for containers.
// It requires cluster configuration object and duration between recommender intervals.
func NewRecommender(config *rest.Config, metricsFetcherInterval time.Duration, historyProvider history.HistoryProvider, useCheckpoints bool) Recommender {
clusterState := model.NewClusterState()
recommender := &recommender{
clusterState: clusterState,
clusterStateFeeder: input.NewClusterStateFeeder(config, historyProvider, clusterState),
checkpointWriter: output.NewCheckpointWriter(clusterState, vpa_clientset.NewForConfigOrDie(config).PocV1alpha1()),
metricsFetchingInterval: metricsFetcherInterval,
vpaClient: vpa_clientset.NewForConfigOrDie(config).PocV1alpha1(),
podResourceRecommender: logic.CreatePodResourceRecommender(),
useCheckpoints: useCheckpoints,
}
glog.V(3).Infof("New Recommender created %+v", recommender)
return recommender
}