Kubernetes manifests
Ship workloads with aligned labels/selectors, sensible probes, resources, and securityContext, plus ConfigMap/Secret conventions. This page walks flow → workload → networking → probes → resources → security → policy → validation → snippet lab.
The SKILL defines namespaces, standard labels (app, version, team), and Deployment rolling-update strategy; document Service types and when to use headless.
Tune liveness/readiness/startup probes for slow starts; list security defaults such as readOnlyRootFilesystem, dropped capabilities, and runAsNonRoot per cluster policy.
If HPA, PDB, and NetworkPolicy live in the same repo, state apply order and minimal examples; note image pull policy and imagePullSecrets differences per environment.
- Scaling: pick one guidance path for replicas, anti-affinity, and topology spread.
- Storage: when PVC vs StatefulSet applies.
- Validation: where
kubectl apply --dry-run=serveror kubeconform runs in CI.
From repo draft to schedulable cluster (flow)
[ Manifest dir / Kustomize or Helm ]
│
▼
┌─────────────┐ Align: labels & selector, name prefix, standard annotations
│ Workload │──── Deployment / SS / DS: strategy, revisionHistoryLimit
└─────────────┘
│
▼
┌─────────────┐ Type: ClusterIP / LB / headless; port & targetPort
│ Service │──── Match Pod port names; avoid magic numbers
└─────────────┘
│
▼
┌─────────────┐ startup → readiness → liveness; resources required
│ Pod template │──── securityContext; probe timeouts/thresholds explained
└─────────────┘
│
▼
┌─────────────┐ dry-run=server / kubeconform; namespace & quotas
│ Validate │──── Change notes: image tag, resource changes, probe tweaks
└─────────────┘
Merge order: align selectors with Service ports first, then probes and resources; slow-start workloads need startupProbe so liveness does not kill pods prematurely.
Labels, Deployment, rolling updates
metadata.labels, spec.selector, and template.metadata.labels must match; version labels aid observability and rollbacks—avoid latest alone.
strategy.type: forRollingUpdate, documentmaxSurge/maxUnavailableand team caps.revisionHistoryLimitcaps old ReplicaSets; if canaries live behind a gateway/Argo, document boundaries vs native rolling updates.
Complete Deployment YAML (all recommended fields):
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
namespace: production
labels:
app: myapp
version: "1.2.3"
team: platform
environment: production
spec:
replicas: 3
revisionHistoryLimit: 5
selector:
matchLabels:
app: myapp # immutable; must match template.labels exactly
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # allow 1 extra Pod during update
maxUnavailable: 0 # always keep replicas Pods available
template:
metadata:
labels:
app: myapp
version: "1.2.3"
spec:
terminationGracePeriodSeconds: 30
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: myapp
containers:
- name: myapp
image: myregistry/myapp:1.2.3-abc1234
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 3000
protocol: TCP
env:
- name: NODE_ENV
value: production
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: myapp-secrets
key: db-password
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: "1"
memory: 1Gi
securityContext:
runAsNonRoot: true
runAsUser: 1001
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
volumeMounts:
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir: {}
Service & headless
ClusterIP is default; external entry via LoadBalancer or Ingress per platform docs. Prefer named container ports for port / targetPort.
clusterIP: Nonefor StatefulSet peer discovery or client-side LB; document DNS shape and client responsibilities.
Complete Service + Ingress configuration example:
---
apiVersion: v1
kind: Service
metadata:
name: myapp
namespace: production
labels:
app: myapp
spec:
type: ClusterIP
selector:
app: myapp # must match Deployment template.labels
ports:
- name: http
port: 80
targetPort: http # reference container port name, not magic numbers
protocol: TCP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp
namespace: production
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/proxy-body-size: "10m"
# cert-manager auto-issues TLS certificate
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: nginx
tls:
- hosts:
- myapp.example.com
secretName: myapp-tls
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: myapp
port:
name: http
Liveness / readiness / startup probes
readiness gates traffic; liveness restarts the container on failure; startup runs only during boot, then hands off to the other two.
Prefer
- HTTP health paths that mean “can serve traffic”; avoid heavy deps in readiness that drain the whole fleet.
- Slow starts: add startup first, then tighten liveness
initialDelaySeconds. - Align
timeoutSeconds,periodSeconds,failureThresholdwith SLOs and comment why.
Avoid
- Identical, overly strict liveness and readiness causing restart flaps or permanent NotReady.
- Downstream calls inside probes causing cascade timeouts (unless explicitly required).
- Exec probes without timeouts or with heavy shells.
Requests, limits & QoS
requests inform scheduling and HPA; limits cap usage. Requests without limits are often Burstable; requests=limits (and not BestEffort) tends toward Guaranteed (see official QoS rules).
- Avoid BestEffort in production; leave headroom for off-heap and stacks on Java/Go runtimes.
- Document latency, GC, and OOM risks when changing CPU/memory; large batch jobs may need a separate workload class.
securityContext & volume mounts
Combine pod- and container-level securityContext: runAsNonRoot, readOnlyRootFilesystem, allowPrivilegeEscalation: false, capabilities.drop: ["ALL"], add capabilities back only as allowlisted.
- ConfigMap/Secret: consistent read-only mount paths; document
defaultModeand who may apply sensitive volumes under RBAC. imagePullPolicyandimagePullSecretsdiffer by environment (CI, staging, prod).
HPA, PDB, NetworkPolicy
Document HPA signal sources (CPU, custom metrics, KEDA) and minimum replicas; review PDB minAvailable / maxUnavailable with release strategy.
- NetworkPolicy: default-deny vs default-allow is platform-specific; generated policies must name namespaces and label selectors explicitly.
HPA configuration example (CPU + custom metrics) + PDB:
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: myapp
namespace: production
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: myapp
minReplicas: 3
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70 # CPU utilization target
- type: Pods
pods:
metric:
name: http_requests_per_second # custom metric (requires custom.metrics.k8s.io)
target:
type: AverageValue
averageValue: "100"
behavior:
scaleDown:
stabilizationWindowSeconds: 300 # scale-down stabilization: prevent rapid flapping
policies:
- type: Percent
value: 25
periodSeconds: 60
scaleUp:
stabilizationWindowSeconds: 30
policies:
- type: Pods
value: 4
periodSeconds: 30
---
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: myapp
namespace: production
spec:
minAvailable: 2 # or maxUnavailable: 1, coordinated with replicas and rolling update strategy
selector:
matchLabels:
app: myapp
---
# securityContext full configuration example
# Under Deployment spec.template.spec:
# securityContext (Pod-level)
# runAsNonRoot: true
# runAsUser: 1001
# runAsGroup: 1001
# fsGroup: 1001
# seccompProfile:
# type: RuntimeDefault
# securityContext (container-level)
# allowPrivilegeEscalation: false
# readOnlyRootFilesystem: true
# capabilities:
# drop: ["ALL"]
# add: ["NET_BIND_SERVICE"] # add back only when listening on ports below 1024
Validation & CI
kubectl apply --dry-run=serverorkubectl diff; kubeconform/kubeval version sets must match clusters.- Policy admission (OPA Gatekeeper, Kyverno) errors should map back to manifest field names.
Probe & resources snippet lab
Generate paste-ready YAML for containers[] from port, probe type, and startup/readiness toggles (includes ports, probes, optional resources); tune for real health checks and capacity before merge.
With startupProbe, liveness/readiness often use initialDelaySeconds: 0 as shown—adjust failureThreshold and periodSeconds for real startup time.
Further reading
- Assigning CPU and memory resources (Kubernetes docs) — requests, limits, and scheduling
- Container probes (Kubernetes docs) — the three probe types and fields
- Pod Security Standards (Kubernetes docs) — baseline aligned with securityContext
---
name: kubernetes-manifests
description: Author production-ready K8s Deployment/Service manifests
tags: [kubernetes, k8s, devops, deployment]
---
# Workloads
1. labels and selector strictly aligned: metadata.labels / spec.selector / template.labels
2. Rolling update: maxSurge=1, maxUnavailable=0 ensures continuous service
3. revisionHistoryLimit: 5 limits stale ReplicaSet accumulation
4. topologySpreadConstraints spreads Pods across availability zones
# Networking
5. Service targetPort references container port name (no magic numbers)
6. Ingress with TLS + cert-manager auto-issuance, ssl-redirect: true
7. ClusterIP is default; LoadBalancer fixed by platform docs; headless documents DNS shape
# Probes
8. startupProbe protects slow-start containers (failureThreshold * periodSeconds >= max startup time)
9. readinessProbe gates traffic; liveness restarts on failure; the two are not identical
10. Probe HTTP path aligned with business readiness semantics; don't call heavy deps from readiness
# Resources & security
11. requests + limits required; Guaranteed QoS (requests=limits) for production critical services
12. securityContext: runAsNonRoot, allowPrivilegeEscalation:false, readOnlyRootFilesystem
13. capabilities.drop: ["ALL"], add back minimum needed capabilities
14. emptyDir mount at /tmp handles temp files with readOnlyRootFilesystem
# Resilience & validation
15. HPA minReplicas/maxReplicas + scaleDown stabilizationWindow prevents flapping
16. PDB minAvailable coordinated with release strategy; ensures no downtime during node maintenance
17. Validation: kubectl apply --dry-run=server + kubeconform with pinned version in CI