Skip to content

02 · Orchestration Handoff (Kubernetes/Swarm)

Swarm (Level 3, module 08) covers a real, useful slice of orchestration. This module is about recognizing the point where a workload has outgrown plain Docker/Compose or Swarm and genuinely needs Kubernetes — and being honest that not every project reaches that point.

Signals it's time to move beyond Compose

  • More than a handful of hosts, especially with heterogeneous hardware/scheduling constraints (GPU nodes, spot instances mixed with on-demand).
  • Multiple teams deploying independently onto shared infrastructure, needing namespace-level isolation and RBAC rather than one shared Docker daemon.
  • Autoscaling based on real metrics (request rate, queue depth), not just a fixed replica count.
  • A need for the broader ecosystem — Helm charts for third-party software, operators that manage stateful services (databases, message queues) declaratively, service meshes for fine-grained traffic control.

Signals Swarm (or plain Compose) is still the right size

  • A single team, a handful of hosts, and predictable load — Swarm's operational simplicity (module 08: docker swarm init, no separate control-plane components to run) can be a genuine advantage, not a limitation, at this scale.
  • The team has no existing Kubernetes operational expertise and the workload doesn't need anything Kubernetes uniquely provides — adopting Kubernetes purely for its reputation, without a concrete requirement it satisfies, tends to add operational burden without matching benefit.

Concept mapping: Swarm to Kubernetes

Swarm concept Kubernetes equivalent Key difference
Service (docker service create) Deployment + Service Kubernetes splits "desired replica set" (Deployment) from "stable network identity" (Service) into two objects
Task Pod A Pod can hold multiple co-scheduled containers sharing a network namespace (module 04 of Level 3's sidecar pattern, natively)
Overlay network CNI network plugin Kubernetes delegates networking to a pluggable CNI implementation rather than a single built-in driver
docker secret Kubernetes Secret Conceptually identical (mounted as files/env, module 09 of Level 3); Kubernetes secrets are base64-encoded by default, not encrypted, unless encryption-at-rest is separately configured
docker config Kubernetes ConfigMap Same purpose, same distinction from Secret
docker stack deploy -c stack.yml kubectl apply -f manifests/ Both apply a declarative desired state; Kubernetes's object model is far larger (dozens of resource kinds vs. Compose's handful)

A Compose file's rough Kubernetes shape

The stack.yml from Level 3's capstone maps conceptually onto:

# deployment.yaml (illustrative — not exhaustive)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
spec:
  replicas: 3
  selector:
    matchLabels: { app: api }
  template:
    metadata:
      labels: { app: api }
    spec:
      containers:
        - name: api
          image: registry.example.com/team/link-shortener:1.0.0
          resources:
            limits: { cpu: "1", memory: "256Mi" }
            requests: { cpu: "250m", memory: "128Mi" }
          volumeMounts:
            - name: db-secret
              mountPath: /run/secrets
      volumes:
        - name: db-secret
          secret: { secretName: database-url }

The resources.limits/requests block is the direct Kubernetes analog of Swarm's deploy.resources.limits/reservations (Level 3, module 03's cgroup mechanism underlies both identically — Kubernetes ultimately configures the same kernel cgroups via its container runtime).

Worked example: a migration decision, reasoned through

A team running the Level 3 capstone stack on 3 Swarm nodes starts needing per-tenant namespace isolation for a new enterprise customer requirement, autoscaling api based on request latency, and a managed Postgres operator for automated failover. None of these are things Swarm provides natively. That combination of concrete requirements — not vague "Kubernetes is more mature" reasoning — is the actual trigger to migrate, and the migration path is translating the existing stack.yml service by service using the table above, rather than a rewrite from scratch.

How It Actually Works

Why Kubernetes needing a pluggable CNI, while Swarm ships one built-in driver, reflects a real architectural difference, not just extra options. Swarm's overlay networking (Level 3, module 01) is baked directly into the Docker Engine's own code — one implementation, VXLAN, covering every Swarm cluster. Kubernetes instead defines the Container Network Interface as a plugin contract (a binary the kubelet invokes with a defined JSON input/output) precisely because different clusters have genuinely different networking requirements — cloud-native clusters often want a plugin that maps Pod IPs directly onto the cloud provider's own VPC routing (avoiding VXLAN encapsulation overhead entirely), while on-prem clusters commonly do need VXLAN or a similar overlay. This pluggability is a direct consequence of Kubernetes targeting far more heterogeneous deployment environments than Swarm was designed for.

Why splitting "Deployment" and "Service" reflects a genuine separation of concerns Swarm collapses into one object. In Swarm, one docker service create simultaneously declares the replica count and the stable VIP/DNS name backing it. Kubernetes deliberately decouples these: a Deployment only manages Pod replica lifecycle (create, replace, roll out new versions) and has no inherent stable network identity at all; a separate Service object provides the stable ClusterIP/DNS name and uses a label selector to dynamically discover whichever Pods currently match, regardless of which Deployment (or even multiple Deployments) created them. This decoupling is what enables patterns Swarm can't express directly, like a single Service load-balancing across two different Deployments during a blue-green rollout, each independently scaled.

Exercise

Take the stack.yml from Level 3's capstone and, without necessarily running it, write out the equivalent Kubernetes Deployment + Service + Secret + NetworkPolicy YAML for just the api and db services, explicitly noting where the internal: true overlay network's isolation guarantee (Level 3, module 01/10) would need to be reproduced with a Kubernetes NetworkPolicy instead, since Kubernetes has no direct equivalent of "internal: true" on a network object itself.