Kubernetes Fundamentals Best Practices
These practices keep your first months with Kubernetes safe and productive. They favor the declarative, self-healing model the platform is built around, and they steer you away from the habits that cause avoidable outages.
How to Use This List
Treat this as a checklist you apply per workload, not a one-time read. Adopt the schema and declarative habits first, then layer in resource, health, and security defaults.
Each group builds on the desired-state model covered in the fundamentals pages. Link back to those pages when a term is unfamiliar.
A - Learn the API, Not Just Commands
Use kubectl explain before copying YAML. It prints the live OpenAPI schema for any field, so you learn what is valid on your actual cluster version.
kubectl explain deployment.spec.template.spec.containers
kubectl explain pod.spec.securityContext --recursiveRead spec vs status deliberately. You author spec; controllers own status. Debugging means comparing the two, not editing status.
Discover objects with kubectl api-resources. It lists every kind, its API group, and its shortname, which demystifies what the cluster can do.
Validate before you apply. Run kubectl diff -f and --dry-run=server to catch schema and admission errors without touching the cluster.
Pin your API versions explicitly. Write apps/v1, not a guessed group, and check deprecations when upgrading minors.
Check field ownership when apply surprises you. Inspect managedFields in -o yaml to see which manager owns a field before fighting an HPA or controller over it.
B - Work Declaratively
Keep manifests in Git and apply from there. Files are the source of truth; the cluster reconciles toward them, which gives you review, history, and rollback.
Prefer apply over create/edit. apply is idempotent and merges, so re-running is safe and drift is healed instead of caused.
Reserve imperative commands for exploration. Use --dry-run=client -o yaml to scaffold manifests, then commit them rather than mutating live objects.
Avoid kubectl edit on shared clusters. It drifts the live object away from your files and leaves no audit trail.
Adopt GitOps once you have more than one environment. Argo CD or Flux continuously reconcile the cluster to Git and detect drift automatically.
C - Make Workloads Resilient
Never run bare Pods for real workloads. Use a Deployment (or StatefulSet/DaemonSet) so a controller reconciles the desired replica count and self-heals.
Set resource requests and limits on every container. Requests drive scheduling; memory limits prevent one Pod from OOM-killing a node's neighbors.
Add readiness and liveness probes. Readiness gates traffic and safe rollouts; liveness restarts wedged containers. Keep probe endpoints cheap.
Run more than one replica for availability. A single replica cannot survive a node failure or a rolling update without downtime.
Let rollouts gate on health. Use kubectl rollout status and readiness probes so a bad image never fully replaces a working one.
Spread replicas across failure domains. Use topology spread constraints or anti-affinity so a single node or zone loss does not take out every replica.
D - Design a Consistent Label Scheme
Adopt the app.kubernetes.io/ recommended labels. Consistent name, instance, component, and part-of labels make tools and dashboards interoperate.
Keep selectors small and stable. A Deployment's selector is immutable, so select on app and add version/tier as extra labels.
Never put high-cardinality data in labels. Per-request IDs belong in logs or annotations, not label indexes that hit etcd.
Verify Service wiring through endpoints. An empty kubectl get endpointslices means the Service selector does not match Pod labels.
Use annotations for non-selecting metadata. Build info, checksums, and tool config are annotations, not labels.
E - Bake In Security and Namespaces
Run containers as non-root with a restricted securityContext. Set runAsNonRoot, drop capabilities, and use a read-only root filesystem where possible.
Pin images by digest and scan them. Immutable digests plus Trivy or Grype scanning keep known-vulnerable or drifting images out of production.
Apply Pod Security Standards (restricted). Enforce the baseline at the namespace level so insecure Pods are rejected at admission.
Isolate workloads with namespaces and default-deny NetworkPolicy. Namespaces scope RBAC and quotas; a default-deny policy makes traffic explicit.
Scope RBAC to least privilege. Grant the narrowest verbs and resources a user or ServiceAccount needs, and audit broad cluster-admin grants.
Disable the default ServiceAccount token when unused. Set automountServiceAccountToken: false on Pods that never call the API server to shrink the blast radius.
When You Are Done
Every workload should be a controller-managed object, defined in Git, with requests/limits, probes, consistent labels, and a non-root securityContext.
Spot-check by running kubectl get all -l app=<name> and confirming the Deployment, ReplicaSet, Pods, and Service all line up. If endpoints are populated and probes pass, reconciliation is doing its job.
FAQs
What is the single most useful command to learn early?
kubectl explain. It teaches the schema of your exact cluster version so you stop guessing field names.
Why avoid imperative commands in production? They leave no auditable record and drift the cluster from your files, which breaks GitOps reconciliation.
How many replicas should I start with? At least two for anything that needs availability, so a node failure or rollout does not cause downtime.
Do I really need requests and limits everywhere? Yes. Without requests the scheduler packs blindly; without memory limits one Pod can OOM its node's neighbors.
What makes a Service return no traffic?
A selector that does not match Pod labels. Check kubectl get endpointslices for an empty backend set.
Where do Pod Security Standards fit in? Enforce the restricted profile per namespace so non-compliant Pods are rejected at admission, before they ever run.
Related
- What Kubernetes Is and Why It Exists
- Declarative vs Imperative
- kubectl Essentials
- API Objects & Reconciliation
- Labels & Selectors
Stack versions: This page was written for Kubernetes 1.36.2, Docker Engine 29.6.1 (BuildKit default), containerd (CRI runtime on nodes), Helm 3, Compose v2, Argo CD (latest - verify at build), and Gateway API (GA - verify controller support at build).