@@ -18,6 +18,7 @@ package gce
18
18
19
19
import (
20
20
"math"
21
+ "strings"
21
22
"time"
22
23
23
24
apiv1 "k8s.io/api/core/v1"
@@ -31,15 +32,59 @@ type GcePriceModel struct {
31
32
32
33
const (
33
34
//TODO: Move it to a config file.
34
- cpuPricePerHour = 0.033174
35
- memoryPricePerHourPerGb = 0.004446
36
- preemptibleDiscount = 0.00698 / 0.033174
35
+ cpuPricePerHour = 0.022890
36
+ memoryPricePerHourPerGb = 0.003067
37
+ preemptibleDiscount = 0.006867 / 0.022890
37
38
gpuPricePerHour = 0.700
38
39
39
40
preemptibleLabel = "cloud.google.com/gke-preemptible"
40
41
)
41
42
42
43
var (
44
+ predefinedCpuPricePerHour = map [string ]float64 {
45
+ "c2" : 0.03398 ,
46
+ "e2" : 0.021811 ,
47
+ "m1" : 0.0348 ,
48
+ "n1" : 0.031611 ,
49
+ "n2" : 0.031611 ,
50
+ "n2d" : 0.027502 ,
51
+ }
52
+ predefinedMemoryPricePerHourPerGb = map [string ]float64 {
53
+ "c2" : 0.00455 ,
54
+ "e2" : 0.002923 ,
55
+ "m1" : 0.0051 ,
56
+ "n1" : 0.004237 ,
57
+ "n2" : 0.004237 ,
58
+ "n2d" : 0.003686 ,
59
+ }
60
+ predefinedPreemptibleDiscount = map [string ]float64 {
61
+ "c2" : 0.00822 / 0.03398 ,
62
+ "e2" : 0.006543 / 0.021811 ,
63
+ "m1" : 0.00733 / 0.0348 ,
64
+ "n1" : 0.006655 / 0.031611 ,
65
+ "n2" : 0.007650 / 0.031611 ,
66
+ "n2d" : 0.006655 / 0.027502 ,
67
+ }
68
+
69
+ customCpuPricePerHour = map [string ]float64 {
70
+ "e2" : 0.022890 ,
71
+ "n1" : 0.033174 ,
72
+ "n2" : 0.033174 ,
73
+ "n2d" : 0.028877 ,
74
+ }
75
+ customMemoryPricePerHourPerGb = map [string ]float64 {
76
+ "e2" : 0.003067 ,
77
+ "n1" : 0.004446 ,
78
+ "n2" : 0.004446 ,
79
+ "n2d" : 0.003870 ,
80
+ }
81
+ customPreemptibleDiscount = map [string ]float64 {
82
+ "e2" : 0.006867 / 0.022890 ,
83
+ "n1" : 0.00698 / 0.033174 ,
84
+ "n2" : 0.00802 / 0.033174 ,
85
+ "n2d" : 0.006980 / 0.028877 ,
86
+ }
87
+
43
88
// e2-micro and e2-small have allocatable set too high resulting in
44
89
// overcommit. To make cluster autoscaler prefer e2-medium given the choice
45
90
// between the three machine types, the prices for e2-micro and e2-small
@@ -278,10 +323,8 @@ func (model *GcePriceModel) NodePrice(node *apiv1.Node, startTime time.Time, end
278
323
}
279
324
}
280
325
if ! basePriceFound {
281
- price = getBasePrice (node .Status .Capacity , startTime , endTime )
282
- if node .Labels != nil && node .Labels [preemptibleLabel ] == "true" {
283
- price = price * preemptibleDiscount
284
- }
326
+ price = getBasePrice (node .Status .Capacity , node .Labels [apiv1 .LabelInstanceType ], startTime , endTime )
327
+ price = price * getPreemptibleDiscount (node )
285
328
}
286
329
// TODO: handle SSDs.
287
330
@@ -295,27 +338,74 @@ func getHours(startTime time.Time, endTime time.Time) float64 {
295
338
return hours
296
339
}
297
340
341
+ func getInstanceFamily (instanceType string ) string {
342
+ return strings .Split (instanceType , "-" )[0 ]
343
+ }
344
+
345
+ func isInstanceCustom (instanceType string ) bool {
346
+ return strings .Contains (instanceType , "custom" )
347
+ }
348
+
349
+ func getPreemptibleDiscount (node * apiv1.Node ) float64 {
350
+ if node .Labels [preemptibleLabel ] != "true" {
351
+ return 1.0
352
+ }
353
+ instanceType := node .Labels [apiv1 .LabelInstanceType ]
354
+ instanceFamily := getInstanceFamily (instanceType )
355
+
356
+ discountMap := predefinedPreemptibleDiscount
357
+ if isInstanceCustom (instanceType ) {
358
+ discountMap = customPreemptibleDiscount
359
+ }
360
+
361
+ if _ , found := discountMap [instanceFamily ]; found {
362
+ return discountMap [instanceFamily ]
363
+ }
364
+ return preemptibleDiscount
365
+ }
366
+
298
367
// PodPrice returns a theoretical minimum price of running a pod for a given
299
368
// period of time on a perfectly matching machine.
300
369
func (model * GcePriceModel ) PodPrice (pod * apiv1.Pod , startTime time.Time , endTime time.Time ) (float64 , error ) {
301
370
price := 0.0
302
371
for _ , container := range pod .Spec .Containers {
303
- price += getBasePrice (container .Resources .Requests , startTime , endTime )
372
+ price += getBasePrice (container .Resources .Requests , "" , startTime , endTime )
304
373
price += getAdditionalPrice (container .Resources .Requests , startTime , endTime )
305
374
}
306
375
return price , nil
307
376
}
308
377
309
- func getBasePrice (resources apiv1.ResourceList , startTime time.Time , endTime time.Time ) float64 {
378
+ func getBasePrice (resources apiv1.ResourceList , instanceType string , startTime time.Time , endTime time.Time ) float64 {
310
379
if len (resources ) == 0 {
311
380
return 0
312
381
}
313
382
hours := getHours (startTime , endTime )
383
+ instanceFamily := getInstanceFamily (instanceType )
384
+ isCustom := isInstanceCustom (instanceType )
314
385
price := 0.0
386
+
315
387
cpu := resources [apiv1 .ResourceCPU ]
388
+ cpuPrice := cpuPricePerHour
389
+ cpuPriceMap := predefinedCpuPricePerHour
390
+ if isCustom {
391
+ cpuPriceMap = customCpuPricePerHour
392
+ }
393
+ if _ , found := cpuPriceMap [instanceFamily ]; found {
394
+ cpuPrice = cpuPriceMap [instanceFamily ]
395
+ }
396
+ price += float64 (cpu .MilliValue ()) / 1000.0 * cpuPrice * hours
397
+
316
398
mem := resources [apiv1 .ResourceMemory ]
317
- price += float64 (cpu .MilliValue ()) / 1000.0 * cpuPricePerHour * hours
318
- price += float64 (mem .Value ()) / float64 (units .GiB ) * memoryPricePerHourPerGb * hours
399
+ memPrice := memoryPricePerHourPerGb
400
+ memPriceMap := predefinedMemoryPricePerHourPerGb
401
+ if isCustom {
402
+ memPriceMap = customMemoryPricePerHourPerGb
403
+ }
404
+ if _ , found := memPriceMap [instanceFamily ]; found {
405
+ memPrice = memPriceMap [instanceFamily ]
406
+ }
407
+ price += float64 (mem .Value ()) / float64 (units .GiB ) * memPrice * hours
408
+
319
409
return price
320
410
}
321
411
0 commit comments