---
title: Docker Interview Questions & Answers (2026): Images, Containers & Networking
description: Docker interview questions that actually get asked in 2026 — images vs containers, Dockerfile layers, volumes, networking, multi-stage builds and Compose.
url: https://usegreenroom.app/blog/docker-interview-questions
last_updated: 2026-06-20
---

← Back to blog

Technical

# Docker interview questions and answers

June 20, 2026 · 16 min read

![Docker interview questions and answers — cover from Greenroom, the AI mock interviewer](/assets/blog/docker-interview-questions-hero.webp)

Docker shows up in almost every backend, DevOps, and cloud interview loop, but the questions rarely stop at "what is a container." Interviewers want to know whether you've actually built and debugged images — whether you understand *why* layers cache the way they do, why your image is 1.2GB when it should be 150MB, why a container that works on your laptop can't reach another container by name, and why a volume disappeared after `docker-compose down`. This guide covers the **Docker interview questions** that actually get asked, organized by area, with a real answer and the reasoning behind it for each one.

## Images, containers, and the core model

### What is the difference between an image and a container?

An image is a read-only template — a set of filesystem layers plus metadata (entrypoint, exposed ports, environment defaults) — built once from a Dockerfile. A container is a running (or stopped) *instance* of that image, with a thin writable layer stacked on top where all runtime changes (new files, log output, temp data) actually live. You can spin up many containers from the same image, each with its own writable layer and process namespace, the same way many objects can be instantiated from one class. The interview tell: candidates who've only read about Docker say "an image is like a snapshot"; candidates who've used it can explain that the writable layer is *ephemeral* — delete the container and everything written to it is gone unless you mounted a volume.

### How is Docker different from a virtual machine?

A VM virtualizes hardware — each VM runs its own full guest OS kernel on top of a hypervisor, which is why VMs are heavy (gigabytes, minutes to boot). A container virtualizes the OS, not the hardware: all containers on a host share the same Linux kernel and are isolated from each other using **namespaces** (separate views of processes, network, mounts, hostname) and resource-limited using **cgroups** (CPU, memory, I/O caps) — no second kernel, no hypervisor. That's why containers start in milliseconds and a base image can be tens of megabytes instead of gigabytes. The honest nuance interviewers want you to add: this also means containers are a *weaker* isolation boundary than VMs — a kernel-level exploit can cross container boundaries in a way it can't cross a hypervisor boundary, which is why untrusted multi-tenant workloads still often run inside VMs (or gVisor/Kata-style sandboxed runtimes) rather than bare containers.

### What are Linux namespaces and cgroups, concretely?

Namespaces give a process its own isolated *view* of a global resource: the PID namespace makes a container's first process look like PID 1 even though it's PID 4821 on the host; the network namespace gives it its own loopback, routing table, and interfaces; the mount namespace gives it its own filesystem tree. Cgroups (control groups) do the opposite job — they don't hide resources, they *limit* them: `docker run --memory=512m --cpus=1` is implemented as a cgroup that the kernel enforces, killing the container's process (OOMKilled) if it exceeds the memory ceiling. Knowing these two primitives by name, and that Docker is essentially a convenient API on top of kernel features that existed before Docker did, is what separates "I use Docker" from "I understand containers."

### What is a Dockerfile, and what do the common instructions do?

A Dockerfile is a build script — a sequence of instructions the Docker engine executes to produce an image, one layer per instruction. The instructions that come up constantly:

```dockerfile
FROM node:20-alpine        # base image — every build starts here
WORKDIR /app                # sets the working directory for subsequent instructions
COPY package*.json ./       # copy only manifest files first (see layer caching below)
RUN npm ci --omit=dev       # install deps — creates a new layer
COPY . .                    # copy the rest of the source
ENV NODE_ENV=production
EXPOSE 3000                 # documentation only — does not actually publish the port
CMD ["node", "server.js"]   # the default command when the container starts
```

`FROM` sets the base; `RUN` executes a command at build time and commits the result as a new layer; `COPY`/`ADD` bring files from the build context into the image (`ADD` additionally supports remote URLs and auto-extracting tar archives — most teams prefer `COPY` for clarity and use `ADD` only when they specifically need that extraction behavior); `ENV` sets environment variables available both at build and run time; `EXPOSE` is purely documentation that doesn't open anything by itself; `CMD` and `ENTRYPOINT` define what runs when the container starts.

### What's the difference between CMD and ENTRYPOINT, and why does it matter?

`CMD` provides the default command, but it's fully overridable — `docker run myimage echo hi` replaces the `CMD` entirely. `ENTRYPOINT` defines the command that always runs; anything passed at `docker run` is appended as arguments to it rather than replacing it. The pattern that actually shows up in real Dockerfiles: `ENTRYPOINT ["docker-entrypoint.sh"]` with `CMD ["node", "server.js"]` — the entrypoint script does fixed setup (wait for the DB, run migrations) and then `exec`s `"$@"`, which is the `CMD`, letting users override just the final command while keeping the setup non-negotiable. Get this wrong in an interview and it's usually because you've only ever used one of the two — using both together, correctly, is the actual signal.

## Image layers, caching, and build performance

### How do image layers work, and why does instruction order matter?

Each instruction in a Dockerfile that modifies the filesystem (`RUN`, `COPY`, `ADD`) produces a new, immutable layer, stacked using a union filesystem (overlay2 on modern Docker) so the container sees one merged view while each layer is stored and cached separately. When you rebuild, Docker reuses every layer up to the *first* one whose instruction or input has changed, and invalidates everything after it — which is exactly why the canonical Node/Python pattern is `COPY package.json` then `RUN npm install` *before* `COPY . .`: dependency manifests change rarely, so that expensive install step stays cached across rebuilds, while only the cheap final `COPY` re-runs when you edit application code. Put `COPY . .` first by mistake and *every* code change invalidates the dependency install too, turning a 2-second rebuild into a 90-second one.

### What's the difference between the build cache and `--no-cache`?

Docker caches each layer keyed by the instruction text and a hash of its inputs (file contents for `COPY`/`ADD`, the exact command string for `RUN`). If nothing about an instruction or its inputs changed since the last build, Docker reuses the cached layer instead of re-executing it — this is why builds get dramatically faster after the first one. `docker build --no-cache` forces every instruction to re-run regardless, which you reach for when debugging a build that's silently using stale cached output (a classic case: an `apt-get update` layer cached from weeks ago serving outdated package lists) or when verifying a build is reproducible from scratch.

### How do you reduce image size?

Start from a smaller base — `alpine` or `slim` variants instead of full Debian/Ubuntu bases, or `distroless` images that strip out the shell and package manager entirely for production. Combine related `RUN` commands with `&&` so cleanup happens in the *same* layer as the install (`RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*`) — if cleanup is a separate `RUN`, the bloat is still baked into the earlier layer and the image doesn't shrink at all. Use a `.dockerignore` to keep `node_modules`, `.git`, and build artifacts out of the build context. And — the biggest single lever — use multi-stage builds (below) so build tools and intermediate artifacts never make it into the final image at all.

### Walk through a multi-stage build and explain why it matters.

A multi-stage build uses multiple `FROM` instructions in one Dockerfile, where later stages can selectively copy artifacts from earlier ones, discarding everything else:

```dockerfile
FROM node:20 AS builder
WORKDIR /app
COPY . .
RUN npm ci && npm run build

FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY package*.json ./
RUN npm ci --omit=dev
CMD ["node", "dist/server.js"]
```

The `builder` stage has the full toolchain — compilers, dev dependencies, source maps, test runners — none of which need to exist in production. The final stage starts from a clean, minimal base and pulls in only the compiled output via `COPY --from=builder`, so the shipped image never contains the build tools, dev dependencies, or intermediate files that made the build possible. This routinely cuts image size by 80-90% for compiled languages (Go binaries, TypeScript builds) and is the single most common "show me you've actually optimized a Docker setup" interview question.

## Storage and volumes

### What's the difference between a volume, a bind mount, and tmpfs?

A **volume** is storage fully managed by Docker, living under Docker's own directory on the host (`/var/lib/docker/volumes/...` on Linux) — you reference it by name, Docker handles the lifecycle, and it's the recommended choice for anything that needs to outlive a container (databases, uploaded files). A **bind mount** maps an exact host path directly into the container (`-v /home/me/code:/app`) — useful for local development where you want live-editing of source files to reflect instantly inside the container, but it ties the container to that host's filesystem layout, which makes it a poor fit for production portability. **tmpfs** mounts live entirely in host memory, never touch disk, and vanish when the container stops — useful for short-lived secrets or sensitive scratch data you explicitly don't want persisted anywhere.

### Why does data disappear after `docker-compose down` or `docker rm`, and how do you prevent it?

Anything written to a container's writable layer — or to a path inside the container that isn't backed by a volume — is deleted the moment that container is removed, because the writable layer only exists as long as the container does. The fix is declaring a named volume and mounting it at the path the application actually writes to:

```yaml
services:
  db:
    image: postgres:16
    volumes:
      - pgdata:/var/lib/postgresql/data
volumes:
  pgdata:
```

The classic interview trap question: "I ran `docker-compose down -v` and my data is gone — why?" The `-v` flag explicitly removes named volumes along with the containers, which is correct behavior, not a bug — interviewers ask this specifically to see if you understand that volumes persist across `down` *without* `-v`, but not with it.

### How would you back up data from a Docker volume?

Run a throwaway container that mounts the target volume read-only alongside a host directory, and tar the contents across:

```bash
docker run --rm -v pgdata:/data:ro -v "$PWD/backup":/backup alpine \
  tar czf /backup/pgdata.tar.gz -C /data .
```

This works because volumes are just directories on the host that any container can mount — you don't need the original application image at all, just something with a shell and `tar`. Restoring is the same idea in reverse: mount the volume read-write and extract the archive into it.

## Networking

### What are Docker's networking modes — bridge, host, and none?

**Bridge** (the default) gives each container its own network namespace and a virtual interface attached to a private internal network, NATed through the host — containers get isolated IPs and reach the outside world through the host, but the outside world can't reach them unless you explicitly publish a port. **Host** mode skips network isolation entirely — the container shares the host's network namespace directly, so a service listening on port 3000 inside the container is reachable on port 3000 on the host with no port mapping at all, at the cost of losing isolation and risking port collisions. **None** gives the container no network interface beyond loopback, used for batch jobs or security-sensitive workloads that should never make network calls.

### How do containers on the same network communicate, and what's Docker's built-in DNS?

Containers attached to the same user-defined bridge network can reach each other **by container name** — Docker runs an internal DNS resolver that maps container/service names to their internal IPs automatically, no manual IP configuration needed. This is why a Compose file's `app` service can connect to `postgresql://db:5432` and it just works: `db` resolves via Docker's embedded DNS to whatever IP the `db` container actually got. The default bridge network (the one you get without explicitly creating one) does *not* have this DNS resolution between containers — only user-defined bridge networks do — which is a frequent source of "why can't my containers see each other by name" confusion, and a good interview signal that you've hit this exact issue before.

### Explain port mapping with `-p`, and a common mistake with it.

`-p 8080:80` maps port 8080 on the host to port 80 inside the container — traffic to `localhost:8080` gets forwarded into the container's port 80. The order matters and is a frequent slip: it's always `host:container`, so `-p 80:8080` is the reverse of what most people mean to write. Without any `-p` flag, a container's ports are reachable from other containers on the same Docker network (via the internal DNS above) but not from the host machine or the outside world at all — `EXPOSE` in a Dockerfile documents intent but doesn't publish anything; only `-p` at run time actually does.

![Docker interview topics — images, containers, Dockerfile, volumes, networking](/assets/blog/pool-system-design.webp)

Docker rounds test the image/container model, layers, volumes, and networking — and increasingly, whether you can read a Compose file at a glance.

## Docker Compose and orchestration basics

### What is Docker Compose, and when do you reach for it over plain `docker run`?

Compose lets you define a multi-container application — services, networks, volumes, environment variables, dependency order — in one YAML file, then bring the whole stack up or down with a single command (`docker compose up`). It's the right tool the moment your app is more than one container: a web service plus a database plus a cache is painful to wire up correctly with a string of `docker run` and `docker network create` commands typed by hand, and easy to get subtly wrong (forgetting a network, mistyping an env var) every time you do it manually. Compose isn't a production orchestrator — it has no built-in healing, scaling, or rolling deploys — which is exactly the gap Kubernetes fills once you outgrow a single host.

### What does `depends_on` actually guarantee in Compose, and what doesn't it guarantee?

`depends_on` controls **start order** — it ensures the dependency container is *started* before the dependent one — but it does not wait for the dependency to be *ready* (a Postgres container can be "started" while still initializing and not yet accepting connections). This is one of the most common real-world Compose bugs: an app container crash-loops on boot because it tried to connect to a database that technically started but wasn't accepting connections yet. The fix is an application-level retry/backoff on startup, or a `healthcheck` on the dependency combined with `depends_on: condition: service_healthy`, which makes Compose actually wait for the health check to pass rather than just the process to start.

### How does Compose's `condition: service_healthy` work, and why use it over a delay?

You define a `healthcheck` on the service (a command Docker runs periodically inside the container to decide if it's "healthy," like `pg_isready` for Postgres), and reference it from a dependent service:

```yaml
services:
  db:
    image: postgres:16
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      retries: 5
  app:
    depends_on:
      db:
        condition: service_healthy
```

This is strictly better than a hardcoded `sleep 10` before starting the app, because a fixed delay is either too short (flaky under load) or wastes time when the dependency is actually ready sooner — the health check ties the wait to the real readiness signal instead of a guess.

### How do containers get destroyed and rebuilt in a real deployment pipeline, and where does Kubernetes come in?

In production, you rarely `docker stop` and manually restart a container — a CI pipeline builds a new image, pushes it to a registry, and an orchestrator (Kubernetes, ECS, Nomad) pulls the new image and replaces running containers according to a rollout strategy (rolling update, blue-green), watching health checks to decide whether to proceed or roll back. Docker itself has no opinion about *how many* replicas should run, what to do when a container dies unexpectedly, or how to roll out a new version without downtime — that's the job layer Kubernetes (or a managed equivalent) sits on top of Docker/containerd to provide. If a JD lists both Docker and Kubernetes, expect the interview to explicitly probe this boundary: what Docker gives you for free versus what you still need an orchestrator for.

<div class="verdict"><strong>The core truth:</strong> Docker interviews aren't testing whether you've memorized fifteen CLI flags — they're testing whether you understand the model well enough to debug it. Anyone can recite "an image is a template, a container is an instance." The candidate who gets the offer is the one who can explain *why* their build was slow, *why* their data vanished, or *why* two containers couldn't see each other, because they've actually hit those bugs.</div>

## Practise explaining, not just memorizing

You can read every answer above and still freeze when an interviewer asks "okay, but why did your image take four minutes to build before you fixed it" and expects a real story, not a definition. Docker interviews are conversational — they probe a scenario and then keep asking "why" until they hit the edge of your actual understanding, which is a different skill than recognizing the right answer on a page. [Greenroom](/) runs spoken technical mock interviews that ask realistic Docker and infrastructure follow-ups and give feedback on how clearly you explain your reasoning, not just whether your final answer was correct. Pair it with our [Kubernetes interview guide](/blog/kubernetes-interview-questions) and [DevOps engineer interview questions](/blog/devops-engineer-interview-questions) for the layer that sits on top of Docker in most real stacks.

## Frequently asked questions

### What are the most common Docker interview questions?

The most common questions cover image vs container, Docker vs virtual machines, namespaces and cgroups, the Dockerfile and its instructions, image layers and build caching, CMD vs ENTRYPOINT, multi-stage builds, volumes vs bind mounts, Docker networking (bridge, host, none) and container-to-container DNS, port mapping, Docker Compose and `depends_on`/healthchecks, and how Docker relates to Kubernetes.

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

An image is a read-only template that packages an application and its dependencies, built from a Dockerfile in layers. A container is a running (or stopped) instance of an image with a writable layer on top. You can create many containers from one image, much like many objects from a class — the image is the blueprint, the container is the live instance.

### What are Docker volumes and why are they used?

Volumes are Docker-managed storage that persists data outside a container's writable layer, so data survives when the container is removed or recreated. Unlike bind mounts, which map a host path directly, volumes are managed by Docker, more portable, and easier to back up. They're used for databases, uploaded files, and any state that must outlive the container.

### Why do multi-stage builds matter for image size?

A multi-stage build separates the stage that compiles or builds your app — with all its compilers, dev dependencies, and intermediate files — from the final stage that ships only the compiled output on a minimal base image. Without it, every build tool and dev dependency used to produce the app ends up baked permanently into the production image. With it, the final image often shrinks by 80-90%, which is why interviewers treat this as a strong signal of real, hands-on Docker experience rather than textbook knowledge.

### How is Docker different from Kubernetes?

Docker builds and runs individual containers and images on a single host; Kubernetes orchestrates many containers across many hosts — deciding how many replicas to run, restarting failed containers, rolling out new versions without downtime, and routing traffic between services. They're complementary, not competing: Kubernetes typically uses a container runtime (Docker historically, containerd today) under the hood to actually run the containers it's scheduling.

### How should I prepare for a Docker interview?

Focus on the image/container model, how the Dockerfile and layer caching actually work, volumes vs bind mounts, networking and container DNS, multi-stage builds, and Compose fundamentals like `depends_on` and health checks, since these are the core topics that come up repeatedly. Practise explaining a real build or networking bug you've debugged out loud with a voice-based mock interview that asks follow-ups, because Docker rounds probe the model through scenarios, not flashcard definitions.

Docker rounds reward understanding the container model well enough to debug it, out loud. Greenroom runs spoken technical interviews that follow up on your reasoning. Free to start.
