Docker Fundamentals — Images, Containers & Dockerfiles Explained
Understand how Docker really works — images vs containers, writing efficient Dockerfiles, layer caching, and the mistakes that bloat your images. A practical beginner-to-confident guide.
Rajesh Vardhan Busam
AWS Certified DevOps Engineer
If you are getting into DevOps, Docker is the first tool to master properly. Almost every modern deployment — Kubernetes, CI/CD pipelines, cloud services — sits on top of containers. Yet most beginners memorise commands without understanding what is actually happening under the hood, and then get stuck the moment something behaves unexpectedly. This guide builds a real mental model of how Docker works, then shows you how to use it well.
Containers vs Virtual Machines
To understand containers, contrast them with virtual machines. A virtual machine virtualises hardware and runs a complete guest operating system, so it is heavy — often gigabytes in size and slow to boot. A container virtualises the operating system instead. It shares the host kernel and packages only your application plus its dependencies, so it is lightweight, starts in milliseconds, and uses far fewer resources.
This efficiency is why a single server can run dozens of containers but only a handful of virtual machines. Containers also give you consistency: the same image runs identically on your laptop, a teammate's machine, and production. The old excuse of it works on my machine disappears.
Images vs Containers — The Key Distinction
People confuse these two constantly, so anchor on this: an image is the blueprint, a container is a running instance of that blueprint. An image is read-only and built in layers. When you run an image, Docker adds a thin writable layer on top — that running thing, with its own process and writable filesystem, is the container.
One image can spawn many containers, exactly like one class can create many objects in programming. Images live in registries such as Docker Hub or Amazon ECR and are pulled down when needed. Containers are ephemeral — you create, stop, and delete them freely, while the image remains.
Understanding the Dockerfile
A Dockerfile is a recipe that describes how to build an image, one instruction at a time. Each instruction creates a new layer stacked on the previous one. Here is a clean, security-aware example for a Node.js app:
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
USER node
EXPOSE 3000
CMD ["node", "server.js"]
Read it top to bottom: start from a small base image, set a working directory, copy the dependency manifest, install dependencies, copy the source, drop to a non-root user, document the port, and define the start command.
Layer Caching — The Concept That Saves You Hours
Docker caches each layer and reuses it if nothing that layer depends on has changed. This is why instruction order matters so much. In the example above, dependencies are installed before the application source is copied. So when you change a line of code, Docker reuses the cached dependency layer and only rebuilds from the source copy onwards — turning a three-minute build into a ten-second one. If you copied everything first and then installed, every code change would reinstall all dependencies. Ordering your Dockerfile from least-frequently-changing to most-frequently-changing is a core skill.
Multi-Stage Builds — Small, Secure Images
Your build environment needs compilers and tools, but your production image should not carry them. Multi-stage builds solve this: you build the application in one stage that has all the tooling, then copy only the finished artifact into a tiny final stage. The result is a smaller image with a smaller attack surface. This single technique can shrink an image from a gigabyte to under a hundred megabytes.
Common Mistakes That Bloat and Weaken Images
- Using a full OS base image when a slim or alpine variant would do — an easy way to cut hundreds of megabytes.
- Skipping a .dockerignore file, so node_modules, the .git folder, and local secrets get baked into the image.
- Running as root — always create and switch to a non-root user.
- Not pinning base image versions, so builds become unreproducible.
- Ignoring multi-stage builds, shipping compilers and build tools to production.
Volumes and Networking Basics
Because containers are ephemeral, anything written inside a container's writable layer disappears when it is removed. For data that must survive — a database, uploaded files — you use volumes, which store data on the host outside the container lifecycle. For containers to talk to each other, Docker provides networks; containers on the same network can reach each other by name. Docker Compose ties images, volumes, and networks together to run a multi-service application locally with a single command.
The Commands You Will Actually Use
Ninety percent of daily Docker work uses a small set of commands: build an image from a Dockerfile, run a container from an image, list running containers, view a container's logs, exec into a container to debug it interactively, stop and remove containers, and prune unused images and volumes to reclaim disk space. Learn these deeply rather than memorising the entire CLI.
Where Docker Fits in the Bigger Picture
Docker on its own manages containers on a single host, which is perfect for local development and simple deployments. In production at scale, you rarely run bare Docker — you run Kubernetes, which schedules, scales, and heals containers across many machines. But Kubernetes runs the very images you build with Docker, so this knowledge is the foundation for everything that follows. Master containers here and Kubernetes becomes far less intimidating.
Frequently Asked Questions
Is Docker still relevant with Kubernetes everywhere? Absolutely — Kubernetes orchestrates containers that you build as Docker images. The skills are complementary, not competing.
How do I make my images smaller? Use a slim base image, a .dockerignore file, and multi-stage builds. These three together usually shrink images dramatically.
Do I need Docker Compose? For local multi-service development, yes — it is the simplest way to run an app with its database and dependencies together.
Our Docker Deep Dive course at Infinity Cloud Labs walks through all of this on real infrastructure, with hands-on labs in both English and Telugu. Get containers right, and the rest of DevOps gets much easier.
Tags
