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
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
kubernetespackage gives you classes that mirror the Kubernetes REST API.AppsV1Apihandles Deployments,CoreV1Apihandles 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) andreplace_namespaced_deployment(for updates). Unlikekubectl apply, these are not declarative merges — they replace the whole object unless you usereplacecarefully. - 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:
- Import and configure: Load your cluster config (either from your
~/.kube/configor from an in-cluster service account). - Instantiate the API client: Create an
AppsV1Apiinstance. - Build the deployment object: Construct
V1Deploymentwith metadata and spec. - Send the request: Call
create_namespaced_deployment. - 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 deploymentmay showErrImagePull. 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_deploymentwithout first reading the existing object, which can drop metadata fields like labels and resource versions. - Catching
ApiExceptiontoo broadly and swallowing the 409 Conflict error, leading to silent failures when a deployment already exists.
Variations
- Use the
kubernetes_asynciolibrary if you want async/await support for high-concurrency deployment automation. - Use
client.ApiClientwith custom configuration (e.g.,client.Configuration(host=..., api_key=...)) instead ofload_kube_configfor explicit cluster endpoints. - Model the deployment spec as a dictionary and unserialize it with
client.V1Deployment.from_dictto 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_deploymentwhen 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_deploymentfor new deployments andreplace_namespaced_deploymentwith a fresh read for updates. - Handle
ApiExceptionstatus 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.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.