kube-proxy: fix healthz return unexpect code 200

This commit is contained in:
cyclinder 2022-04-14 20:55:45 +08:00
parent 7380fc735a
commit 3fa4705aea

View File

@ -44,6 +44,7 @@ type ProxierHealthUpdater interface {
} }
var _ ProxierHealthUpdater = &proxierHealthServer{} var _ ProxierHealthUpdater = &proxierHealthServer{}
var zeroTime = time.Time{}
// proxierHealthServer returns 200 "OK" by default. It verifies that the delay between // proxierHealthServer returns 200 "OK" by default. It verifies that the delay between
// QueuedUpdate() calls and Updated() calls never exceeds healthTimeout. // QueuedUpdate() calls and Updated() calls never exceeds healthTimeout.
@ -57,8 +58,8 @@ type proxierHealthServer struct {
recorder events.EventRecorder recorder events.EventRecorder
nodeRef *v1.ObjectReference nodeRef *v1.ObjectReference
lastUpdated atomic.Value lastUpdated atomic.Value
lastQueued atomic.Value oldestPendingQueued atomic.Value
} }
// NewProxierHealthServer returns a proxier health http server. // NewProxierHealthServer returns a proxier health http server.
@ -80,12 +81,14 @@ func newProxierHealthServer(listener listener, httpServerFactory httpServerFacto
// Updated updates the lastUpdated timestamp. // Updated updates the lastUpdated timestamp.
func (hs *proxierHealthServer) Updated() { func (hs *proxierHealthServer) Updated() {
hs.oldestPendingQueued.Store(zeroTime)
hs.lastUpdated.Store(hs.clock.Now()) hs.lastUpdated.Store(hs.clock.Now())
} }
// QueuedUpdate updates the lastQueued timestamp. // QueuedUpdate updates the lastQueued timestamp.
func (hs *proxierHealthServer) QueuedUpdate() { func (hs *proxierHealthServer) QueuedUpdate() {
hs.lastQueued.Store(hs.clock.Now()) // Set oldestPendingQueued only if it's currently zero
hs.oldestPendingQueued.CompareAndSwap(zeroTime, hs.clock.Now())
} }
// Run starts the healthz HTTP server and blocks until it exits. // Run starts the healthz HTTP server and blocks until it exits.
@ -117,9 +120,9 @@ type healthzHandler struct {
} }
func (h healthzHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) { func (h healthzHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
var lastQueued, lastUpdated time.Time var oldestPendingQueued, lastUpdated time.Time
if val := h.hs.lastQueued.Load(); val != nil { if val := h.hs.oldestPendingQueued.Load(); val != nil {
lastQueued = val.(time.Time) oldestPendingQueued = val.(time.Time)
} }
if val := h.hs.lastUpdated.Load(); val != nil { if val := h.hs.lastUpdated.Load(); val != nil {
lastUpdated = val.(time.Time) lastUpdated = val.(time.Time)
@ -128,15 +131,11 @@ func (h healthzHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
healthy := false healthy := false
switch { switch {
case lastUpdated.IsZero(): case oldestPendingQueued.IsZero():
// The proxy is healthy while it's starting up // The proxy is healthy while it's starting up
// TODO: this makes it useless as a readinessProbe. Consider changing // or the proxy is fully synced.
// to only become healthy after the proxy is fully synced.
healthy = true healthy = true
case lastUpdated.After(lastQueued): case currentTime.Sub(oldestPendingQueued) < h.hs.healthTimeout:
// We've processed all updates
healthy = true
case currentTime.Sub(lastQueued) < h.hs.healthTimeout:
// There's an unprocessed update queued, but it's not late yet // There's an unprocessed update queued, but it's not late yet
healthy = true healthy = true
} }
@ -147,14 +146,12 @@ func (h healthzHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
resp.WriteHeader(http.StatusServiceUnavailable) resp.WriteHeader(http.StatusServiceUnavailable)
} else { } else {
resp.WriteHeader(http.StatusOK) resp.WriteHeader(http.StatusOK)
// In older releases, the returned "lastUpdated" time indicated the last // In older releases, the returned "lastUpdated" time indicated the last
// time the proxier sync loop ran, even if nothing had changed. To // time the proxier sync loop ran, even if nothing had changed. To
// preserve compatibility, we use the same semantics: the returned // preserve compatibility, we use the same semantics: the returned
// lastUpdated value is "recent" if the server is healthy. The kube-proxy // lastUpdated value is "recent" if the server is healthy. The kube-proxy
// metrics provide more detailed information. // metrics provide more detailed information.
lastUpdated = currentTime lastUpdated = currentTime
} }
fmt.Fprintf(resp, `{"lastUpdated": %q,"currentTime": %q}`, lastUpdated, currentTime) fmt.Fprintf(resp, `{"lastUpdated": %q,"currentTime": %q}`, lastUpdated, currentTime)
} }