Create Deployments via Python Client

Create Kubernetes deployments via Python client — Kubernetes for Python Developers tutorial, lesson 46.

Focus: create kubernetes deployments via python client

Sponsored

You've mastered kubectl apply -f deployment.yaml a hundred times, but what happens when your team needs to spin up 50 deployments with different images, replicas, and labels across multiple clusters? Copy-pasting YAML becomes a maintenance nightmare. In this lesson, you'll solve that pain by creating Kubernetes deployments programmatically using the official Python client — turning cluster operations into repeatable, testable, and code-reviewable automation.

The problem this lesson solves

Every Python developer who works with Kubernetes eventually hits the wall of YAML templates. It starts simple: one deployment file. Then you need environment-specific variants, dynamic image tags, or automatic scaling based on CI variables. Before long you're writing Jinja templates and shell scripts to generate YAML, and debugging the mess when a quote breaks production.

The Python client (kubernetes package) eliminates that fragility. Instead of string-munging YAML, you define deployment specs as Python objects, apply them via a typed API, and get immediate feedback through exceptions. This approach shines in scenarios like:

  • Migration scripts: When you need to rollout a new version across hundreds of microservices.
  • Test setups: Spin up ephemeral deployments in a CI pipeline and tear them down after.
  • Custom controllers: Python services that manage Kubernetes resources themselves.

By the end of this lesson, you'll be able to create a deployment programmatically, verify it, and clean up — all from the comfort of your favorite language.

Core concept / mental model

Think of the Kubernetes Python client as a remote control for your cluster. Instead of manually typing commands into kubectl, you send structured Python objects over the API server. It's like the difference between using a GUI file manager and writing a Python script to move files.

Here's the mental model:

  • API client: The kubernetes package gives you classes that mirror the Kubernetes REST API. AppsV1Api handles Deployments, CoreV1Api handles Pods and Services.
  • Resource objects: Every Kubernetes resource (e.g., a Deployment) is represented as a Python class (e.g., V1Deployment). You build one by instantiating its spec components: V1DeploymentSpec, V1PodTemplateSpec, V1Container.
  • Apply vs. create: The client offers create_namespaced_deployment (imperative) and replace_namespaced_deployment (for updates). Unlike kubectl apply, these are not declarative merges — they replace the whole object unless you use replace carefully.
  • Context: Everything is tied to a namespace. You must specify it with every call unless you set a default.

Key insight: The Python client is a thin wrapper over the Kubernetes API. If you understand the YAML structure, you already 90% understand the Python objects — they map 1:1.

How it works step by step

Creating a deployment via Python involves five logical steps:

  1. Import and configure: Load your cluster config (either from your ~/.kube/config or from an in-cluster service account).
  2. Instantiate the API client: Create an AppsV1Api instance.
  3. Build the deployment object: Construct V1Deployment with metadata and spec.
  4. Send the request: Call create_namespaced_deployment.
  5. Verify and manage: Check the status and optionally update or delete.

Let's break down each step with code.

Step 1: Configure the client

from kubernetes import config, client

# Use your local kubeconfig (e.g., from minikube or a real cluster)
config.load_kube_config()

# Alternatively, when running inside a pod:
# config.load_incluster_config()

apps_v1 = client.AppsV1Api()

Step 2: Build the deployment spec

The deployment YAML you're used to:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.25
        ports:
        - containerPort: 80

Translates to this Python:

container = client.V1Container(
    name="nginx",
    image="nginx:1.25",
    ports=[client.V1ContainerPort(container_port=80)]
)

template = client.V1PodTemplateSpec(
    metadata=client.V1ObjectMeta(labels={"app": "nginx"}),
    spec=client.V1PodSpec(containers=[container])
)

spec = client.V1DeploymentSpec(
    replicas=3,
    selector=client.V1LabelSelector(match_labels={"app": "nginx"}),
    template=template
)

deployment = client.V1Deployment(
    api_version="apps/v1",
    kind="Deployment",
    metadata=client.V1ObjectMeta(name="nginx-deployment", labels={"app": "nginx"}),
    spec=spec
)

Step 3: Create the deployment

The final call:

apps_v1.create_namespaced_deployment(
    namespace="default",
    body=deployment
)

Pro tip: Always specify namespace. Using "default" is fine for testing, but in production use a dedicated namespace per environment to avoid collisions.

Hands-on walkthrough

Let's put it all together in a complete script. I'll assume you have minikube running or a test cluster.

Prerequisites

pip install kubernetes

Full example

from kubernetes import config, client
from kubernetes.client.rest import ApiException

def create_deployment(namespace="default", name="nginx-deployment", image="nginx:1.25", replicas=3):
    config.load_kube_config()
    apps_v1 = client.AppsV1Api()

    # Build the container
    container = client.V1Container(
        name=name,
        image=image,
        ports=[client.V1ContainerPort(container_port=80)]
    )

    # Pod template with labels
    pod_labels = {"app": name}
    template = client.V1PodTemplateSpec(
        metadata=client.V1ObjectMeta(labels=pod_labels),
        spec=client.V1PodSpec(containers=[container])
    )

    # Deployment spec
    spec = client.V1DeploymentSpec(
        replicas=replicas,
        selector=client.V1LabelSelector(match_labels=pod_labels),
        template=template
    )

    # Deployment object
    deployment = client.V1Deployment(
        api_version="apps/v1",
        kind="Deployment",
        metadata=client.V1ObjectMeta(name=name, labels=pod_labels),
        spec=spec
    )

    try:
        apps_v1.create_namespaced_deployment(namespace=namespace, body=deployment)
        print("Deployment created.")
    except ApiException as e:
        if e.status == 409:
            print("Deployment already exists. Use replace/update instead.")
        else:
            print(f"Exception when creating deployment: {e}")

if __name__ == "__main__":
    create_deployment()

Run it:

python create_deployment.py

Expected output:

Deployment created.

Verify with kubectl:

kubectl get deployments
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3/3     3            3           10s

Updating an existing deployment

To change the image or replicas, modify the spec and call replace_namespaced_deployment. Here's an update example:

# Fetch current deployment
ret = apps_v1.read_namespaced_deployment(name="nginx-deployment", namespace="default")

# Modify spec
ret.spec.replicas = 5

# Apply update
apps_v1.replace_namespaced_deployment(name="nginx-deployment", namespace="default", body=ret)
print("Deployment updated to 5 replicas.")

Adding environment variables

Often your container needs env vars. Add them when building the container:

env_vars = [
    client.V1EnvVar(name="ENVIRONMENT", value="production"),
    client.V1EnvVar(name="LOG_LEVEL", value="info")
]
container = client.V1Container(
    name="my-app",
    image="myregistry/my-app:latest",
    env=env_vars
)

Handling the 'already exists' error

If you try to create the same deployment twice, you'll get a 409 Conflict. Always catch ApiException and decide whether to skip or update.

Compare options / when to choose what

Approach When to use Pros Cons
kubectl apply Ad-hoc operations, learning, small projects Familiar, declarative, easy for humans Not programmable, hard to integrate with Python logic
Python client create Automation, CI/CD, dynamic deployments Programmable, testable, typed More verbose, replaces (not merges) by default; needs error handling
Helm Complex applications, templated multi-resource deployment Versioned, reusable, handles rollbacks New templating language, YAML indentation pitfalls

When to pick the Python client:

  • You need to embed Kubernetes orchestration into a larger Python application (e.g., a workflow engine).
  • You want to generate configurations based on runtime data (e.g., autoscaling based on queue length).
  • You prefer linting and unit-testing your infrastructure code.

When to stick with kubectl/Helm:

  • Quick interactive debugging.
  • Human-written static configs that rarely change.
  • Teams already invested in Helm chart ecosystems.

Troubleshooting & edge cases

ImportError: No module named 'kubernetes'

Make sure you've installed the package in the correct environment:

pip install --upgrade kubernetes

ApiException: (401) Reason: Unauthorized

Your kubeconfig may lack credentials. Check with kubectl auth can-i create deployments. Refresh token or re-authenticate.

ApiException: (403) Reason: Forbidden

Your service account doesn't have RBAC permissions to create deployments. Add a Role or ClusterRole allowing apps/deployments create.

Deployment not becoming ready

  • Check image pull: kubectl describe deployment may show ErrImagePull. Ensure the image name is correct and the registry is accessible.
  • Check resource limits: if the pod requests more CPU/memory than nodes can provide, it stays pending.

Using replace overwrites labels

When you update via replace, the entire metadata is replaced. If you rely on labels for service selection, ensure they remain in the metadata of the updated object.

Race conditions

If you try to create and update in rapid succession, use read_namespaced_deployment before modifying to get the latest object version.

What you learned & what's next

In this lesson, you learned how to create Kubernetes deployments via the Python client — building a V1Deployment object with spec, template, and container definitions, sending it to the API server, and handling common errors. You also explored updating deployments and adding environment variables. Now you can automate deployments from Python scripts, which is a huge step toward infrastructure-as-code.

Next in the track, you'll probably dive into Services — how to expose your deployment internally or externally. The same client approach applies: build a V1Service object and call create_namespaced_service. Or you might learn about ConfigMaps and Secrets to manage configuration. Whichever it is, you now have the foundation to automate any Kubernetes resource.

Keep practicing: try writing a function that creates a deployment from a dictionary or JSON, and handle the case where the deployment already exists by updating it instead of failing.

Practice recap

Try this mini exercise: Write a Python script that takes a list of deployment names and image tags (from a dictionary), creates them via the Python client, and prints a summary. Then modify one deployment's replicas and update it without dropping its labels. This will solidify your understanding of the object model and error handling.

Common mistakes

  • Forgetting to call config.load_kube_config() — you'll get an ApiException with 'Connection refused' because it tries to talk to localhost:8080.
  • Using replace_namespaced_deployment without first reading the existing object, which can drop metadata fields like labels and resource versions.
  • Catching ApiException too broadly and swallowing the 409 Conflict error, leading to silent failures when a deployment already exists.

Variations

  1. Use the kubernetes_asyncio library if you want async/await support for high-concurrency deployment automation.
  2. Use client.ApiClient with custom configuration (e.g., client.Configuration(host=..., api_key=...)) instead of load_kube_config for explicit cluster endpoints.
  3. Model the deployment spec as a dictionary and unserialize it with client.V1Deployment.from_dict to keep your code DRY when working with JSON templates.

Real-world use cases

  • CI/CD pipeline script that creates a preview deployment for each pull request using the Python client, with the git SHA as the image tag.
  • A Python-based operator that watches a queue and automatically scales up a worker deployment by calling replace_namespaced_deployment when backlog grows.
  • An internal developer portal where users submit a form to create a new microservice deployment, powered by a Flask API wrapping the Python client.

Key takeaways

  • The Python client maps 1:1 to Kubernetes YAML objects — if you understand one, you can understand the other.
  • Always load kube config explicitly and specify a namespace with every API call.
  • Use create_namespaced_deployment for new deployments and replace_namespaced_deployment with a fresh read for updates.
  • Handle ApiException status codes (especially 401, 403, 409) to give meaningful feedback to users.
  • The Python client is ideal for dynamic, programmatic deployment logic — prefer it over kubectl when your infrastructure is code-driven.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.