Docker is an open-source platform that packages an application with all its dependencies into a lightweight, portable, immutable image, and runs it as an isolated process called a container. It solves the classic "works on my machine" problem by giving every environment — dev, CI, staging, prod — the exact same runtime.
Docker Architecture
Docker follows a client–server model. The CLI talks to the daemon over a Unix socket or REST API; the daemon pulls images from a registry and uses the Linux kernel to run containers.
- Docker Client — the
dockerCLI that talks to the daemon. - Docker Daemon (dockerd) — long-running process that builds images, manages containers, networks, volumes.
- containerd — high-level container runtime that handles image pull/push and lifecycle.
- runc — low-level OCI runtime that actually
clone()s the container process. - Registry — stores & distributes images (public: Docker Hub; private: ECR, GCR, Harbor).
Dockerfile → Image → Container
Three words that sound similar. Interviewers love the distinction.
| Term | What it is | Analogy |
|---|---|---|
| Dockerfile | Plain-text recipe with build instructions. Text only, no binaries. | Class source code (.java) |
| Image | Immutable, versioned, layered artifact produced by docker build. Stored in a registry. |
Compiled class / jar |
| Container | A running instance of an image — a live process with its own filesystem, network, PIDs. | Object instance |
Image Layers & Union Filesystem
Each Dockerfile instruction (FROM, RUN, COPY, …) produces a read-only layer. Layers are stacked by a union filesystem (overlay2 is the default driver) and presented as a single merged directory to the container. When you start a container, Docker adds a thin read-write layer on top — all runtime changes go there (copy-on-write).
- Reuse — identical layers are shared across images on disk (big space win).
- Caching —
docker buildreuses a layer if its instruction + inputs are unchanged. Order matters: stable steps first, frequently-changing last. - Immutability — you can't edit a layer; a new image = new layers + new hashes.
- Storage drivers —
overlay2(default, fast),btrfs,zfs, legacyaufs.
All the Dockerfile Instructions
You only need a handful daily, but interviews can ask about any of them.
| Instruction | Purpose |
|---|---|
FROM | Base image; first instruction. Multi-stage uses multiple FROMs. |
ARG | Build-time variable. Only available during docker build. |
ENV | Runtime env var. Persists in the image and in running containers. |
WORKDIR | Sets cwd for subsequent instructions and for the running container. |
COPY | Copy files from build context into the image. Preferred for local files. |
ADD | Like COPY, but also extracts tar archives and fetches URLs. Avoid unless needed. |
RUN | Executes a command at build time in a new layer. Used for installing deps. |
CMD | Default command/args run when a container starts. Overridable by docker run <cmd>. |
ENTRYPOINT | The "main" executable. Harder to override. CMD supplies its args. |
EXPOSE | Documents the listening port. Doesn't publish — use -p for that. |
VOLUME | Declares a mount point for persistent / shared data. |
USER | Switches UID/GID for subsequent RUN and the container process. Security win. |
HEALTHCHECK | Periodic command that marks the container healthy/unhealthy. |
ONBUILD | Triggers a command when this image is used as a base. Rare. |
STOPSIGNAL | Signal sent on docker stop (default SIGTERM). |
LABEL | Key/value metadata. Maintainer info, build SHA, etc. |
SHELL | Overrides the default shell (/bin/sh -c) used by RUN/CMD/ENTRYPOINT. |
CMD vs ENTRYPOINT — The Classic Question
Both define what the container runs. The difference is how they combine and how easy they are to override.
- ENTRYPOINT sets the executable — think "this container IS a java process".
- CMD provides default arguments — easy to swap per
docker run. - Exec form
["a","b"]runs directly viaexecve()— receives signals. Shell forma bruns under/bin/sh -c, which eats signals (zombie problem). - Use ENTRYPOINT + CMD for apps; use only CMD for general-purpose images where users will override the command.
COPY vs ADD
| Feature | COPY | ADD |
|---|---|---|
| Copy local files | Yes | Yes |
| Auto-extract local tar | No | Yes (.tar, .tar.gz, .tar.xz) |
| Fetch remote URL | No | Yes (doesn't auto-extract URLs) |
| Recommendation | Default choice — predictable, explicit | Only when you need the extra behavior |
Multi-Stage Builds — Shipping Only the Runtime
A multi-stage Dockerfile uses multiple FROM sections. The final stage COPY --from=<stage>s only the build artifacts it needs — JDK & Maven stay behind, the final image ships JRE + jar.
Why it matters: a Java multi-stage build typically drops image size from ~800 MB (full JDK + Maven + cache) to ~180 MB (JRE + jar) — faster pulls, faster cold starts, smaller attack surface.
Docker Networking — The 5 Drivers
| Driver | Behaviour | When to use |
|---|---|---|
| bridge (default) | Private virtual network on the host. Containers get an IP; port publish via -p. DNS by container name on user-defined bridges. | Single-host dev, most Compose setups |
| host | Container shares the host's network namespace — no isolation, no -p, zero NAT overhead. | Perf-critical workloads, low-latency servers |
| none | No networking at all. Container has lo only. | Batch jobs that don't need the network |
| overlay | Multi-host network across a Swarm cluster. VXLAN tunnels under the hood. | Swarm services / multi-node apps |
| macvlan | Assigns a MAC + IP on the physical LAN. Container appears as a real host on the network. | Legacy apps that need a real IP on the LAN |
Data Persistence — Volumes vs Bind Mounts vs tmpfs
Container filesystems are ephemeral — when the container is removed, its RW layer goes with it. For persistent or shared data, mount storage from outside.
| Type | Managed by | Use case |
|---|---|---|
| Named Volume | Docker (in /var/lib/docker/volumes/) | DB data, anything that needs to survive restarts. Portable, backupable. |
| Bind Mount | You — any host path | Dev workflow: mount source code into the container for live reload. |
| tmpfs | Host RAM, never on disk | Secrets / scratch files you never want persisted. |
How Container Isolation Actually Works
A container is just a Linux process (or tree of processes) with aggressive kernel-level isolation. Two kernel features do the work.
🧱 Namespaces — what the process can see
pid— its own PID 1, can't see host processesnet— its own network stack, interfaces, portsmnt— its own mount table & rootfsuts— its own hostnameipc— its own semaphores / shared memoryuser— its own UID/GID mappingscgroup— hides host cgroup hierarchy
📏 cgroups v2 — how much the process can use
CPU shares, memory limits, block-I/O weights, PIDs count. docker run --memory=512m --cpus=1.5 writes directly to cgroup files under /sys/fs/cgroup/.
🛡️ Capabilities · seccomp · AppArmor/SELinux
- Capabilities — Docker drops most Linux capabilities by default (e.g.,
CAP_SYS_ADMIN). Add/drop with--cap-add/--cap-drop. - seccomp — syscall filter applied by default to block ~44 dangerous syscalls.
- AppArmor / SELinux — MAC policies further restrict what the container can ask the kernel to do.
Docker Compose
Compose defines a multi-container app in a single YAML — services, networks, volumes, env. One command (docker compose up) brings up the whole stack. Ideal for local dev and simple single-host deployments.
Commands You'll Be Asked About
Best Practices
Image Best Practices
- Pin versions —
node:20.11.1-alpine, neverlatest - Copy
package.json/pom.xmlbefore source to maximize cache hits - Use multi-stage builds — ship only runtime artifacts
- Prefer Alpine or distroless for small surface area
- Combine
RUNs with&&to keep layer count down - Use
.dockerignore— stripnode_modules,.git, secrets - Add
HEALTHCHECK— lets orchestrators know when to route traffic
Security Best Practices
- Run as non-root (
USER node) — never PID 1 as root - Read-only root filesystem (
--read-only) - Drop capabilities (
--cap-drop=ALL, add only what's needed) - Scan images (Trivy, Snyk, Docker Scout)
- Never bake secrets into layers — use build secrets / runtime env / Vault
- Sign images (Docker Content Trust / Cosign)
- Keep base images patched; rebuild on CVE alerts
Interview Q&A
docker run, docker start, and docker exec?exec -it sh to debug).FROM, apt install, COPY package.json + npm install) first, and frequently-changing ones (COPY . .) last.CMD is in shell form — PID 1 is /bin/sh -c, which doesn't forward SIGTERM to your app. Use exec form: CMD ["node","server.js"]. (2) Your app ignores SIGTERM and exceeds the stop grace period (default 10s). Handle SIGTERM in code, or raise with --stop-timeout.http://db:5432 works. On the default bridge there's no DNS, only IPs. Across hosts, use an overlay network (Swarm) or Kubernetes Services.docker rm a container?/var/lib/docker/volumes/ and are removed only with docker volume rm (or docker rm -v).ubuntu vs alpine vs distroless), un-cleaned package manager caches (apt-get install … without rm -rf /var/lib/apt/lists/*), or files that should have been in .dockerignore..dockerignore file?.gitignore, but for the build context sent to the daemon. Keeps node_modules, .git, .env, local logs, and test artifacts out of the image — faster builds, smaller images, fewer leaked secrets.EXPOSE is purely documentation — it tells readers / orchestrators which port the app listens on. HEALTHCHECK actually runs a command periodically and flips the container's status to healthy/unhealthy. Load balancers & orchestrators use the latter to decide whether to route traffic.docker run nginx — step by step?POST /containers/create to the daemon. (2) Daemon looks for nginx:latest locally; if missing, pulls manifest + layers from Docker Hub. (3) Layers are assembled via overlay2 into a rootfs. (4) Daemon asks containerd → runc to clone() a process with new namespaces + cgroups applied. (5) Process starts as PID 1 inside the container; stdout/stderr stream back to the daemon → CLI.One-Line Summary
Docker = build immutable images from a Dockerfile + run them as isolated Linux processes using namespaces, cgroups, and a union filesystem — giving you portable, reproducible, dense deployments at near-native performance.