Skip to main content

Docker Is Enough Until the Second Server: Why We Still Bet on Kubernetes

9 min readDora NodaDora Noda
Share
On this page

"You probably don't need Kubernetes." That sentence — or one of its politer cousins — now opens half the infrastructure writing on the internet. A widely shared PaaS-first guide, refreshed in July 2026, declares the "Kubernetes Default era officially over." AI coding-agent boilerplates ship "PaaS first, never Kubernetes" as default policy, requiring a written decision record before anyone is allowed to touch a cluster. And a whole shelf of self-hosted tools — Coolify, Dokploy, CapRover — will happily take your VPS and never once show you a kubelet.

Here is the uncomfortable part for someone writing on a Kubernetes-based platform's blog: they're mostly right. If you are a solo founder with a side project on one VPS, a control plane buys you nothing. The honest version of this post's verdict fits in a table, so here it is up front — the rest of the article is the evidence:

Where you areWhat winsWhy
Solo project, one box, your own appsDocker Compose via Coolify, Dokku, or DokployNothing to orchestrate; a control plane is pure overhead
One team, a few services, one boxSame shelf, or Swarm/Nomad for light clusteringHealth restarts and easy redeploys without YAML sprawl
Multi-node fleet on hardware you ownKubernetes with declarative machine managementMachines become desired state, not pets you SSH into
Hosting other people's appsKubernetes, full stopTenant isolation needs namespaces, RBAC, quotas — not another Compose project on a shared daemon

The backlash's real claim is that the first two rows cover 95% of workloads and the last two barely exist. That claim holds beautifully — until the second server.


The backlash's best numbers, stated fairly

Steel-manning first, because the argument earned its audience. The PaaS-first guide's math is deliberately provocative and directionally hard to dismiss: a managed-platform premium of roughly 30% over raw compute, against three senior SREs at something like $750k a year in loaded cost to run a DIY cluster hosting $5,000 a month of compute. Its break-even: you need on the order of $2.5M in annual raw compute before the savings pay for the team. Below that line — which is nearly everyone reading this — the guide says 90% of product-led companies belong on zero-ops platforms, with Kubernetes reserved for top-100-scale sites and custom GPU training farms.

There is a genuine insight buried in the snark: Kubernetes' own documentation is blunt that it is not a traditional all-inclusive PaaS. It does not build your source code, does not run your CI, does not provide databases, queues, or logging. Teams that adopted it expecting Heroku with YAML got complexity without the payoff, and their resentment is load-bearing evidence, not vibes. The 2026 engineering-standards fashion — document the decision to move beyond PaaS, default-deny Kubernetes in agent-generated stacks — is a rational immune response to a decade of premature adoption.

Concede the small end completely: a single service on a single host should be a docker compose up -d and a nap. Nobody disputes this, least of all the people running control planes. The dispute is only about what happens next — whether "start simple" and "stay simple" are the same advice. They are not, and the difference has a concrete shape: it is the week you need a second machine.

Meet the Docker-native contenders

The single-box shelf is not a strawman; it is good software that wins its home turf. Know the three names, because the rest of this post is about their load-bearing walls:

ToolSubstrateMulti-server storyMaturity signal
Coolify (since 2021, ~50k+ stars)Plain Docker, orchestrated over SSH/WireGuardNative multi-server support; the all-rounder with 280+ one-click servicesv4, Apache-2.0, weekly releases
Dokploy (since 2024, ~24k stars)Docker Swarm + TraefikSwarm-based scheduling across nodesPre-1.0 (v0.29.x), moving fast
CapRover (since 2017, ~12k stars)Docker Swarm clusteringNative Swarm clustering, the original pitchRock-stable veteran, slower cadence, dated UI

Two of the three build on Swarm, and Coolify — the one that doesn't — still provisions each machine as an SSH endpoint that its control plane reaches out to. That sentence is the entire argument of this post in miniature: every tool on this shelf manages servers it connects to. None of them manages machines as declared state. On one box the difference is invisible. Watch what happens when the fleet grows past one.

The second-server seam: what concretely breaks

Outgrowing the single box is not a vibe shift; it is five specific mechanisms failing in sequence. If none of these has bitten you, you haven't outgrown anything and should close this tab with our blessing.

1. Provisioning stays manual. The second machine arrives as an SSH session and an install script, not as a line in a manifest. The third arrives the same way. There is no object anywhere that says "this fleet has four machines of this shape," so there is nothing to diff, review, or roll back — fleet topology lives in whoever ran the script last. Declarative machine APIs exist precisely to end this: a MachineDeployment says the fleet's shape, and controllers create, join, and heal nodes until reality matches.

2. Lifecycle is re-run-the-script. Operating-system upgrades, container-runtime patches, certificate rotation — on hand-raised nodes each of these is a runbook executed per box, in sequence, by a human who remembers the order. A rolling machine replacement (new node up, workloads drained across, old node deleted) is the kind of choreography controllers do tirelessly and humans do until the 3 a.m. page. This is the labor the backlash's $750k-SRE math is actually pricing. The mistake is assuming the labor is intrinsic to Kubernetes rather than intrinsic to hand-operated machines — under declarative management, the upgrade is a version string change, not a weekend.

3. Two of the three contenders stand on frozen ground. Docker Swarm is not dead — Mirantis guarantees support through 2030 and 100+ enterprises run it in production — but it is feature-frozen: no new capabilities, maintenance releases only, while the surrounding ecosystem (Portainer advisories, plugin authors, Mirantis' own v4 engine) redirects toward Kubernetes. Rough market-share figures put Swarm near 2.5% against Kubernetes' ~80% of production orchestration. Betting a growing fleet's future on a substrate its own steward has put in maintenance mode is a different risk than running it on one box today, where frozen is just another word for stable.

4. Tenant isolation hits a structural ceiling. Your own half-dozen services can share a Docker daemon on trust. Other people's apps cannot. Namespaces, RBAC, resource quotas, and network policy are not enterprise garnish — they are the mechanism by which one tenant's crypto miner, fork bomb, or honest traffic spike stops being every other tenant's outage. A shared daemon with project separation is a naming convention; a cluster with admission control and per-tenant quotas is a boundary. The moment the platform hosts apps written by people who don't work here, the first one stops qualifying.

5. The middle has a name and no owner. The ecosystem even named the gap: the "too big for one server, too small for Kubernetes" band, roughly two to ten hosts, where Swarm's Raft consensus is overkill and a full control plane feels absurd. Single-box tools stop at one; Kubernetes starts paying for itself at dozens of services. Pretending the band doesn't exist — that every workload is either a side project or a top-100 website — is the backlash's actual sleight of hand. Fleets live in that band for years.

The conflation at the heart of the backlash

Notice what the PaaS-first argument is really pricing: running Kubernetes yourself. Three SREs, cluster upgrades, YAML hell, the IDP trap — every cost in the ledger is the cost of operating a control plane by hand. Fair. Now separate that from a cost the ledger never lists, because its author never considered it: running someone else's opinionated PaaS on Kubernetes you never see.

That is the entire bex architecture bet, and it changes which line items apply. Under Cluster API, machines are Kubernetes objects: desired state submitted to an API server, reconciled by controllers against infrastructure providers (CAPH for Hetzner cloud and bare metal, equivalents elsewhere). Provisioning, healing, and rolling upgrades are control loops, not runbooks.

The tenant experience is git push, buildpacks, a custom domain, HTTPS — the exact surface the single-box tools sell. The control plane is underneath, absorbing precisely the operational burden the backlash is reacting to, without reintroducing the vendor lock-in PaaS-first correctly fears: the fleet runs on machines you own, described by manifests you can read.

Rule of thumb, suitable for taping to a monitor: the backlash argues against operating Kubernetes; it says nothing against standing on it. Conflating the two is like refusing to ride in cars because engine repair is expensive. Somebody still has to run the engine. The question is only whether that somebody is your team at 3 a.m. or a reconciliation loop that never sleeps.

When "overkill" is actually true

So here is the honest ruling, with the concession first. One box, one team, your own code: take Coolify or Dokploy or plain Compose and never feel a flicker of guilt. The control plane would cost you more than it saves, the PaaS-first guide's break-even math is on your side, and anyone telling you otherwise is selling something. "Kubernetes is overkill" is true there — completely, boringly true.

It stays true right up until the workload stops matching the premise: the second machine that needs provisioning, the first tenant you don't employ, the upgrade you can't afford to do by hand anymore. Past that seam, "Docker is enough" isn't wrong the way a typo is wrong — it's wrong the way a ladder is wrong for reaching orbit. Fine tool, wrong regime. The take holds until the second server, and not one server further.

Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own, with the Kubernetes control plane underneath and never in your way. Figures on the PaaS-first argument come from Sanj's PaaS-first guide (July 2026 refresh); project stats are approximate GitHub/forum figures at publish time — Coolify, Dokploy, CapRover; Swarm support status via Mirantis' long-term support commitment; Cluster API machine lifecycle via the Cluster API Hetzner provider. Star the repo on GitHub or deploy your first app today.

Related articles

Run this on infrastructure you own

bex is the open-source, AI-native Render alternative — push a git repo and get a running HTTPS service on your own machines.

Get started with bex