mrkeyoor.com_
Sun 20 Sept 12:45 UTC
PyPIInfraupdated 19 Sept 2026

kubernetes review

Our Python 3.12 sandbox imported kubernetes 36.0.3 successfully, but the import alone took 2.21 seconds and the install occupied 58 MB across 22 packages. This is the official generated Python client for the Kubernetes API. CoreV1Api covers pods, services, secrets, and namespaces; AppsV1Api handles deployments and related workloads; watch streams changes; stream supports exec and attach. Version 36.0.3 matches the Kubernetes 1.36 API surface, and the project marks the 34, 35, and 36 GA client lines as maintained. The breadth is useful for cluster automation, though generated methods and models make small scripts feel much larger than their job.

Verdict

Use kubernetes when complete official API coverage and version matching matter more than install weight or generated-call ergonomics. For controllers or mostly custom-resource code, an operator framework or smaller dynamic client removes a lot of plumbing.

We installed it

Lab card: what happened when we installed kubernetesScreenshot of kubernetes documentation
Install✓ · 0.9s22 packages on disk · 58 MB
Importimport kubernetes in 2.21s · pure Python · requires Python >=3.10
Known vulns0(pip-audit)

Answers from our run

Does kubernetes install cleanly?

Yes. In a fresh container with an empty cache, pip install kubernetes finished in 0.9s, leaving 22 packages and 58 MB on disk. pip-audit reported no known vulnerabilities.

What does kubernetes need to run?

Python >=3.10, and nothing compiled: it is pure Python. In our run import kubernetes succeeded in 2.21s.

kubernetes or kopf: which should you use?

kopf: Use it for a Python operator with handlers, retries, finalizers, and status updates. Use kubernetes when complete official API coverage and version matching matter more than install weight or generated-call ergonomics.

When should you not use kubernetes?

You are building an operator with retries, finalizers, reconciliation state, and event handlers; this client supplies API calls, not an operator framework

API stability4/5The project follows semantic versioning and publishes a client-to-cluster compatibility table. Within a supported major, familiar helpers such as load_kube_config(), CoreV1Api, Watch, and stream remain recognizable. Each major is generated from a Kubernetes minor, however, so API objects and model fields follow upstream additions and removals. Pinning the major to the cluster version is part of using this client safely.
Docs3/5The main README explains installation, synchronous and asyncio examples, watches, compatibility, exec and attach troubleshooting, and debug logging. Every generated API and model has reference material under kubernetes/README.md. Finding one call still takes work because the reference is generated and method names expose many keyword options without a task-oriented explanation. The examples directory fills some gaps but is not a production guide.
Maintenance5/5GitHub reports a push on August 17, 2026, an unarchived repository, and 71 open issues and pull requests. Release 36.0.3 was published on July 13, 2026, and the README currently marks GA lines 34, 35, and 36 as maintained. Releases track Kubernetes minors under SIG API Machinery, giving users a clear support window even though fixes may not be backported to every maintained line.
Ecosystem5/5The package's latest supplied weekly count is 25,377,113 downloads, and GitHub reports 7,647 stars. It is the official Python client, so Kubernetes examples and many automation projects use its generated class names and configuration helpers. That reach comes with a sizable dependency footprint: our clean install placed 22 packages on disk, and custom resources still fall back to dictionary-shaped APIs.

Use it if

  • You are writing Python automation that must cover the official Kubernetes 1.36 API, including typed resource models
  • The code runs in a pod and should authenticate through its mounted service-account token and cluster CA
  • You need pod exec or attach through the library's WebSocket-based stream helper
  • You need both synchronous calls and an asyncio client under one official package
Skip it if

Setup reality

Our fresh Python 3.12 install of kubernetes 36.0.3 succeeded in 0.9 seconds. It left 22 packages using 58 MB, and pip-audit reported 0 known vulnerabilities. The package declares 16 direct dependencies, requires Python 3.10 or newer, and is pure Python. It does not ship py.typed, so type checkers cannot treat the whole installed package as a declared typed distribution. import kubernetes worked and took 2.21 seconds.

Local scripts normally call config.load_kube_config(), which reads the selected kubeconfig context and may run an external credential plugin. That means aws, gke-gcloud-auth-plugin, or az must be installed when the kubeconfig refers to one. In a pod, call config.load_incluster_config() and grant the service account only the RBAC verbs and resources it needs. A 403 arrives as ApiException; the useful Kubernetes Status message is in its body.

Client 36 tracks Kubernetes 1.36. The compatibility table marks older or newer clusters as sharing only part of the API surface, so pin the client major to the clusters you operate. Lists should use label selectors and pagination on large clusters. Watches can end when the server closes the connection or a resource version expires. Production watchers need a relist-and-resume loop instead of assuming one generator runs forever.

Use kubernetes.stream.stream() for exec and attach. Calling the generated connect method directly does not perform the supported WebSocket flow. The README also warns that stream changes the API client's request protocol, so create a new client before returning to normal REST calls. The asyncio package needs an async ApiClient context manager to close its session. Generated method names are long, and many options arrive as keyword arguments, so keep the generated API reference open while wiring uncommon endpoints.

Patterns

Load config for either execution location load-config

from kubernetes import client, config
from kubernetes.config.config_exception import ConfigException

try:
    config.load_incluster_config()      # running as a pod
except ConfigException:
    config.load_kube_config()           # local kubeconfig

v1 = client.CoreV1Api()
print(v1.list_namespace().items[0].metadata.name)

Try in-cluster configuration first when one script runs locally and as a pod. An explicit kubeconfig context avoids sending a local command to the wrong cluster.

Filter pods at the API server list-with-selectors

v1 = client.CoreV1Api()

pods = v1.list_namespaced_pod(
    namespace='default',
    label_selector='app=web,tier!=canary',
    field_selector='status.phase=Running',
    _request_timeout=30,
)
for p in pods.items:
    print(p.metadata.name, p.status.pod_ip)

Label and field selectors reduce response work. Kubernetes supports field selection only for documented fields, and the server rejects unsupported ones.

Paginate a cluster-wide pod list paginate-large-lists

v1 = client.CoreV1Api()
continue_token = None

while True:
    resp = v1.list_pod_for_all_namespaces(limit=500, _continue=continue_token)
    for pod in resp.items:
        handle(pod)
    continue_token = resp.metadata._continue
    if not continue_token:
        break

The argument is _continue because continue is a Python keyword. Reuse the returned token without changing the other list parameters.

Create objects from a YAML file apply-manifest

from kubernetes import client, config, utils

config.load_kube_config()
k8s = client.ApiClient()

utils.create_from_yaml(k8s, 'deployment.yaml', namespace='staging')

# or apply semantics instead of create
utils.create_from_yaml(k8s, 'deployment.yaml', apply=True)

The default action is create, so an existing object produces a 409 inside FailToCreateError. Use apply only when server-side apply semantics suit the manifest.

Patch deployment replicas patch-resource

apps = client.AppsV1Api()

apps.patch_namespaced_deployment(
    name='web',
    namespace='default',
    body={'spec': {'replicas': 5}},
)

# scale subresource is cheaper for just replicas
apps.patch_namespaced_deployment_scale(
    name='web', namespace='default', body={'spec': {'replicas': 5}}
)

A patch leaves omitted fields alone. The scale subresource is the narrower endpoint when replicas are the only intended change.

Watch pod changes watch-events

from kubernetes import client, config, watch

config.load_kube_config()
v1 = client.CoreV1Api()
w = watch.Watch()

for event in w.stream(v1.list_namespaced_pod, namespace='default'):
    print(event['type'], event['object'].metadata.name)
    if done:
        w.stop()

A watch is a long-running HTTP stream, not a permanent subscription. Relist and restart when the resource version expires or the server closes it.

Execute a command in a pod exec-into-pod

from kubernetes.stream import stream

resp = stream(
    v1.connect_get_namespaced_pod_exec,
    'web-0',
    'default',
    command=['/bin/sh', '-c', 'cat /etc/hostname'],
    container='app',
    stderr=True,
    stdout=True,
    stdin=False,
    tty=False,
    _preload_content=True,
)
print(resp)

Wrap the generated exec method with stream(). Create another API client before ordinary REST calls because stream changes the existing client's protocol handling.

Read a custom resource custom-resources

co = client.CustomObjectsApi()

obj = co.get_namespaced_custom_object(
    group='cert-manager.io',
    version='v1',
    namespace='default',
    plural='certificates',
    name='web-tls',
)
print(obj['status']['conditions'])

CustomObjectsApi returns dictionaries. plural must match the CRD resource name, such as certificates, rather than its singular Kind.

Discover a resource at runtime dynamic-client

from kubernetes import config, dynamic
from kubernetes.client import api_client

client_ = dynamic.DynamicClient(
    api_client.ApiClient(configuration=config.load_kube_config())
)

api = client_.resources.get(api_version='apps/v1', kind='Deployment')
for d in api.get(namespace='default').items:
    print(d.metadata.name, d.spec.replicas)

The dynamic client discovers resource metadata from the API server. This helps with unknown kinds but gives up generated model attributes.

Handle Kubernetes API failures handle-api-errors

import json
from kubernetes.client.rest import ApiException

try:
    v1.read_namespaced_secret('db-creds', 'default')
except ApiException as exc:
    if exc.status == 404:
        create_secret()
    elif exc.status == 403:
        reason = json.loads(exc.body)['message']
        raise PermissionError(reason) from exc
    else:
        raise

ApiException covers HTTP failures. Branch on status and parse body for the server's Status message instead of relying on the short reason phrase.

Maintain a local informer cache shared-informer

from kubernetes import client, config
from kubernetes.informer import SharedInformer, ADDED, MODIFIED, DELETED

config.load_kube_config()
v1 = client.CoreV1Api()

informer = SharedInformer(
    v1.list_pod_for_all_namespaces,
    resync_period=300,
    label_selector='app=web',
)
informer.add_event_handler(ADDED, lambda obj: print('added', obj.metadata.name))
informer.add_event_handler(DELETED, lambda obj: print('gone', obj.metadata.name))
informer.start()

pods = informer.cache.list()          # served from memory
one = informer.cache.get_by_key('default/web-0')

Handlers run around a shared local cache. Keep callbacks quick and thread-safe because this helper does not provide a controller workqueue.

Use the asyncio client async-client

import asyncio
from kubernetes.aio import client, config
from kubernetes.aio.client.api_client import ApiClient

async def main():
    await config.load_kube_config()
    async with ApiClient() as api:
        v1 = client.CoreV1Api(api)
        pods = await v1.list_pod_for_all_namespaces()
        for p in pods.items:
            print(p.metadata.namespace, p.metadata.name)

asyncio.run(main())

Close ApiClient with async with. Leaving it open can produce an unclosed aiohttp session at shutdown.

Alternatives

PackageRegistryPick it when
kopfPyPIUse it for a Python operator with handlers, retries, finalizers, and status updates
lightkubePyPIUse it when a smaller resource-oriented client is easier for application code
pykube-ngPyPIUse it for object-style scripting around common Kubernetes resources
kr8sPyPIUse it for a compact sync and async API centered on resource objects

More infra guides

boto3 · opentelemetry-api · psutil · distro · @opentelemetry/api · google-cloud-storage · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.