"Should we use Docker or Kubernetes?" is a question I hear framed as an either/or choice more often than it should be, because it's usually not one. Docker (or more precisely, containers and the OCI image format Docker popularized) and Kubernetes solve different problems at different layers, and the real question underneath the question is almost always "do we need an orchestrator yet, or are we solving a problem we don't have." Here's how I actually walk through that decision.

They're not the same category of tool

Docker packages an application and its dependencies into a portable, isolated unit — a container. That's the whole job: build once, run consistently anywhere that has a container runtime, regardless of what's installed on the host underneath. Kubernetes doesn't replace that — it orchestrates many containers across many machines: scheduling them onto available capacity, restarting them when they crash, scaling them up and down, routing traffic to healthy instances, and rolling out updates without downtime. You can run Docker containers with zero Kubernetes involved (most small projects do, forever, correctly). You cannot run Kubernetes without containers — it needs something to orchestrate. The comparison "Docker vs Kubernetes" is really "containers alone vs. containers plus an orchestration layer."

When plain Docker (or Docker Compose) is the right answer

  • A single application, or a handful of services, on one or a few servers. If your entire stack fits comfortably on one to three machines and doesn't need to auto-scale based on load, Kubernetes' operational overhead (a control plane to maintain, YAML to write and review, new failure modes to learn) is a cost with no matching benefit yet.
  • A small team without dedicated platform/infrastructure capacity. Kubernetes rewards teams that can invest in operating it well. A two-person team maintaining both the product and a Kubernetes cluster is often worse off than the same team running Docker Compose on a couple of well-monitored VPS instances.
  • Predictable, steady load. If traffic doesn't spike unpredictably, the auto-scaling case for Kubernetes weakens considerably — you can right-size a couple of servers and move on.

This describes a large share of real production systems, including plenty of profitable, reliable ones. "We're not using Kubernetes" is not a maturity gap to apologize for; for a lot of systems, it's the correct engineering decision.

When Kubernetes earns its complexity

  • Genuinely variable load that benefits from automatic horizontal scaling — traffic that meaningfully spikes and needs more instances brought up (and back down) without a human watching a dashboard at 3am.
  • Many services that need to be scheduled, health-checked, and routed to independently — once you're past a handful of services with different scaling and deployment needs, manually coordinating that across servers becomes its own full-time job, which is exactly the job Kubernetes automates.
  • Multi-environment, multi-region, or high-availability requirements where you need consistent, declarative infrastructure that can be reproduced and failed over reliably — Kubernetes' declarative model (desired state, continuously reconciled) is a genuine advantage here over hand-maintained server configuration.
  • A team that can actually operate it — this is the condition people skip evaluating honestly. Kubernetes done well needs someone who understands networking (CNI), storage (persistent volumes), and the control plane deeply enough to debug it under pressure. Kubernetes done badly — adopted because of resume-driven development or because "that's what serious companies use" — creates more incidents than it prevents.

The honest decision framework

  1. Do you have more than a handful of independently-scaling services? If no, you probably don't need Kubernetes yet.
  2. Does your load genuinely spike in ways that matter to the business (not just "it would be nice to auto-scale")? If no, right-sized fixed capacity is simpler and often cheaper.
  3. Do you (or will you soon) have someone whose job includes operating the orchestration layer itself, not just deploying to it? If no, a managed platform (see below) or plain containers is the more honest choice.
  4. Is the operational complexity Kubernetes adds actually smaller than the complexity it removes for your specific system? For a genuinely large, multi-service system under variable load with a team to run it, usually yes. For a five-service SaaS app run by three engineers, often no.

The middle ground people forget exists

Between "Docker Compose on a VPS" and "self-managed Kubernetes cluster" there's a meaningful middle tier: managed container platforms (ECS/Fargate, Cloud Run, App Runner, managed Kubernetes offerings like EKS/GKE/AKS where the cloud provider runs the control plane for you). These give you a good chunk of orchestration's benefits — scaling, health checks, rolling deploys — without you operating the control plane yourself. For a lot of teams sitting on the fence, this is genuinely the right answer, not a consolation prize: it's less operational surface than self-managed Kubernetes, more automation than plain Docker, and a sensible next step before committing to running Kubernetes yourselves.

What actually goes wrong when teams choose wrong

Adopting Kubernetes too early shows up as: hours lost to YAML debugging instead of building the product, an under-resourced cluster nobody fully understands becoming a recurring incident source, and a team that's now maintaining a distributed system's control plane on top of their actual product.

Staying on plain Docker too long shows up differently: manual scaling decisions made under pressure during a traffic spike, deployment coordination across services becoming an increasingly fragile manual process, and engineering time going into home-grown scripts that re-invent (worse) what an orchestrator already does well.

Neither failure mode is about the tools being bad — both are about the tool not matching the actual current shape and stage of the system.

Practical migration path, if you do outgrow plain Docker

  1. Get genuinely comfortable with Docker first — proper multi-stage builds, health checks, resource limits set on containers. Weak container fundamentals become Kubernetes problems, just harder to diagnose.
  2. Start with a managed orchestration platform rather than self-hosting a control plane, unless you specifically have (or are hiring for) the operational expertise to run Kubernetes itself well.
  3. Migrate one service at a time, not a big-bang cutover — validate health checks, scaling behavior, and rollback under real traffic on the least critical service first.
  4. Build the observability layer (see my DevOps Roadmap for where this fits) before you need it during an incident, not during one.

Frequently asked questions

Can I run Kubernetes without Docker? Yes, and increasingly this is the norm — Kubernetes deprecated direct Docker Engine support (dockershim) back in v1.24, and clusters today typically run containerd or CRI-O as the actual container runtime instead. This doesn't change anything about the Docker-vs-Kubernetes decision above; you're still building standard OCI-format container images (the docker build workflow still applies), Kubernetes just doesn't need the full Docker Engine specifically to run them.

Is Docker Swarm a real alternative to Kubernetes? It's a real, much simpler orchestrator built into Docker itself, and for genuinely small-to-medium deployments it's a legitimate middle ground — easier to learn and operate than Kubernetes, with a smaller but real feature set (service discovery, load balancing, rolling updates). It's seen far less adoption and ecosystem investment than Kubernetes in recent years, which matters for hiring and long-term support, but dismissing it outright isn't quite fair — it solves the "I want orchestration but Kubernetes is too much" problem reasonably well for teams that fit that description.

How much does running Kubernetes actually cost, beyond the servers themselves? This is the cost people underestimate most. Self-managed Kubernetes needs someone maintaining the control plane, applying security patches, managing upgrades (which can be genuinely disruptive), and understanding networking deeply enough to debug it. Managed Kubernetes (EKS/GKE/AKS) removes the control-plane operational burden but adds a direct cost line and doesn't remove the need to understand what's happening inside your cluster. Budget for the person, not just the compute.

We're already on Kubernetes and it feels like overkill — is it worth migrating back to something simpler? Sometimes, but migrating away from an already-working system (however over-engineered) has its own real cost and risk, and "it feels complicated" isn't always the same as "it's actually causing problems." Worth doing this migration if you can point to concrete, recurring costs (incidents caused by the complexity, engineering time genuinely diverted from the product, team turnover from operational burnout) rather than a general sense that a simpler architecture would be nicer. If the system is stable and the team has absorbed the operational cost, "it's more complex than it needs to be" alone often isn't worth the migration risk.

The actual answer

Docker (containers) is close to a default good decision for almost any modern application — the packaging and consistency benefits are hard to argue against even for a single-server deployment. Kubernetes is a genuine, powerful answer to a genuine, specific problem: orchestrating many services reliably at a scale where doing it by hand has already become painful. The mistake isn't choosing either tool — it's choosing Kubernetes before that pain is real, or refusing to consider it once it clearly is.