YAML for Kubernetes: Essential Manifest Patterns
Kubernetes is configured entirely through YAML manifests. Every pod, deployment, service, and ingress is defined in YAML. Mastering these patterns is essential for anyone working with container orchestration. This guide covers the most important resource types with production-ready examples.
The Four Required Fields
Every Kubernetes manifest needs:
apiVersion: apps/v1 # API version for this resource type
kind: Deployment # Resource type
metadata: # Resource identification
name: my-app
namespace: production
labels:
app: my-app
spec: # Desired state specification
# ... resource-specific configuration
Deployment
The most common resource β manages a set of identical pods:
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-server
labels:
app: api-server
environment: production
spec:
replicas: 3
selector:
matchLabels:
app: api-server
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app: api-server
spec:
containers:
- name: api
image: myapp/api:v1.2.3
ports:
- containerPort: 8080
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: db-credentials
key: url
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 15
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
Key Patterns
Always set resource requests and limits: Without them, a single pod can consume all node resources.
Always configure health probes:
livenessProbe: Restart the pod if it becomes unresponsivereadinessProbe: Stop sending traffic until the pod is ready
Use specific image tags: Never use latest in production β it makes rollbacks impossible.
Service
Exposes pods to network traffic:
apiVersion: v1
kind: Service
metadata:
name: api-server
spec:
type: ClusterIP
selector:
app: api-server
ports:
- port: 80
targetPort: 8080
protocol: TCP
Service types:
- ClusterIP (default): Internal cluster access only
- NodePort: Exposes on each node IP at a static port
- LoadBalancer: Provisions a cloud load balancer
- ExternalName: Maps to a DNS name
ConfigMap and Secret
ConfigMap (non-sensitive data)
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
LOG_LEVEL: "info"
MAX_CONNECTIONS: "100"
config.yaml: |
server:
port: 8080
timeout: 30s
Secret (sensitive data)
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
type: Opaque
stringData:
url: "postgres://user:password@db:5432/myapp"
api-key: "sk-1234567890"
Using in Pods
# As environment variables
env:
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: app-config
key: LOG_LEVEL
# As a mounted file
volumes:
- name: config
configMap:
name: app-config
Ingress
Routes external HTTP traffic to services:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-ingress
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- api.example.com
secretName: tls-secret
rules:
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-server
port:
number: 80
Horizontal Pod Autoscaler
Scale pods based on CPU or custom metrics:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: api-server-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: api-server
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
Common Mistakes
1. Indentation Errors
YAML indentation is critical in Kubernetes. A misplaced space changes the structure entirely. Validate your manifests with our YAML Validator.
2. Label Mismatches
The Service selector must exactly match the Pod labels. A mismatch means the Service cannot find any pods to route traffic to.
3. Missing Resource Limits
Pods without resource limits can starve other workloads. Always include both requests (guaranteed minimum) and limits (maximum allowed).
4. Mutable Image Tags
Using latest or other mutable tags makes rollbacks impossible and deployments unpredictable. Pin to specific versions or use immutable digests.
Multi-Document Manifests
Combine related resources in one file using --- as a document separator:
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-server
spec:
# ... deployment spec
---
apiVersion: v1
kind: Service
metadata:
name: api-server
spec:
# ... service spec
For more on YAML syntax patterns, see our YAML syntax tutorial.
FAQ
Should I write Kubernetes YAML by hand or use generators?
Start by writing YAML by hand to understand the structure. For production, use tools like Helm (templated manifests), Kustomize (overlay-based customization), or CDK8s (code-based generation). These tools reduce repetition and enable environment-specific configuration without duplicating manifests.
How do I debug Kubernetes YAML errors?
Use kubectl apply --dry-run=client -f manifest.yaml to validate without applying. For syntax errors, kubectl explain deployment.spec.template.spec.containers shows the expected structure. The kubeval and kubeconform tools validate against Kubernetes API schemas before deployment.
Related Resources
- YAML Validator β Validate Kubernetes manifests
- YAML for Docker Compose β Docker YAML patterns
- YAML Linting Best Practices β Catch errors before deploy