kubernetes-manifests
Kubernetes Manifest Authoring
Write and review production-ready Kubernetes manifests following security, resource management, and operational best practices.
Workflow
- Identify the application type: .NET API, React SPA, worker service, or other
- Determine the target resources: Deployment, Service, Ingress, HPA, PDB, NetworkPolicy
- Generate manifests using the patterns below
- Apply the security context, resource limits, and health probes
- Validate against the Pre-Deployment Checklist
Core Manifest Structure
Every manifest includes these four required fields:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
namespace: production
labels:
app.kubernetes.io/name: my-app
app.kubernetes.io/version: "1.0.0"
app.kubernetes.io/component: api
app.kubernetes.io/managed-by: kustomize
spec:
# ...
Use declarative YAML with kubectl apply. Store manifests in version control. Express desired state only.
Security Context
Apply to every pod and container. Non-negotiable for production.
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
containers:
- name: app
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
| Setting | Requirement |
|---|---|
runAsNonRoot: true |
Required |
allowPrivilegeEscalation: false |
Required |
readOnlyRootFilesystem: true |
Recommended (mount emptyDir for /tmp) |
capabilities.drop: [ALL] |
Recommended |
hostNetwork/hostPID/hostIPC |
Never use unless explicitly justified |
For .NET images, use UID 1654 (the app user). For nginx-unprivileged, use UID 101.
Resource Management
Always set memory requests and limits. Set CPU requests; omit CPU limits unless required.
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "512Mi"
| Application Type | Memory Request | Memory Limit | CPU Request |
|---|---|---|---|
| .NET API | 256Mi | 512Mi | 100m |
| React/Nginx frontend | 64Mi | 128Mi | 50m |
| Worker service | 128Mi-512Mi | 256Mi-1Gi | 100m-500m |
Set requests = limits for critical services to achieve Guaranteed QoS (lowest eviction priority).
Health Probes
Configure all three probe types. Use dedicated endpoints.
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 10
periodSeconds: 15
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
startupProbe:
httpGet:
path: /startup
port: 8080
failureThreshold: 30
periodSeconds: 10
| Probe | Purpose | On Failure |
|---|---|---|
| Liveness | Detect deadlocks/hangs | Restart container |
| Readiness | Control traffic routing | Remove from Service endpoints |
| Startup | Handle slow-starting apps | Delay other probes |
Use startupProbe for slow-starting apps instead of large initialDelaySeconds. Keep probes lightweight.
For .NET apps: /health/live, /health/ready, /health/startup. For React/Nginx: /health for both liveness and readiness.
Labels
Apply the app.kubernetes.io/ recommended labels to all resources:
labels:
app.kubernetes.io/name: myapp
app.kubernetes.io/instance: myapp-production
app.kubernetes.io/version: "1.2.3"
app.kubernetes.io/component: frontend
app.kubernetes.io/part-of: my-platform
app.kubernetes.io/managed-by: kustomize
Add custom labels for cross-cutting concerns: environment, team, cost-center, tier.
Container Images
- Never use
:latestin production. Pin semantic versions or git SHAs. - Use digest references (
@sha256:...) for maximum reproducibility. - Use distroless/minimal base images.
- Set
imagePullPolicy: IfNotPresentfor tagged images.
Graceful Shutdown
Add a preStop hook to handle the delay between endpoint removal and ingress controller configuration updates:
lifecycle:
preStop:
exec:
command: ["sleep", "10"]
terminationGracePeriodSeconds: 45
terminationGracePeriodSeconds must exceed preStop delay + application shutdown timeout.
High Availability
Topology Spread
Distribute pods across zones:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app: myapp
Pod Disruption Budget
Protect against voluntary disruptions (node drains, upgrades):
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: myapp-pdb
spec:
minAvailable: "50%"
selector:
matchLabels:
app: myapp
Use percentages for scaling flexibility. Never set maxUnavailable: 0 or minAvailable: 100%.
HPA (Stateless Apps)
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: myapp-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: myapp
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
behavior:
scaleDown:
stabilizationWindowSeconds: 300
Services and Ingress
Use ClusterIP for inter-service communication. Use Ingress over multiple LoadBalancer services.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp-ingress
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- myapp.example.com
secretName: myapp-tls
rules:
- host: myapp.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 80
ConfigMaps and Secrets
Use ConfigMaps for non-sensitive config. Use Secrets for sensitive data. Prefer volume mounts over environment variables. Enable encryption at rest for Secrets.
volumes:
- name: config-volume
configMap:
name: app-config
- name: secret-volume
secret:
secretName: app-secrets
Use immutable ConfigMaps (immutable: true) for stable configurations. Keep ConfigMaps under 1 MiB.
Deployment Strategy
| Strategy | Use Case |
|---|---|
RollingUpdate (default) |
Stateless web services, APIs |
Recreate |
Stateful apps, single-version requirements |
| Blue/Green, Canary | Advanced (requires Flagger, Argo Rollouts) |
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
Application-Specific Guidance
For detailed .NET and React/Vite manifest patterns, see:
- references/dotnet-manifests.md — GC configuration, Kestrel ports, structured logging, chiseled images
- references/react-manifests.md — NGINX SPA routing, runtime env vars, non-root NGINX, CSP headers
- references/kustomize.md — Base/overlay structure, generators, patches, components, GitOps integration
Pre-Deployment Checklist
- Resource requests and limits defined (memory required; CPU requests required, limits optional)
- All three health probes configured (liveness, readiness, startup)
- Security context applied: non-root, no privilege escalation, read-only root filesystem
- Labels applied:
app.kubernetes.io/name,version,component,managed-by - Specific image tags pinned (never
:latest) - ConfigMaps for config, Secrets for sensitive data (mounted as volumes)
- PodDisruptionBudget defined for critical workloads
- Topology spread or anti-affinity configured for HA
-
preStophook andterminationGracePeriodSecondsconfigured for graceful shutdown - Manifests validated with
kubeconform -strict -summary