Docker is a platform for packaging applications so they run the same way on a laptop, in CI, and in the cloud. If you are asking what is Docker, you probably need a concise explanation of containers, images, and why teams adopt them instead of shipping tarballs and prayer.
The problem Docker solves
Software rarely fails because the code is wrong on day one. It fails because environments diverge: different library versions, missing system packages, wrong Node or Python patch level, or secrets baked into the wrong config file.
Containers fix the “works on my machine” gap by bundling:
- Your application binaries or scripts
- Runtime dependencies
- A filesystem snapshot
- Default startup command
The host operating system still provides the kernel, but each container thinks it has its own isolated userspace.
Containers vs. virtual machines
Virtual machines emulate hardware and run a full guest OS. Containers share the host kernel and isolate processes with namespaces and cgroups. That makes containers lighter to start and easier to pack onto the same hardware.
| Virtual machine | Container | |
|---|---|---|
| Boot time | Minutes | Seconds or less |
| Footprint | Full OS per VM | App + libs only |
| Isolation | Strong hardware boundary | Process-level (good, not absolute) |
| Use case | Multi-tenant legacy apps | Microservices, CI jobs, dev envs |
Docker popularized the workflow; Kubernetes and other orchestrators handle running many containers at scale.
Understanding that distinction helps when you read job posts asking for “Docker experience” versus “Kubernetes experience.” Docker skills transfer directly to building images; orchestration skills focus on scheduling, health checks, and rolling updates across a fleet.
Images, containers, and registries
Three words appear in every Docker conversation:
- Image — read-only template (layers stacked via a Dockerfile or build tool).
- Container — a running instance of an image.
- Registry — storage for images (Docker Hub, ECR, GHCR, etc.).
Typical flow:
- Write a
Dockerfiledescribing how to build the image. - Run
docker buildto create a local image tag. - Run
docker runto start a container from that tag. - Push the image to a registry so production can pull the same bits.
Immutability matters: never SSH into production and apt-get upgrade. Build a new image version, roll it out, roll back if needed.
A minimal Dockerfile for a Node API
FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
ENV NODE_ENV=production
EXPOSE 3000
CMD ["node", "server.js"]
Multi-stage builds go further: compile in a builder image, copy only artifacts into a slim runtime image. That keeps attack surface and image size down.
Layer caching speeds rebuilds: put rarely changing instructions (dependency install) before frequently changing copies of source code. A one-line app change should not reinstall every npm package if the lockfile stayed the same.
Networking and storage basics
By default, containers get private networks. You map ports with -p 8080:3000 for local testing. In orchestrators, services discover each other through DNS names instead of hard-coded IPs.
Data inside a container disappears when the container is removed unless you attach volumes or bind mounts. Stateless app containers plus external databases (RDS, Cloud SQL) remain the common pattern.
For local development, bind-mounting source code into a container lets you edit on the host while processes run inside the same Linux environment production uses. Just watch file permission quirks on macOS and Windows bind mounts—they can make hot reload feel sluggish compared to native runs.
When Docker is worth it
Containers help when:
- You deploy frequently and need reproducible builds.
- Multiple services must run together locally (API + worker + Redis).
- CI pipelines should test exactly what production runs.
They are optional overhead when you ship a single static site or a managed function with no custom runtime. Do not containerize for fashion—containerize when environment parity saves more time than it costs.
Platform teams sometimes provide golden base images with approved CA bundles, logging agents, and vulnerability scan gates. Consuming those bases beats copying random latest tags from the internet.
Security habits that matter
Containers are not sandbox escapes by default, but misconfiguration hurts:
- Run as a non-root user inside the image.
- Scan images for known CVEs in base layers.
- Pin base image digests in production pipelines.
- Keep secrets out of images; inject at runtime from a vault.
- Limit container capabilities on the host.
Treat images like compiled binaries: sign them, version them, and restrict who can push to production registries.
Supply-chain attacks on public images happen. Prefer internal mirrors or vendor-verified bases, and rebuild when critical CVEs land in OpenSSL, glibc, or your language runtime.
Docker Compose for local stacks
Compose files describe multiple services in YAML—web, database, queue worker—so docker compose up boots the whole dev environment. It is not a production orchestrator, but it shortens onboarding dramatically.
services:
api:
build: .
ports: ["3000:3000"]
environment:
DATABASE_URL: postgres://db:5432/app
db:
image: postgres:16-alpine
environment:
POSTGRES_PASSWORD: devonly
Add health checks in Compose so dependent services wait until Postgres accepts connections—otherwise APIs crash-loop on startup races.
Working with Docker in CI/CD
Continuous integration should build the same Dockerfile developers use locally. Typical pipeline steps:
docker buildwith a git SHA tag.- Run unit tests inside the image or against a
docker composetest stack. - Push to a registry on main branch merges.
- Deploy by updating the image tag in your orchestrator or PaaS.
Caching registry layers between CI runs cuts build times dramatically. Many teams use buildkit cache exporters or dedicated remote caches.
Common misconceptions
“Docker replaces Kubernetes.”
Docker builds and runs containers; Kubernetes schedules them across clusters. You can use one without the other, though they often appear together.
“Containers are always faster.”
They start quickly, but poor image design (huge layers, running as root, no health checks) still creates slow deploys.
“One container per repo is mandatory.”
Many repos ship multiple images (API vs. worker). Match boundaries to scaling needs, not folder count.
FAQ
What is the difference between Docker and a VM?
VMs virtualize hardware; containers virtualize the OS process space on a shared kernel.
Do I need Docker on my laptop?
Helpful for backend and full-stack work; front-end-only projects may never touch it.
How does Docker relate to cloud services like ECS or Cloud Run?
Those services run container images you build locally or in CI. The packaging step is the same; the platform handles scaling.
Can I run Windows containers on Linux?
Not interchangeably—images target a specific OS family. Most developer content focuses on Linux containers.
How big should a container image be?
Smaller is faster to pull and scan. Alpine or distroless bases help; stripping dev dependencies in multi-stage builds matters more than exotic compression tricks.
What happens to logs inside a container?
They go to stdout/stderr by default. Collect them with your platform’s log driver—do not assume files inside the container are durable.
Docker is infrastructure ergonomics: smaller, repeatable units of deployment. Once images become your contract between dev and ops, debugging production surprises gets a lot quieter. Learn the Dockerfile, respect image immutability, and treat Compose as your team’s shared dev environment—not a shortcut around documenting dependencies.
Further Reading
Discover more articles on similar topics across our network
Comments
Loading comments…