From 863925f9ac64d44bb08b17fd6b986a698c03fd9c Mon Sep 17 00:00:00 2001 From: Min RK Date: Thu, 26 Apr 2018 17:18:53 +0200 Subject: [PATCH 1/2] use shared client in reflector avoids creating a new client for each reflector --- kubespawner/reflector.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kubespawner/reflector.py b/kubespawner/reflector.py index 5780b8bd..0e7e3357 100644 --- a/kubespawner/reflector.py +++ b/kubespawner/reflector.py @@ -7,9 +7,9 @@ from traitlets.config import LoggingConfigurable from traitlets import Any, Dict, Unicode -from kubernetes import client, config, watch +from kubernetes import config, watch from tornado.ioloop import IOLoop - +from .clients import shared_client class NamespacedResourceReflector(LoggingConfigurable): """ @@ -92,7 +92,7 @@ def __init__(self, *args, **kwargs): config.load_incluster_config() except config.ConfigException: config.load_kube_config() - self.api = getattr(client, self.api_group_name)() + self.api = shared_client(self.api_group_name) # FIXME: Protect against malicious labels? self.label_selector = ','.join(['{}={}'.format(k, v) for k, v in self.labels.items()]) From f076ec713d801b05391451885be50f08adfe8e87 Mon Sep 17 00:00:00 2001 From: Min RK Date: Thu, 26 Apr 2018 17:21:18 +0200 Subject: [PATCH 2/2] monkeypatch kubernetes to avoid creating unused threadpools for each client kubernetes creates client objects in a number of places e.g. every time a Watch is instantiated. These objects create a max-size thread pool for async requests, which bogs down the process if enough client objects are instantiated. Since we don't use async requests, these pools go totally unused. api_client is monkeypatched to avoid creating these ThreadPools in the first place. A patch has been submitted upstream to swagger-codegen, which is responsible for creating the ThreadPool. --- kubespawner/clients.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/kubespawner/clients.py b/kubespawner/clients.py index bcd24b3b..ef636a4c 100644 --- a/kubespawner/clients.py +++ b/kubespawner/clients.py @@ -1,6 +1,23 @@ +"""Shared clients for kubernetes + +avoids creating multiple kubernetes client objects, +each of which spawns an unused max-size thread pool +""" + +from unittest.mock import Mock import weakref import kubernetes.client +from kubernetes.client import api_client + +# FIXME: remove when instantiating a kubernetes client +# doesn't create N-CPUs threads unconditionally. +# monkeypatch threadpool in kubernetes api_client +# to avoid instantiating ThreadPools. +# This is known to work for kubernetes-4.0 +# and may need updating with later kubernetes clients +_dummy_pool = Mock() +api_client.ThreadPool = lambda *args, **kwargs: _dummy_pool _client_cache = {}