Introduction
Infrastructure as Code (IaC) is revolutionizing how we manage cloud-native applications, and Pulumi brings a unique advantage by allowing developers to define and deploy Kubernetes resources using familiar programming languages. Unlike YAML-heavy configurations, Pulumi enables us to programmatically create, manage, and version Kubernetes resources with Python, TypeScript, Go, and more.
In this guide, we’ll walk through deploying an Nginx application on Minikube using Pulumi with Python, ensuring a scalable, maintainable, and declarative approach to Kubernetes management.
Step 1: Installing Pulumi & Setting Up the Environment
Before we start, install Pulumi and its dependencies:
Install Pulumi
curl -fsSL https://get.pulumi.com | sh
Install Kubernetes CLI (kubectl) & Minikube
sudo apt install -y kubectl
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube
Start Minikube
minikube start
Step 2: Initialize a Pulumi Project
pulumi new kubernetes-python
During setup:
- Project name: pulumi-k8s
- Stack name: dev
- Dependencies: Pulumi will install pulumi_kubernetes
Verify installation:
pulumi version
kubectl version --client
Step 3: Defining Kubernetes Resources in Python
Now, modify __main__.py to define an Nginx deployment and service using Pulumi:
Corrected __main__.py
import pulumi
import pulumi_kubernetes as k8s
# Define labels for the application
app_labels = {"app": "nginx"}
# Define the Deployment
deployment = k8s.apps.v1.Deployment(
"nginx-deployment",
metadata=k8s.meta.v1.ObjectMetaArgs(
namespace="default",
name="nginx-deployment",
labels=app_labels,
),
spec=k8s.apps.v1.DeploymentSpecArgs(
replicas=2,
selector=k8s.meta.v1.LabelSelectorArgs(
match_labels=app_labels,
),
template=k8s.core.v1.PodTemplateSpecArgs(
metadata=k8s.meta.v1.ObjectMetaArgs(
labels=app_labels,
),
spec=k8s.core.v1.PodSpecArgs(
containers=[
k8s.core.v1.ContainerArgs(
name="nginx",
image="nginx:latest",
ports=[k8s.core.v1.ContainerPortArgs(container_port=80)],
)
]
),
),
),
)
# Define a ClusterIP Service
service = k8s.core.v1.Service(
"nginx-service",
metadata=k8s.meta.v1.ObjectMetaArgs(
namespace="default",
name="nginx-service",
),
spec=k8s.core.v1.ServiceSpecArgs(
selector=app_labels,
ports=[k8s.core.v1.ServicePortArgs(port=80, target_port=80)],
type="ClusterIP", # Ensures it is NOT a LoadBalancer
),
)
# Export the service name
pulumi.export("service_name", service.metadata.name)
Step 4: Deploying the Kubernetes Resources
After defining the resources, apply them using:
pulumi up
This will:
Create an Nginx Deployment with 2 replicas
Create a ClusterIP Service
Deploy everything to Minikube
To verify the deployment:
kubectl get all -n default
Step 5: Accessing the Application
Since we’re using ClusterIP, we need to port-forward to access the application:
kubectl port-forward svc/nginx-service 8080:80 -n default
Now, open http://localhost:8080 in your browser, and you should see the Nginx welcome page!
Why Choose Pulumi Over YAML?
- Programmatic Infrastructure – Use Python, TypeScript, Go, etc., instead of complex YAML.
- Reusability & Automation – Write functions, use loops, and manage dependencies efficiently.
- Version Control & CI/CD – Easily integrate with Git, Terraform, and GitHub Actions.
Conclusion
With Pulumi, managing Kubernetes infrastructure becomes developer-friendly and scalable. Unlike traditional YAML-based approaches, Pulumi enables real programming constructs, making it easier to define, update, and manage Kubernetes workloads efficiently.
What do you think? Have you used Pulumi before for Kubernetes? Let’s discuss in the comments!![]()