Let’s keep in touch! Join me on the Javier Tiniaco Leyba newsletter 📩

Docker Unpacked: A 10,000-Foot Guide for In-Depth Understanding

Written in

by

Docker software logo

Docker is a open-source platform for developing, shipping, and running applications inside containers. These containers act as lightweight, portable units that package your code along with its dependencies, ensuring consistency across different environments.

“Docker” is both the name of a company (Docker Inc.) and the name commonly used for its container technology, much of which is open source.

  • Docker Inc. is a commercial company that develops products like Docker Desktop, Docker Hub, Docker Scout, and paid subscription plans.​
  • The core Docker Engine, CLI, and several related components are open-source projects, typically under permissive licenses such as Apache 2.0.​
  • So when people say “Docker,” they might mean the company, the open source engine, or the broader ecosystem; context is important to understand which one is meant.

In this exploration, I will be referring by default to the open-source Docker project, not the company. Let’s dive in!

What is Docker Used For?

Docker is used to package, run, and manage applications in a consistent, portable way across different machines and environments. In practice, it has become a core tool for modern software development, deployment, and operations because it simplifies how applications are built, shipped, and scaled. Here are the main common use cases of Docker:

  • Packaging applications with all dependencies into a single, portable unit (a container) so they run the same on any compatible machine (laptop, server, or cloud).
  • Creating consistent development environments where every team member uses identical stacks, avoiding “it works on my machine” issues.
  • Running automated tests and continuous integration/continuous delivery (CI/CD) pipelines, where containers provide fast, reproducible test and build stages.
  • Deploying microservices architectures, where each service runs in its own container and can be independently updated, scaled, and rolled back.
  • Scaling applications horizontally by starting many identical containers behind a load balancer to handle traffic spikes.
  • Supporting hybrid and multi-cloud setups, letting teams move workloads between on‑premises and different cloud providers without major rewrites.
  • Isolating services on a single host (e.g., database, cache, API, frontend) to avoid dependency conflicts while using the same underlying OS.
  • Providing reproducible environments for data science and machine learning experiments, ensuring that models and notebooks run identically on any machine.
  • Powering local development for complex systems (e.g., web apps with databases, queues, and caches) through tools like Docker Compose.
  • Simplifying edge/IoT and remote deployments, where the same containerized service can be rolled out and updated across many devices.

What Problems Does Docker Aim to Solve?

Docker solves a cluster of recurring problems in the software lifecycle: inconsistent environments, dependency conflicts, slow and fragile deployments, and difficulty scaling. Instead of configuring each machine by hand, teams package applications and their dependencies into containers, which behave the same everywhere, from laptops to production servers. Here are some common problems solved by Docker:

  • Environment drift between dev, test, and production (“it works on my machine”): containers encapsulate the runtime, libraries, and configuration so the application behaves consistently across all stages.
  • Dependency hell and version conflicts: each service brings its own isolated dependencies, avoiding clashes when different apps need different versions of the same library or tool.
  • Slow, error‑prone environment setup: onboarding new developers or spinning up test environments becomes running a few container commands instead of manual OS and package configuration.
  • Fragile, manual deployments: images provide a repeatable artifact, so operations teams deploy the same container that was built and tested, reducing configuration errors on servers.
  • Difficult horizontal scaling: stateless containers can be replicated quickly to handle more load, then removed just as easily when traffic drops.
  • Limited portability across infrastructure: the same container image can run on different clouds, on‑prem servers, and developer laptops, easing hybrid and multi‑cloud strategies.
  • Risky changes and rollbacks: versioned images allow quick rollbacks by redeploying a previous image tag if a new release misbehaves.
  • Complex multi‑service local setups: tools like Docker Compose make it easy to run full stacks—databases, caches, queues, APIs—locally without installing each component natively.

Docker Pros and Cons

Using Docker provides distinct advantages and potential drawbacks for modern development and deployment:

Pros of Using Docker

  • Efficient resource usage: Containers share the host OS kernel, making them lighter and more efficient than virtual machines, which require separate OS instances.
  • Portability: Docker images encapsulate all application dependencies, ensuring the app runs the same across different systems, such as developers’ laptops, test machines, cloud servers, or on-prem environments.
  • Rapid, consistent deployment: With Docker, teams can quickly build, test, and deploy containers, minimizing configuration discrepancies between environments and speeding up release cycles.
  • Scalability and orchestration: Solutions like Docker Compose and Kubernetes (both actively maintained) allow for managing multiple containers/services easily, supporting automatic scaling and self-healing.
  • Simplified CI/CD: Containers help automate testing, building, and deployment workflows, making continuous integration and delivery more reliable.
  • Isolation: Multiple applications and services can run independently on a single host without version or dependency conflicts, boosting security and maintainability.

Cons of Using Docker

  • Security concerns: Containers offer process-level isolation, not the full OS isolation of VMs, which can expose risks if underlying vulnerabilities are present or containers are misconfigured.
  • Persistent storage complexity: Managing data persistence and volume configuration across containers and hosts can be challenging compared to traditional server setups.
  • Networking challenges: Container networks are flexible but can be complicated to configure and troubleshoot, especially for multi-host and hybrid-cloud deployments.
  • Image management: Old, unused, or overly large images can clutter disk space and introduce security issues if not regularly cleaned and updated.
  • Learning curve: While basic Docker use is accessible, mastering production orchestration, networking, and security best practices requires time, especially when moving to Kubernetes.
  • Limited support for stateful or GUI apps: Docker excels at stateless, backend services but can be less ideal for heavy stateful or desktop applications.

What Does “Stateful” Mean in Docker?

Limited support for stateful or GUI apps does not mean Docker cannot run them; it means you need extra work and the experience is less smooth than for simple stateless backend services. Stateful apps keep important data that must survive restarts or moves, such as:

  • Databases (PostgreSQL, MySQL, MongoDB) whose data must not be lost.
  • Message brokers (RabbitMQ, Kafka) that store messages or logs.
  • Applications that keep user sessions, uploaded files, or configuration on disk.

Containers are designed to be ephemeral: if a container is deleted, anything stored only inside its filesystem disappears. To run stateful apps safely, you must:

  • Use volumes or external storage systems (e.g., bind mounts, network storage, managed DB services).
  • Plan for backups, replication, and failover outside the container itself.

This makes stateful workloads more complex to design and operate than stateless services, where you can freely kill and recreate containers without worrying about data.

Examples of stateful apps in Docker

  • PostgreSQL/MySQL in a container, writing data to a Docker volume rather than the container’s local filesystem.
  • Redis with persistence enabled, storing data on a mounted volume.
  • A monolithic web app that writes user-uploaded files to disk, which must be mapped to persistent storage rather than the container’s writable layer.

These setups work, but require clear storage architecture, monitoring, and backup strategies; otherwise crashes, rescheduling, or host failures can lead to data loss or inconsistency.

What “GUI Apps” Means in Docker

GUI (desktop) applications expect:

  • Direct access to a display server (X11/Wayland on Linux, Windows desktop APIs, macOS GUI).
  • Sound devices, GPU, and possibly hardware acceleration.

Containers, especially on servers, typically run headless (no display). To run GUI apps, you must:

  • Forward the display (e.g., mount X11 socket, use -e DISPLAY, or run VNC/noVNC inside the container).
  • Provide GPU access if needed (NVIDIA Docker / GPU passthrough).

This adds friction and platform-specific hacks compared to running CLI or web services.

Examples of GUI Apps in Docker

  • An IDE (like VS Code desktop) or full desktop environment inside a container, accessed via VNC/Remote Desktop in a browser.
  • A graphical browser (e.g., Firefox/Chrome) in a container for automated testing, with X11 forwarding or a headless mode plus VNC/WebDriver.
  • A native desktop app for design or engineering tools containerized for reproducible environments, accessed via remote display.

These are all possible, but they are niche, more fragile, and often overkill compared to:

  • Running the GUI app natively and using Docker only for backend services.
  • Using headless versions (e.g., headless Chrome) or web UIs, which fit Docker’s strengths much better.

In short: Docker can run stateful and GUI apps, but they clash with the default “ephemeral, headless, easily replaceable container” model, so you must compensate with explicit storage, networking, and display setup, and accept more operational complexity.

What are the Alternatives to Docker?

There are several well-supported alternatives to Docker for containerization and container management as of 2026. Each has unique features and strengths, some focusing on security, performance, developer experience, or production stability.

  • Podman: A drop-in replacement for Docker that is daemonless (no root-required daemon), supports rootless containers, and uses the same Dockerfile/image formats. Podman places heavy emphasis on security by allowing containers to run without root privileges.
  • containerd: A core container runtime used by Kubernetes and formerly by Docker. You can use it directly, bypassing Docker’s extra layers, for a lightweight, production-grade container management experience.
  • CRI-O: Designed for Kubernetes, CRI-O serves as an open-source, lightweight runtime specifically to run containers in Kubernetes clusters using Open Container Initiative (OCI) standards.
  • LXC/LXD: Linux Containers (LXC) and their management tool, LXD, can run full system or “machine” containers, functioning much like lightweight VMs with stronger OS-level isolation.
  • Rancher Desktop: A popular developer tool that lets you build, run, and manage containers with built-in Kubernetes, providing a graphical interface and developer-friendly experience. Often used as an alternative to Docker Desktop.
  • Nerdctl: A CLI designed to mimic Docker’s CLI while running on top of containerd, providing compatibility and flexibility for managing containers directly with containerd.
  • OpenShift: Red Hat’s enterprise Kubernetes platform includes its own container runtime options, being a popular alternative in enterprise and managed Kubernetes deployments.
  • Kubernetes: While not a container runtime, Kubernetes is widely used for container orchestration and often used alongside or instead of Docker’s native tools for production workloads.
  • Others: Tools like runc (the underlying runtime for Docker), gVisor (sandboxed containers), and Kata Containers (VM-backed containers) provide additional options for specific security or isolation requirements.

These alternatives have seen rapid adoption in both cloud-native and enterprise environments, providing viable and often superior solutions for various containerization needs.

What is a Docker Container?

A Docker container is a lightweight, isolated environment that runs an application together with everything it needs (its code, runtime, libraries, and configuration). It is created from a Docker image and runs as a process on the host machine, while sharing the host’s operating system kernel rather than needing its own full OS.

In practice, you can think of a Docker container as:

  • A portable unit of deployment: the same container can run on a laptop, a server, or in the cloud and behave consistently, which is what makes Docker so useful for development, testing, and production.
  • A runnable instance of an image: when you “start” an image, you get a container.
  • An isolated sandbox: it has its own filesystem, network interfaces, environment variables, and resource limits, so multiple containers on the same host do not interfere with each other.

How does Docker Containers Run?

Docker containers run as isolated processes that share the same host OS kernel, not a “guest OS” per container like virtual machines do.

  • On Linux, each container is just one or more normal processes on the host, but wrapped in Linux namespaces and cgroups so they see their own filesystem, process list, network, etc. They all share the same Linux kernel.
  • On Windows, “process‑isolated” Windows containers also share the host Windows kernel; optionally, you can use Hyper‑V‑isolated containers, which put each container in a tiny VM, but even there you don’t install a full OS per app.

What are the Different Modes for Running Docker Containers?

At a high level, people usually talk about “modes” of running containers along these axes: foreground vs background, interactive vs non‑interactive, and different isolation/networking options.

Foreground vs Background

  • Foreground mode (default)
    • docker run IMAGE ...
    • The container’s main process attaches to your terminal; you see its logs directly, and when you Ctrl+C, the container stops.
  • Detached/background mode
    • docker run -d IMAGE ...
    • The container runs in the background, your terminal is freed, and you use docker logs / docker exec to interact later.

Interactive VS. Non-interactive

  • Interactive with TTY
    • docker run -it IMAGE /bin/bash
    • Allocates a pseudo‑TTY and keeps STDIN open; ideal for “SSH‑like” shell sessions inside a container.
  • Non-interactive
    • docker run IMAGE some-command
    • Runs the command, prints output, and exits; good for batch jobs or one‑off commands.

Network Modes

  • Default bridge network
    • docker run IMAGE (no special flags)
    • Container gets its own private IP on a bridge; can reach the outside world via NAT; you map ports with -p.
  • Host network mode
    • docker run --network host IMAGE
    • Container shares the host’s network stack; no port mapping needed, but less isolation.
  • Custom bridge networks
    • docker network create mynet + docker run --network mynet ...
    • Lets multiple containers talk to each other by name; common for multi‑container setups.
  • Other special modes
    • --network none (no network), or advanced types like overlay (in Swarm / orchestration contexts).

Privilege / security modes

  • Normal (unprivileged) mode
    • Default: limited capabilities and isolation from host devices.
  • Privileged mode
    • docker run --privileged ...
    • Broad access to host devices and kernel capabilities; only for special/admin use cases.
  • Capability / user‑scoped modes
    • --user--cap-add--cap-drop to fine‑tune privileges.

Restart and lifecycle behavior

  • One‑shot / no restart
    • Default: container exits when its main process finishes.
  • With restart policies
    • docker run --restart=always|on-failure|unless-stopped ...
    • Controls whether and when Docker automatically restarts the container.

Putting it together, a “mode” is usually a combination, like “interactive foreground on default bridge” (docker run -it IMAGE), or “detached background service on host network with restart always” (docker run -d --network host --restart always IMAGE).

What is a Docker Service?

The word “service” is a bit overloaded, but in Docker’s own terminology:

  • In Docker Swarm mode, a Docker service is a declarative definition of how a containerized application should run across a cluster:
    • Which image to run.
    • How many replicas.
    • What ports to expose.
    • Constraints, update strategy, etc.
  • The service is like a higher‑level object above containers:
    • You create a service; Docker Swarm then creates and maintains the right number of container tasks.
    • If a container dies, Swarm recreates one to match the service spec.

In more informal usage (outside Swarm):

  • People often say “service” to mean “one logical part of a multi‑container app” (e.g. a web service and a db service in a Compose file), even though technically those are Compose services, not Swarm services.
  • In Docker Compose, a service section in docker-compose.yml defines:
    • The image (or build context),
    • Environment, volumes, ports, etc.,
    • For a logical component of your app (web, api, db, cache…).

What is the Default Location for Changes/Files Inside a Docker Container?

Files created or changed inside a running Docker container, by default, are stored in the container’s writable layer. This layer sits on top of the read-only image layers in a union filesystem. All data is kept inside Docker’s internal storage until the container is deleted, at which point the data is lost unless you use volumes or bind mounts.

What is a Docker volume?

Docker volume is a special storage location managed by Docker, typically found on the host at /var/lib/docker/volumes/ (Linux). Volumes provide persistent storage that exists independently of the container lifecycle, making it possible to keep data even if the container is removed or recreated. Volumes are managed using Docker CLI commands, can be shared between containers, and are preferred for durable, production data.

What is a Docker Bind Mount?

Docker bind mount links a specific directory or file on the host directly into the container’s filesystem. Changes are instantly visible on both host and container sides. This mounting method is common for local development (e.g. syncing code into containers), but lacks the portability and management features of Docker volumes, and has potential security/performance implications.

Comparison Table: Persistence, Features, Functionality, Pros/Cons

Storage TypePersistenceComplexityFeatures/FunctionalityProsCons
Default Container FSEphemeral. Deleted when container is removedVery SimpleNo config; just use /path inside containerZero config; good for testingData lost if container is deleted; not for production
Docker VolumePersistent. Survives container removal; managed by DockerModerate (use CLI)Shareable, Docker-managed, portable, good performanceEasy durability; safe sharing across containersInternals are less visible/controlled; need CLI to manage
Docker Bind MountPersistent (links directly to host); relies on host directorySimple (dev)Direct host path mapping, instant sync, host-visibleFull host control; real-time dev edit/testSecurity risk; host-related path issues; not portable; performance hits
Docker Compose WatchDev-only sync; persistence handled by underlying storage (FS/vol)Higher (rules)Watches host paths and syncs changes into containers and/or triggers rebuild/restart actions for servicesFine-grained, code-focused sync; good isolation; can ignore files; great for hot reloadExtra configuration; not a general storage primitive; needs a running dev process; dev use only

What is the Difference Between a Docker Bind Mount and Docker Compose watch?

A bind mount is a low-level storage mechanism; Compose watch is a higher-level dev convenience for syncing code and triggering rebuilds/restarts.

What is a Docker Image?

A Docker image is a read-only blueprint for creating containers. It packages everything an application needs to run—its code, runtime, libraries, system tools, and configuration—into a single, versioned artifact.

  • A Docker image is a template, a bit like a snapshot or a golden disk image: when you run it, Docker creates a container from it.
  • Images are immutable: once built, they do not change. Any changes at runtime happen in a separate writable layer in the container, leaving the original image untouched.
  • Images are built from a Dockerfile (a script of build instructions) and are stored in registries (like Docker Hub or private registries), so they can be shared and reused across machines and environments.

The Docker image’s OS family and CPU architecture must be compatible with the host, but you don’t need a separate image for every tiny host variant.

OS Compatibility

For Linux containers:

  • Containers share the host’s Linux kernel, so a Linux container image must run on a Linux kernel that supports the syscalls/features it needs.
  • You can usually run an Ubuntu-based image on a Debian, Fedora, or other Linux host, because they all share a Linux kernel ABI; the root filesystem inside the image (Ubuntu, Alpine, etc.) does not have to match the host distro exactly.
  • You cannot run a native Windows container image directly on a plain Linux host (or vice versa); that requires a VM or special compatibility layer.

For Windows containers:

Windows containers normally require that the container base image version is compatible with the Windows host version (same OS family and close build version), unless you use Hyper‑V isolation to relax that constraint.

CPU / Architecture Compatibility

  • The CPU architecture must match: an amd64 image needs an amd64 host (or emulation), an arm64 image needs an arm64 host, etc.
  • For popular images like Python, maintainers publish multi‑arch images under the same tag (e.g. python:3.12), which internally include variants for amd64arm64, etc. The registry and Docker engine negotiate and pull the right one for your host.
  • If you build your own images, you typically build at least one per architecture you care about; multi‑platform builds bundle these into a single logical image name.

Docker Image Tags and Repositories

  1. Docker image repositories
  • A Docker image repository is the named collection of related image versions for one piece of software.
    • Example: library/nginx (official Nginx images), myuser/myapp (your app’s images).
  • Inside a repository, you store multiple variants of the same image (different versions, builds, or configurations).
  • Repositories live in a registry (like Docker Hub, GitHub Container Registry, AWS ECR, etc.) and are what you push to and pull from, e.g. docker push myuser/myapp:1.0.
  1. Docker image tags
  • A Docker image tag is the label that identifies a specific version or variant inside a repository.
    • Full reference: registry/namespace/repository:tag, e.g. docker.io/library/nginx:1.27myuser/myapp:prod-2025-11-25.
  • If you omit the tag (e.g. docker pull nginx), Docker defaults to the :latest tag.
  • Tags are mainly used for:
    • Versioning (e.g. 1.0.01.1.02025-11-25).
    • Differentiating builds (e.g. -alpine-slim-debug).
    • Making deployments reproducible and rollbacks easy (you know exactly which image version you’re running).
  • Multiple tags can point to the same image ID, and a single image can exist in multiple repositories.

What is a Docker File?

A Dockerfile is a plain-text file that contains the step‑by‑step instructions for building a Docker image. It acts like a “recipe” that Docker follows to assemble everything your application needs into an image. A Dockerfile:

  • Specifies a base image to start from (for example, a minimal Linux image or a language runtime like Node, Python, or Java).
  • Lists build steps, such as copying your source code into the image, installing packages and dependencies, setting environment variables, and exposing ports.
  • Defines how the container should start by specifying the default command or entrypoint that runs when a container is created from the image.

In short, the flow is: Dockerfile → Docker image → Docker container. You write the Dockerfile, use it to build an image, and then run that image as one or more containers.

What are Docker Registries?

Docker (container) registry is a service that stores and distributes container images. It’s the place your docker push sends images to, and where docker pull fetches them from. Registries organize images into repositories (e.g. library/nginxmyuser/myapp), each with multiple tags (versions).

Main Types of Registries

  • Public hosted registries (SaaS)
    • Examples: Docker Hub, GitHub Container Registry, GitLab Container Registry, Quay.io, AWS ECR Public.
    • Anyone can pull public images; you usually need an account/token to push.
    • Good for open source, sharing base images, or simple team setups.
  • Private hosted registries (cloud provider / vendor)
    • Examples: AWS ECR, Google Artifact Registry / GCR, Azure Container Registry, GitHub/GitLab private repos, JFrog Artifactory SaaS.
    • Integrated with the provider’s IAM/permissions and often with CI/CD.
    • Used to keep proprietary images private and close to your infrastructure.
  • Self‑hosted / on‑prem registries
    • Examples: Docker’s open-source registry image, Harbor, JFrog Artifactory self‑hosted, Nexus, GitLab self-managed.
    • You run and manage them on your own servers.
    • Used when you need full control (compliance, air‑gapped networks, strict security).

What is Docker Hub?

Conceptually: Docker Hub is “just” one very popular public registry; managed by Docker Inc. the company, the registry concept itself is generic. Docker Hub is Docker’s official cloud-based container registry for storing, sharing, and managing Docker images. It is the default place Docker uses when you docker pull or docker push an image, unless you configure another registry. Docker Hub provides:

  • A large public catalog of images, including “official” images for common operating systems, databases, runtimes, and languages (e.g., Ubuntu, Nginx, PostgreSQL, Python…).
  • Private and public repositories where you and your team can push your own images for use in development, CI/CD, and production.
  • Integration with developer workflows: image versioning (tags), organization and team access control, and automation features like build triggers and security scanning on some plans.

One can find Docker Official images in Docker Hub. According to Docker Hub, official images are:

Docker Official Images are a curated set of Docker open source and drop-in solution repositories. These images have clear documentation, promote best practices, and are designed for the most common use cases.

What is Virtualization?

Virtualization is a technique that lets one physical computer behave as if it were many separate computers, each with its own operating system and applications. It does this by inserting a software layer (usually called a hypervisor) between the hardware and the operating systems, so resources like CPU, memory, storage, and network can be sliced up and allocated to multiple “virtual machines” (VMs).

With virtualization, a single physical server can host several independent virtual machines, and each VM thinks it is running on its own dedicated hardware. This improves hardware utilization, simplifies management, and makes it easier to isolate workloads, move systems between servers, and recover from failures.

What is the Difference Between Virtualization and Conteinerization?

Containerization is a way to package and run applications so that each app has its own isolated environment but shares the host operating system’s kernel. Virtualization, in contrast, creates full virtual machines, each with its own complete operating system on top of a hypervisor.

  • Containers share the host OS kernel but have their own filesystem, dependencies, and resource limits.
  • Because there is no extra guest OS per container, they are lightweight, start very fast, and use fewer resources than virtual machines.
  • Tools such as Docker, containerd, Podman, and orchestrators like Kubernetes are built around this model of packaging and running applications.

How Containerization Differs From Virtualization

At a high level:

  • Virtualization virtualizes the hardware: each VM looks like its own machine, with its own OS.
  • Containerization virtualizes the OS user space: many containers share one OS kernel, each running its own isolated application environment.

Key differences:

  • Architecture:
    • Virtualization: Hypervisor → multiple full OS instances (VMs) → apps.
    • Containerization: Host OS kernel → many isolated user-space environments (containers) → apps.
  • Resource usage:
    • Virtualization: Each VM needs its own OS, so CPU, RAM, and disk overhead are higher.
    • Containerization: Containers reuse the host OS, so they are much lighter and denser.
  • Startup time:
    • Virtualization: VMs must boot an OS, so startup is slower (seconds to minutes).
    • Containerization: Containers just start a process, so startup is very fast (milliseconds to seconds).
  • Isolation & security:
    • Virtualization: Strong isolation; each VM has its own kernel, ideal for multi-tenant and high‑security boundaries.
    • Containerization: Process-level isolation; strong enough for many use cases but generally weaker than full VM isolation.
  • OS flexibility:
    • Virtualization: You can run different OSes on the same host (e.g., Linux and Windows VMs on one hypervisor).
    • Containerization: Containers must be compatible with the host kernel (e.g., Linux containers need a Linux kernel).
  • Typical use cases:
    • Virtualization: Legacy apps, mixed-OS environments, strong isolation needs, running entire servers as VMs.
    • Containerization: Microservices, cloud‑native apps, CI/CD pipelines, rapid scaling of stateless services.

Summary table: Containerization vs Virtualization

AspectVirtualization (VMs)Containerization (Containers)
What is virtualizedHardware (full machine)OS user space (process environment)
OS per instanceFull guest OS per VMShared host OS kernel
Resource overheadHigh (OS per VM)Low (no extra OS per container)
Startup timeSlower (boot full OS)Fast (start a process)
Isolation strengthStrong (separate kernels)Moderate/strong (namespaces, cgroups; same kernel)
OS diversityCan run different OSes on same hostMust match host kernel family
DensityFewer instances per hostMany more containers per host
Typical toolsVMware, Hyper‑V, KVM, VirtualBoxDocker, containerd, Podman, Kubernetes
Best suited forLegacy apps, mixed OS, strict isolation, full serversMicroservices, cloud‑native apps, CI/CD, rapid scale‑out

What is Docker Compose?

Docker Compose is a tool that lets you define and run multi-container Docker applications using a single YAML configuration file. Instead of starting and wiring each container manually, you describe your whole app stack (services, networks, volumes) in one file and bring everything up with a single command.

  • You write a compose.yml / docker-compose.yml file that lists your services (e.g., webapidb), the images they use, ports, environment variables, volumes, and networks.
  • Then you use commands like docker compose up and docker compose down to start or stop the entire stack in one go, making it ideal for local development, testing environments, and small deployments or prototypes.

A Common Use Case for Docker Compose

A classic example is a small web application with a database and a cache, e.g. a Node.js + PostgreSQL + Redis stack.

  • The Node.js service runs your API or web frontend.
  • The PostgreSQL service provides the relational database.
  • The Redis service handles caching or sessions.

With Docker Compose you describe all three services, their images, environment variables, networks, and volumes in one YAML file and bring the whole stack up with a single command, instead of manually starting and wiring each container.

What is a Docker Compose file?

A Docker Compose file is a YAML configuration file that describes a multi‑container application: which services (containers) it has, how they are built or which images they use, and how they connect to networks and volumes.

  • It’s usually named compose.yaml or docker-compose.yml and acts as a single source of truth that lets you start or stop the entire stack with commands like docker compose up and docker compose down.
  • A top‑level services section where each service (like webdbcache) is defined with its image or build context, ports, environment variables, volumes, and dependencies.
  • Optional volumes and networks sections that declare named volumes (for data persistence) and custom networks for service‑to‑service communication.

Here’s an example of a docker-compose.yml file for web application that starts multiple services as containers: a relational database (MariaDB), PHP, a Job scheduler, a que manager, PHPMyAdmin…

What is Kubernetes and what is its Relation to Docker?

Kubernetes is an open‑source platform for orchestrating containers: it automates deploying, scaling, networking, and healing large numbers of containerized applications across a cluster of machines. You describe your desired state in YAML (how many instances, what image, what resources), and Kubernetes continuously works to keep the real state matching that description.

What is Kubernetes (k8s)?

  • Kubernetes manages clusters made of a control plane (the “brain”) and worker nodes (machines that actually run containers).
  • On each worker node, Kubernetes runs containers inside pods, which are the smallest deployable units and can hold one or more tightly related containers.
  • Kubernetes provides built‑in features such as service discovery, load balancing, rolling updates and rollbacks, autoscaling, and self‑healing (restarting or rescheduling failed pods).

How Kubernetes relates to Docker

  • Docker is primarily a container runtime and packaging tool: it builds images and runs individual containers on a single host.
  • Kubernetes is a container orchestrator: it schedules and manages many containers across many hosts; it expects a container runtime on each node (historically often Docker, now typically an OCI‑compatible runtime like containerd).
  • In practice, Docker (or another runtime) runs the containers, while Kubernetes decides where and how many of those containers should run, wires networking, and handles scaling and resilience.

What are the differences between Kubernetes and Docker Compose?

Kubernetes and Docker Compose both manage groups of containers, but they target very different scales and use cases.

  • Docker Compose: A simple tool to define and run multi-container Docker apps on a single machine, mainly for local development, testing, and small deployments.
  • Kubernetes: A full container orchestration platform for running containers across a cluster of machines with high availability, scaling, and resilience.

Scope and scale

  • Compose runs everything on one host; great for “my laptop” or a simple server.
  • Kubernetes runs across many nodes (VMs/servers), managing placement, scaling, and failover of workloads.

Features

  • Compose:
    • Defines services, networks, and volumes in one YAML file.
    • Starts/stops stacks with docker compose up/down.
    • No built‑in autoscaling, health‑based rescheduling, or rolling updates.
  • Kubernetes:
    • Provides deployments, services, ingress, ConfigMaps, Secrets, Jobs, etc.
    • Handles rolling updates/rollbacks, self‑healing, autoscaling, and built‑in service discovery and load balancing.

Complexity and learning curve

  • Compose: Simple, quick to learn, ideal for everyday dev work and simple demos.
  • Kubernetes: More concepts (pods, deployments, services, namespaces, etc.) and a steeper learning curve, designed for production and large teams.

Relationship to Docker

  • Compose sits directly on top of Docker: it assumes Docker as the engine and uses Docker’s CLI and networking.
  • Kubernetes can work with multiple container runtimes (e.g., containerd); Docker is just one way to build and run the images that Kubernetes will schedule.

Typical use cases

  • Use Docker Compose for:
    • Local development of a web app + database + cache.
    • Lightweight integration tests and small single‑host setups.
  • Use Kubernetes for:
    • Production microservices across multiple nodes/clouds.
    • Systems that need high availability, autoscaling, and sophisticated traffic and rollout control.

Kubernetes VS Docker Compose: Summary Table

AspectDocker ComposeKubernetes
Primary purposeDefine and run multi‑container apps on a single host for dev/test and small setups.Orchestrate containerized apps across a cluster of nodes for scalable, resilient production.
ScopeSingle machine (local or single server).Multiple machines (cluster of nodes).
Abstraction levelWorks directly with Docker containers and services defined in one YAML file.Introduces pods, deployments, services, etc., managed via multiple manifest files.
FeaturesSimple service definition, basic networking and volumes; no built‑in autoscaling or self‑healing.Advanced scheduling, autoscaling, rolling updates, self‑healing, service discovery, load balancing.
Typical use casesLocal development, demos, integration tests, small single‑host deployments.Production microservices, high‑availability systems, large and distributed workloads.
ComplexityEasy to learn and use; minimal setup and concepts.Steep learning curve; many components and concepts to understand.
Relation to DockerDepends directly on Docker as the container engine.Uses a container runtime (often containerd); Docker mainly used to build images.

Docker Containers vs Virtual Environments

Docker containers might be an overkill for some use cases, lets analyze the case of Python virtual environments.

When to prefer Python virtual environments

  • For pure Python projects: Use virtualenv/venv if your only isolation need is for Python packages (e.g., web apps, scripts, small CLI tools), and all collaborators are on similar OS/platforms.
  • Lightweight/local dev: Virtual environments are fast, simple, and don’t require Docker installed—great for hacking, prototyping, or when you don’t need to package system-level dependencies.
  • Low resource use: Unlike containers, venv adds no overhead; it just points to dedicated Python interpreters and package locations.

When to prefer Docker containers

  • Polyglot or system dependencies: If your app/project requires OS-level packages (database clients, C libraries, compilers, APIs, Node.js, Java…), Docker provides full isolation including those parts.
  • Production consistency/reproducibility: Docker guarantees the same environment wherever deployed (Linux, Mac, Windows) regardless of how different the system is, so “works on my machine” issues vanish.
  • Multiple services/microservices: Orchestrate multiple containers (e.g., web + db + cache) using Compose/Kubernetes to mirror production/compo­­sable setups.
  • Complex setups: If your project or organization needs strict build reproducibility, automated testing, deployment, and team-wide consistency, Docker solves these broadly, even outside Python.

Similar logic for other languages/apps

  • Node.js/Ruby/Java/.NET/Go, etc: Node uses nvm/npm for per-project isolation, Ruby has rvm, Java supports Gradle/Maven “local” dependencies, but all can benefit from Docker containers if you have native/system dependencies, need infrastructure pieces, or want reproducibility across dev/prod.
  • Simple scripts vs. web servers/services: For local scripty use, stick with the language’s isolation (venv, rvm, nvm, etc). For services/apps used by teams or deployed remotely, Docker usually wins.
  • Apps with external requirements: If you need Redis, PostgreSQL, NGINX or anything besides pure language libraries, Docker lets you bundle and sync the whole stack.

Summary Table

Isolation ToolScopeOverheadPortabilitySystem depsMulti-serviceProd consistency
Python venvPython deps onlyLowMediumNoNoLow
Docker containerFull stack (OS, libs)ModerateHighYesYesHigh
Node/Ruby/etc envLanguage deps onlyLowMediumNoNoLow

For pure language projects, use venv/rvm/nvm/etc; for full-stack reproducibility and deployment, use Docker. You can even combine: Docker containers that activate a venv internally for extra isolation

Tech Roles that Benefit from Docker Knowledge

Docker knowledge is commonly required in various software roles, especially those focused on development, operations, and data infrastructure. Professionals use Docker because it simplifies deployment, enhances reproducibility, and supports scalable architecture.

  • DevOps Engineers use Docker to automate deployments, manage containerized infrastructure, and enable continuous integration/continuous deployment pipelines.
  • Backend and Full-Stack developers rely on Docker to build, test, and run applications in consistent environments across different machines.
  • Data Scientists, Machine Learning (ML) Engineers and AI Engineers frequently run experiments in Docker containers to ensure environment consistency and reproducibility of results.
  • System Administrators implement conteinerization for efficient application isolation and resource management on servers.
  • Cloud architects use containerization when designing microservice architectures on platforms such as AWS, Azure, or Google Cloud.

Contenerization technologies are valued across these roles for making modern application development, deployment, and maintenance faster and more reliable.

Docker Desktop

What is Docker Desktop?

Docker Desktop is a desktop application from the Docker Inc. enterprise (mainly for Windows and macOS, and now also available on Linux) that bundles Docker’s container engine with a graphical interface and a preconfigured virtualized environment, so you can build, run, and manage containers from your workstation with minimal setup. It’s targeted at developers and provides a “batteries included” Docker environment plus extras like integrated Kubernetes, automatic updates, and simple resource controls.

What tools does Docker Desktop include?

Typical Docker Desktop installations include:

  • Docker Engine (the Docker daemon and core container runtime)
  • Docker CLI (the docker command-line client)
  • Docker Compose and Buildx
  • A GUI dashboard to manage containers, images, volumes, and logs
  • Optional single-node Kubernetes cluster
  • Credential helpers and integration with Docker Hub and registries
  • Supporting VM/WSL2 components that actually run the Linux containers on non-Linux hosts

Exact contents can vary slightly by version and OS, but the goal is to give you a complete local container development environment in one install.

Closing notes

Over this thread, the journey moved from Docker fundamentals to more advanced ecosystem concepts, gradually building a mental model that connects containers, images, Dockerfiles, Docker Compose, Docker Hub, and Kubernetes. We clarified the difference between images and containers, how Docker uses the host OS kernel for process isolation, and why multi‑architecture images and tags matter for running the same app on different CPU/OS combinations. We explored how data is handled —default container filesystems, volumes, and bind mounts—and how those ideas compare to Kubernetes’ own volume abstractions. Along the way, we tied Docker to real workflows: using registries (public, private, self‑hosted), understanding when to choose Docker vs language‑level tools like Python virtual environments, and recognizing when Docker Compose is sufficient versus when full orchestration with Kubernetes is appropriate. The result is a coherent, high‑level picture of modern container-based development and deployment, from local “works on my machine” prevention to scalable, cloud‑native architectures. I hope that you found this journey as interesting and enriching as I did! I wish you happy deployments.

Let’s keep in touch! Join me on the Javier Tiniaco Leyba newsletter 📩

Leave a Reply

Discover more from Tiniaco Leyba

Subscribe now to keep reading and get access to the full archive.

Continue reading