From 1a3b51b9efab1a04e508dc19c1e036290049c3be Mon Sep 17 00:00:00 2001 From: thev1ndu Date: Mon, 31 Aug 2026 12:29:46 +0530 Subject: [PATCH] Add example for enabling TCP keepalive via socket_options Configuration.socket_options is already wired through to urllib3, but there is no example showing how to use it. Long-lived watches and log streams can hang when a connection is silently dropped; TCP keepalive lets the kernel detect the dead peer. Add an example and list it in the examples README. Fixes #2067 --- examples/README.md | 1 + examples/tcp_keepalive.py | 68 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 examples/tcp_keepalive.py diff --git a/examples/README.md b/examples/README.md index 43a11fba4e..c6774dda22 100644 --- a/examples/README.md +++ b/examples/README.md @@ -9,6 +9,7 @@ comments throughout the code. - pod_logs.py — basic (blocking) pod log streaming example - pod_logs_non_blocking.py — non-blocking streaming of pod logs with graceful shutdown +- tcp_keepalive.py — enable TCP keepalive via Configuration.socket_options so dead connections on long-lived watches/log streams are detected ## Setup diff --git a/examples/tcp_keepalive.py b/examples/tcp_keepalive.py new file mode 100644 index 0000000000..204d83a83f --- /dev/null +++ b/examples/tcp_keepalive.py @@ -0,0 +1,68 @@ +# Copyright 2026 The Kubernetes Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Shows how to enable TCP keepalive on the client connections. + +Long-lived requests such as watches or `follow=True` log streams can hang +silently when the connection is dropped by a load balancer or a firewall +without a FIN/RST reaching the client. Enabling TCP keepalive lets the +kernel detect a dead peer and close the socket, so the client raises an +error instead of blocking forever. + +The `socket_options` on `Configuration` are passed straight to the +underlying urllib3 connection pool, on top of urllib3's own defaults. +""" + +import socket + +from kubernetes import client, config + + +def keepalive_socket_options(): + """Return socket options that enable TCP keepalive. + + TCP_KEEPIDLE / TCP_KEEPINTVL / TCP_KEEPCNT are not available on every + platform, so they are added only when the running platform exposes them. + """ + options = [(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)] + + # Start probing after 30s idle, probe every 10s, drop after 6 failures. + if hasattr(socket, "TCP_KEEPIDLE"): + options.append((socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 30)) + if hasattr(socket, "TCP_KEEPINTVL"): + options.append((socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 10)) + if hasattr(socket, "TCP_KEEPCNT"): + options.append((socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 6)) + + return options + + +def main(): + config.load_kube_config() + + configuration = client.Configuration.get_default_copy() + configuration.socket_options = keepalive_socket_options() + + api_client = client.ApiClient(configuration=configuration) + v1 = client.CoreV1Api(api_client=api_client) + + print("Listing pods with TCP keepalive enabled:") + ret = v1.list_pod_for_all_namespaces(watch=False) + for i in ret.items: + print(f"{i.status.pod_ip}\t{i.metadata.namespace}\t{i.metadata.name}") + + +if __name__ == '__main__': + main()