You know how to use both. You brought Aurora Libros up with compose.yaml and per-environment overrides in module 4, and you deployed it on a cluster with a StatefulSet, Ingress, HPA and a rehearsed rollback in module 6. This lesson is not here to tell you which one wins, but to give you the criteria to decide which one your project needs, with the exact equivalences between both formats and an honest figure for the cost of maintaining a cluster.

Contents

  1. They are not the same category of tool
  2. The right question
  3. An in-depth comparison, dimension by dimension
  4. Conceptual equivalences
  5. The same aurora-api, in both formats
  6. Decision tree
  7. The middle road: Compose in production
  8. Swarm as a stepping stone, and the services that run Compose
  9. Kompose and the real limits of conversion
  10. The hidden cost of Kubernetes
  11. Aurora Libros at three sizes

  1. They are not the same category of tool

Comparing Compose with Kubernetes is like comparing a recipe with an industrial kitchen. Both are there so you can eat, but one is a document and the other is a system with staff.

Docker Compose Kubernetes
What it is A descriptor for a multi-container application, plus a CLI that applies it A distributed orchestrator with its own control plane
Where it lives On your machine, talking to a daemon On a cluster of nodes, with etcd and controllers
What it does when something falls over Restarts the container according to restart: Reschedules the workload onto another node
Execution model A docker compose up that you run Permanent reconciliation loops
Desired state Exists for as long as the command lasts Persistent in etcd, watched at all times
Smallest unit The container The Pod (one or more containers)

The structural difference is in the fourth row. Compose runs what you ask for and finishes; Kubernetes stores your intent and never stops comparing it with reality. That loop is what gives you a node failing at four in the morning and the Pods reappearing on another one without waking anybody. It is also what forces you to maintain a control plane.

  1. The right question

It is not "which one is better?". It is a battery of concrete questions:

  1. Can you afford for the platform to be down for fifteen minutes while you restart a machine?
  2. How many nodes are you really going to have within a year: one, three or thirty?
  3. Is there anybody on the team who can debug a CrashLoopBackOff without searching the Internet?
  4. Who is on call at three in the morning, and is being paid for it?
  5. Is your load constant, or does it have ×8 peaks that demand autoscaling?
  6. Does the budget cover the control plane plus the nodes with spare headroom?

If you answered "fifteen minutes is acceptable, one node, nobody, nobody, constant, no" — which is the situation of most projects — then Compose is the professional answer, and saying so out loud will save you a year of suffering. If you answered the opposite on three or more questions, Kubernetes starts to pay for its cost.

  1. An in-depth comparison, dimension by dimension

Dimension Docker Compose Kubernetes
Mental model One file, services, up/down Declarative API, objects, controllers, selectors
Learning curve Hours Weeks, and months to operate it well
Scope One host (or Swarm, with deploy:) Tens or thousands of nodes
High availability Whatever the host has: if it falls, everything falls Reschedules onto another node automatically
Rescheduling on failure Does not exist The Deployment guarantees it
Manual scaling --scale api=4 on the same host kubectl scale, across the whole cluster
Autoscaling No HPA, VPA and Cluster Autoscaler
Networking Bridge with DNS by service name CNI, Service, NetworkPolicy, optional mesh
Discovery Docker's internal DNS Cluster DNS + stable Service objects
Load balancing DNS round-robin or your own proxy Service (L4) + Ingress (L7)
Storage Local host volumes PV/PVC, StorageClass, dynamic provisioning
Configuration environment, env_file ConfigMap, mountable or injectable
Secrets A file on disk or secrets: (Swarm) Secret + integration with external managers
Updates Recreates the container: there is an outage Rolling update with maxSurge/maxUnavailable
Rollback Go back to the previous tag by hand kubectl rollout undo, with history
Probes healthcheck (a single one) Liveness, readiness and startup, separately
Observability Daemon logs, Prometheus if you set it up Native metrics and events, an enormous ecosystem
Extensibility None to speak of CRDs, operators, webhooks
Multi-tenancy No Namespaces, RBAC, quotas
Infrastructure cost That of one VM Control plane + nodes + spare headroom
Operational cost Close to zero High and permanent
Who maintains it Anybody on the team Somebody who knows how, on call
Team maturity required One developer At least one person with real experience

The last three rows decide more projects than all the ones above put together, and they are the ones that show up least often in comparisons on the Internet.

  1. Conceptual equivalences

Almost everything you wrote in the Aurora Libros compose.yaml has a translation. What changes is not the idea, but how many objects it takes to express it.

Compose Kubernetes Note
services: api: Deployment + Service Two objects where there was one
image: spec.containers[].image Identical; the same OCI image
ports: "8080:8080" Service (internal) or Ingress (external) Exposure is split into two layers
environment: ConfigMap + envFrom Configuration moves out of the descriptor
secrets: / .env Secret (+ external manager) Secret is base64, not encrypted by default
volumes: (named) PersistentVolumeClaim With a StorageClass and an access mode
volumes: (bind mount) hostPath (avoid it) or a mounted ConfigMap Rarely what you want
deploy.replicas spec.replicas Compose only honors it in Swarm
deploy.resources.limits resources.requests / limits K8s distinguishes what it asks for from what it caps
healthcheck: livenessProbe + readinessProbe + startupProbe From one probe to three semantics
depends_on: condition: initContainers + readinessProbe There is no global ordering; there are retries
restart: unless-stopped restartPolicy: Always (implicit) The Deployment already guarantees it
networks: NetworkPolicy In Compose it isolates; in K8s you have to declare it
profiles: Kustomize overlays Both enable subsets
compose.prod.yaml (override) overlays/prod with patches Same idea, different mechanics
docker compose up -d kubectl apply -k overlays/prod One applies and exits; the other leaves controllers behind

Two rows deserve a warning. The depends_on one: in Kubernetes global ordered startup does not exist; the API Pod will start even if PostgreSQL is not there, it will fail, and CrashLoopBackOff will retry it until the database answers. It is ugly to watch and it is the right behavior: it forces the application to tolerate its dependencies being absent, which is exactly what you learned in 06-01. And the Secret one: it is base64-encoded, not encrypted; without encryption at rest for etcd and RBAC set up properly, it is not a secret, it is text that is inconvenient to read.

  1. The same aurora-api, in both formats

Compose, as it ended up after module 4:

# compose.yaml (fragment)
services:
  api:
    image: ghcr.io/auroralibros/aurora-api:2.0.0
    restart: unless-stopped
    environment:
      DB_HOST: aurora-db
      DB_NAME: aurora_books
      DB_USER: aurora
      REDIS_URL: redis://aurora-cache:6379
      LOG_LEVEL: info
    secrets: [db_password]
    ports: ["8080:8080"]
    depends_on:
      aurora-db:   { condition: service_healthy }
      aurora-cache: { condition: service_started }
    healthcheck:
      test: ["CMD", "node", "-e", "fetch('http://localhost:8080/health/live')"]
      interval: 10s
      timeout: 3s
      retries: 3
      start_period: 20s
    deploy:
      replicas: 3
      resources:
        limits: { cpus: "1.0", memory: 512M }
    read_only: true
    cap_drop: [ALL]
    security_opt: ["no-new-privileges:true"]

Twenty-eight lines. Now the same thing in Kubernetes, without cutting anything essential:

# k8s/base/api.yaml
apiVersion: v1
kind: ConfigMap
metadata: { name: aurora-config, namespace: aurora }
data:
  DB_HOST: aurora-db
  DB_NAME: aurora_books
  DB_USER: aurora
  REDIS_URL: redis://aurora-cache:6379
  LOG_LEVEL: info
---
apiVersion: apps/v1
kind: Deployment
metadata: { name: aurora-api, namespace: aurora }
spec:
  replicas: 3
  selector:
    matchLabels: { app: aurora-api }
  template:
    metadata:
      labels: { app: aurora-api }
    spec:
      securityContext:
        runAsNonRoot: true
        runAsUser: 10001
      containers:
        - name: api
          image: ghcr.io/auroralibros/aurora-api:2.0.0
          ports: [{ containerPort: 8080, name: http }]
          envFrom:
            - configMapRef: { name: aurora-config }
          env:
            - name: DB_PASSWORD
              valueFrom:
                secretKeyRef: { name: aurora-secrets, key: db-password }
          resources:
            requests: { cpu: "250m", memory: "256Mi" }
            limits:   { cpu: "1000m", memory: "512Mi" }
          startupProbe:
            httpGet: { path: /health/live, port: http }
            failureThreshold: 30
            periodSeconds: 2
          livenessProbe:
            httpGet: { path: /health/live, port: http }
            periodSeconds: 10
          readinessProbe:
            httpGet: { path: /health/ready, port: http }
            periodSeconds: 5
          securityContext:
            readOnlyRootFilesystem: true
            allowPrivilegeEscalation: false
            capabilities: { drop: [ALL] }
---
apiVersion: v1
kind: Service
metadata: { name: aurora-api, namespace: aurora }
spec:
  selector: { app: aurora-api }
  ports: [{ port: 80, targetPort: http }]
Compose Kubernetes
Lines for the same service 28 63
Objects declared 1 3 (ConfigMap, Deployment, Service)
Files in a complete project 1 + overrides Dozens, plus the overlays
What you gain — Rescheduling, separate probes, RBAC, HPA

The ratio of more than twice the YAML is not a cosmetic detail: it multiplies per service, and with four services and three environments you end up with a directory nobody reads in full any more. In exchange, every extra line buys something real. The question is whether you need what it buys.

  1. Decision tree

graph TD
    A["How much downtime do you tolerate?"] -->|"Minutes, no drama"| B["More than one node?"]
    A -->|"Seconds or none"| E["Is there anybody who knows K8s?"]
    B -->|No| C["Unpredictable load peaks?"]
    B -->|Yes| E
    C -->|No| D["**Compose on one host**<br/>set up properly"]
    C -->|Yes| F["Does it fit in a managed<br/>container service?"]
    F -->|Yes| G["**Cloud Run / Container Apps**<br/>autoscales with no cluster"]
    F -->|No| E
    E -->|"No, and we cannot hire"| H["**Managed or Compose**<br/>never self-managed K8s"]
    E -->|Yes| I["Budget for a control<br/>plane + headroom?"]
    I -->|No| H
    I -->|Yes| J["**Managed Kubernetes**<br/>module 6 as it stands"]

Five criteria, and not one of them is "what everybody else is doing". Notice that the path towards Kubernetes demands two yeses in a row — knowledge and budget — and that node H exists because the worst possible decision is a self-managed cluster nobody knows how to repair.

  1. The middle road: Compose in production

There is a very widespread and false idea: that Compose "is not for production". Compose on a properly set up host serves millions of requests a day at real companies. What it takes is setting it up with judgment:

# compose.prod.yaml — what turns a toy into production
services:
  api:
    image: ghcr.io/auroralibros/aurora-api@sha256:9f2c...   # digest, not a tag
    restart: unless-stopped                                  # survives a reboot
    logging:
      driver: json-file
      options: { max-size: "10m", max-file: "3" }            # the disk does not fill up
    deploy:
      resources:
        limits: { cpus: "1.0", memory: 512M }                # nobody eats the host
    healthcheck: { test: ["CMD", "node", "healthcheck.js"], interval: 10s }
Production requirement How Compose meets it
Starting after a host reboot restart: unless-stopped + Docker under systemd
Not losing data aurora-data volume + an external, tested backup
Not filling the disk Log rotation + scheduled docker system prune
Reproducible image Reference by digest, never :latest
Updating without a long outage docker compose up -d --pull always (seconds)
Rolling back The previous digest is in Git; up -d again
Monitoring cAdvisor + Prometheus + alerts (05-06)
Backups Scheduled pg_dump to remote storage
TLS certificate Caddy or Traefik in front, with automatic renewal

The two gaps it cannot close: the host is a single point of failure (if the machine dies, the service dies until you bring up another one) and there is no autoscaling. If the business tolerates those two gaps — and a great many businesses do — you have solved the platform with one file, with no control plane and no on-call rota.

An honest sizing rule: a 4 vCPU, 8 GB VM with a well-tuned Aurora Libros stack comfortably serves several hundred requests per second. Before assuming you need a cluster, measure with the load test from 06-06.

  1. Swarm as a stepping stone, and the services that run Compose

If the only problem is the single point of failure, there is an intermediate step before the big leap.

Option What it solves What it costs Status in 2026
Docker Swarm Several nodes, rescheduling, rolling updates Very little learning: deploy: in the same file Maintained, with barely any evolution
Compose + a standby host Recovering quickly after an outage A well-rehearsed manual procedure Trivial
ECS with Compose Runs a compose.yaml on AWS Tying yourself to the provider In use
Cloud Run / Container Apps Autoscaling with no cluster, even down to zero Less control over networking and state Very mature
Managed Kubernetes Everything from module 6 Cost and knowledge The standard

Swarm (06-03) deserves a paragraph of honesty: it is simple, it works, and taking your compose.yaml to three nodes costs you adding deploy: and running docker stack deploy. But its ecosystem is frozen, hiring somebody who knows it gets harder every year and third-party documentation is scarce. As a temporary stepping stone it is reasonable; as a five-year bet, think twice.

Cloud Run-style services are the new development that changes the decision tree: they autoscale from zero to hundreds of instances without any cluster existing to maintain. For ghcr.io/auroralibros/aurora-api:2.0.0 — stateless, with probes, twelve-factor and graceful shutdown — they fit without touching a thing. State moves to a managed database, and availability stops being your problem.

  1. Kompose and the real limits of conversion

kompose translates a compose.yaml into Kubernetes manifests. It is useful as a starting point and dangerous as a finished result.

kompose convert -f compose.yaml -o k8s/
# INFO Kubernetes file "aurora-api-service.yaml" created
# INFO Kubernetes file "aurora-api-deployment.yaml" created
# WARN Volume mount on the host "./data" isn't supported - ignoring
# WARN Service "aurora-db" won't be created because 'ports' is not specified
What it converts well What it converts badly or ignores
image, command, ports depends_on (it loses it: there is no ordering)
environment → individual variables healthcheck → it does not generate the three probes
deploy.replicas Bind mounts → a warning, and then it is on you
restart → restartPolicy secrets → it leaves them as files or loses them
networks (partially) profiles, extends, develop.watch
No Ingress, HPA, PDB or NetworkPolicy at all

The practical conclusion: kompose saves you the first 60 % of the typing and saves you none of the thinking. Everything that makes a deployment production-ready — separate probes, measured requests and limits, a PDB, a network policy, an Ingress with TLS — is still your work. Treat it as a draft, review it line by line, and never apply it directly against a real cluster.

  1. The hidden cost of Kubernetes

What does not appear in the slide decks:

Cost What it means in practice
The cluster Control plane (managed or not) + nodes + headroom for rescheduling
Idle resources You need spare capacity so the Pods from a failed node fit somewhere
Upgrades New versions every few months, with limited support and APIs that get removed
The YAML debt Dozens of files per environment; overlays cover it up but do not remove it
New failure modes CrashLoopBackOff, ImagePullBackOff, Pending for lack of resources, Evicted under memory pressure, a PVC that will not bind, cluster DNS failing
Harder debugging The problem can be in the app, the Pod, the node, the CNI, the CSI or the Ingress
Tooling around it Helm or Kustomize, a GitOps setup, a secrets manager, a metrics system
Continuous training The ecosystem changes faster than the knowledge consolidates
The on-call rota Somebody has to answer at three in the morning

The last row is the one that decides. Phrase it like this in the meeting: "if the cluster breaks on a Saturday at three in the morning, who fixes it, how fast, and paid how much?". If there is no answer with a person's name in it, Kubernetes is not an option yet, however good it looks on the architecture diagram.

And it is worth saying the other way round too: when the answer does exist, Kubernetes gives back far more than it costs. Real autoscaling, deployments with no outage, automatic rescheduling, per-team quotas and an ecosystem that solves problems you did not know you had. The mistake is not choosing Kubernetes; it is choosing it too early.

  1. Aurora Libros at three sizes

Small shop Growing With campaign peaks
Traffic 5-20 req/s 100-300 req/s 40 req/s with ×8-15 peaks
Team 2 developers 6 people, 1 with systems skills 4 developers
On-call No Business hours No
Tolerable outage 30 min 5 min Zero during a campaign
Recommendation Compose on one host Managed Kubernetes Cloud Run or similar
Why One file, zero cluster, minimum cost The traffic and the team already justify it Autoscales with no cluster to maintain
Database On the same host, with tested backups Managed, with a replica Managed, non-negotiable
Risk accepted The host is a single point of failure Permanent operational cost Dependence on the provider
Next step Monitoring and tested backups PDB, HPA and an error budget Measure cost per request at peak

Look at the third column: a lot of traffic at peak does not imply Kubernetes. It implies autoscaling, and there is more than one way to get it. And in the second one, what tips the balance is not just the traffic: it is that there is a person with a systems profile. Without that person, the recommendation would be different even if the traffic were the same.

Common Mistakes and Tips

  • Choosing Kubernetes for your CV. It is a real, human reason, and it is the worst of them all for the project. If you want to learn it, set up a lab cluster with kind, not the company's production platform.
  • Believing that "Compose is not for production". With digests, limits, log rotation, tested backups and monitoring, Compose sustains real businesses. What it does not give you is tolerance to the host falling over, or autoscaling.
  • Applying the output of kompose without reviewing it. It loses depends_on, it does not generate the three probes or an Ingress, HPA or PDB, and it ignores bind mounts.
  • Migrating to Kubernetes without having measured. Before justifying a cluster on performance grounds, run the load test from 06-06 against the current host. The real limit is usually in the database, and a cluster does not move it.
  • Translating depends_on expecting ordered startup. It does not exist. The application has to retry; if it does not, fix that before migrating.
  • Treating Secret objects as encrypted. They are base64. Without encryption at rest for etcd and strict RBAC, they protect nothing.
  • Tip: write the decision and its reasons in a short document inside the repository, with a date. A year from now you will want to know why it was chosen, and whether the premises still hold.
  • Tip: keep the compose.yaml alive even if you deploy on Kubernetes. It is the best way to bring the whole stack up locally to develop and debug.
  • Tip: when in doubt, start with Compose. Migrating from Compose to Kubernetes with a well-built image is days of work; dismantling a cluster nobody knows how to operate takes months.

Exercises

Exercise 1 — Translate a complete service. Take the aurora-cache service (redis:7-alpine, not exposed externally, with a volume for optional persistence, a 256 MB memory limit and a healthcheck using redis-cli ping) exactly as it stands in the compose.yaml. Write it in Kubernetes: Deployment, an internal Service and a PersistentVolumeClaim. State which element of the original has no direct equivalent and how you solve it.

Exercise 2 — Apply the decision tree. For each scenario, walk the tree from §6, state the final node and justify the decision in three sentences. (a) An internal invoicing API used by 30 employees during office hours, with one developer who also acts as the administrator. (b) A ticket-selling platform that sells out a concert in 90 seconds, with a five-person platform team and an on-call rota. (c) A corporate blog with 400 visits a day that an external supplier wants to deploy on a managed cluster "because it is the standard".

Exercise 3 — The real cost of the decision. Aurora Libros is growing and management asks whether "we should move to Kubernetes". Prepare a one-page comparison with: estimated monthly infrastructure cost in both scenarios (use approximate provider figures and state your assumptions), learning and setup time, what measurable improvement the cluster brings, what new risk it introduces, and your recommendation together with the condition that would have to be met to change it.

Solutions

Solution 1.

apiVersion: v1
kind: PersistentVolumeClaim
metadata: { name: aurora-cache-data, namespace: aurora }
spec:
  accessModes: [ReadWriteOnce]
  resources: { requests: { storage: 1Gi } }
---
apiVersion: apps/v1
kind: Deployment
metadata: { name: aurora-cache, namespace: aurora }
spec:
  replicas: 1
  strategy: { type: Recreate }        # a single ReadWriteOnce PVC
  selector: { matchLabels: { app: aurora-cache } }
  template:
    metadata: { labels: { app: aurora-cache } }
    spec:
      containers:
        - name: redis
          image: redis:7-alpine
          args: ["--maxmemory", "200mb", "--maxmemory-policy", "allkeys-lru"]
          ports: [{ containerPort: 6379, name: redis }]
          resources:
            requests: { cpu: "50m", memory: "128Mi" }
            limits:   { cpu: "500m", memory: "256Mi" }
          livenessProbe:
            exec: { command: ["redis-cli", "ping"] }
            periodSeconds: 10
          readinessProbe:
            exec: { command: ["redis-cli", "ping"] }
            periodSeconds: 5
          volumeMounts: [{ name: data, mountPath: /data }]
      volumes:
        - name: data
          persistentVolumeClaim: { claimName: aurora-cache-data }
---
apiVersion: v1
kind: Service
metadata: { name: aurora-cache, namespace: aurora }
spec:
  selector: { app: aurora-cache }
  ports: [{ port: 6379, targetPort: redis }]

What has no direct equivalent is Compose's single healthcheck: here it has been split into liveness and readiness, both using redis-cli ping but with different periods, because in Kubernetes "it is alive" and "it can take traffic" are separate questions. Three more decisions the brief did not give you and that you have to reason about: strategy: Recreate instead of rolling, because a ReadWriteOnce PVC cannot be mounted on two Pods at once and the rolling update would get stuck; Redis's --maxmemory set below the container's limits.memory, so Redis evicts keys before the kernel kills the process with an OOM; and the absence of externally exposed ports, since a Service with no type is ClusterIP and can only be reached from inside the cluster, which is exactly what was asked for.

Solution 2.

(a) Internal invoicing API. Tolerable outage: hours, because outside office hours nobody is using it. A single node is enough and there are no peaks. Final node: Compose on a properly set up host. The single administrator cannot sustain a cluster, and a deployment with restart: unless-stopped, tested backups and basic monitoring covers the requirement with room to spare. Adding Kubernetes here would multiply the operational cost without improving anything you could notice.

(b) Ticket sales. The tolerable outage is zero during the 90 seconds that matter, there is a platform team and there is an on-call rota. The peak is brutal but predictable to the second, which lets you pre-scale ahead of the event instead of waiting for the HPA to react. Final node: managed Kubernetes. This is the textbook case: real high availability, autoscaling, deployments without outages and a team that can operate it. Here the cluster gives back what it costs.

(c) Corporate blog. 400 visits a day is about 0.005 requests per second on average. The tolerable outage is hours. Final node: Compose on one host, or plain static hosting if the content allows it. A managed cluster for this costs more per month than the blog itself generates in value, and it adds a dependency nobody on the team will know how to repair. Being "the standard" is not a requirement: ask the supplier to justify the decision using the same criteria as the tree and the conversation ends on its own.

Solution 3. Structure of the comparison (the amounts are illustrative and must be replaced with those of the real provider and region):

Item Compose on one host Managed Kubernetes
Compute 1 VM of 4 vCPU / 8 GB 3 nodes of 2 vCPU / 4 GB + headroom
Control plane 0 The provider's fixed monthly cost
Database On the host (or managed) Managed, effectively mandatory
Load balancer and TLS Traefik on the same host The provider's load balancer, billed separately
Infrastructure Baseline Between 2.5 and 4 times the baseline
Setup Already done 2-4 weeks of real work
Training 0 1-3 months until you operate it fluently
Maintenance Host patches Patches + cluster upgrades

Measurable improvements from the cluster: automatic recovery when a node fails (from "minutes with human intervention" to "seconds without it"), autoscaling from 3 to 12 replicas under peaks, and outage-free deployments with a one-command rollback. New risks: dependence on knowledge that does not exist on the team today, more configuration surface that can fail, and a fixed cost that does not go down when traffic does.

Recommendation: stay on Compose and revisit the decision with a concrete trigger, not with a date. For example: "we move to managed Kubernetes when two of these three conditions are met: sustained host CPU above 60 %, the business setting an availability target above 99.9 %, or somebody with real experience operating clusters joining the team". Writing down the trigger turns a discussion of opinions into a verifiable condition, and that is the real deliverable of the exercise.

Conclusion

You can now defend the decision with criteria instead of with fashion. You are clear about the first and most forgotten point: they are not the same category of tool. Compose is a descriptor you run and it finishes; Kubernetes stores your intent in etcd and never stops reconciling it with reality. Every other difference follows from that one, including the good ones — automatic rescheduling, autoscaling, outage-free deployments — and the expensive ones.

You have the dimension-by-dimension comparison, with the three rows that decide more projects than any other: infrastructure cost, operational cost and team maturity. You have the complete equivalences table, with its two important warnings: depends_on has no translation because in Kubernetes ordered startup does not exist, and a Secret is base64, not encryption. And you have seen the same aurora-api in both formats: 28 lines against 63, one object against three, with the right question hanging over it — do you need what those extra lines buy?

The decision tree gives you five concrete criteria and a detail worth remembering: reaching Kubernetes demands two yeses in a row, knowledge and budget, and the worst option of all is a self-managed cluster nobody knows how to repair. You know that Compose in production is a perfectly professional decision when the host is set up properly — digests, limits, log rotation, tested backups, automatic TLS — with its two declared gaps: single point of failure and no autoscaling. You know the intermediate steps: Swarm, honest but frozen; the services that run your image without any cluster existing; and kompose, which saves you 60 % of the typing and none of the thinking.

And you take away the question that puts everything else in order: if the cluster breaks on a Saturday at three in the morning, who fixes it, how fast, and paid how much?. With the three versions of Aurora Libros — the small shop on Compose, the growing one on managed Kubernetes, the campaign one autoscaling without a cluster — you have three reference answers and the habit of writing the decision down, with its date and its review trigger, inside the repository.

In the next lesson we come down from the infrastructure to the desktop: Docker Desktop. What exactly that Linux VM you have been using without seeing it is, why it explains bind mount performance, what features it adds, what licensing terms it has — and why it is worth checking them before installing it at your company — and what alternatives exist on each operating system.

Docker: From Beginner to Advanced

Module 1: Introduction to Docker

Module 2: Working with Docker Images

Module 3: Docker Containers

Module 4: Docker Compose

Module 5: Advanced Docker Concepts

Module 6: Docker in Production

Module 7: Docker Ecosystem and Tools

© Copyright 2026. All rights reserved