mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-31 15:25:57 +00:00
windows/service: implement graceful shutdown when run as windows service
- Fixes https://github.com/kubernetes/kubernetes/issues/72900 The issue here originally is that os.Exit() is called which exits the process too early (before svc.Execute updates the status to stopped). This is picked up as service error and leads to restarting, if restart-on-fail is configured for the windows service. svc.Execute already guarantees that the application is exited after, so that os.Exit call would be unnecessary. This rework also adds graceful shutdown, which also resolves the underlying root cause. The graceful shutdown is not guaranteed to succeed, since the service controller can decide to kill the service any time after exceeding a shutdown timeout.
This commit is contained in:
parent
ccd83ce1c5
commit
f243c88779
@ -19,8 +19,7 @@ limitations under the License.
|
||||
package service
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"k8s.io/apiserver/pkg/server"
|
||||
"k8s.io/klog"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
@ -80,9 +79,19 @@ Loop:
|
||||
case svc.Interrogate:
|
||||
s <- c.CurrentStatus
|
||||
case svc.Stop, svc.Shutdown:
|
||||
s <- svc.Status{State: svc.Stopped}
|
||||
// TODO: Stop the kubelet gracefully instead of killing the process
|
||||
os.Exit(0)
|
||||
klog.Infof("Service stopping")
|
||||
// We need to translate this request into a signal that can be handled by the the signal handler
|
||||
// handling shutdowns normally (currently apiserver/pkg/server/signal.go).
|
||||
// If we do not do this, our main threads won't be notified of the upcoming shutdown.
|
||||
// Since Windows services do not use any console, we cannot simply generate a CTRL_BREAK_EVENT
|
||||
// but need a dedicated notification mechanism.
|
||||
server.RequestShutdown()
|
||||
|
||||
// Free up the control handler and let us terminate as gracefully as possible.
|
||||
// If that takes too long, the service controller will kill the remaining threads.
|
||||
// As per https://docs.microsoft.com/en-us/windows/desktop/services/service-control-handler-function
|
||||
s <- svc.Status{State: svc.StopPending}
|
||||
break Loop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import (
|
||||
)
|
||||
|
||||
var onlyOneSignalHandler = make(chan struct{})
|
||||
var shutdownHandler = make(chan os.Signal, 2)
|
||||
|
||||
// SetupSignalHandler registered for SIGTERM and SIGINT. A stop channel is returned
|
||||
// which is closed on one of these signals. If a second signal is caught, the program
|
||||
@ -30,14 +31,21 @@ func SetupSignalHandler() <-chan struct{} {
|
||||
close(onlyOneSignalHandler) // panics when called twice
|
||||
|
||||
stop := make(chan struct{})
|
||||
c := make(chan os.Signal, 2)
|
||||
signal.Notify(c, shutdownSignals...)
|
||||
signal.Notify(shutdownHandler, shutdownSignals...)
|
||||
go func() {
|
||||
<-c
|
||||
<-shutdownHandler
|
||||
close(stop)
|
||||
<-c
|
||||
<-shutdownHandler
|
||||
os.Exit(1) // second signal. Exit directly.
|
||||
}()
|
||||
|
||||
return stop
|
||||
}
|
||||
|
||||
// RequestShutdown emulates a received event that is considered as shutdown signal (SIGTERM/SIGINT)
|
||||
func RequestShutdown() {
|
||||
select {
|
||||
case shutdownHandler <- shutdownSignals[0]:
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user