Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
a8a86604
Commit
a8a86604
authored
Nov 03, 2016
by
Kubernetes Submit Queue
Committed by
GitHub
Nov 03, 2016
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #35204 from gmarek/node-affinity
Automatic merge from submit-queue Add node affinity test to scheduler benchmark cc @wojtek-t
parents
973fa6b3
d0ef0d23
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
157 additions
and
24 deletions
+157
-24
BUILD
test/integration/scheduler_perf/BUILD
+3
-0
scheduler_test.go
test/integration/scheduler_perf/scheduler_test.go
+118
-21
runners.go
test/utils/runners.go
+36
-3
No files found.
test/integration/scheduler_perf/BUILD
View file @
a8a86604
...
@@ -38,8 +38,11 @@ go_test(
...
@@ -38,8 +38,11 @@ go_test(
library = "go_default_library",
library = "go_default_library",
tags = ["automanaged"],
tags = ["automanaged"],
deps = [
deps = [
"//pkg/api:go_default_library",
"//plugin/pkg/scheduler/factory:go_default_library",
"//test/integration/framework:go_default_library",
"//test/integration/framework:go_default_library",
"//test/utils:go_default_library",
"//test/utils:go_default_library",
"//vendor:github.com/golang/glog",
"//vendor:github.com/golang/glog",
"//vendor:github.com/renstrom/dedent",
],
],
)
)
test/integration/scheduler_perf/scheduler_test.go
View file @
a8a86604
...
@@ -22,10 +22,13 @@ import (
...
@@ -22,10 +22,13 @@ import (
"testing"
"testing"
"time"
"time"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/plugin/pkg/scheduler/factory"
"k8s.io/kubernetes/test/integration/framework"
"k8s.io/kubernetes/test/integration/framework"
testutils
"k8s.io/kubernetes/test/utils"
testutils
"k8s.io/kubernetes/test/utils"
"github.com/golang/glog"
"github.com/golang/glog"
"github.com/renstrom/dedent"
)
)
const
(
const
(
...
@@ -39,19 +42,86 @@ func TestSchedule100Node3KPods(t *testing.T) {
...
@@ -39,19 +42,86 @@ func TestSchedule100Node3KPods(t *testing.T) {
if
testing
.
Short
()
{
if
testing
.
Short
()
{
t
.
Skip
(
"Skipping because we want to run short tests"
)
t
.
Skip
(
"Skipping because we want to run short tests"
)
}
}
if
min
:=
schedulePods
(
100
,
3000
);
min
<
threshold3K
{
config
:=
defaultSchedulerBenchmarkConfig
(
100
,
3000
)
if
min
:=
schedulePods
(
config
);
min
<
threshold3K
{
t
.
Errorf
(
"To small pod scheduling throughput for 3k pods. Expected %v got %v"
,
threshold3K
,
min
)
t
.
Errorf
(
"To small pod scheduling throughput for 3k pods. Expected %v got %v"
,
threshold3K
,
min
)
}
else
{
}
else
{
fmt
.
Printf
(
"Minimal observed throughput for 3k pod test: %v
\n
"
,
min
)
fmt
.
Printf
(
"Minimal observed throughput for 3k pod test: %v
\n
"
,
min
)
}
}
}
}
// TestSchedule100Node3KPods schedules 3k pods using Node affinity on 100 nodes.
func
TestSchedule100Node3KNodeAffinityPods
(
t
*
testing
.
T
)
{
if
testing
.
Short
()
{
t
.
Skip
(
"Skipping because we want to run short tests"
)
}
config
:=
baseConfig
()
config
.
numNodes
=
100
config
.
numPods
=
3000
// number of Node-Pod sets with Pods NodeAffinity matching given Nodes.
numGroups
:=
10
nodeAffinityKey
:=
"kubernetes.io/sched-perf-node-affinity"
nodeStrategies
:=
make
([]
testutils
.
CountToStrategy
,
0
,
10
)
for
i
:=
0
;
i
<
numGroups
;
i
++
{
nodeStrategies
=
append
(
nodeStrategies
,
testutils
.
CountToStrategy
{
Count
:
config
.
numNodes
/
numGroups
,
Strategy
:
testutils
.
NewLabelNodePrepareStrategy
(
nodeAffinityKey
,
fmt
.
Sprintf
(
"%v"
,
i
)),
})
}
config
.
nodePreparer
=
framework
.
NewIntegrationTestNodePreparer
(
config
.
schedulerConfigFactory
.
Client
,
nodeStrategies
,
"scheduler-perf-"
,
)
affinityTemplate
:=
dedent
.
Dedent
(
`
{
"nodeAffinity": {
"requiredDuringSchedulingIgnoredDuringExecution": {
"nodeSelectorTerms": [{
"matchExpressions": [{
"key": "`
+
nodeAffinityKey
+
`",
"operator": "In",
"values": ["%v"]
}]
}]
}
}
}`
)
podCreatorConfig
:=
testutils
.
NewTestPodCreatorConfig
()
for
i
:=
0
;
i
<
numGroups
;
i
++
{
podCreatorConfig
.
AddStrategy
(
"sched-perf-node-affinity"
,
config
.
numPods
/
numGroups
,
testutils
.
NewCustomCreatePodStrategy
(
&
api
.
Pod
{
ObjectMeta
:
api
.
ObjectMeta
{
GenerateName
:
"sched-perf-node-affinity-pod-"
,
Annotations
:
map
[
string
]
string
{
api
.
AffinityAnnotationKey
:
fmt
.
Sprintf
(
affinityTemplate
,
i
)},
},
Spec
:
testutils
.
MakePodSpec
(),
}),
)
}
config
.
podCreator
=
testutils
.
NewTestPodCreator
(
config
.
schedulerConfigFactory
.
Client
,
podCreatorConfig
)
if
min
:=
schedulePods
(
config
);
min
<
threshold30K
{
t
.
Errorf
(
"To small pod scheduling throughput for 30k pods. Expected %v got %v"
,
threshold30K
,
min
)
}
else
{
fmt
.
Printf
(
"Minimal observed throughput for 30k pod test: %v
\n
"
,
min
)
}
}
// TestSchedule1000Node30KPods schedules 30k pods on 1000 nodes.
// TestSchedule1000Node30KPods schedules 30k pods on 1000 nodes.
func
TestSchedule1000Node30KPods
(
t
*
testing
.
T
)
{
func
TestSchedule1000Node30KPods
(
t
*
testing
.
T
)
{
if
testing
.
Short
()
{
if
testing
.
Short
()
{
t
.
Skip
(
"Skipping because we want to run short tests"
)
t
.
Skip
(
"Skipping because we want to run short tests"
)
}
}
if
min
:=
schedulePods
(
1000
,
30000
);
min
<
threshold30K
{
config
:=
defaultSchedulerBenchmarkConfig
(
1000
,
30000
)
if
min
:=
schedulePods
(
config
);
min
<
threshold30K
{
t
.
Errorf
(
"To small pod scheduling throughput for 30k pods. Expected %v got %v"
,
threshold30K
,
min
)
t
.
Errorf
(
"To small pod scheduling throughput for 30k pods. Expected %v got %v"
,
threshold30K
,
min
)
}
else
{
}
else
{
fmt
.
Printf
(
"Minimal observed throughput for 30k pod test: %v
\n
"
,
min
)
fmt
.
Printf
(
"Minimal observed throughput for 30k pod test: %v
\n
"
,
min
)
...
@@ -64,37 +134,64 @@ func TestSchedule1000Node30KPods(t *testing.T) {
...
@@ -64,37 +134,64 @@ func TestSchedule1000Node30KPods(t *testing.T) {
// if testing.Short() {
// if testing.Short() {
// t.Skip("Skipping because we want to run short tests")
// t.Skip("Skipping because we want to run short tests")
// }
// }
// if min := schedulePods(2000, 60000); min < threshold60K {
// config := defaultSchedulerBenchmarkConfig(2000, 60000)
// if min := schedulePods(config); min < threshold60K {
// t.Errorf("To small pod scheduling throughput for 60k pods. Expected %v got %v", threshold60K, min)
// t.Errorf("To small pod scheduling throughput for 60k pods. Expected %v got %v", threshold60K, min)
// } else {
// } else {
// fmt.Printf("Minimal observed throughput for 60k pod test: %v\n", min)
// fmt.Printf("Minimal observed throughput for 60k pod test: %v\n", min)
// }
// }
// }
// }
// schedulePods schedules specific number of pods on specific number of nodes.
type
testConfig
struct
{
// This is used to learn the scheduling throughput on various
numPods
int
// sizes of cluster and changes as more and more pods are scheduled.
numNodes
int
// It won't stop until all pods are scheduled.
nodePreparer
testutils
.
TestNodePreparer
// It retruns the minimum of throughput over whole run.
podCreator
*
testutils
.
TestPodCreator
func
schedulePods
(
numNodes
,
numPods
int
)
int32
{
schedulerConfigFactory
*
factory
.
ConfigFactory
destroyFunc
func
()
}
func
baseConfig
()
*
testConfig
{
schedulerConfigFactory
,
destroyFunc
:=
mustSetupScheduler
()
schedulerConfigFactory
,
destroyFunc
:=
mustSetupScheduler
()
defer
destroyFunc
()
return
&
testConfig
{
c
:=
schedulerConfigFactory
.
Client
schedulerConfigFactory
:
schedulerConfigFactory
,
destroyFunc
:
destroyFunc
,
}
}
func
defaultSchedulerBenchmarkConfig
(
numNodes
,
numPods
int
)
*
testConfig
{
baseConfig
:=
baseConfig
()
nodePreparer
:=
framework
.
NewIntegrationTestNodePreparer
(
nodePreparer
:=
framework
.
NewIntegrationTestNodePreparer
(
c
,
baseConfig
.
schedulerConfigFactory
.
Client
,
[]
testutils
.
CountToStrategy
{{
Count
:
numNodes
,
Strategy
:
&
testutils
.
TrivialNodePrepareStrategy
{}}},
[]
testutils
.
CountToStrategy
{{
Count
:
numNodes
,
Strategy
:
&
testutils
.
TrivialNodePrepareStrategy
{}}},
"scheduler-perf-"
,
"scheduler-perf-"
,
)
)
if
err
:=
nodePreparer
.
PrepareNodes
();
err
!=
nil
{
glog
.
Fatalf
(
"%v"
,
err
)
}
defer
nodePreparer
.
CleanupNodes
()
config
:=
testutils
.
NewTestPodCreatorConfig
()
config
:=
testutils
.
NewTestPodCreatorConfig
()
config
.
AddStrategy
(
"sched-test"
,
numPods
,
testutils
.
NewSimpleWithControllerCreatePodStrategy
(
"rc1"
))
config
.
AddStrategy
(
"sched-test"
,
numPods
,
testutils
.
NewSimpleWithControllerCreatePodStrategy
(
"rc1"
))
podCreator
:=
testutils
.
NewTestPodCreator
(
c
,
config
)
podCreator
:=
testutils
.
NewTestPodCreator
(
baseConfig
.
schedulerConfigFactory
.
Client
,
config
)
podCreator
.
CreatePods
()
baseConfig
.
nodePreparer
=
nodePreparer
baseConfig
.
podCreator
=
podCreator
baseConfig
.
numPods
=
numPods
baseConfig
.
numNodes
=
numNodes
return
baseConfig
}
// schedulePods schedules specific number of pods on specific number of nodes.
// This is used to learn the scheduling throughput on various
// sizes of cluster and changes as more and more pods are scheduled.
// It won't stop until all pods are scheduled.
// It retruns the minimum of throughput over whole run.
func
schedulePods
(
config
*
testConfig
)
int32
{
defer
config
.
destroyFunc
()
if
err
:=
config
.
nodePreparer
.
PrepareNodes
();
err
!=
nil
{
glog
.
Fatalf
(
"%v"
,
err
)
}
defer
config
.
nodePreparer
.
CleanupNodes
()
config
.
podCreator
.
CreatePods
()
prev
:=
0
prev
:=
0
minQps
:=
int32
(
math
.
MaxInt32
)
minQps
:=
int32
(
math
.
MaxInt32
)
...
@@ -103,10 +200,10 @@ func schedulePods(numNodes, numPods int) int32 {
...
@@ -103,10 +200,10 @@ func schedulePods(numNodes, numPods int) int32 {
// This can potentially affect performance of scheduler, since List() is done under mutex.
// This can potentially affect performance of scheduler, since List() is done under mutex.
// Listing 10000 pods is an expensive operation, so running it frequently may impact scheduler.
// Listing 10000 pods is an expensive operation, so running it frequently may impact scheduler.
// TODO: Setup watch on apiserver and wait until all pods scheduled.
// TODO: Setup watch on apiserver and wait until all pods scheduled.
scheduled
:=
schedulerConfigFactory
.
ScheduledPodLister
.
Indexer
.
List
()
scheduled
:=
config
.
schedulerConfigFactory
.
ScheduledPodLister
.
Indexer
.
List
()
if
len
(
scheduled
)
>=
numPods
{
if
len
(
scheduled
)
>=
config
.
numPods
{
fmt
.
Printf
(
"Scheduled %v Pods in %v seconds (%v per second on average).
\n
"
,
fmt
.
Printf
(
"Scheduled %v Pods in %v seconds (%v per second on average).
\n
"
,
numPods
,
int
(
time
.
Since
(
start
)
/
time
.
Second
),
numPods
/
int
(
time
.
Since
(
start
)
/
time
.
Second
))
config
.
numPods
,
int
(
time
.
Since
(
start
)
/
time
.
Second
),
config
.
numPods
/
int
(
time
.
Since
(
start
)
/
time
.
Second
))
return
minQps
return
minQps
}
}
// There's no point in printing it for the last iteration, as the value is random
// There's no point in printing it for the last iteration, as the value is random
...
...
test/utils/runners.go
View file @
a8a86604
...
@@ -635,6 +635,39 @@ func (*TrivialNodePrepareStrategy) CleanupNode(node *api.Node) *api.Node {
...
@@ -635,6 +635,39 @@ func (*TrivialNodePrepareStrategy) CleanupNode(node *api.Node) *api.Node {
return
&
nodeCopy
return
&
nodeCopy
}
}
type
LabelNodePrepareStrategy
struct
{
labelKey
string
labelValue
string
}
func
NewLabelNodePrepareStrategy
(
labelKey
string
,
labelValue
string
)
*
LabelNodePrepareStrategy
{
return
&
LabelNodePrepareStrategy
{
labelKey
:
labelKey
,
labelValue
:
labelValue
,
}
}
func
(
s
*
LabelNodePrepareStrategy
)
PreparePatch
(
*
api
.
Node
)
[]
byte
{
labelString
:=
fmt
.
Sprintf
(
"{
\"
%v
\"
:
\"
%v
\"
}"
,
s
.
labelKey
,
s
.
labelValue
)
patch
:=
fmt
.
Sprintf
(
`{"metadata":{"labels":%v}}`
,
labelString
)
return
[]
byte
(
patch
)
}
func
(
s
*
LabelNodePrepareStrategy
)
CleanupNode
(
node
*
api
.
Node
)
*
api
.
Node
{
objCopy
,
err
:=
api
.
Scheme
.
DeepCopy
(
*
node
)
if
err
!=
nil
{
return
&
api
.
Node
{}
}
nodeCopy
,
ok
:=
(
objCopy
)
.
(
*
api
.
Node
)
if
!
ok
{
return
&
api
.
Node
{}
}
if
node
.
Labels
!=
nil
&&
len
(
node
.
Labels
[
s
.
labelKey
])
!=
0
{
delete
(
nodeCopy
.
Labels
,
s
.
labelKey
)
}
return
nodeCopy
}
func
DoPrepareNode
(
client
clientset
.
Interface
,
node
*
api
.
Node
,
strategy
PrepareNodeStrategy
)
error
{
func
DoPrepareNode
(
client
clientset
.
Interface
,
node
*
api
.
Node
,
strategy
PrepareNodeStrategy
)
error
{
var
err
error
var
err
error
patch
:=
strategy
.
PreparePatch
(
node
)
patch
:=
strategy
.
PreparePatch
(
node
)
...
@@ -717,7 +750,7 @@ func (c *TestPodCreator) CreatePods() error {
...
@@ -717,7 +750,7 @@ func (c *TestPodCreator) CreatePods() error {
return
nil
return
nil
}
}
func
m
akePodSpec
()
api
.
PodSpec
{
func
M
akePodSpec
()
api
.
PodSpec
{
return
api
.
PodSpec
{
return
api
.
PodSpec
{
Containers
:
[]
api
.
Container
{{
Containers
:
[]
api
.
Container
{{
Name
:
"pause"
,
Name
:
"pause"
,
...
@@ -804,7 +837,7 @@ func NewSimpleCreatePodStrategy() TestPodCreateStrategy {
...
@@ -804,7 +837,7 @@ func NewSimpleCreatePodStrategy() TestPodCreateStrategy {
ObjectMeta
:
api
.
ObjectMeta
{
ObjectMeta
:
api
.
ObjectMeta
{
GenerateName
:
"simple-pod-"
,
GenerateName
:
"simple-pod-"
,
},
},
Spec
:
m
akePodSpec
(),
Spec
:
M
akePodSpec
(),
}
}
return
NewCustomCreatePodStrategy
(
basePod
)
return
NewCustomCreatePodStrategy
(
basePod
)
}
}
...
@@ -816,7 +849,7 @@ func NewSimpleWithControllerCreatePodStrategy(controllerName string) TestPodCrea
...
@@ -816,7 +849,7 @@ func NewSimpleWithControllerCreatePodStrategy(controllerName string) TestPodCrea
GenerateName
:
controllerName
+
"-pod-"
,
GenerateName
:
controllerName
+
"-pod-"
,
Labels
:
map
[
string
]
string
{
"name"
:
controllerName
},
Labels
:
map
[
string
]
string
{
"name"
:
controllerName
},
},
},
Spec
:
m
akePodSpec
(),
Spec
:
M
akePodSpec
(),
}
}
if
err
:=
createController
(
client
,
controllerName
,
namespace
,
podCount
,
basePod
);
err
!=
nil
{
if
err
:=
createController
(
client
,
controllerName
,
namespace
,
podCount
,
basePod
);
err
!=
nil
{
return
err
return
err
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment