Skip to content
This repository was archived by the owner on Apr 17, 2019. It is now read-only.

Commit 9a5da01

Browse files
committed
Merge pull request #1124 from piosz/nanny
[Addon resizer] Added ExponentialEstimator to pod nanny
2 parents d6ee218 + a434839 commit 9a5da01

File tree

731 files changed

+459434
-22
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

731 files changed

+459434
-22
lines changed

addon-resizer/Godeps/Godeps.json

Lines changed: 566 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

addon-resizer/Godeps/Readme

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

addon-resizer/nanny/estimator.go

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@ import (
2020
api "k8s.io/kubernetes/pkg/api/v1"
2121

2222
"k8s.io/kubernetes/pkg/api/resource"
23+
)
2324

24-
inf "speter.net/go/exp/math/dec/inf"
25+
const (
26+
eps = float64(0.01)
2527
)
2628

2729
// Resource defines the name of a resource, the quantity, and the marginal value.
@@ -36,20 +38,33 @@ type LinearEstimator struct {
3638
}
3739

3840
func (e LinearEstimator) scaleWithNodes(numNodes uint64) *api.ResourceRequirements {
41+
return calculateResources(numNodes, e.Resources)
42+
}
43+
44+
// ExponentialEstimator estimates the amount of resources in the way that
45+
// prevents from frequent updates but may end up with larger resource usage
46+
// than actually needed (though no more than ScaleFactor).
47+
type ExponentialEstimator struct {
48+
Resources []Resource
49+
ScaleFactor float64
50+
}
51+
52+
func (e ExponentialEstimator) scaleWithNodes(numNodes uint64) *api.ResourceRequirements {
53+
n := uint64(16)
54+
for n < numNodes {
55+
n = uint64(float64(n)*e.ScaleFactor + eps)
56+
}
57+
return calculateResources(n, e.Resources)
58+
}
59+
60+
func calculateResources(numNodes uint64, resources []Resource) *api.ResourceRequirements {
3961
limits := make(api.ResourceList)
4062
requests := make(api.ResourceList)
41-
for _, r := range e.Resources {
42-
num := inf.NewDec(int64(numNodes), 0)
43-
num.Mul(num, r.ExtraPerNode.Amount)
44-
num.Add(num, r.Base.Amount)
45-
limits[r.Name] = resource.Quantity{
46-
Amount: num,
47-
Format: r.Base.Format,
48-
}
49-
requests[r.Name] = resource.Quantity{
50-
Amount: num,
51-
Format: r.Base.Format,
52-
}
63+
for _, r := range resources {
64+
val := r.Base.MilliValue() + r.ExtraPerNode.MilliValue()*int64(numNodes)
65+
newRes := resource.NewMilliQuantity(val, r.Base.Format)
66+
limits[r.Name] = *newRes
67+
requests[r.Name] = *newRes
5368
}
5469
return &api.ResourceRequirements{
5570
Limits: limits,

addon-resizer/nanny/estimator_test.go

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ limitations under the License.
1717
package nanny
1818

1919
import (
20-
"reflect"
2120
"testing"
2221

2322
resource "k8s.io/kubernetes/pkg/api/resource"
@@ -90,6 +89,27 @@ var (
9089
Resources: []Resource{},
9190
}
9291

92+
exponentialEstimator = ExponentialEstimator{
93+
Resources: []Resource{
94+
{
95+
Base: resource.MustParse("0.3"),
96+
ExtraPerNode: resource.MustParse("1"),
97+
Name: "cpu",
98+
},
99+
{
100+
Base: resource.MustParse("30Mi"),
101+
ExtraPerNode: resource.MustParse("1Mi"),
102+
Name: "memory",
103+
},
104+
{
105+
Base: resource.MustParse("30Gi"),
106+
ExtraPerNode: resource.MustParse("1Gi"),
107+
Name: "storage",
108+
},
109+
},
110+
ScaleFactor: 1.5,
111+
}
112+
93113
baseResources = api.ResourceList{
94114
"cpu": resource.MustParse("0.3"),
95115
"memory": resource.MustParse("30Mi"),
@@ -126,8 +146,34 @@ var (
126146
"memory": resource.MustParse("33Mi"),
127147
}
128148
noResources = api.ResourceList{}
149+
150+
sixteenNodeResources = api.ResourceList{
151+
"cpu": resource.MustParse("16.3"),
152+
"memory": resource.MustParse("46Mi"),
153+
"storage": resource.MustParse("46Gi"),
154+
}
155+
twentyFourNodeResources = api.ResourceList{
156+
"cpu": resource.MustParse("24.3"),
157+
"memory": resource.MustParse("54Mi"),
158+
"storage": resource.MustParse("54Gi"),
159+
}
129160
)
130161

162+
func verifyResources(t *testing.T, kind string, got, want api.ResourceList) {
163+
if len(got) != len(want) {
164+
t.Errorf("%s not equal got: %+v want: %+v", kind, got, want)
165+
}
166+
for res, val := range want {
167+
actVal, ok := got[res]
168+
if !ok {
169+
t.Errorf("missing resource %s in %s", res, kind)
170+
}
171+
if val.Cmp(actVal) != 0 {
172+
t.Errorf("not equal resource %s in %s, got: %+v, want: %+v", res, kind, actVal, val)
173+
}
174+
}
175+
}
176+
131177
func TestEstimateResources(t *testing.T) {
132178
testCases := []struct {
133179
e ResourceEstimator
@@ -137,6 +183,8 @@ func TestEstimateResources(t *testing.T) {
137183
}{
138184
{fullEstimator, 0, baseResources, baseResources},
139185
{fullEstimator, 3, threeNodeResources, threeNodeResources},
186+
{fullEstimator, 16, sixteenNodeResources, sixteenNodeResources},
187+
{fullEstimator, 24, twentyFourNodeResources, twentyFourNodeResources},
140188
{noCPUEstimator, 0, noCPUBaseResources, noCPUBaseResources},
141189
{noCPUEstimator, 3, threeNodeNoCPUResources, threeNodeNoCPUResources},
142190
{noMemoryEstimator, 0, noMemoryBaseResources, noMemoryBaseResources},
@@ -145,16 +193,22 @@ func TestEstimateResources(t *testing.T) {
145193
{noStorageEstimator, 3, threeNodeNoStorageResources, threeNodeNoStorageResources},
146194
{emptyEstimator, 0, noResources, noResources},
147195
{emptyEstimator, 3, noResources, noResources},
196+
{exponentialEstimator, 0, sixteenNodeResources, sixteenNodeResources},
197+
{exponentialEstimator, 3, sixteenNodeResources, sixteenNodeResources},
198+
{exponentialEstimator, 10, sixteenNodeResources, sixteenNodeResources},
199+
{exponentialEstimator, 16, sixteenNodeResources, sixteenNodeResources},
200+
{exponentialEstimator, 17, twentyFourNodeResources, twentyFourNodeResources},
201+
{exponentialEstimator, 20, twentyFourNodeResources, twentyFourNodeResources},
202+
{exponentialEstimator, 24, twentyFourNodeResources, twentyFourNodeResources},
148203
}
149204

150-
for i, tc := range testCases {
205+
for _, tc := range testCases {
151206
got := tc.e.scaleWithNodes(tc.numNodes)
152207
want := &api.ResourceRequirements{
153208
Limits: tc.limits,
154209
Requests: tc.requests,
155210
}
156-
if !reflect.DeepEqual(got, want) {
157-
t.Errorf("scaleWithNodes got %v, want %v in test case %d", got, want, i)
158-
}
211+
verifyResources(t, "limits", got.Limits, want.Limits)
212+
verifyResources(t, "requests", got.Requests, want.Limits)
159213
}
160214
}

addon-resizer/nanny/main/pod_nanny.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ var (
4848
containerName = flag.String("container", "pod-nanny", "The name of the container to watch. This defaults to the nanny itself.")
4949
// Flags to control runtime behavior.
5050
pollPeriod = time.Millisecond * time.Duration(*flag.Int("poll-period", 10000, "The time, in milliseconds, to poll the dependent container."))
51+
estimator = flag.String("estimator", "linear", "The estimator to use. Currently supported: linear, exponential")
5152
)
5253

5354
func main() {
@@ -107,8 +108,19 @@ func main() {
107108
}
108109

109110
log.Infof("Resources: %v", resources)
110-
est := nanny.LinearEstimator{
111-
Resources: resources,
111+
112+
var est nanny.ResourceEstimator
113+
if *estimator == "linear" {
114+
est = nanny.LinearEstimator{
115+
Resources: resources,
116+
}
117+
} else if *estimator == "exponential" {
118+
est = nanny.ExponentialEstimator{
119+
Resources: resources,
120+
ScaleFactor: 1.5,
121+
}
122+
} else {
123+
log.Fatalf("Estimator %s not supported", *estimator)
112124
}
113125

114126
// Begin nannying.

addon-resizer/nanny/nanny_lib.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ import (
2424
"time"
2525

2626
log "github.com/golang/glog"
27+
inf "gopkg.in/inf.v0"
2728
api "k8s.io/kubernetes/pkg/api/v1"
28-
inf "speter.net/go/exp/math/dec/inf"
2929
)
3030

3131
// checkResource determines whether a specific resource needs to be over-written.
@@ -38,7 +38,7 @@ func checkResource(threshold int64, actual, expected api.ResourceList, res api.R
3838
if !ok && !expOk {
3939
return false
4040
}
41-
q := new(inf.Dec).QuoRound(val.Amount, expVal.Amount, 2, inf.RoundDown)
41+
q := new(inf.Dec).QuoRound(val.AsDec(), expVal.AsDec(), 2, inf.RoundDown)
4242
lower := inf.NewDec(100-threshold, 2)
4343
upper := inf.NewDec(100+threshold, 2)
4444
if q.Cmp(lower) == -1 || q.Cmp(upper) == 1 {

addon-resizer/vendor/github.com/beorn7/perks/LICENSE

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)