diff --git a/cmd/kubelet/app/server.go b/cmd/kubelet/app/server.go index 0b8d8e67fce..897fa25ff6f 100644 --- a/cmd/kubelet/app/server.go +++ b/cmd/kubelet/app/server.go @@ -44,6 +44,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" + utilnet "k8s.io/apimachinery/pkg/util/net" utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/wait" @@ -933,9 +934,23 @@ func buildKubeletClientConfig(ctx context.Context, s *options.KubeletServer, nod } kubeClientConfigOverrides(s, clientConfig) - closeAllConns, err := updateDialer(clientConfig) - if err != nil { - return nil, nil, err + // Kubelet needs to be able to recover from stale http connections. + // HTTP2 has a mechanism to detect broken connections by sending periodical pings. + // HTTP1 only can have one persistent connection, and it will close all Idle connections + // once the Kubelet heartbeat fails. However, since there are many edge cases that we can't + // control, users can still opt-in to the previous behavior for closing the connections by + // setting the environment variable DISABLE_HTTP2. + var closeAllConns func() + if s := os.Getenv("DISABLE_HTTP2"); len(s) > 0 { + klog.InfoS("HTTP2 has been explicitly disabled, updating Kubelet client Dialer to forcefully close active connections on heartbeat failures") + closeAllConns, err = updateDialer(clientConfig) + if err != nil { + return nil, nil, err + } + } else { + closeAllConns = func() { + utilnet.CloseIdleConnectionsFor(clientConfig.Transport) + } } return clientConfig, closeAllConns, nil }