@@ -23,9 +23,11 @@ import (
23
23
"k8s.io/apimachinery/pkg/types"
24
24
"k8s.io/apimachinery/pkg/util/sets"
25
25
"k8s.io/apimachinery/pkg/util/wait"
26
+ utilfeature "k8s.io/apiserver/pkg/util/feature"
26
27
"k8s.io/client-go/tools/record"
27
28
"k8s.io/component-base/metrics"
28
29
"k8s.io/klog"
30
+ "k8s.io/kubernetes/pkg/features"
29
31
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
30
32
"k8s.io/kubernetes/pkg/kubelet/prober/results"
31
33
"k8s.io/kubernetes/pkg/kubelet/status"
@@ -37,7 +39,7 @@ var ProberResults = metrics.NewCounterVec(
37
39
& metrics.CounterOpts {
38
40
Subsystem : "prober" ,
39
41
Name : "probe_total" ,
40
- Help : "Cumulative number of a liveness or readiness probe for a container by result." ,
42
+ Help : "Cumulative number of a liveness, readiness or startup probe for a container by result." ,
41
43
StabilityLevel : metrics .ALPHA ,
42
44
},
43
45
[]string {"probe_type" ,
@@ -89,6 +91,9 @@ type manager struct {
89
91
// livenessManager manages the results of liveness probes
90
92
livenessManager results.Manager
91
93
94
+ // startupManager manages the results of startup probes
95
+ startupManager results.Manager
96
+
92
97
// prober executes the probe actions.
93
98
prober * prober
94
99
}
@@ -103,11 +108,13 @@ func NewManager(
103
108
104
109
prober := newProber (runner , refManager , recorder )
105
110
readinessManager := results .NewManager ()
111
+ startupManager := results .NewManager ()
106
112
return & manager {
107
113
statusManager : statusManager ,
108
114
prober : prober ,
109
115
readinessManager : readinessManager ,
110
116
livenessManager : livenessManager ,
117
+ startupManager : startupManager ,
111
118
workers : make (map [probeKey ]* worker ),
112
119
}
113
120
}
@@ -116,6 +123,8 @@ func NewManager(
116
123
func (m * manager ) Start () {
117
124
// Start syncing readiness.
118
125
go wait .Forever (m .updateReadiness , 0 )
126
+ // Start syncing startup.
127
+ go wait .Forever (m .updateStartup , 0 )
119
128
}
120
129
121
130
// Key uniquely identifying container probes
@@ -125,12 +134,13 @@ type probeKey struct {
125
134
probeType probeType
126
135
}
127
136
128
- // Type of probe (readiness or liveness )
137
+ // Type of probe (liveness, readiness or startup )
129
138
type probeType int
130
139
131
140
const (
132
141
liveness probeType = iota
133
142
readiness
143
+ startup
134
144
135
145
probeResultSuccessful string = "successful"
136
146
probeResultFailed string = "failed"
@@ -144,6 +154,8 @@ func (t probeType) String() string {
144
154
return "Readiness"
145
155
case liveness :
146
156
return "Liveness"
157
+ case startup :
158
+ return "Startup"
147
159
default :
148
160
return "UNKNOWN"
149
161
}
@@ -157,6 +169,18 @@ func (m *manager) AddPod(pod *v1.Pod) {
157
169
for _ , c := range pod .Spec .Containers {
158
170
key .containerName = c .Name
159
171
172
+ if c .StartupProbe != nil && utilfeature .DefaultFeatureGate .Enabled (features .StartupProbe ) {
173
+ key .probeType = startup
174
+ if _ , ok := m .workers [key ]; ok {
175
+ klog .Errorf ("Startup probe already exists! %v - %v" ,
176
+ format .Pod (pod ), c .Name )
177
+ return
178
+ }
179
+ w := newWorker (m , startup , pod , c )
180
+ m .workers [key ] = w
181
+ go w .run ()
182
+ }
183
+
160
184
if c .ReadinessProbe != nil {
161
185
key .probeType = readiness
162
186
if _ , ok := m .workers [key ]; ok {
@@ -190,7 +214,7 @@ func (m *manager) RemovePod(pod *v1.Pod) {
190
214
key := probeKey {podUID : pod .UID }
191
215
for _ , c := range pod .Spec .Containers {
192
216
key .containerName = c .Name
193
- for _ , probeType := range [... ]probeType {readiness , liveness } {
217
+ for _ , probeType := range [... ]probeType {readiness , liveness , startup } {
194
218
key .probeType = probeType
195
219
if worker , ok := m .workers [key ]; ok {
196
220
worker .stop ()
@@ -223,6 +247,21 @@ func (m *manager) UpdatePodStatus(podUID types.UID, podStatus *v1.PodStatus) {
223
247
ready = ! exists
224
248
}
225
249
podStatus .ContainerStatuses [i ].Ready = ready
250
+
251
+ var started bool
252
+ if c .State .Running == nil {
253
+ started = false
254
+ } else if ! utilfeature .DefaultFeatureGate .Enabled (features .StartupProbe ) {
255
+ // the container is running, assume it is started if the StartupProbe feature is disabled
256
+ started = true
257
+ } else if result , ok := m .startupManager .Get (kubecontainer .ParseContainerID (c .ContainerID )); ok {
258
+ started = result == results .Success
259
+ } else {
260
+ // The check whether there is a probe which hasn't run yet.
261
+ _ , exists := m .getWorker (podUID , c .Name , startup )
262
+ started = ! exists
263
+ }
264
+ podStatus .ContainerStatuses [i ].Started = & started
226
265
}
227
266
// init containers are ready if they have exited with success or if a readiness probe has
228
267
// succeeded.
@@ -262,3 +301,10 @@ func (m *manager) updateReadiness() {
262
301
ready := update .Result == results .Success
263
302
m .statusManager .SetContainerReadiness (update .PodUID , update .ContainerID , ready )
264
303
}
304
+
305
+ func (m * manager ) updateStartup () {
306
+ update := <- m .startupManager .Updates ()
307
+
308
+ started := update .Result == results .Success
309
+ m .statusManager .SetContainerStartup (update .PodUID , update .ContainerID , started )
310
+ }
0 commit comments