| name | kubernetes-patterns |
| description | Kubernetes workload patterns, resource management, RBAC, probes, autoscaling, ConfigMap/Secret handling, and kubectl debugging for production-grade deployments. |
| origin | ECC |
Kubernetes Patterns
Production-grade Kubernetes patterns for deploying, managing, and debugging workloads reliably.
When to Activate
- Writing Kubernetes manifests (Deployments, Services, Ingress, Jobs)
- Configuring resource requests/limits, liveness/readiness probes
- Setting up RBAC, namespaces, or ServiceAccounts
- Managing configuration and secrets in K8s
- Debugging CrashLoopBackOff, OOMKilled, pending pods, or image pull errors
- Configuring HPA (Horizontal Pod Autoscaler) or PodDisruptionBudgets
- Reviewing K8s YAML for security or correctness
When to Use
Same as When to Activate above. This alias satisfies repo skill-format conventions. Use this skill any time you are writing, reviewing, or debugging Kubernetes YAML and workloads.
How It Works
This skill provides copy-pasteable, production-grade YAML patterns and kubectl debugging commands organized by task:
- Deployment template — A fully configured production
Deployment with security context, rolling update strategy, all three probe types, resource limits, and environment injection from ConfigMap/Secret.
- Probes — Decision table for startup vs liveness vs readiness, with correct
failureThreshold × periodSeconds math.
- Services & Ingress — ClusterIP, LoadBalancer, and TLS Ingress patterns with cert-manager annotations.
- ConfigMaps & Secrets —
envFrom, file-mount, and external secrets guidance.
- Resource management — Requests vs limits rules of thumb by workload type (web API, JVM, worker, sidecar).
- RBAC — Least-privilege ServiceAccount → Role → RoleBinding chain.
- HPA & PDB — Autoscaling and node-drain safety configurations.
- Jobs & CronJobs — One-off and scheduled workload patterns with correct
restartPolicy.
- kubectl cheatsheet — Logs, exec, rollback, port-forward, dry-run, and common error diagnosis commands.
- Anti-patterns & checklist — What NOT to do, and a security/reliability/observability checklist.
Examples
See the sections below for complete, runnable examples. Quick references:
Core Workload Patterns
Deployment — Production Template
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
namespace: my-namespace
labels:
app: my-app
version: "1.0.0"
spec:
replicas: 3
selector:
matchLabels:
app: my-app
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app: my-app
version: "1.0.0"
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1001
fsGroup: 1001
terminationGracePeriodSeconds: 30
containers:
- name: my-app
image: ghcr.io/org/my-app:1.0.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
protocol: TCP
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
startupProbe:
httpGet:
path: /health
port: 8080
failureThreshold: 30
periodSeconds: 5
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 0
periodSeconds: 30
failureThreshold: 3
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
failureThreshold: 2
envFrom:
- configMapRef:
name: my-app-config
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: my-app-secrets
key: db-password
volumeMounts:
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir: {}
Probes — Liveness, Readiness, Startup
Understanding when to use each probe is critical:
| Probe | Failure Action | Use For |
|---|
startupProbe | Kills container if slow to start | Slow-starting apps (JVM, Python) |
livenessProbe | Restarts container | Deadlock / hung process detection |
readinessProbe | Removes from Service endpoints | Temporary unavailability (DB reconnect) |
startupProbe:
httpGet:
path: /health
port: 8080
failureThreshold: 30
periodSeconds: 5
livenessProbe:
httpGet:
path: /health
port: 8080
periodSeconds: 30
failureThreshold: 3
readinessProbe:
httpGet:
path: /ready
port: 8080
periodSeconds: 10
failureThreshold: 2
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 60
Services and Ingress
Service Types
apiVersion: v1
kind: Service
metadata:
name: my-app
namespace: my-namespace
spec:
selector:
app: my-app
ports:
- port: 80
targetPort: 8080
protocol: TCP
type: ClusterIP
spec:
type: LoadBalancer
ports:
- port: 443
targetPort: 8080
Ingress with TLS
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app
namespace: my-namespace
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
ingressClassName: nginx
tls:
- hosts:
- myapp.example.com
secretName: my-app-tls
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app
port:
number: 80
ConfigMaps and Secrets
ConfigMap — Non-sensitive configuration
apiVersion: v1
kind: ConfigMap
metadata:
name: my-app-config
namespace: my-namespace
data:
LOG_LEVEL: "info"
APP_ENV: "production"
MAX_CONNECTIONS: "100"
app.yaml: |
server:
port: 8080
timeout: 30s
volumes:
- name: config
configMap:
name: my-app-config
items:
- key: app.yaml
path: app.yaml
volumeMounts:
- name: config
mountPath: /etc/app
readOnly: true
Secrets — Sensitive data
kubectl create secret generic my-app-secrets \
--from-literal=db-password='s3cr3t' \
--namespace=my-namespace \
--dry-run=client -o yaml | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
name: my-app-secrets
namespace: my-namespace
type: Opaque
data:
db-password: czNjcjN0
Important: Raw Kubernetes Secrets are only base64-encoded, not encrypted at rest unless your cluster has encryption configured. Use Sealed Secrets or External Secrets Operator for production.
Resource Requests and Limits
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"
Rules of thumb:
| Workload Type | CPU Request | Memory Request | Notes |
|---|
| Web API | 100–250m | 128–256Mi | Set limits 2-4x requests |
| Worker/consumer | 250–500m | 256–512Mi | Memory limit = request for predictability |
| JVM app | 500m–1 | 512Mi–2Gi | Allow headroom above -Xmx for JVM overhead |
| Sidecar | 10–50m | 32–64Mi | Keep minimal |
containers:
- name: app
image: myapp:latest
resources:
limits:
cpu: "2"
memory: "1Gi"
RBAC — Roles and ServiceAccounts
Principle of Least Privilege
Two patterns depending on whether the app calls the Kubernetes API:
Pattern A — App does NOT need the Kubernetes API (most apps)
Disable token automounting on the ServiceAccount. The Role/RoleBinding are not needed.
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-app-sa
namespace: my-namespace
automountServiceAccountToken: false
spec:
template:
spec:
serviceAccountName: my-app-sa
automountServiceAccountToken: false
Pattern B — App DOES need the Kubernetes API (operators, controllers, config watchers)
Enable the token and grant only the permissions actually required.
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-app-sa
namespace: my-namespace
automountServiceAccountToken: true
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: my-app-role
namespace: my-namespace
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["my-app-secrets"]
verbs: ["get"]
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: my-app-rolebinding
namespace: my-namespace
subjects:
- kind: ServiceAccount
name: my-app-sa
namespace: my-namespace
roleRef:
kind: Role
apiGroup: rbac.authorization.k8s.io
name: my-app-role
spec:
template:
spec:
serviceAccountName: my-app-sa
Horizontal Pod Autoscaler (HPA)
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-app-hpa
namespace: my-namespace
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
HPA requires resources.requests to be set on all containers — it calculates utilization as current / request.
PodDisruptionBudget (PDB)
Prevent too many pods going down during node drains or rolling updates:
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: my-app-pdb
namespace: my-namespace
spec:
minAvailable: 2
selector:
matchLabels:
app: my-app
Namespaces and Multi-Tenancy
kubectl create namespace my-namespace
kubectl apply -f - <<EOF
apiVersion: v1
kind: ResourceQuota
metadata:
name: my-namespace-quota
namespace: my-namespace
spec:
hard:
requests.cpu: "4"
requests.memory: 4Gi
limits.cpu: "8"
limits.memory: 8Gi
pods: "20"
EOF
Jobs and CronJobs
apiVersion: batch/v1
kind: Job
metadata:
name: db-migrate
namespace: my-namespace
spec:
backoffLimit: 3
ttlSecondsAfterFinished: 3600
template:
spec:
restartPolicy: OnFailure
containers:
- name: migrate
image: ghcr.io/org/my-app:1.0.0
command: ["python", "manage.py", "migrate"]
resources:
requests:
cpu: "100m"
memory: "256Mi"
apiVersion: batch/v1
kind: CronJob
metadata:
name: cleanup-job
namespace: my-namespace
spec:
schedule: "0 2 * * *"
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 1
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: cleanup
image: ghcr.io/org/cleanup:1.0.0
resources:
requests:
cpu: "50m"
memory: "64Mi"
kubectl Debugging Cheatsheet
kubectl get pods -n my-namespace
kubectl get pods -n my-namespace -o wide
kubectl describe pod <pod-name> -n my-namespace
kubectl logs <pod-name> -n my-namespace
kubectl logs <pod-name> -n my-namespace --previous
kubectl logs <pod-name> -n my-namespace -c <container>
kubectl exec -it <pod-name> -n my-namespace -- sh
kubectl exec -it <pod-name> -n my-namespace -- bash
kubectl top pods -n my-namespace
kubectl top nodes
kubectl rollout status deployment/my-app -n my-namespace
kubectl rollout history deployment/my-app -n my-namespace
kubectl rollout undo deployment/my-app -n my-namespace
kubectl rollout undo deployment/my-app --to-revision=2 -n my-namespace
kubectl scale deployment my-app --replicas=5 -n my-namespace
kubectl get events -n my-namespace --sort-by='.lastTimestamp'
kubectl port-forward pod/<pod-name> 8080:8080 -n my-namespace
kubectl port-forward svc/my-app 8080:80 -n my-namespace
kubectl apply -f deployment.yaml --dry-run=client
kubectl apply -f deployment.yaml --dry-run=server
Diagnosing Common Errors
kubectl logs <pod-name> --previous -n my-namespace
kubectl describe pod <pod-name> -n my-namespace
kubectl describe pod <pod-name> -n my-namespace
kubectl describe pod <pod-name> -n my-namespace
kubectl describe pod <pod-name> -n my-namespace | grep -A5 "Last State"
Anti-Patterns
image: myapp:latest
image: ghcr.io/org/myapp:1.4.2
image: ghcr.io/org/myapp@sha256:abc123...
securityContext: {}
securityContext:
runAsNonRoot: true
runAsUser: 1001
containers:
- name: app
image: myapp:1.0.0
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"
apiVersion: v1
kind: ConfigMap
data:
DB_PASSWORD: "mysecretpassword"
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
roleRef:
kind: ClusterRole
name: cluster-admin
spec:
minAvailable: 0
spec:
restartPolicy: Always
Best Practices Checklist
Security
Reliability
Observability
Related Skills
docker-patterns — Multi-stage Dockerfiles and image security
deployment-patterns — CI/CD pipelines, rollback strategy, health check endpoints
security-review — Broader security hardening context
git-workflow — GitOps integration with K8s (ArgoCD / Flux patterns)