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
a049a978
Commit
a049a978
authored
Jul 18, 2016
by
k8s-merge-robot
Committed by
GitHub
Jul 18, 2016
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #28803 from lukaszo/ds
Automatic merge from submit-queue Make Daemonset use GeneralPredicates fixes: #21454 #22205
parents
648ec143
528bf7af
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
116 additions
and
63 deletions
+116
-63
daemoncontroller.go
pkg/controller/daemon/daemoncontroller.go
+20
-21
daemoncontroller_test.go
pkg/controller/daemon/daemoncontroller_test.go
+29
-4
predicates.go
plugin/pkg/scheduler/algorithm/predicates/predicates.go
+0
-36
predicates_test.go
plugin/pkg/scheduler/algorithm/predicates/predicates_test.go
+1
-2
daemon_set.go
test/e2e/daemon_set.go
+66
-0
No files found.
pkg/controller/daemon/daemoncontroller.go
View file @
a049a978
...
...
@@ -27,7 +27,6 @@ import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/api/validation"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/client/cache"
clientset
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
...
...
@@ -41,12 +40,11 @@ import (
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/metrics"
utilruntime
"k8s.io/kubernetes/pkg/util/runtime"
"k8s.io/kubernetes/pkg/util/sets"
"k8s.io/kubernetes/pkg/util/validation/field"
"k8s.io/kubernetes/pkg/util/wait"
"k8s.io/kubernetes/pkg/util/workqueue"
"k8s.io/kubernetes/pkg/watch"
"k8s.io/kubernetes/plugin/pkg/scheduler/algorithm/predicates"
"k8s.io/kubernetes/plugin/pkg/scheduler/schedulercache"
)
const
(
...
...
@@ -670,25 +668,22 @@ func (dsc *DaemonSetsController) syncDaemonSet(key string) error {
}
func
(
dsc
*
DaemonSetsController
)
nodeShouldRunDaemonPod
(
node
*
api
.
Node
,
ds
*
extensions
.
DaemonSet
)
bool
{
// Check if the node satisfies the daemon set's node selector.
nodeSelector
:=
labels
.
Set
(
ds
.
Spec
.
Template
.
Spec
.
NodeSelector
)
.
AsSelector
()
if
!
nodeSelector
.
Matches
(
labels
.
Set
(
node
.
Labels
))
{
return
false
}
// If the daemon set specifies a node name, check that it matches with node.Name.
if
!
(
ds
.
Spec
.
Template
.
Spec
.
NodeName
==
""
||
ds
.
Spec
.
Template
.
Spec
.
NodeName
==
node
.
Name
)
{
return
false
}
// TODO: Move it to the predicates
for
_
,
c
:=
range
node
.
Status
.
Conditions
{
if
c
.
Type
==
api
.
NodeOutOfDisk
&&
c
.
Status
==
api
.
ConditionTrue
{
return
false
}
}
newPod
:=
&
api
.
Pod
{
Spec
:
ds
.
Spec
.
Template
.
Spec
}
newPod
:=
&
api
.
Pod
{
Spec
:
ds
.
Spec
.
Template
.
Spec
,
ObjectMeta
:
ds
.
Spec
.
Template
.
ObjectMeta
}
newPod
.
Spec
.
NodeName
=
node
.
Name
pods
:=
[]
*
api
.
Pod
{
newPod
}
pods
:=
[]
*
api
.
Pod
{}
for
_
,
m
:=
range
dsc
.
podStore
.
Indexer
.
List
()
{
pod
:=
m
.
(
*
api
.
Pod
)
...
...
@@ -705,19 +700,23 @@ func (dsc *DaemonSetsController) nodeShouldRunDaemonPod(node *api.Node, ds *exte
}
pods
=
append
(
pods
,
pod
)
}
_
,
notFittingCPU
,
notFittingMemory
,
notFittingNvidiaGPU
:=
predicates
.
CheckPodsExceedingFreeResources
(
pods
,
node
.
Status
.
Allocatable
)
if
len
(
notFittingCPU
)
+
len
(
notFittingMemory
)
+
len
(
notFittingNvidiaGPU
)
!=
0
{
dsc
.
eventRecorder
.
Eventf
(
ds
,
api
.
EventTypeNormal
,
"FailedPlacement"
,
"failed to place pod on %q: insufficent free resources"
,
node
.
ObjectMeta
.
Name
)
return
false
}
ports
:=
sets
.
String
{}
for
_
,
pod
:=
range
pods
{
if
errs
:=
validation
.
AccumulateUniqueHostPorts
(
pod
.
Spec
.
Containers
,
&
ports
,
field
.
NewPath
(
"spec"
,
"containers"
));
len
(
errs
)
>
0
{
dsc
.
eventRecorder
.
Eventf
(
ds
,
api
.
EventTypeNormal
,
"FailedPlacement"
,
"failed to place pod on %q: host port conflict"
,
node
.
ObjectMeta
.
Name
)
return
false
nodeInfo
:=
schedulercache
.
NewNodeInfo
(
pods
...
)
nodeInfo
.
SetNode
(
node
)
fit
,
err
:=
predicates
.
GeneralPredicates
(
newPod
,
nil
,
nodeInfo
)
if
err
!=
nil
{
if
re
,
ok
:=
err
.
(
*
predicates
.
PredicateFailureError
);
ok
{
message
:=
re
.
Error
()
glog
.
V
(
2
)
.
Infof
(
"Predicate failed on Pod: %s, for reason: %v"
,
newPod
.
Name
,
message
)
}
if
re
,
ok
:=
err
.
(
*
predicates
.
InsufficientResourceError
);
ok
{
message
:=
re
.
Error
()
glog
.
V
(
2
)
.
Infof
(
"Predicate failed on Pod: %s, for reason: %v"
,
newPod
.
Name
,
message
)
}
message
:=
fmt
.
Sprintf
(
"GeneralPredicates failed due to %v."
,
err
)
glog
.
Warningf
(
"Predicate failed on Pod %s - %s"
,
newPod
.
Name
,
message
)
}
return
true
return
fit
}
// byCreationTimestamp sorts a list by creation timestamp, using their names as a tie breaker.
...
...
pkg/controller/daemon/daemoncontroller_test.go
View file @
a049a978
...
...
@@ -90,6 +90,9 @@ func newNode(name string, label map[string]string) *api.Node {
Conditions
:
[]
api
.
NodeCondition
{
{
Type
:
api
.
NodeReady
,
Status
:
api
.
ConditionTrue
},
},
Allocatable
:
api
.
ResourceList
{
api
.
ResourcePods
:
resource
.
MustParse
(
"100"
),
},
},
}
}
...
...
@@ -201,10 +204,8 @@ func TestOneNodeDaemonLaunchesPod(t *testing.T) {
func
TestNotReadNodeDaemonDoesNotLaunchPod
(
t
*
testing
.
T
)
{
manager
,
podControl
:=
newTestController
()
node
:=
newNode
(
"not-ready"
,
nil
)
node
.
Status
=
api
.
NodeStatus
{
Conditions
:
[]
api
.
NodeCondition
{
{
Type
:
api
.
NodeReady
,
Status
:
api
.
ConditionFalse
},
},
node
.
Status
.
Conditions
=
[]
api
.
NodeCondition
{
{
Type
:
api
.
NodeReady
,
Status
:
api
.
ConditionFalse
},
}
manager
.
nodeStore
.
Add
(
node
)
ds
:=
newDaemonSet
(
"foo"
)
...
...
@@ -238,6 +239,7 @@ func allocatableResources(memory, cpu string) api.ResourceList {
return
api
.
ResourceList
{
api
.
ResourceMemory
:
resource
.
MustParse
(
memory
),
api
.
ResourceCPU
:
resource
.
MustParse
(
cpu
),
api
.
ResourcePods
:
resource
.
MustParse
(
"100"
),
}
}
...
...
@@ -558,3 +560,26 @@ func TestDSManagerNotReady(t *testing.T) {
manager
.
podStoreSynced
=
alwaysReady
syncAndValidateDaemonSets
(
t
,
manager
,
ds
,
podControl
,
1
,
0
)
}
// Daemon with node affinity should launch pods on nodes matching affinity.
func
TestNodeAffinityDaemonLaunchesPods
(
t
*
testing
.
T
)
{
manager
,
podControl
:=
newTestController
()
addNodes
(
manager
.
nodeStore
.
Store
,
0
,
4
,
nil
)
addNodes
(
manager
.
nodeStore
.
Store
,
4
,
3
,
simpleNodeLabel
)
daemon
:=
newDaemonSet
(
"foo"
)
affinity
:=
map
[
string
]
string
{
api
.
AffinityAnnotationKey
:
fmt
.
Sprintf
(
`
{"nodeAffinity": { "requiredDuringSchedulingIgnoredDuringExecution": {
"nodeSelectorTerms": [{
"matchExpressions": [{
"key": "color",
"operator": "In",
"values": ["%s"]
}]
}]
}}}`
,
simpleNodeLabel
[
"color"
]),
}
daemon
.
Spec
.
Template
.
ObjectMeta
.
Annotations
=
affinity
manager
.
dsStore
.
Add
(
daemon
)
syncAndValidateDaemonSets
(
t
,
manager
,
daemon
,
podControl
,
3
,
0
)
}
plugin/pkg/scheduler/algorithm/predicates/predicates.go
View file @
a049a978
...
...
@@ -429,42 +429,6 @@ func getResourceRequest(pod *api.Pod) *resourceRequest {
return
&
result
}
func
CheckPodsExceedingFreeResources
(
pods
[]
*
api
.
Pod
,
allocatable
api
.
ResourceList
)
(
fitting
[]
*
api
.
Pod
,
notFittingCPU
,
notFittingMemory
,
notFittingNvidiaGPU
[]
*
api
.
Pod
)
{
totalMilliCPU
:=
allocatable
.
Cpu
()
.
MilliValue
()
totalMemory
:=
allocatable
.
Memory
()
.
Value
()
totalNvidiaGPU
:=
allocatable
.
NvidiaGPU
()
.
Value
()
milliCPURequested
:=
int64
(
0
)
memoryRequested
:=
int64
(
0
)
nvidiaGPURequested
:=
int64
(
0
)
for
_
,
pod
:=
range
pods
{
podRequest
:=
getResourceRequest
(
pod
)
fitsCPU
:=
(
totalMilliCPU
-
milliCPURequested
)
>=
podRequest
.
milliCPU
fitsMemory
:=
(
totalMemory
-
memoryRequested
)
>=
podRequest
.
memory
fitsNVidiaGPU
:=
(
totalNvidiaGPU
-
nvidiaGPURequested
)
>=
podRequest
.
nvidiaGPU
if
!
fitsCPU
{
// the pod doesn't fit due to CPU request
notFittingCPU
=
append
(
notFittingCPU
,
pod
)
continue
}
if
!
fitsMemory
{
// the pod doesn't fit due to Memory request
notFittingMemory
=
append
(
notFittingMemory
,
pod
)
continue
}
if
!
fitsNVidiaGPU
{
// the pod doesn't fit due to NvidiaGPU request
notFittingNvidiaGPU
=
append
(
notFittingNvidiaGPU
,
pod
)
continue
}
// the pod fits
milliCPURequested
+=
podRequest
.
milliCPU
memoryRequested
+=
podRequest
.
memory
nvidiaGPURequested
+=
podRequest
.
nvidiaGPU
fitting
=
append
(
fitting
,
pod
)
}
return
}
func
podName
(
pod
*
api
.
Pod
)
string
{
return
pod
.
Namespace
+
"/"
+
pod
.
Name
}
...
...
plugin/pkg/scheduler/algorithm/predicates/predicates_test.go
View file @
a049a978
...
...
@@ -1840,8 +1840,7 @@ func TestInterPodAffinity(t *testing.T) {
ObjectMeta
:
api
.
ObjectMeta
{
Labels
:
podLabel2
,
Annotations
:
map
[
string
]
string
{
api
.
AffinityAnnotationKey
:
`
{"podAffinity": {
api
.
AffinityAnnotationKey
:
`{"podAffinity": {
"requiredDuringSchedulingIgnoredDuringExecution": [{
"labelSelector": {
"matchExpressions": [{
...
...
test/e2e/daemon_set.go
View file @
a049a978
...
...
@@ -197,6 +197,72 @@ var _ = framework.KubeDescribe("Daemon set [Serial]", func() {
Expect
(
c
.
DaemonSets
(
ns
)
.
Delete
(
dsName
))
.
NotTo
(
HaveOccurred
())
})
It
(
"should run and stop complex daemon with node affinity"
,
func
()
{
complexLabel
:=
map
[
string
]
string
{
daemonsetNameLabel
:
dsName
}
nodeSelector
:=
map
[
string
]
string
{
daemonsetColorLabel
:
"blue"
}
framework
.
Logf
(
"Creating daemon with a node affinity %s"
,
dsName
)
affinity
:=
map
[
string
]
string
{
api
.
AffinityAnnotationKey
:
fmt
.
Sprintf
(
`
{"nodeAffinity": { "requiredDuringSchedulingIgnoredDuringExecution": {
"nodeSelectorTerms": [{
"matchExpressions": [{
"key": "%s",
"operator": "In",
"values": ["%s"]
}]
}]
}}}`
,
daemonsetColorLabel
,
nodeSelector
[
daemonsetColorLabel
]),
}
_
,
err
:=
c
.
DaemonSets
(
ns
)
.
Create
(
&
extensions
.
DaemonSet
{
ObjectMeta
:
api
.
ObjectMeta
{
Name
:
dsName
,
},
Spec
:
extensions
.
DaemonSetSpec
{
Selector
:
&
unversioned
.
LabelSelector
{
MatchLabels
:
complexLabel
},
Template
:
api
.
PodTemplateSpec
{
ObjectMeta
:
api
.
ObjectMeta
{
Labels
:
complexLabel
,
Annotations
:
affinity
,
},
Spec
:
api
.
PodSpec
{
Containers
:
[]
api
.
Container
{
{
Name
:
dsName
,
Image
:
image
,
Ports
:
[]
api
.
ContainerPort
{{
ContainerPort
:
9376
}},
},
},
},
},
},
})
Expect
(
err
)
.
NotTo
(
HaveOccurred
())
By
(
"Initially, daemon pods should not be running on any nodes."
)
err
=
wait
.
Poll
(
dsRetryPeriod
,
dsRetryTimeout
,
checkRunningOnNoNodes
(
f
,
complexLabel
))
Expect
(
err
)
.
NotTo
(
HaveOccurred
(),
"error waiting for daemon pods to be running on no nodes"
)
By
(
"Change label of node, check that daemon pod is launched."
)
nodeList
:=
framework
.
GetReadySchedulableNodesOrDie
(
f
.
Client
)
Expect
(
len
(
nodeList
.
Items
))
.
To
(
BeNumerically
(
">"
,
0
))
newNode
,
err
:=
setDaemonSetNodeLabels
(
c
,
nodeList
.
Items
[
0
]
.
Name
,
nodeSelector
)
Expect
(
err
)
.
NotTo
(
HaveOccurred
(),
"error setting labels on node"
)
daemonSetLabels
,
_
:=
separateDaemonSetNodeLabels
(
newNode
.
Labels
)
Expect
(
len
(
daemonSetLabels
))
.
To
(
Equal
(
1
))
err
=
wait
.
Poll
(
dsRetryPeriod
,
dsRetryTimeout
,
checkDaemonPodOnNodes
(
f
,
complexLabel
,
[]
string
{
newNode
.
Name
}))
Expect
(
err
)
.
NotTo
(
HaveOccurred
(),
"error waiting for daemon pods to be running on new nodes"
)
By
(
"remove the node selector and wait for daemons to be unscheduled"
)
_
,
err
=
setDaemonSetNodeLabels
(
c
,
nodeList
.
Items
[
0
]
.
Name
,
map
[
string
]
string
{})
Expect
(
err
)
.
NotTo
(
HaveOccurred
(),
"error removing labels on node"
)
Expect
(
wait
.
Poll
(
dsRetryPeriod
,
dsRetryTimeout
,
checkRunningOnNoNodes
(
f
,
complexLabel
)))
.
NotTo
(
HaveOccurred
(),
"error waiting for daemon pod to not be running on nodes"
)
By
(
"We should now be able to delete the daemon set."
)
Expect
(
c
.
DaemonSets
(
ns
)
.
Delete
(
dsName
))
.
NotTo
(
HaveOccurred
())
})
})
func
separateDaemonSetNodeLabels
(
labels
map
[
string
]
string
)
(
map
[
string
]
string
,
map
[
string
]
string
)
{
...
...
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