Interview Q&A · 38 questions · 18 answered publicly

Docker Interview Questions

Ordered by how often they're asked. Sign in free to see every answer, rate your confidence and run timed mock interviews.

  1. Most asked What is a container, and how does it differ from a virtual machine?

    Summary

    A container is an isolated process (or group of processes) on the host's Linux kernel, isolated with namespaces (what it can see: processes, network, mounts, users) and limited with cgroups (how much CPU, memory and I/O it may use), running from an image's filesystem. A virtual machine runs a full guest operating system with its own kernel on a hypervisor.

    Longer Answer

    Containers start in milliseconds, use little overhead and pack densely, but share the host kernel, so isolation is weaker than a VM's: a kernel vulnerability can affect every container on the host. VMs give stronger isolation and can run different kernels or operating systems. Many platforms combine them: containers inside VMs, or micro-VMs per container (Firecracker in AWS Fargate and Lambda, Kata Containers) for stronger isolation.

    On macOS and Windows, Docker Desktop runs containers inside a lightweight Linux VM.

    Key Points

    • Namespaces isolate; cgroups limit.
    • Shared host kernel.
    • Fast and light, weaker isolation than VMs.
    • Micro-VMs for stronger isolation.

    Permalink

  2. Most asked What is the difference between an image and a container, and how do image layers work?

    Summary

    An image is a read-only template: an ordered stack of filesystem layers plus metadata (entrypoint, environment, exposed ports). A container is a running (or stopped) instance of an image with a thin writable layer on top. Layers are content-addressed and shared between images, so pulling and storing many images that share a base is efficient.

    Longer Answer

    Each filesystem-changing Dockerfile instruction (RUN, COPY, ADD) creates a layer. The storage driver (overlay2 on most Linux hosts) presents the layers as one filesystem using a union mount; changes made by the container go to its writable layer with copy-on-write and disappear when the container is removed (persistent data belongs in volumes).

    Because layers are immutable, deleting a file in a later layer does not shrink the image: the bytes remain in the earlier layer. That is why cleanup must happen in the same RUN instruction that created the files, or in a multi-stage build.

    Key Points

    • Image = read-only layers + metadata.
    • Container = image + writable layer.
    • Layers shared and content-addressed.
    • Deleting in a later layer does not shrink the image.

    Permalink

  3. Most asked How does Docker build caching work, and how do you order a Dockerfile to use it well?

    Summary

    Each instruction's result is cached; on rebuild, Docker reuses cached layers until it reaches an instruction whose inputs changed (the instruction text, or for COPY/ADD the checksums of copied files), and every instruction after that is rebuilt. So put rarely changing steps first and frequently changing ones (copying source code) last.

    Longer Answer

    Classic pattern: copy only the dependency manifests, install dependencies, then copy the rest of the source. Code edits then reuse the cached dependency layer.

    FROM node:22-slim
    WORKDIR /app
    COPY package.json package-lock.json ./
    RUN npm ci --omit=dev
    COPY . .
    CMD ["node", "server.js"]
    

    BuildKit adds cache mounts (RUN --mount=type=cache,target=/root/.npm npm ci) that keep package-manager caches between builds, and remote cache export/import (--cache-to, --cache-from) so CI runners share caches. A .dockerignore keeps irrelevant files (.git, node_modules, logs) from invalidating COPY . ..

    Key Points

    • Cache reused until the first changed instruction.
    • Dependencies before source code.
    • .dockerignore to avoid needless invalidation.
    • BuildKit cache mounts and remote caches.

    Permalink

  4. Most asked What are multi-stage builds, and why use them?

    Summary

    A multi-stage Dockerfile has several FROM stages: build tools and dependencies live in earlier stages, and the final stage copies only the built artifacts (COPY --from=build ...) into a small runtime image. The final image excludes compilers, source code, dev dependencies and build secrets.

    Longer Answer

    FROM golang:1.23 AS build
    WORKDIR /src
    COPY go.mod go.sum ./
    RUN go mod download
    COPY . .
    RUN CGO_ENABLED=0 go build -o /out/app ./cmd/app
    
    FROM gcr.io/distroless/static-debian12:nonroot
    COPY --from=build /out/app /app
    ENTRYPOINT ["/app"]
    

    Benefits: much smaller images (faster pulls, faster scaling), smaller attack surface, and one Dockerfile for both build and runtime. Stages can also be targeted for tests (docker build --target test).

    Key Points

    • Build in one stage, ship from another.
    • No compilers or dev dependencies in the final image.
    • Smaller and more secure.
    • Target stages for tests.

    Permalink

  5. Most asked CMD or ENTRYPOINT: what is the difference, and what are exec and shell forms?

    Summary

    ENTRYPOINT sets the executable the container runs; CMD provides default arguments (or a default command if there is no entrypoint), which docker run image args overrides. The exec form (["node", "server.js"]) runs the process directly; the shell form (node server.js) wraps it in /bin/sh -c.

    Longer Answer

    Prefer the exec form: with the shell form, the shell becomes PID 1 and typically does not forward signals, so docker stop (SIGTERM) does not reach your application, which is killed after the timeout instead of shutting down gracefully. A common pattern is an ENTRYPOINT script that prepares the environment and ends with exec "$@" so the real process replaces the shell, plus CMD for default arguments.

    Key Points

    • ENTRYPOINT = executable; CMD = default args.
    • Exec form runs the process directly.
    • Shell form breaks signal handling.
    • Entrypoint scripts end with exec "$@".

    Permalink

  6. Most asked What are Dockerfile best practices for production images?

    Summary

    Use a small, trusted, pinned base image; use multi-stage builds; order instructions for caching; combine package installs with cleanup in one layer; use a .dockerignore; run as a non-root user; use exec-form entrypoints; add a health check where the platform uses it; never bake secrets into images; and label images with source and version metadata.

    Longer Answer

    More details:

    • Pin base images by version, and in high-security setups by digest (python:3.12-slim@sha256:...), and rebuild regularly to pick up patches.
    • apt-get update && apt-get install -y --no-install-recommends ... && rm -rf /var/lib/apt/lists/* in a single RUN.
    • COPY rather than ADD unless you need its extras.
    • USER 10001 (and files owned appropriately) so a container escape starts unprivileged.
    • One process per container; configuration from environment variables.
    • Lint with hadolint and scan with Trivy or Docker Scout in CI.

    Key Points

    • Small pinned base; multi-stage.
    • Cache-friendly order; single-layer cleanup.
    • Non-root; exec form; no secrets.
    • Lint and scan in CI.

    Permalink

  7. Most asked ARG or ENV: what is the difference, and how do you pass secrets into a build safely?

    Summary

    ARG defines build-time variables available only while building (set with --build-arg); ENV sets environment variables persisted in the image and present at runtime. Neither is safe for secrets: build args can appear in image history and metadata, and ENV values are stored in the image.

    Longer Answer

    Use BuildKit secret mounts: RUN --mount=type=secret,id=npmrc,target=/root/.npmrc npm ci, passed with docker build --secret id=npmrc,src=$HOME/.npmrc. The secret is available only during that RUN step and never written to a layer. For SSH access to private repositories, use --mount=type=ssh. Runtime secrets belong in the orchestrator's secret mechanism, not the image.

    Code Example

    # syntax=docker/dockerfile:1
    RUN --mount=type=secret,id=npm_token \
        NPM_TOKEN=$(cat /run/secrets/npm_token) npm ci
    

    Key Points

    • ARG: build-time; ENV: persisted runtime.
    • Neither is safe for secrets.
    • BuildKit --mount=type=secret.
    • Runtime secrets from the orchestrator.

    Permalink

  8. Most asked How do you secure Docker containers and images?

    Summary

    Use minimal, regularly rebuilt base images from trusted sources; scan images for vulnerabilities in CI and registries; sign images and verify signatures; run as non-root; drop capabilities (--cap-drop ALL); use a read-only root filesystem; set resource limits; never mount the Docker socket into containers; and keep secrets out of images.

    Longer Answer

    Additional measures: keep Docker Engine and the host kernel patched; use rootless Docker or user namespaces to reduce the impact of escapes; apply the default seccomp and AppArmor/SELinux profiles (never --privileged unless unavoidable); generate SBOMs; and restrict who can access the Docker daemon, because access to it (or its socket) is effectively root on the host.

    Key Points

    • Minimal trusted images; scan and sign.
    • Non-root, drop capabilities, read-only FS.
    • Never mount docker.sock; no --privileged.
    • Daemon access = root.

    Permalink

  9. Most asked Why does PID 1 matter in containers, and what problems can it cause?

    Summary

    The container's main process runs as PID 1, which Linux treats specially: it does not get default signal handlers (signals it does not handle are ignored, so SIGTERM may do nothing), and it is responsible for reaping orphaned child processes, which otherwise become zombies.

    Longer Answer

    Symptoms: containers take the full stop timeout (10 s in Docker, 30 s grace period in Kubernetes) to stop and are then killed, losing in-flight work; zombie processes accumulate when the app spawns children. Fixes: handle SIGTERM in the application, use the exec form, and run a tiny init when needed (docker run --init, which uses tini, or tini/dumb-init as the entrypoint).

    Key Points

    • PID 1 lacks default signal handlers.
    • Must reap zombie processes.
    • Handle SIGTERM; exec form.
    • --init / tini for reaping and forwarding.

    Permalink

  10. Most asked How do you make Docker images smaller?

    Summary

    Start from a minimal base (slim, Alpine, distroless or scratch for static binaries), use multi-stage builds to leave build tools behind, install only runtime dependencies (--no-install-recommends, production-only packages), clean caches in the same layer, exclude unneeded files with .dockerignore, and inspect layers to find what is large.

    Longer Answer

    Tools: docker image history and dive show what each layer adds. Alpine uses musl libc, which can cause subtle differences or slow builds for languages with native extensions (Python wheels often target glibc), so -slim Debian-based images are a safer default for many stacks; distroless images contain only the runtime and no shell, which also reduces attack surface (debug with ephemeral debug containers).

    Smaller images pull faster, which directly speeds up autoscaling and deploys, and have fewer packages to patch.

    Key Points

    • Minimal bases; multi-stage.
    • Runtime dependencies only; same-layer cleanup.
    • dive / history to inspect.
    • Alpine musl caveats; distroless has no shell.

    Permalink

  11. Most asked Volumes, bind mounts and tmpfs: when do you use each?

    Summary

    Named volumes are managed by Docker and are the right choice for persistent container data (databases in development, uploaded files); bind mounts map a host path into the container, ideal for development (live-editing source code) or specific host files; tmpfs mounts keep data in memory only, for temporary or sensitive data.

    Longer Answer

    Data in a container's writable layer disappears with the container and is slower (copy-on-write), so anything that must persist goes in a volume. Bind mounts depend on the host's directory layout and permissions (UID mismatches between host and container are a common annoyance) and can expose host files, so avoid them in production. In orchestrators, persistent storage is provided by the platform (Kubernetes PersistentVolumes, EFS for ECS).

    Key Points

    • Volumes: persistent, Docker-managed.
    • Bind mounts: dev and host files.
    • tmpfs: memory only.
    • Writable layer is ephemeral.

    Permalink

  12. Most asked How does Docker networking work? Explain bridge, host and user-defined networks.

    Summary

    By default containers attach to a bridge network with private IPs and reach the outside world through NAT; -p 8080:80 publishes a container port on the host. User-defined bridge networks add automatic DNS, so containers resolve each other by name, and better isolation. --network host shares the host's network stack (no isolation, no port mapping). Overlay networks span multiple hosts (Swarm).

    Longer Answer

    Containers on the default bridge cannot resolve each other by name, which is why Docker Compose creates a user-defined network per project where services reach each other as http://api:8000. Inside a container, localhost is the container itself, not the host or another container, a frequent beginner mistake; use the service name, or host.docker.internal (Docker Desktop, or with --add-host) to reach the host. Publishing ports binds to all interfaces by default (0.0.0.0), so bind to 127.0.0.1: for local-only access.

    Key Points

    • Bridge + NAT; -p publishes ports.
    • User-defined networks provide DNS.
    • Host network shares the host stack.
    • localhost inside a container is the container.

    Permalink

  13. Most asked What is Docker Compose used for, and how do you handle service start-up order?

    Summary

    Compose defines multi-container applications in a YAML file (compose.yaml): services, images or builds, ports, volumes, networks, environment and dependencies, and starts them together with docker compose up. It is the standard tool for local development environments and simple single-host deployments.

    Longer Answer

    depends_on controls start order, but by default only waits for containers to start, not for the service inside to be ready. Use depends_on with condition: service_healthy plus a healthcheck on the dependency (for example pg_isready for PostgreSQL), and still make applications retry connections, because dependencies can restart later too.

    Other useful features: profiles for optional services, env_file, override files for per-developer settings, watch for syncing code changes, and include to combine projects.

    Code Example

    services:
      db:
        image: postgres:17
        healthcheck:
          test: ["CMD-SHELL", "pg_isready -U postgres"]
          interval: 5s
          retries: 10
      api:
        build: .
        depends_on:
          db:
            condition: service_healthy
    

    Key Points

    • Multi-container apps in YAML.
    • Great for local development.
    • depends_on + service_healthy + healthcheck.
    • Apps must still retry connections.

    Permalink

  14. Most asked How do you limit a container's CPU and memory, and what happens when it exceeds them?

    Summary

    Use --memory (and optionally --memory-swap) and --cpus (or CPU shares) with docker run, or deploy.resources.limits in Compose. When a container exceeds its memory limit, the kernel's OOM killer kills a process inside it (the container usually exits with code 137); exceeding the CPU limit causes throttling, not killing.

    Longer Answer

    Runtimes inside containers must respect the limits: modern JVMs (container-aware since Java 10, backported to 8u191), Node.js and Go read cgroup limits, but explicit tuning (-XX:MaxRAMPercentage, --max-old-space-size) is still common. Without limits, one container can starve everything else on the host. docker stats shows live usage.

    Key Points

    • --memory and --cpus.
    • Memory over limit: OOM kill (137).
    • CPU over limit: throttling.
    • Make runtimes respect cgroup limits.

    Permalink

  15. Most asked How should you tag Docker images, and why is 'latest' a problem?

    Summary

    Tag images with immutable, traceable identifiers such as the Git commit SHA (and optionally a semantic version), and deploy by those tags or by digest. latest is just a default tag name, not 'the newest version': it moves, so different hosts can run different code under the same tag, rollbacks are unclear, and caches may serve stale images.

    Longer Answer

    Good practice: org/app:1.4.2 plus org/app:git-3f9c2ab; enable tag immutability in the registry (ECR, Artifact Registry) so a tag can never be overwritten; deploy by digest (@sha256:...) for full reproducibility; and use latest (if at all) only for local convenience. Record which tag runs in each environment for audits and rollbacks.

    Key Points

    • Immutable tags: commit SHA, semver.
    • 'latest' moves and is ambiguous.
    • Registry tag immutability.
    • Deploy by digest for reproducibility.

    Permalink

  16. Most asked How do you debug a container that exits immediately or behaves differently in production?

    Summary

    Check the exit code and logs (docker ps -a, docker logs <id>, docker inspect for state and OOMKilled), run it interactively with an overridden entrypoint (docker run -it --entrypoint sh image), and compare its environment, configuration, mounts, user and architecture with what you expect.

    Longer Answer

    Frequent causes: the main process runs in the background and the container exits (the main process must stay in the foreground); missing environment variables or config files; file permissions when running as non-root; wrong CPU architecture (exec format error when an arm64 image runs on amd64); and localhost assumptions. For running containers, docker exec -it <id> sh (or docker debug for images without a shell) lets you inspect from inside.

    Key Points

    • Exit code, logs, inspect.
    • Override entrypoint to explore.
    • Foreground process; env; permissions; arch.
    • exec or docker debug into running containers.

    Permalink

  17. Most asked How do you run Docker builds in CI pipelines efficiently and safely?

    Summary

    Use BuildKit with remote caching (registry or CI cache) so ephemeral runners reuse layers, build once and push an immutable tag, scan the image, sign it, and deploy that exact digest to every environment. Avoid privileged Docker-in-Docker on shared runners where possible; use rootless or remote builders.

    Longer Answer

    Pipeline sketch: build with --cache-from/--cache-to, run tests against the built image, scan (Trivy, Grype, Docker Scout) and fail on critical vulnerabilities with an exception process, generate an SBOM and provenance attestations, sign (cosign), push with the commit SHA tag, and promote the same digest through environments. Authenticate to registries with OIDC or short-lived tokens, not stored passwords.

    Key Points

    • Remote build caches.
    • Build once, promote the same digest.
    • Scan, SBOM, sign.
    • Avoid privileged DinD; OIDC to registries.

    Permalink

  18. Most asked What is a software supply chain attack on containers, and how do you defend against it?

    Summary

    An attacker compromises something you build from rather than your code directly: a malicious or typo-squatted base image, a compromised dependency, a tampered CI pipeline, or a pushed image replaced in a registry. Defences: trusted, pinned sources; vulnerability and malware scanning; signed images with signature verification before deploy; SBOMs and provenance attestations; and locked-down CI and registries.

    Longer Answer

    Frameworks such as SLSA describe levels of build integrity. Practical steps: use official or verified-publisher images and internal mirrors; pin by digest; generate provenance with BuildKit (--provenance, --sbom); sign with Sigstore cosign; verify signatures at admission in Kubernetes (Kyverno, policy-controller); enable registry tag immutability; and require least-privilege, short-lived credentials in CI.

    Key Points

    • Attacks via bases, dependencies, CI, registries.
    • Pin, scan, sign, verify.
    • SBOM and provenance (SLSA).
    • Locked-down CI and registries.

    Permalink

  19. Why is mounting the Docker socket into a container dangerous?
  20. What is BuildKit, and what does docker buildx add?
  21. COPY or ADD: what is the difference?
  22. What does HEALTHCHECK do in a Dockerfile, and do orchestrators use it?
  23. How do container logs work in Docker, and how do you stop them filling the disk?
  24. What is the OCI, and how do Docker, containerd, runc and Podman relate?
  25. What should you consider when choosing a base image?
  26. How do you handle configuration for containers across environments?
  27. What is the Docker build context, and why does it matter?
  28. Why might a container work on your laptop but fail on a server or in CI?
  29. How do you run a database in Docker for local development, and should you do it in production?
  30. How do you speed up a slow Docker build?
  31. Explain what happens when you run docker run nginx.
  32. What is Docker Swarm, and why do most teams use Kubernetes or managed services instead?
  33. What are rootless Docker and user namespaces?
  34. How do you clean up disk space used by Docker?
  35. How do you run multiple processes in one container, and should you?
  36. What changed with Docker Desktop licensing, and what are the alternatives?
  37. How do you handle time zones, locales and certificates in minimal images?
  38. Docker Compose in production: is it appropriate?