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
a80b1798
Commit
a80b1798
authored
Apr 18, 2016
by
Filip Grzadkowski
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add pod condition PodScheduled to detect situation
when scheduler tried to schedule a Pod, but failed. Ref #24404
parent
26c99fee
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
103 additions
and
3 deletions
+103
-3
resource_helpers.go
pkg/api/resource_helpers.go
+36
-3
types.go
pkg/api/types.go
+2
-0
types.go
pkg/api/v1/types.go
+2
-0
kubelet.go
pkg/kubelet/kubelet.go
+10
-0
etcd.go
pkg/registry/pod/etcd/etcd.go
+4
-0
factory.go
plugin/pkg/scheduler/factory/factory.go
+14
-0
scheduler.go
plugin/pkg/scheduler/scheduler.go
+22
-0
scheduler_test.go
plugin/pkg/scheduler/scheduler_test.go
+7
-0
scheduler_predicates.go
test/e2e/scheduler_predicates.go
+6
-0
No files found.
pkg/api/resource_helpers.go
View file @
a80b1798
...
@@ -18,6 +18,7 @@ package api
...
@@ -18,6 +18,7 @@ package api
import
(
import
(
"k8s.io/kubernetes/pkg/api/resource"
"k8s.io/kubernetes/pkg/api/resource"
"k8s.io/kubernetes/pkg/api/unversioned"
)
)
// Returns string version of ResourceName.
// Returns string version of ResourceName.
...
@@ -80,12 +81,44 @@ func IsPodReadyConditionTrue(status PodStatus) bool {
...
@@ -80,12 +81,44 @@ func IsPodReadyConditionTrue(status PodStatus) bool {
// Extracts the pod ready condition from the given status and returns that.
// Extracts the pod ready condition from the given status and returns that.
// Returns nil if the condition is not present.
// Returns nil if the condition is not present.
func
GetPodReadyCondition
(
status
PodStatus
)
*
PodCondition
{
func
GetPodReadyCondition
(
status
PodStatus
)
*
PodCondition
{
_
,
condition
:=
GetPodCondition
(
&
status
,
PodReady
)
return
condition
}
func
GetPodCondition
(
status
*
PodStatus
,
conditionType
PodConditionType
)
(
int
,
*
PodCondition
)
{
for
i
,
c
:=
range
status
.
Conditions
{
for
i
,
c
:=
range
status
.
Conditions
{
if
c
.
Type
==
PodReady
{
if
c
.
Type
==
conditionType
{
return
&
status
.
Conditions
[
i
]
return
i
,
&
status
.
Conditions
[
i
]
}
}
}
return
-
1
,
nil
}
// Updates existing pod condition or creates a new one. Sets LastTransitionTime to now if the
// status has changed.
// Returns true if pod condition has changed or has been added.
func
UpdatePodCondition
(
status
*
PodStatus
,
condition
*
PodCondition
)
bool
{
condition
.
LastTransitionTime
=
unversioned
.
Now
()
// Try to find this pod condition.
conditionIndex
,
oldCondition
:=
GetPodCondition
(
status
,
condition
.
Type
)
if
oldCondition
==
nil
{
// We are adding new pod condition.
status
.
Conditions
=
append
(
status
.
Conditions
,
*
condition
)
return
true
}
else
{
// We are updating an existing condition, so we need to check if it has changed.
if
condition
.
Status
==
oldCondition
.
Status
{
condition
.
LastTransitionTime
=
oldCondition
.
LastTransitionTime
}
status
.
Conditions
[
conditionIndex
]
=
*
condition
// Return true if one of the fields have changed.
return
condition
.
Status
!=
oldCondition
.
Status
||
condition
.
Reason
!=
oldCondition
.
Reason
||
condition
.
Message
!=
oldCondition
.
Message
||
!
condition
.
LastProbeTime
.
Equal
(
oldCondition
.
LastProbeTime
)
||
!
condition
.
LastTransitionTime
.
Equal
(
oldCondition
.
LastTransitionTime
)
}
}
return
nil
}
}
// IsNodeReady returns true if a node is ready; false otherwise.
// IsNodeReady returns true if a node is ready; false otherwise.
...
...
pkg/api/types.go
View file @
a80b1798
...
@@ -1058,6 +1058,8 @@ type PodConditionType string
...
@@ -1058,6 +1058,8 @@ type PodConditionType string
// These are valid conditions of pod.
// These are valid conditions of pod.
const
(
const
(
// PodScheduled represents status of the scheduling process for this pod.
PodScheduled
PodConditionType
=
"PodScheduled"
// PodReady means the pod is able to service requests and should be added to the
// PodReady means the pod is able to service requests and should be added to the
// load balancing pools of all matching services.
// load balancing pools of all matching services.
PodReady
PodConditionType
=
"Ready"
PodReady
PodConditionType
=
"Ready"
...
...
pkg/api/v1/types.go
View file @
a80b1798
...
@@ -1288,6 +1288,8 @@ type PodConditionType string
...
@@ -1288,6 +1288,8 @@ type PodConditionType string
// These are valid conditions of pod.
// These are valid conditions of pod.
const
(
const
(
// PodScheduled represents status of the scheduling process for this pod.
PodScheduled
PodConditionType
=
"PodScheduled"
// PodReady means the pod is able to service requests and should be added to the
// PodReady means the pod is able to service requests and should be added to the
// load balancing pools of all matching services.
// load balancing pools of all matching services.
PodReady
PodConditionType
=
"Ready"
PodReady
PodConditionType
=
"Ready"
...
...
pkg/kubelet/kubelet.go
View file @
a80b1798
...
@@ -3286,6 +3286,16 @@ func (kl *Kubelet) generateAPIPodStatus(pod *api.Pod, podStatus *kubecontainer.P
...
@@ -3286,6 +3286,16 @@ func (kl *Kubelet) generateAPIPodStatus(pod *api.Pod, podStatus *kubecontainer.P
s
.
Phase
=
GetPhase
(
spec
,
s
.
ContainerStatuses
)
s
.
Phase
=
GetPhase
(
spec
,
s
.
ContainerStatuses
)
kl
.
probeManager
.
UpdatePodStatus
(
pod
.
UID
,
s
)
kl
.
probeManager
.
UpdatePodStatus
(
pod
.
UID
,
s
)
s
.
Conditions
=
append
(
s
.
Conditions
,
status
.
GeneratePodReadyCondition
(
spec
,
s
.
ContainerStatuses
,
s
.
Phase
))
s
.
Conditions
=
append
(
s
.
Conditions
,
status
.
GeneratePodReadyCondition
(
spec
,
s
.
ContainerStatuses
,
s
.
Phase
))
// s (the PodStatus we are creating) will not have a PodScheduled condition yet, because converStatusToAPIStatus()
// does not create one. If the existing PodStatus has a PodScheduled condition, then copy it into s and make sure
// it is set to true. If the existing PodStatus does not have a PodScheduled condition, then create one that is set to true.
if
_
,
oldPodScheduled
:=
api
.
GetPodCondition
(
&
pod
.
Status
,
api
.
PodScheduled
);
oldPodScheduled
!=
nil
{
s
.
Conditions
=
append
(
s
.
Conditions
,
*
oldPodScheduled
)
}
api
.
UpdatePodCondition
(
&
pod
.
Status
,
&
api
.
PodCondition
{
Type
:
api
.
PodScheduled
,
Status
:
api
.
ConditionTrue
,
})
if
!
kl
.
standaloneMode
{
if
!
kl
.
standaloneMode
{
hostIP
,
err
:=
kl
.
GetHostIP
()
hostIP
,
err
:=
kl
.
GetHostIP
()
...
...
pkg/registry/pod/etcd/etcd.go
View file @
a80b1798
...
@@ -166,6 +166,10 @@ func (r *BindingREST) setPodHostAndAnnotations(ctx api.Context, podID, oldMachin
...
@@ -166,6 +166,10 @@ func (r *BindingREST) setPodHostAndAnnotations(ctx api.Context, podID, oldMachin
for
k
,
v
:=
range
annotations
{
for
k
,
v
:=
range
annotations
{
pod
.
Annotations
[
k
]
=
v
pod
.
Annotations
[
k
]
=
v
}
}
api
.
UpdatePodCondition
(
&
pod
.
Status
,
&
api
.
PodCondition
{
Type
:
api
.
PodScheduled
,
Status
:
api
.
ConditionTrue
,
})
finalPod
=
pod
finalPod
=
pod
return
pod
,
nil
return
pod
,
nil
}))
}))
...
...
plugin/pkg/scheduler/factory/factory.go
View file @
a80b1798
...
@@ -289,6 +289,7 @@ func (f *ConfigFactory) CreateFromKeys(predicateKeys, priorityKeys sets.String,
...
@@ -289,6 +289,7 @@ func (f *ConfigFactory) CreateFromKeys(predicateKeys, priorityKeys sets.String,
NodeLister
:
f
.
NodeLister
.
NodeCondition
(
getNodeConditionPredicate
()),
NodeLister
:
f
.
NodeLister
.
NodeCondition
(
getNodeConditionPredicate
()),
Algorithm
:
algo
,
Algorithm
:
algo
,
Binder
:
&
binder
{
f
.
Client
},
Binder
:
&
binder
{
f
.
Client
},
PodConditionUpdater
:
&
podConditionUpdater
{
f
.
Client
},
NextPod
:
func
()
*
api
.
Pod
{
NextPod
:
func
()
*
api
.
Pod
{
return
f
.
getNextPod
()
return
f
.
getNextPod
()
},
},
...
@@ -448,6 +449,19 @@ func (b *binder) Bind(binding *api.Binding) error {
...
@@ -448,6 +449,19 @@ func (b *binder) Bind(binding *api.Binding) error {
// return b.Pods(binding.Namespace).Bind(binding)
// return b.Pods(binding.Namespace).Bind(binding)
}
}
type
podConditionUpdater
struct
{
*
client
.
Client
}
func
(
p
*
podConditionUpdater
)
Update
(
pod
*
api
.
Pod
,
condition
*
api
.
PodCondition
)
error
{
glog
.
V
(
2
)
.
Infof
(
"Updating pod condition for %s/%s to (%s==%s)"
,
pod
.
Namespace
,
pod
.
Name
,
condition
.
Type
,
condition
.
Status
)
if
api
.
UpdatePodCondition
(
&
pod
.
Status
,
condition
)
{
_
,
err
:=
p
.
Pods
(
pod
.
Namespace
)
.
UpdateStatus
(
pod
)
return
err
}
return
nil
}
type
clock
interface
{
type
clock
interface
{
Now
()
time
.
Time
Now
()
time
.
Time
}
}
...
...
plugin/pkg/scheduler/scheduler.go
View file @
a80b1798
...
@@ -37,6 +37,10 @@ type Binder interface {
...
@@ -37,6 +37,10 @@ type Binder interface {
Bind
(
binding
*
api
.
Binding
)
error
Bind
(
binding
*
api
.
Binding
)
error
}
}
type
PodConditionUpdater
interface
{
Update
(
pod
*
api
.
Pod
,
podCondition
*
api
.
PodCondition
)
error
}
// Scheduler watches for new unscheduled pods. It attempts to find
// Scheduler watches for new unscheduled pods. It attempts to find
// nodes that they fit on and writes bindings back to the api server.
// nodes that they fit on and writes bindings back to the api server.
type
Scheduler
struct
{
type
Scheduler
struct
{
...
@@ -50,6 +54,10 @@ type Config struct {
...
@@ -50,6 +54,10 @@ type Config struct {
NodeLister
algorithm
.
NodeLister
NodeLister
algorithm
.
NodeLister
Algorithm
algorithm
.
ScheduleAlgorithm
Algorithm
algorithm
.
ScheduleAlgorithm
Binder
Binder
Binder
Binder
// PodConditionUpdater is used only in case of scheduling errors. If we succeed
// with scheduling, PodScheduled condition will be updated in apiserver in /bind
// handler so that binding and setting PodCondition it is atomic.
PodConditionUpdater
PodConditionUpdater
// NextPod should be a function that blocks until the next pod
// NextPod should be a function that blocks until the next pod
// is available. We don't use a channel for this, because scheduling
// is available. We don't use a channel for this, because scheduling
...
@@ -92,6 +100,12 @@ func (s *Scheduler) scheduleOne() {
...
@@ -92,6 +100,12 @@ func (s *Scheduler) scheduleOne() {
glog
.
V
(
1
)
.
Infof
(
"Failed to schedule: %+v"
,
pod
)
glog
.
V
(
1
)
.
Infof
(
"Failed to schedule: %+v"
,
pod
)
s
.
config
.
Error
(
pod
,
err
)
s
.
config
.
Error
(
pod
,
err
)
s
.
config
.
Recorder
.
Eventf
(
pod
,
api
.
EventTypeWarning
,
"FailedScheduling"
,
"%v"
,
err
)
s
.
config
.
Recorder
.
Eventf
(
pod
,
api
.
EventTypeWarning
,
"FailedScheduling"
,
"%v"
,
err
)
s
.
config
.
PodConditionUpdater
.
Update
(
pod
,
&
api
.
PodCondition
{
Type
:
api
.
PodScheduled
,
Status
:
api
.
ConditionFalse
,
Reason
:
"Unschedulable"
,
Message
:
err
.
Error
(),
})
return
return
}
}
metrics
.
SchedulingAlgorithmLatency
.
Observe
(
metrics
.
SinceInMicroseconds
(
start
))
metrics
.
SchedulingAlgorithmLatency
.
Observe
(
metrics
.
SinceInMicroseconds
(
start
))
...
@@ -120,11 +134,19 @@ func (s *Scheduler) scheduleOne() {
...
@@ -120,11 +134,19 @@ func (s *Scheduler) scheduleOne() {
}
}
bindingStart
:=
time
.
Now
()
bindingStart
:=
time
.
Now
()
// If binding succeded then PodScheduled condition will be updated in apiserver so that
// it's atomic with setting host.
err
:=
s
.
config
.
Binder
.
Bind
(
b
)
err
:=
s
.
config
.
Binder
.
Bind
(
b
)
if
err
!=
nil
{
if
err
!=
nil
{
glog
.
V
(
1
)
.
Infof
(
"Failed to bind pod: %+v"
,
err
)
glog
.
V
(
1
)
.
Infof
(
"Failed to bind pod: %+v"
,
err
)
s
.
config
.
Error
(
pod
,
err
)
s
.
config
.
Error
(
pod
,
err
)
s
.
config
.
Recorder
.
Eventf
(
pod
,
api
.
EventTypeNormal
,
"FailedScheduling"
,
"Binding rejected: %v"
,
err
)
s
.
config
.
Recorder
.
Eventf
(
pod
,
api
.
EventTypeNormal
,
"FailedScheduling"
,
"Binding rejected: %v"
,
err
)
s
.
config
.
PodConditionUpdater
.
Update
(
pod
,
&
api
.
PodCondition
{
Type
:
api
.
PodScheduled
,
Status
:
api
.
ConditionFalse
,
Reason
:
"BindingRejected"
,
Message
:
err
.
Error
(),
})
return
return
}
}
metrics
.
BindingLatency
.
Observe
(
metrics
.
SinceInMicroseconds
(
bindingStart
))
metrics
.
BindingLatency
.
Observe
(
metrics
.
SinceInMicroseconds
(
bindingStart
))
...
...
plugin/pkg/scheduler/scheduler_test.go
View file @
a80b1798
...
@@ -43,6 +43,12 @@ type fakeBinder struct {
...
@@ -43,6 +43,12 @@ type fakeBinder struct {
func
(
fb
fakeBinder
)
Bind
(
binding
*
api
.
Binding
)
error
{
return
fb
.
b
(
binding
)
}
func
(
fb
fakeBinder
)
Bind
(
binding
*
api
.
Binding
)
error
{
return
fb
.
b
(
binding
)
}
type
fakePodConditionUpdater
struct
{}
func
(
fc
fakePodConditionUpdater
)
Update
(
pod
*
api
.
Pod
,
podCondition
*
api
.
PodCondition
)
error
{
return
nil
}
func
podWithID
(
id
,
desiredHost
string
)
*
api
.
Pod
{
func
podWithID
(
id
,
desiredHost
string
)
*
api
.
Pod
{
return
&
api
.
Pod
{
return
&
api
.
Pod
{
ObjectMeta
:
api
.
ObjectMeta
{
Name
:
id
,
SelfLink
:
testapi
.
Default
.
SelfLink
(
"pods"
,
id
)},
ObjectMeta
:
api
.
ObjectMeta
{
Name
:
id
,
SelfLink
:
testapi
.
Default
.
SelfLink
(
"pods"
,
id
)},
...
@@ -128,6 +134,7 @@ func TestScheduler(t *testing.T) {
...
@@ -128,6 +134,7 @@ func TestScheduler(t *testing.T) {
gotBinding
=
b
gotBinding
=
b
return
item
.
injectBindError
return
item
.
injectBindError
}},
}},
PodConditionUpdater
:
fakePodConditionUpdater
{},
Error
:
func
(
p
*
api
.
Pod
,
err
error
)
{
Error
:
func
(
p
*
api
.
Pod
,
err
error
)
{
gotPod
=
p
gotPod
=
p
gotError
=
err
gotError
=
err
...
...
test/e2e/scheduler_predicates.go
View file @
a80b1798
...
@@ -45,8 +45,14 @@ func getPodsScheduled(pods *api.PodList) (scheduledPods, notScheduledPods []api.
...
@@ -45,8 +45,14 @@ func getPodsScheduled(pods *api.PodList) (scheduledPods, notScheduledPods []api.
for
_
,
pod
:=
range
pods
.
Items
{
for
_
,
pod
:=
range
pods
.
Items
{
if
!
masterNodes
.
Has
(
pod
.
Spec
.
NodeName
)
{
if
!
masterNodes
.
Has
(
pod
.
Spec
.
NodeName
)
{
if
pod
.
Spec
.
NodeName
!=
""
{
if
pod
.
Spec
.
NodeName
!=
""
{
_
,
scheduledCondition
:=
api
.
GetPodCondition
(
&
pod
.
Status
,
api
.
PodScheduled
)
Expect
(
scheduledCondition
!=
nil
)
.
To
(
Equal
(
true
))
Expect
(
scheduledCondition
.
Status
)
.
To
(
Equal
(
api
.
ConditionTrue
))
scheduledPods
=
append
(
scheduledPods
,
pod
)
scheduledPods
=
append
(
scheduledPods
,
pod
)
}
else
{
}
else
{
_
,
scheduledCondition
:=
api
.
GetPodCondition
(
&
pod
.
Status
,
api
.
PodScheduled
)
Expect
(
scheduledCondition
!=
nil
)
.
To
(
Equal
(
true
))
Expect
(
scheduledCondition
.
Status
)
.
To
(
Equal
(
api
.
ConditionFalse
))
notScheduledPods
=
append
(
notScheduledPods
,
pod
)
notScheduledPods
=
append
(
notScheduledPods
,
pod
)
}
}
}
}
...
...
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