Testing Kubernetes Applications — Minikube, Kind & K3s Guide
Testing Kubernetes applications requires validating that your deployments, services, and configurations work correctly against a real cluster before reaching production. In this guide, you will learn how to use Kind and Minikube for local testing, write integration tests that run against ephemeral clusters, and validate resource definitions with conformance testing tools. The DodaTech infrastructure team uses Kind clusters in CI to validate every manifest change for Doda Browser's backend services before deploying to production EKS.
Learning Path
flowchart LR A[Docker Containers] --> B[Kubernetes Basics] B --> C[Testing K8s Apps
You are here] C --> D[Service Mesh Testing] D --> E[Production Deployments] style C fill:#f90,color:#fff
Local Kubernetes Testing Options
| Tool | Startup | Use Case |
|---|---|---|
| Minikube | 2–5 min | Full VM-based cluster with addons |
| Kind | 30–60s | Lightweight, ideal for CI |
| K3s | 10–20s | Minimal resource edge cluster |
| MicroK8s | 30–60s | Snap-based single-node cluster |
Validating Kubernetes Manifests
Before deploying, validate your YAML files are syntactically correct:
# Dry-run validation
kubectl apply --dry-run=client -f deployment.yaml
# Schema validation with kubeconform
kubeconform -summary deployment.yaml
# Linting with kube-linter
kube-linter lint deployment.yaml
Expected output:
kubeconform: deployment.yaml - PASS
kube-linter: no lint errors found
Integration Testing with Kind
Kind runs Kubernetes clusters in Docker containers, perfect for CI:
import subprocess, json, time, requests
def create_kind_cluster(name="test-cluster"):
subprocess.run(["kind", "create", "cluster", "--name", name], check=True)
print(f"Cluster {name} created")
def deploy_app():
subprocess.run(["kubectl", "apply", "-f", "deployment.yaml"], check=True)
subprocess.run(["kubectl", "apply", "-f", "service.yaml"], check=True)
subprocess.run(["kubectl", "rollout", "status", "deployment/myapp", "--timeout=60s"], check=True)
print("App deployed successfully")
def wait_for_service(name="myapp-service", namespace="default", timeout=60):
start = time.time()
while time.time() - start < timeout:
result = subprocess.run([
"kubectl", "get", "service", name,
"-n", namespace, "-o", "json]
], capture_output=True, text=True)
svc = json.loads(result.stdout)
if svc.get("status", {}).get("loadBalancer", {}).get("ingress"):
return svc["status"]["loadBalancer"]["ingress"][0]
time.sleep(2)
return None
def test_service():
create_kind_cluster()
deploy_app()
endpoint = wait_for_service()
if endpoint:
r = requests.get(f"http://{endpoint['ip']}:8080/health")
assert r.status_code == 200
print("Service health check passed")
subprocess.run(["kind", "delete", "cluster", "--name", "test-cluster"])
test_service()
Testing ConfigMaps and Secrets
import subprocess, yaml
def test_configmap():
result = subprocess.run(
["kubectl", "get", "configmap", "app-config", "-o", "yaml"],
capture_output=True, text=True
)
config = yaml.safe_load(result.stdout)
data = config["data"]
assert data["LOG_LEVEL"] == "debug"
assert "DATABASE_URL" in data
print("ConfigMap validation passed")
def test_secret_mounts():
result = subprocess.run(
["kubectl", "get", "pod", "-l", "app=myapp", "-o", "json"],
capture_output=True, text=True
)
pods = json.loads(result.stdout)
for pod in pods["items"]:
volumes = pod["spec"]["volumes"]
has_secret = any(v.get("secret") for v in volumes)
assert has_secret, f"Pod {pod['metadata']['name']} missing secret volume"
print("Secret mount validation passed")
test_configmap()
test_secret_mounts()
Testing Network Policies
import subprocess
def test_network_isolation():
result = subprocess.run([
"kubectl", "run", "test-pod", "--image=busybox",
"--restart=Never", "--rm", "-it", "--", "wget", "-qO-",
"http://other-service:8080]
], capture_output=True, text=True, timeout=10)
if "Connection refused" in result.stderr or "wget: bad address" in result.stderr:
print("Network isolation correct: cross-namespace blocked")
else:
print("Network policy may need review")
Conformance Testing with Sonobuoy
Sonobuoy runs the Kubernetes conformance test suite to verify your cluster meets K8s standards:
sonobuoy run --mode=certified-conformance
sonobuoy status
sonobuoy retrieve .
sonobuoy results *.tar.gz
Practice Questions
1. What is the difference between Kind and Minikube?
Kind runs Kubernetes in Docker containers (fast, good for CI). Minikube runs a VM-based cluster with more features but slower startup.
2. How do you validate a Kubernetes manifest before deploying it?
Use kubectl apply --dry-run=client, kubeconform for schema validation, and kube-linter for best practice checks.
3. Why should you test network policies?
Network policies control pod-to-pod communication. Testing them ensures your security isolation rules work as intended before production.
4. What is Sonobuoy used for?
Sonobuoy runs the Kubernetes conformance suite to verify your cluster passes official K8s conformance tests.
Challenge: Create a Kind-based CI pipeline that deploys a three-tier application (frontend, API, database), runs health checks on each service, validates ConfigMaps and Secrets, and tests network isolation between tiers.
FAQ
What's Next
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro