Blog

A Quick Explanation of Docker

Key Takeaways

  • Docker packages application code and user-space dependencies into images; containers are the runnable instances created from those images.
  • Containers reduce the “it works on my machine” problem, but architecture, configuration, external services, and the host kernel still matter.
  • Ordinary Linux containers share their container host’s kernel. Virtual machines have their own guest kernels; the two technologies can work together.
  • A practical Docker workflow is: write a Dockerfile, build an image, optionally publish it to a registry, and run containers from it.
  • Plan explicitly for security and persistent storage. Isolation does not make a container a VM, and removing a container destroys its writable layer.

Docker is a platform for building, distributing, and running applications in containers—isolated processes with the files and dependencies they need. It can make development and deployment more consistent without requiring a separate operating system for every application.

The motivation is familiar: “it works on my machine.” Docker helps you share an application’s packaged environment instead of asking every developer and server administrator to reconstruct it. It complements virtual machines rather than universally replacing them.

What is Docker?

The Docker platform includes tools for building images and managing containers. Docker Engine provides the daemon and APIs that manage objects such as containers, images, networks, and volumes; the Docker CLI sends it commands.

Docker images vs containers

An image is an immutable, layered package containing application files, libraries, runtime dependencies, and startup metadata. Changing the package means creating a new image.

A container is an instance created from an image, with its own runtime configuration and writable filesystem layer. You can create several containers from the same image without changing that image.

How isolation and communication work

For Linux containers, namespaces give processes separate views of resources such as process IDs and networks. Control groups, or cgroups, provide resource accounting and controls. These are operating-system mechanisms, not a separate operating system inside each container.

Containers are isolated yet communicate with one another through well-defined channels, subject to configuration. For example, containers attached to the same user-defined bridge network can resolve one another by name and communicate over application ports. Network membership, published ports, permissions, and runtime settings determine what is reachable.

Why Docker Helps With “It Works on My Machine”

Suppose your application needs a particular language runtime and system library. Without packaging, each developer and deployment environment must install compatible dependencies. An image can carry those user-space dependencies alongside the application, reducing differences in what is installed.

That makes onboarding and collaboration more repeatable: a teammate starts from a shared artifact rather than a growing installation checklist. The same packaging approach can serve a monolith, a background worker, or several independently deployed services; microservices are not a prerequisite.

Consistency still has limits. Secrets, environment variables, mounted files, permissions, networking, external databases, CPU architecture, and kernel behavior can differ between environments. Test the image in its intended deployment environment—not just on your laptop.

Docker vs Virtual Machines

Isn’t this just like a VM? Both provide isolated environments, but at different layers. A VM virtualizes hardware and runs a guest operating system, including its kernel. An ordinary Linux container runs isolated processes against the container host’s Linux kernel.

Virtual machines                  Linux containers
--------------------------        --------------------------
App + libs | App + libs            App processes | App processes
Guest OS   | Guest OS              Image files   | Image files
(kernel A) | (kernel B)            Docker Engine / runtime
Hypervisor                        Shared Linux host kernel
Hardware                          Hardware

This simplified comparison follows the distinction in Docker’s container overview. The container host can itself be a VM.

ConsiderationOrdinary Linux containersVirtual machines
KernelShare the container host’s Linux kernel.Each VM has a guest kernel.
PackagingApplication files and user-space dependencies.A guest operating system plus applications.
Startup and overheadOften lower overhead because there is no guest OS to boot per container.Include guest OS startup and resource costs.
IsolationShared-kernel process isolation; configuration matters.A separate guest-kernel and hypervisor boundary.
Useful whenYou want repeatable application packaging on compatible hosts.You need a separate operating system or kernel boundary.

Containers often start faster and use fewer resources than a comparable full VM, but that is a tendency, not a performance guarantee. Application startup, image downloads, storage, networking, and any underlying VM all affect the result. Measure your workload.

What changes on macOS and Windows?

Linux containers require a Linux kernel, not necessarily a Linux desktop. Docker Desktop normally supplies a managed Linux VM on macOS and Windows for local Linux containers. Its virtualization documentation describes this arrangement; on Windows, the WSL 2 backend provides a Linux-kernel environment.

Windows containers instead require a compatible Windows environment. With process isolation, they share the Windows host kernel; with Hyper-V isolation, each runs inside an optimized VM with its own kernel. “Every Docker container shares your desktop’s kernel” is therefore incorrect.

CPU architecture still matters

A Linux image built only for x86-64 does not run natively on an ARM host. A multi-platform image groups platform-specific variants, such as linux/amd64 and linux/arm64, under one image reference. Emulation is another option, but can add overhead. Neither approach makes a Windows application into a Linux application.

A Minimal Docker Workflow

With Docker installed and its engine running in Linux-container mode, create an empty directory containing these two files. You do not need Python installed on your host.

hello.py

print("It works in this container!")

Dockerfile

FROM python:3-slim
WORKDIR /app
COPY hello.py .
USER 10001:10001
CMD ["python", "hello.py"]

The official Python image supplies the interpreter and its dependencies. The Dockerfile instructions select that base, set the working directory, copy your application, choose a non-root user, and specify the default startup command. This application needs no third-party packages.

From that directory, build and run it:

docker build -t quick-docker:demo .
docker run --rm quick-docker:demo

The program prints It works in this container! and exits. In the build command, -t assigns the image name and tag, and . supplies the current directory as the build context. In docker run, --rm removes the container after it exits, not the image.

To share the result, publish the image to a registry—an image storage and distribution service—such as Docker Hub or a private registry. Other environments can then pull that image and create containers from it. Our broader Docker introduction explores the surrounding concepts.

Where Persistent Data Belongs

A container’s writable layer survives stopping and restarting that same container, but disappears when the container is removed. Treat it as disposable. Use volumes or appropriate external storage for data that must outlive a container.

This example writes a file in one container and reads it from another. Run it in a POSIX shell, such as Bash in Linux, macOS, or WSL; BusyBox supplies the small command-line utilities:

docker volume create quick-docker-data
docker run --rm --mount type=volume,src=quick-docker-data,dst=/data busybox:1 sh -c 'echo saved > /data/message.txt'
docker run --rm --mount type=volume,src=quick-docker-data,dst=/data busybox:1 cat /data/message.txt

The second container prints saved, even though the first was removed. The named volume persists independently. For real applications, configure volume ownership for the application’s non-root user and plan backups; a local volume alone is not protection against losing the host.

How Docker Fits With Kubernetes

Docker can build and test images that you later deploy to Kubernetes. Kubernetes nodes use a Container Runtime Interface, or CRI, compatible runtime, such as containerd or CRI-O; they do not require Docker Engine.

Kubernetes removed its built-in Docker Engine integration, dockershim, in version 1.24. That did not invalidate Docker-built images, as the official dockershim removal FAQ explains. See our Kubernetes vs Docker comparison for the distinction between packaging applications and orchestrating them across machines.

Common Mistakes to Avoid

  • Treating a container as a VM security boundary. Ordinary containers share a kernel. Choose stronger isolation when your threat model requires it.
  • Granting unnecessary privileges. Run applications as non-root where possible, avoid privileged mode, and grant only required capabilities and host access.
  • Mounting the Docker socket casually. Access to the socket can give a container control over the daemon’s host; with a root-running daemon, this can amount to root access. A read-only socket mount does not make the API read-only.
  • Trusting an image because it runs. Check its publisher and build provenance, scan for vulnerabilities, keep images and hosts patched, and keep secrets out of images.
  • Assuming isolation includes resource limits. Docker containers have no CPU or memory constraints by default. Set and test appropriate resource limits.

The OWASP Docker Security Cheat Sheet provides a practical hardening checklist. Security depends on how you build and run the container, not merely on using Docker.

When Should You Consider Docker?

Start with Docker when dependency setup, onboarding, or shipping a repeatable application artifact is causing friction. Prefer a VM when you need a separate guest OS, custom kernel, or isolation boundary that ordinary containers do not provide. Use containers inside VMs when you need both application packaging and machine-level separation.

You do not need to redesign your application into microservices or adopt Kubernetes to benefit. Containerize one application, test it in the target environment, and compare the operational cost with your existing workflow.

FAQ

What is the difference between a Docker image and a container?

An image is an immutable, layered package of application files, dependencies, and startup metadata. A container is an instance created from that image, with runtime configuration and a writable layer.

Do containers replace virtual machines?

Not entirely. Ordinary containers share their container host’s kernel, while VMs provide separate guest operating systems and kernels. Containers can run inside VMs, combining application packaging with machine-level isolation.

Does Docker run on macOS and Windows?

Yes. Docker Desktop normally runs local Linux containers inside a managed Linux VM on macOS and Windows. Windows containers require a compatible Windows environment and use process or Hyper-V isolation.

Does Kubernetes require Docker Engine?

No. Kubernetes requires a CRI-compatible runtime, such as containerd or CRI-O, rather than Docker Engine. Docker-built images remain usable on Kubernetes when their operating system and architecture match the target nodes.

Are Docker containers secure?

Containers provide isolation, but ordinary shared-kernel containers are not equivalent to a VM security boundary. Use least privilege, trusted and scanned images, patched hosts, and carefully restricted network, filesystem, and Docker daemon access.

Further Reading

Written by Sam Erickson

Software engineer. I write every article on StackChief myself. Author of Mastering the Tech Interview. More about me