Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CloseIdleConnections of wrapped Transport RoundTrippers #104844

Merged
merged 2 commits into from Nov 16, 2021

Conversation

aojea
Copy link
Member

@aojea aojea commented Sep 8, 2021

/kind bug
/kind cleanup

Fixes #100849

Add a function func CloseIdleConnectionsFor(transport http.RoundTripper) that allow to close the idle connections that belong to the transport, if the transport implements the RoundTripperWrapper interface.

Use this new function to close the idle connections on kubelet and avoid using a custom dialer that forces the kubelet to create multiple TCP connections , instead of reusing a single one.

Don't use a custom dialer for the kubelet if is not rotating certificates, so we can reuse TCP connections and have only one between the apiserver and the kubelet.
If users experiment problems with stale connections  using HTTP1.1, they can force the previous behavior of the kubelet by setting the environment variable DISABLE_HTTP2.

@k8s-ci-robot k8s-ci-robot added release-note Denotes a PR that will be considered when it comes time to generate release notes. kind/bug Categorizes issue or PR as related to a bug. kind/cleanup Categorizes issue or PR as related to cleaning up code, process, or technical debt. size/L Denotes a PR that changes 100-499 lines, ignoring generated files. do-not-merge/needs-kind Indicates a PR lacks a `kind/foo` label and requires one. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. do-not-merge/needs-sig Indicates an issue or PR lacks a `sig/foo` label and requires one. needs-triage Indicates an issue or PR lacks a `triage/foo` label and requires one. needs-priority Indicates a PR lacks a `priority/foo` label and requires one. and removed do-not-merge/needs-kind Indicates a PR lacks a `kind/foo` label and requires one. labels Sep 8, 2021
@k8s-ci-robot k8s-ci-robot added area/apiserver area/kubelet sig/api-machinery Categorizes an issue or PR as relevant to SIG API Machinery. sig/auth Categorizes an issue or PR as relevant to SIG Auth. sig/node Categorizes an issue or PR as relevant to SIG Node. and removed do-not-merge/needs-sig Indicates an issue or PR lacks a `sig/foo` label and requires one. labels Sep 8, 2021
@aojea
Copy link
Member Author

aojea commented Sep 8, 2021

E0908 16:39:20.689451 2358 server.go:293] "Failed to run kubelet" err="failed to run Kubelet: transport doesn't implement closeIdler: %!w()"

this is not working, maybe I'm missing some wrapper 🤔

@ehashman ehashman added this to Triage in SIG Node PR Triage Sep 9, 2021
@fedebongio
Copy link
Contributor

/assign @liggitt
Jordan, giving it to you because people is asking you as part of #100849, hope you don't mind
/cc @caesarxuchao
/triage accepted

@k8s-ci-robot k8s-ci-robot added the triage/accepted Indicates an issue or PR is ready to be actively worked on. label Sep 9, 2021
@k8s-ci-robot k8s-ci-robot removed the needs-triage Indicates an issue or PR lacks a `triage/foo` label and requires one. label Sep 9, 2021
cmd/kubelet/app/server.go Outdated Show resolved Hide resolved
@aojea
Copy link
Member Author

aojea commented Nov 16, 2021

/assign @wojtek-t

Copy link
Member

@wojtek-t wojtek-t left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see... so the expectation would be:

  1. kubelets using http/2 would use the http/2 ping timeout and this CloseIdleConnections mechanism
  2. kubelets that automatically negotiated back to http/1.1 would use only this CloseIdleConnections mechanism
  3. a kubelet could be forced to use http/1.1 and use the old tear-down-all-connections mechanism by explicitly setting DISABLE_HTTP2

That limits the exposure to regressions because of this new mechanism without an escape hatch to kubelets which:

  1. don't use client certificate rotation
  2. use http/2

That seems reasonable to me, though I'd like a sig-node reviewer to ack as well.

That seems reasonable to me as well and it seems we have an ACK from sig-node reviewer.

I just added a couple nits to the PR.

staging/src/k8s.io/apimachinery/pkg/util/net/http.go Outdated Show resolved Hide resolved
staging/src/k8s.io/client-go/rest/connection_test.go Outdated Show resolved Hide resolved
staging/src/k8s.io/client-go/rest/connection_test.go Outdated Show resolved Hide resolved
staging/src/k8s.io/client-go/rest/connection_test.go Outdated Show resolved Hide resolved
staging/src/k8s.io/client-go/rest/request_test.go Outdated Show resolved Hide resolved
enableHTTP2 bool
}{
{"HTTP1", false},
{"HTTP2", false},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

interestingly, the http1 client shows a different behavior here than the http2, in http2 the connection is not closed after the timeout, I think that is because of

https://datatracker.ietf.org/doc/html/rfc7540#section-9.1

HTTP/2 connections are persistent. For best performance, it is
expected that clients will not close connections until it is
determined that no further communication with a server is necessary
(for example, when a user navigates away from a particular web page)
or until the server closes the connection.

Antonio Ojea added 2 commits November 16, 2021 15:39
It iterates over the wrapped transports until it finds one
that implements the CloseIdleConnections method and executes it.

add test for closeidle http1 connections

add test for http1.1 reconnect with inflight request

add test to reuse connection request

add test for request connect after timeout

add test for client-go request concurrency
Don't use a custom dialer for the kubelet if is not rotating
certificates, so we can reuse TCP connections because we don't need
a customer dialer.

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 heartbet 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.
@k8s-ci-robot k8s-ci-robot removed the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Nov 16, 2021
@wojtek-t
Copy link
Member

/lgtm
/approve

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Nov 16, 2021
@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: aojea, pacoxu, wojtek-t

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Nov 16, 2021
@k8s-ci-robot k8s-ci-robot merged commit 45f77ca into kubernetes:master Nov 16, 2021
SIG Node PR Triage automation moved this from Needs Approver to Done Nov 16, 2021
SIG Auth Old automation moved this from Pending other SIGs to Closed / Done Nov 16, 2021
@k8s-ci-robot k8s-ci-robot added this to the v1.23 milestone Nov 16, 2021
@JohnRusk
Copy link

@aojea Out of curiousity, how does the use of a custom dialer (before this PR) prevent re-use of connections? I've been looking at the code in this PR because you said in another thread that it might explain the issue I've been seeing. (#65954 (comment))

@aojea
Copy link
Member Author

aojea commented Jan 17, 2022

@aojea Out of curiousity, how does the use of a custom dialer (before this PR) prevent re-use of connections? I've been looking at the code in this PR because you said in another thread that it might explain the issue I've been seeing. (#65954 (comment))

The client go constructor create a new transport if the dialer is customized

if c.TLS.GetCert != nil || c.Dial != nil || c.Proxy != nil {

Before #105490 each group version created a new transport

christarazi added a commit to christarazi/cilium that referenced this pull request Mar 31, 2022
Following up from cilium#19259, this
commit implements the same logic as kubelet [1] to close all idle
connections. We can rely on HTTP/2 to determine which connections are
idle (HTTP/2 pings), instead of closing all connections indiscriminately
(when the heartbeat fails) via the custom dialer in setDialer().

We can assume HTTP/2 support as it has been supported since K8s 1.20
[2]. Users can disable HTTP/2 by setting the DISABLE_HTTP2 environment
variable, however this only really meant from very advanced users, hence
no documentation. Kubernetes has been running with HTTP/2 as the default
for a long time (~since Dec 2020) without major issues.

CloseIdleConnectionsFor() was introduced in K8s 1.23 [3], hence this commit
cannot be backported to any earlier version of Cilium which doesn't
support K8s 1.23.

[1]: kubernetes/kubernetes#104844
[2]: kubernetes/kubernetes#95981
[3]: kubernetes/kubernetes@b9d865a

Suggested-by: André Martins <andre@cilium.io>
Signed-off-by: Chris Tarazi <chris@isovalent.com>
pchaigno pushed a commit to cilium/cilium that referenced this pull request Apr 4, 2022
Following up from #19259, this
commit implements the same logic as kubelet [1] to close all idle
connections. We can rely on HTTP/2 to determine which connections are
idle (HTTP/2 pings), instead of closing all connections indiscriminately
(when the heartbeat fails) via the custom dialer in setDialer().

We can assume HTTP/2 support as it has been supported since K8s 1.20
[2]. Users can disable HTTP/2 by setting the DISABLE_HTTP2 environment
variable, however this only really meant from very advanced users, hence
no documentation. Kubernetes has been running with HTTP/2 as the default
for a long time (~since Dec 2020) without major issues.

CloseIdleConnectionsFor() was introduced in K8s 1.23 [3], hence this commit
cannot be backported to any earlier version of Cilium which doesn't
support K8s 1.23.

[1]: kubernetes/kubernetes#104844
[2]: kubernetes/kubernetes#95981
[3]: kubernetes/kubernetes@b9d865a

Suggested-by: André Martins <andre@cilium.io>
Signed-off-by: Chris Tarazi <chris@isovalent.com>
pchaigno pushed a commit to pchaigno/cilium that referenced this pull request Apr 5, 2022
[ upstream commit 365c788 ]

Following up from cilium#19259, this
commit implements the same logic as kubelet [1] to close all idle
connections. We can rely on HTTP/2 to determine which connections are
idle (HTTP/2 pings), instead of closing all connections indiscriminately
(when the heartbeat fails) via the custom dialer in setDialer().

We can assume HTTP/2 support as it has been supported since K8s 1.20
[2]. Users can disable HTTP/2 by setting the DISABLE_HTTP2 environment
variable, however this only really meant from very advanced users, hence
no documentation. Kubernetes has been running with HTTP/2 as the default
for a long time (~since Dec 2020) without major issues.

CloseIdleConnectionsFor() was introduced in K8s 1.23 [3], hence this commit
cannot be backported to any earlier version of Cilium which doesn't
support K8s 1.23.

[1]: kubernetes/kubernetes#104844
[2]: kubernetes/kubernetes#95981
[3]: kubernetes/kubernetes@b9d865a

Suggested-by: André Martins <andre@cilium.io>
Signed-off-by: Chris Tarazi <chris@isovalent.com>
Signed-off-by: Paul Chaignon <paul@cilium.io>
pchaigno pushed a commit to cilium/cilium that referenced this pull request Apr 6, 2022
[ upstream commit 365c788 ]

Following up from #19259, this
commit implements the same logic as kubelet [1] to close all idle
connections. We can rely on HTTP/2 to determine which connections are
idle (HTTP/2 pings), instead of closing all connections indiscriminately
(when the heartbeat fails) via the custom dialer in setDialer().

We can assume HTTP/2 support as it has been supported since K8s 1.20
[2]. Users can disable HTTP/2 by setting the DISABLE_HTTP2 environment
variable, however this only really meant from very advanced users, hence
no documentation. Kubernetes has been running with HTTP/2 as the default
for a long time (~since Dec 2020) without major issues.

CloseIdleConnectionsFor() was introduced in K8s 1.23 [3], hence this commit
cannot be backported to any earlier version of Cilium which doesn't
support K8s 1.23.

[1]: kubernetes/kubernetes#104844
[2]: kubernetes/kubernetes#95981
[3]: kubernetes/kubernetes@b9d865a

Suggested-by: André Martins <andre@cilium.io>
Signed-off-by: Chris Tarazi <chris@isovalent.com>
Signed-off-by: Paul Chaignon <paul@cilium.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. area/apiserver area/kubelet cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. kind/bug Categorizes issue or PR as related to a bug. kind/cleanup Categorizes issue or PR as related to cleaning up code, process, or technical debt. lgtm "Looks good to me", indicates that a PR is ready to be merged. priority/important-longterm Important over the long term, but may not be staffed and/or may need multiple releases to complete. release-note Denotes a PR that will be considered when it comes time to generate release notes. sig/api-machinery Categorizes an issue or PR as relevant to SIG API Machinery. sig/auth Categorizes an issue or PR as relevant to SIG Auth. sig/node Categorizes an issue or PR as relevant to SIG Node. size/L Denotes a PR that changes 100-499 lines, ignoring generated files. triage/accepted Indicates an issue or PR is ready to be actively worked on.
Projects
Archived in project
SIG Auth Old
Closed / Done
Development

Successfully merging this pull request may close these issues.

kubelet don't share transport by default after #95427