Kubernetes, managed Kubernetes, Amazon ECS, Cloud Run, Nomad, Docker Swarm and K3s compared by what they schedule, who runs the control plane and where they fit.
Container orchestration tools decide where containers run, restart them when they crash, roll out new versions and connect them to each other. Once an application grows past one host, something has to do that scheduling, and the choice of tool sets how much cluster software your team operates for the next few years.
This guide compares the orchestrators people actually shortlist in 2026, what each one schedules and who runs its control plane. For how Kubernetes itself handles scheduling, health checks and service discovery, see Kubernetes orchestration explained.
An orchestrator keeps a declared state running: you say "three replicas of this image, with this much CPU and memory, reachable on this port", and the scheduler places those containers on machines with room, replaces them when a health check fails and rolls traffic to a new version without dropping requests. Service discovery, secrets delivery, autoscaling and log collection sit around that core, and tools differ mostly in how many of those pieces they ship and how much of the control plane you operate.
The Kubernetes documentation describes the same loop as controllers that keep comparing actual state to desired state, and every tool in this list works the same way, with a different scope.
Kubernetes is the default answer when a team needs an orchestrator that runs anywhere. Deployments, StatefulSets, Jobs and DaemonSets cover most workload shapes, and custom resources with operators extend the API to databases, certificates and message brokers.
Running it yourself means operating etcd, the API server, the scheduler, upgrades every few months and the networking and ingress add-ons you choose. The project publishes about three minor releases a year and supports each minor for roughly fourteen months, so cluster upgrades become a standing item on the roadmap. That control is worth it when you need on-premises clusters, a specific CNI or service mesh, or the same API across several clouds.
Amazon EKS, Google Kubernetes Engine and Azure Kubernetes Service run the control plane for you and integrate the cluster with the provider's load balancers, IAM and storage. You still own the workloads, the manifests or Helm charts, node configuration and add-ons such as ingress controllers and autoscalers.
Each provider also offers a mode that manages nodes: GKE Autopilot, EKS Auto Mode and EKS on Fargate take node pools off your plate in exchange for less control over instance types. Managed Kubernetes is the common way to run Kubernetes in production, and the EKS vs ECS vs Fargate comparison covers the AWS side in detail.
Amazon ECS is AWS's own orchestrator, where a task definition describes the containers, CPU, memory and IAM role and an ECS service keeps a number of tasks running behind a load balancer. Tasks run on AWS Fargate with no servers to manage, or on EC2 instances you size yourself.
There is no control plane to upgrade and no add-ons to choose, which is why ECS is a common default for AWS-only backends. The tradeoff is portability, since task definitions do not run anywhere else, and a smaller ecosystem than Kubernetes for things like custom controllers. What is Amazon ECS goes deeper on clusters, services and launch types.
Cloud Run runs containers as services that scale with incoming requests, including down to zero, plus jobs for batch work. You deploy an image, set concurrency, CPU and memory, and Google handles placement and scaling. Its API is based on Knative, so services can be described in a Kubernetes-style YAML file.
It fits stateless HTTP services and event handlers well. Long-running background processes, sidecars with complex lifecycles and workloads that need node-level control fit GKE better.
Nomad is a single binary scheduler that runs containers alongside plain binaries, Java applications and virtual machines through task drivers. A job file declares groups of tasks, and Nomad places them across clients. It pairs with Consul for service discovery and Vault for secrets.
It suits teams with mixed workloads or on-premises fleets that want one scheduler with less to operate than Kubernetes. Nomad Community Edition has been source-available under the Business Source License since HashiCorp's August 2023 change, which matters if your organization has rules about licenses for infrastructure software.
Swarm mode is built into Docker Engine. docker swarm init turns a host into a manager, other hosts join as workers, and docker stack deploy takes a Compose file and runs its services with replicas, overlay networking, secrets and rolling updates, as described in the Swarm mode docs.
The appeal is that a team already using Compose can get multi-host scheduling with very little new tooling. The Swarm mode docs cover services, replicas, overlay networks and rolling updates, without a built-in autoscaler or custom-controller model like Kubernetes, so Swarm stays a fit for small clusters with predictable load.
K3s is a lightweight, certified Kubernetes distribution packaged as a single binary. A single-server install uses an embedded SQLite datastore instead of etcd by default, and it runs comfortably on small VMs, ARM boards and edge sites.
You get the Kubernetes API and tooling, so manifests and Helm charts work unchanged, with less memory and fewer moving parts. It is common for edge fleets, homelabs and CI clusters, and you still operate it yourself.
Encore combines an open source infrastructure SDK with a platform that provisions and deploys into your own AWS or GCP account. It sits above the orchestrator rather than replacing it: you declare services, object storage buckets and Pub/Sub topics in application code, and when you create an environment you pick the compute it runs on, Fargate ECS, EKS, Cloud Run or GKE, in your own account.

A media service that stores uploads and generates thumbnails in a separate worker looks like this:
Run in your terminal to get started locally.
// media/media.ts
import { api, APIError, Header } from "encore.dev/api";
import { authHandler, Gateway } from "encore.dev/auth";
import { secret } from "encore.dev/config";
import { Bucket } from "encore.dev/storage/objects";
import { Topic, Subscription } from "encore.dev/pubsub";
const authToken = secret("AuthToken");
interface AuthParams {
authorization: Header<"Authorization">;
}
interface AuthData {
userID: string;
}
// Local/dev: compare to a secret. Replace with your IdP verifier before production.
export const auth = authHandler<AuthParams, AuthData>(async (params) => {
const token = params.authorization.replace(/^Bearer\s+/i, "");
if (!token || token !== authToken()) {
throw APIError.unauthenticated("invalid token");
}
return { userID: "uploader" };
});
export const gateway = new Gateway({ authHandler: auth });
export const uploads = new Bucket("uploads", { versioned: false });
interface Uploaded {
key: string;
contentType: string;
}
export const uploaded = new Topic<Uploaded>("uploaded", {
deliveryGuarantee: "at-least-once",
});
interface UploadParams {
key: string;
contentType: string;
data: string; // base64-encoded file contents
}
export const upload = api(
{ expose: true, method: "PUT", path: "/uploads/:key", auth: true },
async ({ key, contentType, data }: UploadParams): Promise<{ key: string }> => {
const bytes = Buffer.from(data, "base64");
// Reject only when the decoded object is larger than 5 MiB.
if (bytes.length > 5 * 1024 * 1024) {
throw new Error("file too large");
}
// notExists rejects overwrite of another caller's object at the same key.
await uploads.upload(key, bytes, { contentType, notExists: true });
await uploaded.publish({ key, contentType });
return { key };
},
);
// Runs as its own consumer. Writing to a derived key makes retries safe.
const _ = new Subscription(uploaded, "make-thumbnail", {
handler: async (event) => {
const original = await uploads.download(event.key);
// Resize `original` with your image library here.
await uploads.upload(`thumbs/${event.key}`, original, {
contentType: event.contentType,
});
},
});
Publishing after the upload leaves a small gap: if the process stops between the two calls, the object exists without a thumbnail event. Persist an outbox row (or make thumbnail generation recoverable from the bucket listing) when every upload must produce a worker job.
encore run starts the service with a local Pub/Sub broker and object storage on the local filesystem, so the upload and the thumbnail worker run together on a laptop before any cluster exists. On deploy, the bucket becomes S3 or Cloud Storage and the topic becomes SNS with SQS or GCP Pub/Sub. Encore provisions an IAM role for the service on AWS or a service account on GCP.
On Kubernetes, each service becomes its own Deployment in a namespace per environment, with ingress and service accounts configured by the platform. On AWS you choose EKS Fargate, managed node groups or EKS Auto Mode for the pods, and you can deploy into an existing EKS or GKE cluster next to workloads that are not built with Encore. Each environment also chooses between running all services in one process or one process per service, without code changes. For other orchestrators, encore build docker produces an image you can run on Nomad, Swarm or K3s yourself.
A coding agent can add the thumbnail worker, the bucket and the topic in one change and test it under encore run, with no manifest, task definition or Helm chart to update alongside it.
Best fit: backend teams that want services, storage and queues running on ECS, EKS, Cloud Run or GKE in their own account, defined by the code that uses them.
Backend teams that want the orchestrator without writing manifests for every bucket and queue can install Encore, declare those resources in application code and pick ECS, EKS, Cloud Run or GKE per environment in their own account.
Pick based on who will operate the control plane and how many add-ons you are prepared to own, then check whether you need Kubernetes at all before committing to it.
Kubernetes and its managed versions (EKS, GKE, AKS) are the most common, followed by Amazon ECS and Google Cloud Run for teams that stay inside one cloud. HashiCorp Nomad, Docker Swarm and K3s cover smaller clusters, mixed workloads and edge sites.
Docker builds and runs containers on one host. Swarm mode, which is built into Docker Engine, adds multi-host orchestration with services, replicas and rolling updates, but on its own a Docker host does not reschedule containers onto other machines when it fails.
Declare services, buckets and Pub/Sub topics in application code with the Encore SDK, then create an environment in your AWS account and pick Fargate ECS or one of the EKS compute options. Encore builds the images, provisions the resources and deploys each service to that compute in your own account.
No. Amazon ECS and Cloud Run schedule containers without a Kubernetes control plane, and Nomad or Swarm can run small clusters with less to operate. Kubernetes fits when you need its ecosystem, custom controllers or portability across clouds.
Deploy to your cloud on AWS and Google Cloud
without managing infrastructure
Encore lets developers and agents define application infrastructure directly in code, then automatically provisions it from local development to production in your AWS or GCP account.