Docker
Packaging an application as an immutable image and running it as an isolated process: the Dockerfile and build cache, lifecycle and signals, networks and volumes, and the namespaces and cgroups underneath. It is the shared vocabulary for deployment discussions.
on this pageshowhide
guide
overview
~2 minDocker packages an application and everything it needs into an image, and runs that image as an isolated process on a shared Linux kernel. Interviewers use it as common ground for deployment talk: almost every backend role touches a Dockerfile, and the way a candidate writes one shows how they think about build speed, image size and privilege. Underneath, the questions test one picture — whether you see a container as the process it really is, with a restricted view of the system and limits enforced by the kernel, or as a small virtual machine. Most wrong answers about signals, memory, storage and security follow from the second picture. The hub follows an image from source to production. [Dockerfile & Images](/topics/cloud-docker-dockerfile) is the build recipe, and [Layers & Build Cache](/topics/cloud-docker-layers) explains why the order of its lines decides rebuild time and size. [Registries & Distribution](/topics/cloud-docker-registries) moves the result between machines by tag or by digest. [Container Lifecycle](/topics/cloud-docker-lifecycle) covers starting, stopping and restarting, with signals, exit codes and resource limits; [Container Networking](/topics/cloud-docker-networking) and [Volumes & Storage](/topics/cloud-docker-volumes) give a container reachable ports and state that outlives it. [Hardening & Confinement](/topics/cloud-docker-security) asks what a default container may do to its host. [Engine Operations](/topics/cloud-docker-engine) is the daemon and the host disk behind it, [Deploying Containers](/topics/cloud-docker-deployment) is production without an orchestrator, [Developer Experience](/topics/cloud-docker-devex) is Docker in a working day, and [Diagnostics & Triage](/topics/cloud-docker-troubleshooting) turns a symptom into the next command. [Kernel Isolation & Runtimes](/topics/cloud-docker-internals) sits under all of it: namespaces, cgroups and the chain of programs that actually launches a process. Junior rounds check the vocabulary — image versus container, `CMD` versus `ENTRYPOINT`, volume versus bind mount, what `-p` publishes. Senior rounds become trade-offs and incident stories: a deploy that drops in-flight requests, a host whose disk filled with logs, a CI build cache that never hits, a mounted socket that quietly hands out root. Learn the Dockerfile and the layer model first, then the lifecycle. Networking, storage and registries make sense once you can build and run an image, and security and internals pay off most once all of those are familiar.
primer
### An image is a stack of read-only layers An image is not a disk file but an ordered set of filesystem layers plus a config that says what to run, as whom and with which environment. Each layer is named by a hash of its content, so identical layers are stored and transferred once, and an existing layer never changes — a layer added afterwards can only add files or hide them. That single property explains most image-size surprises, secrets surviving in history, and why a pull skips what a host already holds. ### The build cache follows instruction order The builder reuses a step only when every step above it was reused too, so the order of a Dockerfile is a performance decision: stable, expensive steps first, frequently edited source last. **Multi-stage builds** separate what you need to build from what you ship, and BuildKit adds cache mounts and build secrets that never become layers. On CI runners that start cold, the cache has to be exported and imported on purpose. ### Containers are processes, not machines A running container is an ordinary host process placed in its own **namespaces**, which decide what it can see, and **cgroups**, which decide how much it can use. There is no guest kernel. Treating it as a VM produces the classic wrong answers: trusting `free` to show the container's limit, assuming root inside is harmless, expecting a start to cost what a boot costs. ### PID 1 decides how a container dies A container lives exactly as long as its main process. Stop requests arrive as signals to that process, and the kernel treats PID 1 specially, so a graceful shutdown depends on the form of `ENTRYPOINT`, on whether the app handles `SIGTERM`, and on whether anything reaps child processes. An exit code above 128 names the signal that ended it — the first clue in most crash stories. ### The writable layer is disposable Files written into a container's own filesystem vanish with that container. State that matters belongs in a **named volume** managed by Docker, a **bind mount** of a host path, or `tmpfs` in memory, and each has different ownership, portability and backup behaviour. Interviewers expect you to say where the data lives before you say how it gets there. ### Networks give names; published ports cross to the host Containers on a network you create find each other by name through Docker's embedded DNS; the default bridge offers no such lookup. Publishing a port is a separate step that opens a path from the host into the container, and it only helps if the process listens on the container's interfaces rather than its own loopback. ### Tags are names, digests are identities A registry stores manifests and layer blobs, and a tag is a movable pointer to a manifest. Anything that must be reproducible — a deploy, a rollback, an audit trail — pins the digest; tags serve people and pipelines that want "the current build". ### The defaults trust the host too much Unless told otherwise, a container's process starts as UID 0, the daemon itself is privileged, and whoever can reach the daemon's socket controls the host. Hardening removes privilege step by step: a non-root user, dropped capabilities, seccomp and AppArmor profiles, a read-only root filesystem, rootless mode. A strong answer says which of these narrows what an attacker gets after a compromise, rather than claiming any of them prevents one.
- Image
- An ordered stack of read-only filesystem layers plus a config naming the command, user, environment and ports. The template containers are created from.
- Container
- A running or stopped instance of an image: a process tree with its own namespaces, cgroup limits and a thin writable layer on top of the image.
- Layer
- One read-only filesystem diff produced by a build step, identified by the hash of its content and shared between every image that contains it.
- Dockerfile
- The text recipe a builder executes top to bottom: a base image, then instructions that add files, run commands and set runtime metadata.
- Build context
- The set of files sent to the builder for a build, usually a directory filtered by .dockerignore. COPY and ADD can only read from it.
- BuildKit
- Docker's build engine. It runs independent stages in parallel, skips unused ones, and supports cache mounts, build secrets and multi-platform output.
- Multi-stage build
- A Dockerfile with several FROM stages, where later stages copy chosen artifacts from earlier ones and only the final stage becomes the shipped image.
- Manifest
- The registry document listing an image's config and layer digests. Its own hash is the image digest; a manifest list points at per-platform manifests.
- Digest
- A sha256 hash of content, written as sha256:... It identifies exactly one manifest or blob and cannot be repointed, unlike a tag.
- Tag
- A human-readable name such as 1.4 or latest that a registry maps to a manifest. It can be moved to different content at any time.
- Namespace
- A kernel feature that gives a process its own view of one global resource, such as process IDs, network stack, mounts or hostname.
- cgroup
- A kernel mechanism that groups processes and accounts for and limits their CPU, memory, I/O and process count. Container resource limits are cgroup settings.
- PID 1
- The first process in a container's PID namespace. The kernel gives it special signal handling and makes it the parent of orphaned processes.
- Named volume
- Storage created and managed by Docker under its data directory, mounted into containers and kept after they are removed until deleted explicitly.
- Bind mount
- A host file or directory mounted directly into a container. Both sides see the same files, with the host's ownership and permissions.
- User-defined network
- A network created with docker network create. Its members get name resolution through the embedded DNS and isolation from other networks.
- dockerd
- The Docker daemon. It serves the Engine API on a socket, manages images, networks and volumes, and delegates container execution to containerd.
- runc
- The low-level OCI runtime that creates a container's namespaces and cgroups from a runtime spec, starts the process and then exits.
Follow one image from source to a running process. `docker build` sends a **build context** — the directory, minus whatever `.dockerignore` excludes — to BuildKit, which runs the Dockerfile stage by stage, reuses cached steps and commits new layers. `docker push` uploads the layers the registry does not already hold, then a manifest listing them, and moves the tag to that manifest's digest. On the target host, `docker pull` resolves the tag, fetches only the missing layers and unpacks them into the local image store. `docker run` is a request to **dockerd** over its API socket. The daemon assembles the container's filesystem from the image layers plus a fresh writable layer, then hands the container to **containerd**, which starts a small shim that has **runc** create namespaces and cgroups from an OCI runtime spec and exec the entrypoint. runc exits once the process is running; the shim stays behind as its parent and holds its stdio and exit status. Whatever the process prints goes to the configured log driver, and whatever it writes to disk lands in the writable layer unless a mount says otherwise. The rest of the hub attaches to that path: - **Dockerfile and layers** decide what the image contains and how fast it rebuilds; **registries** decide which bytes a host actually runs. - **Lifecycle, networking and volumes** are mostly `docker run` flags — restart policy, limits, ports, networks, mounts. A scheduler later restates most of them in its own spec, which is where **deployment** hands off. - **Security** narrows what the process may do to its host; **internals** explain how each restriction is enforced. - **Engine operations, developer experience and diagnostics** are the same machinery seen from the host, the laptop and the incident. Several of those sections meet in a dozen lines of one Dockerfile: ```dockerfile # build stage: toolchain, module cache and source never ship FROM golang:1.23 AS build WORKDIR /src COPY go.mod go.sum ./ RUN go mod download # stays cached until the manifests change COPY . . RUN CGO_ENABLED=0 go build -o /out/app ./cmd/app # runtime stage: one static binary, no shell, non-root user FROM gcr.io/distroless/static-debian12:nonroot COPY --from=build /out/app /app USER nonroot ENTRYPOINT ["/app"] # exec form: the binary itself is PID 1 ``` Copying the manifests before the source is the layers section's cache rule. The second `FROM` is where size and attack surface are decided. `USER` is the first hardening step. The exec-form `ENTRYPOINT` is the lifecycle section's signal story: a shell-form command would put a shell in front of the app as PID 1, and this runtime image has no shell to put there anyway.
- Dockerfile & Images →
The build recipe every other section refers to: base images, the core instructions, multi-stage builds and the build context.
- Layers & Build Cache →
Why instruction order decides rebuild time and image size, and what a digest actually identifies.
- Container Lifecycle →
How a container starts, stops and restarts: signals, PID 1, exit codes and resource limits.
- Container Networking →
Default versus user-defined networks, embedded DNS and port publishing, where most connectivity questions start.
- Volumes & Storage →
Where state survives a container, and the ownership surprises that bind mounts bring.
- Hardening & Confinement →
Hardening the defaults once the basics are solid: non-root users, capabilities, the daemon socket and secrets kept out of layers.
Calling a container a lightweight VM: it shares the host kernel, so root inside, kernel bugs and memory reporting all behave unlike a guest OS.
Deleting files in a later
RUNto shrink an image: the bytes stay in the earlier layer, and a secret removed that way still ships.Passing tokens through
--build-argorENV, which anyone who pulls the image can read — see Secrets at Build & Runtime.Using a shell-form
ENTRYPOINTor a wrapper script withoutexec, so the app never seesSIGTERMand everydocker stopends in a kill after the grace period.Deploying
:latestas if it meant the newest build: it is an ordinary mutable tag, and two hosts can run different content under it.Expecting container names to resolve on the default bridge network; name lookup needs a network you created.
Binding the app to
127.0.0.1inside the container and then blaming-pwhen nothing answers on the published port.Treating membership of the
dockergroup, or a mounteddocker.sock, as a routine permission: either one hands out root on the host.Sizing memory from
freeortopinside a container: they report the host, while the real limit lives in the container's cgroup.Leaving the default
json-filelog driver without rotation options on a busy host, where container logs grow until the disk fills.Running
docker image prune -aon a shared host expecting only dangling images to go; it removes every image no container uses.
This guide assumes a current Docker Engine on a Linux host with cgroup v2, running rootful unless an answer says otherwise. A few changes still decide which answer is right: - **Engine 20.10** added cgroup v2 support and moved rootless mode out of experimental status, so resource-limit and privilege answers differ on older hosts. - **Engine 23.0** made BuildKit the default builder for Docker Engine on Linux and deprecated the legacy builder. Tutorials that set `DOCKER_BUILDKIT=1` describe the time before, and cache behaviour, parallel stages and secret mounts all depend on which builder ran. - **Compose v2** ships as the `docker compose` CLI plugin; the standalone Python `docker-compose` v1 binary is end-of-life. - **Kubernetes 1.24** removed dockershim, so nodes run containers through a CRI runtime such as containerd; images built with Docker still run unchanged. When a behaviour depends on the builder, the cgroup version or rootless mode, say which one you are describing — interviewers who run older hosts will notice.
Docker is best placed as one implementation of open standards. Docker Engine delegates execution to containerd and runc, and its images follow the OCI image format, so any OCI-compliant runtime can run what `docker build` produces. That is why Kubernetes could drop Docker as a node runtime without breaking anyone's images. Around it sit tools you may be asked to choose among. Podman offers a Docker-compatible CLI without a long-running central daemon and is designed around rootless use. Buildah, kaniko and standalone BuildKit build images without the Docker daemon, which matters on CI runners where a privileged daemon is unwelcome. Docker Compose describes a multi-container application on one host; Kubernetes and other schedulers take over placement, restarts and networking across many hosts. Against virtual machines the trade is isolation for density: a container shares the host kernel and starts like a process, a VM carries its own kernel and a stronger boundary. Sandboxed runtimes such as gVisor sit between the two when that boundary matters.
explore
- Dockerfile & Images47 questions
- Base Images & FROM4 questions
- RUN, COPY & ADD4 questions
- CMD vs ENTRYPOINT5 questions
- ARG vs ENV5 questions
- USER, WORKDIR & Metadata Instructions6 questions
- Multi-Stage Builds5 questions
- Build Context & .dockerignore5 questions
- BuildKit, Secrets & Cache Mounts5 questions
- BuildKit vs Legacy Builder4 questions
- Multi-Platform Builds4 questions
- Layers & Build Cache22 questions
- Union Filesystems & overlay24 questions
- Build Cache & Instruction Ordering5 questions
- Manifests, Digests & Content Addressing5 questions
- Image Size Optimization4 questions
- Build Reproducibility4 questions
- Container Lifecycle50 questions
- Container States & Commands6 questions
- Signals & the PID 1 Problem5 questions
- Restart Policies5 questions
- exec, attach & Logs4 questions
- Runtime Health Checks5 questions
- Exit Codes5 questions
- Resource Limits & OOM4 questions
- Copy, Commit & Export4 questions
- Device & GPU Access4 questions
- One Process per Container4 questions
- Running Third-Party Images4 questions
- Container Networking28 questions
- Network Drivers4 questions
- Port Publishing & NAT4 questions
- Embedded DNS & Service Discovery4 questions
- Container-to-Container Patterns4 questions
- Default vs User-Defined Bridges4 questions
- IPAM & Subnet Exhaustion5 questions
- Connectivity Troubleshooting3 questions
- Volumes & Storage20 questions
- Bind Mounts, Volumes & tmpfs6 questions
- Volume Lifecycle & Drivers6 questions
- Permissions & UID Mapping5 questions
- Backup, Restore & Migration3 questions
- Registries & Distribution37 questions
- Push, Pull & the Registry API5 questions
- Tags vs Digests & Mutability6 questions
- Private Registries & Auth5 questions
- Rate Limits & Mirrors4 questions
- Signing & Content Trust4 questions
- Image Pull Performance5 questions
- Build Attestations & SBOM4 questions
- Tagging Strategy4 questions
- Deploying Containers11 questions
- Production on One Host3 questions
- The PaaS Image Contract4 questions
- Handoff to a Scheduler4 questions
- Hardening & Confinement45 questions
- Capabilities, seccomp & AppArmor6 questions
- Read-Only Rootfs & Hardening5 questions
- User Namespaces & Non-Root Containers5 questions
- Rootless Mode & Daemon Attack Surface4 questions
- Privileged Containers & Escape Paths5 questions
- The docker.sock Exposure Risk5 questions
- Secrets at Build & Runtime5 questions
- Scanning Images for CVEs5 questions
- Base Image CVE Hygiene5 questions
- Engine Operations39 questions
- Daemon Configuration4 questions
- Inspect, Stats & Events4 questions
- Log Drivers & Rotation5 questions
- Disk Usage & Pruning4 questions
- Contexts & Remote Engines4 questions
- Desktop's Linux VM4 questions
- Install & Version Skew4 questions
- Windows Containers3 questions
- Egress Proxies & Registry TLS3 questions
- Engine API & Clients4 questions
- Developer Experience16 questions
- Inner Dev Loop4 questions
- Debugging Into a Container4 questions
- Running Tests in Containers4 questions
- Building Images in CI4 questions
- Diagnostics & Triage15 questions
- Failing Build Triage3 questions
- Crash-Loop Triage4 questions
- Debugging Without a Shell4 questions
- Performance Diagnosis4 questions
- Kernel Isolation & Runtimes27 questions
- Linux Namespaces4 questions
- cgroups & Resource Enforcement5 questions
- dockerd, containerd & runc5 questions
- OCI Image & Runtime Specs5 questions
- Containers vs VMs5 questions
- CRI & the Dockershim Removal3 questions
- AI Engineerroleanchors this topic
- Backend Developerroleanchors this topic
- Data Engineerroleanchors this topic
- DevOps / SRE Engineerroleanchors this topic
- DevSecOps Engineerroleanchors this topic
- Full Stack Developerroleanchors this topic
- Java Backend Developerroleanchors this topic
- Java SDETroleanchors this topic
- Kotlin Backend Developerroleanchors this topic
- MLOps Engineerroleanchors this topic
- Machine Learning Engineerroleanchors this topic
- PostgreSQL DBAroleanchors this topic
- QA Engineerroleanchors this topic
- Server-Side Game Developerroleanchors this topic
- Dockerskill
- Forward Deployed Engineerrole
- GitLab CI/CDskill
questions
357 · 12 sectionsIn a Dockerfile, what is the difference between the ARG and ENV instructions — when does each value exist, and which of them is visible to a process inside the running container?
basics
~20 sARG is a build-time variable: it exists only while docker build runs, is set with --build-arg, and is gone at runtime. ENV is baked into the image, so it exists during the build and is present as an environment variable in every container started from the image.
You are picking the base image named in a Dockerfile's FROM instruction for a backend service. Compare a full distribution image (debian/ubuntu), a -slim variant, Alpine, distroless images, and scratch, and explain how you would choose between them.
basics
~20 sFROM sets the filesystem your image starts from. Full distro images have every tool but are large; -slim strips docs and extras; Alpine is tiny but uses musl libc; distroless ships only the runtime with no shell or package manager; scratch is empty and only fits static binaries. Pick the smallest image that still runs and that you can still debug.
Docker's BuildKit builder replaced the classic image builder as the default. What does BuildKit do differently, and what does that change about how you write a Dockerfile?
basics
~20 sThe classic builder ran instructions strictly top to bottom, one container per step. BuildKit builds a dependency graph, so independent stages run in parallel, unused stages are skipped, and only the build-context files actually needed are transferred. It also adds features the old builder lacks: secret, cache and ssh mounts, and multi-platform builds.
In a Dockerfile, what is the difference between the CMD and ENTRYPOINT instructions, and what happens to each of them when you pass extra arguments after the image name in `docker run`?
basics
~20 sENTRYPOINT is the executable that always runs; CMD gives default arguments, or the whole command when there is no ENTRYPOINT. Arguments after the image name in docker run replace CMD but are appended to ENTRYPOINT.
When you run `docker build -t app .`, what does the trailing `.` mean, and what actually gets sent to the builder before the first instruction executes?
basics
~20 sThe . is the build context: the directory tree the CLI packages up and hands to the builder before building. Only files inside it can be used by COPY, and everything not excluded by .dockerignore is transferred.
In a Dockerfile, why do teams copy the dependency manifest (for example package.json or pom.xml) and run the dependency install before copying the rest of the application source? What goes wrong if the whole source tree is copied first?
basics
~20 sEach build instruction becomes a cached layer, and once one instruction misses the cache every later one is rebuilt. Copying source first means any code edit invalidates the dependency install. Copy the manifest, install, then copy source, so installs stay cached until dependencies change.
In a container image reference, what is the difference between the tag form nginx:1.27 and the digest form nginx@sha256:1a2b3c..., and what guarantee does each one give you?
basics
~20 sA tag is a mutable label the registry can repoint at new content at any time. A digest is the sha256 hash of the image manifest, so one digest always resolves to byte-identical content. Tags name an image; digests identify it.
A running container writes a 2 GB file into a path inside itself. Where does that data physically live on the host, what happens to it when the container is removed, and why does the image on disk stay unchanged?
basics
~20 sIt lands in the container's own thin writable layer on the host, on top of the read-only image layers. Removing the container deletes that layer and the data. Image layers are never written to, which is why many containers can share one image.
In a Dockerfile, someone installs packages in one RUN instruction and deletes the package cache in a separate, later RUN instruction, but the built image is no smaller. Explain why, and how you would fix it.
basics
~20 sEvery Dockerfile instruction commits its own read-only layer. A later layer can only mark files as deleted; the bytes still sit in the earlier layer and still ship. Delete in the same RUN that created the files.
How does the container image builder decide whether an individual Dockerfile instruction can reuse a cached layer? Contrast the rule used for RUN with the rule used for COPY and ADD.
basics
~20 sFor RUN the key is the literal command string plus the parent layer and environment — the builder never inspects what the command would produce. For COPY and ADD from the build context the key is a checksum of the copied files' content and metadata. Any mismatch rebuilds that step and everything below it.
How does `docker cp` move files between the host and a container, and what can't it do?
basics
~20 sdocker cp streams a tar archive through the Docker Engine API, so the daemon does the extraction and the image needs no shell or tar binary. It works on stopped containers, expands no wildcards, and does not preserve ownership unless you pass -a.
How do you give a Docker container access to one host device such as /dev/ttyACM0, and why is --privileged the wrong answer?
basics
~20 sUse docker run --device /dev/ttyACM0:/dev/ttyACM0. Docker creates that one device node inside the container and permits it in the container's device allow-list. --privileged works only by unlocking every host device at once, which is far too broad.
Explain the difference between 'docker exec' and 'docker attach', and why pressing Ctrl+C in one of them can take a production container down.
basics
~20 sdocker exec starts a new process inside a running container; exiting it leaves the container alone. docker attach connects your terminal to the container's existing main process (PID 1), so Ctrl+C sends SIGINT to that process and usually stops the container.
After a container stops, where do you find the exit code it reported, and what do the values 0 and 1 tell you about what happened?
basics
~20 sdocker ps -a shows Exited (N) in the STATUS column, and docker inspect --format '{{.State.ExitCode}}' <container> gives the number. 0 means the main process finished successfully; any non-zero value means it failed — 1 is the generic "the application errored" code.
What does the Dockerfile `HEALTHCHECK` instruction do at runtime, and where do you see its result?
basics
~20 sIt tells Docker a command to run periodically inside the running container to test whether the app actually works. Exit 0 means healthy, 1 means unhealthy. The result shows in docker ps as (healthy), (unhealthy) or (starting) next to the container's uptime, with details in docker inspect.
What is Docker's default `bridge` network (docker0), and why does Docker recommend creating your own bridge network instead?
basics
~20 sEvery container started without --network lands on the shared default bridge, docker0, where peers can only be reached by IP address. A bridge you create with docker network create adds name-based discovery, membership-scoped isolation and per-network options.
In Docker, how does one container reach another container by name, and why does that same lookup fail when both containers run on the built-in default `bridge` network?
basics
~20 sOn a user-defined network Docker runs an embedded DNS server at 127.0.0.11 that resolves container names and network aliases to container IPs. The built-in default bridge network has no such DNS: there you only have raw IPs or the deprecated --link flag.
Compare Docker's `bridge`, `host` and `none` network drivers: what does each do to a container's networking, and when would you choose each?
basics
~20 sbridge gives the container its own network namespace on a virtual switch with NAT for outbound traffic and published ports for inbound - the default. host puts the container directly in the host's network namespace: no isolation, no NAT, no port publishing. none gives a namespace with only loopback: no external networking at all.
Walk through how you would put two containers on the same Docker network, attach a third container to that network after it is already running, and later detach it. What does membership in a Docker network give a container, and what keeps it isolated from containers on a different network?
basics
~20 sRun docker network create appnet, then start containers with --network appnet. A running container is attached later with docker network connect appnet NAME and removed with docker network disconnect. Membership gives an interface and IP on that bridge, so members reach each other on any port. Docker's isolation iptables rules block traffic between different bridges.
Explain what docker run -p 8080:80 does: which number is which, how the capital -P flag differs, and what has to be true of the process inside the container for the mapping to work at all.
basics
~20 sThe form is host:container, so -p 8080:80 sends traffic arriving at host port 8080 to port 80 in the container. Capital -P publishes every EXPOSEd port to a random free host port; docker port shows the result. The container process must listen on 0.0.0.0, not 127.0.0.1, or nothing reaches it.
Walk through the lifecycle of a Docker named volume: how you create one, how you find out where its data physically lives, how it gets attached to a container, and what happens to the data when that container is deleted.
basics
~20 sCreate with docker volume create name, list with docker volume ls, see its host path and driver with docker volume inspect name, attach with -v name:/path. Named volumes outlive containers: deleting the container leaves the volume until you run docker volume rm.
Docker can attach storage to a container as a bind mount, a named volume, or a tmpfs mount. How do these three differ, and when would you reach for each?
basics
~20 sA bind mount maps a host path into the container — good for local source code and config. A named volume is Docker-managed storage that outlives containers — good for databases and app data. A tmpfs mount lives only in RAM — good for scratch files and secrets.
You bind-mount a host directory into a Docker container, the process inside writes files there, and afterwards those files on the host are owned by root and your normal user cannot delete them. Explain why this happens and what determines the owner recorded on the host.
basics
~20 sA bind mount is a passthrough to the same host inodes; Docker translates nothing. The kernel records the numeric UID of the writing process, and containers run as UID 0 by default, so the host sees root-owned files.
A Dockerfile contains the instruction `VOLUME /var/lib/data`. What does the Docker daemon do when someone runs a container from that image, and why do hosts running such images accumulate dozens of unnamed volumes?
basics
~20 sEvery container started from that image gets a fresh anonymous volume (a random 64-hex-character name) mounted at /var/lib/data unless the run command supplies its own mount. Each docker run creates another one, and they are only cleaned up by --rm, docker rm -v or a prune — hence the pile-up.
A team ships a container image that runs its process as a non-root user and bind-mounts the source tree from each developer's machine. Describe the available strategies for making the container user's numeric ID line up with the host user's, and the tradeoffs of each.
basics
~20 sOptions: pass --user with the host's numeric UID/GID at run time; bake the UID in at build time with a build argument; or start as root, chown the mount in an entrypoint, then drop privileges with gosu. Each trades reproducibility against portability.
A `docker pull` of an image from your company's internal registry fails with `pull access denied for myapp, repository does not exist or may require 'docker login'`. What does that error actually mean, and how do you work through it?
basics
~20 sThe registry answered with an auth error, and the client cannot tell "no such repository" from "you are not allowed". Check the image reference includes the registry hostname, run docker login <registry> with valid credentials, and confirm your account has pull rights on that repository.
In `docker pull` output, what do the per-layer lines `Already exists`, `Downloading` and `Extracting` each mean?
basics
~20 sAlready exists means that layer, identified by its sha256 digest, is already in the host's local image store, so nothing is transferred. Downloading is the compressed layer blob arriving from the registry. Extracting is that blob being decompressed and unpacked onto disk.
A `docker pull` from Docker Hub fails with `toomanyrequests: You have reached your pull rate limit`. What is Docker Hub actually counting, how does the limit differ for anonymous versus authenticated pulls, and what is your first fix?
basics
~20 sDocker Hub counts image manifest requests, not layers or bytes. Anonymous pulls are counted per source IP address and get the smallest quota; authenticated pulls count against your Docker account and get more; paid plans get more still. First fix: docker login on the machine that pulls.
Why does a CI job push one container image under both a git-SHA tag and a `stable` tag?
basics
~20 sThe git-SHA tag is a permanent name for one exact build, so it can be redeployed later and traced back to a commit. The stable tag only points at whichever build is current, so it answers what is live now, not what shipped when.
A team deploys containers using the image tag `:latest`. What problems does that cause, and what would you use instead?
basics
~20 s:latest is an ordinary mutable tag with no special meaning — it is not "the newest image". Different hosts can run different content under the same name, rollback has nothing to roll back to, and caching makes it unpredictable. Deploy explicit version tags resolved to digests.
Why must a container on a managed platform bind the injected PORT on 0.0.0.0?
basics
~20 sThe platform chooses the port, passes it in as an environment variable, and then connects to the container's IP on that port. An app that hardcodes a different port, or listens only on 127.0.0.1, is unreachable from outside its own network namespace.
On a single Docker host, how do you replace a running container with a new image version?
basics
~20 sPull the new image while the old container still serves, then stop it, remove it and run a new container on the new tag. Pin an immutable tag, and keep the previous image for rollback.
Which `docker run` flags does a scheduler take over, and what stays in the image?
basics
~20 sA scheduler takes over the host-shaped docker run flags — --restart, -p, -v, --cpus, --memory and health checking — restating them as fields in its own spec. The image keeps what it runs and as whom: ENTRYPOINT/CMD, USER, its filesystem, and logging to stdout.
What goes wrong when a systemd unit runs `docker run -d` and the container also sets --restart=always?
basics
~20 sTwo supervisors watch one container and systemd watches the wrong process. docker run -d exits at once, so the unit looks dead while the container runs, and the engine's restart policy revives a container systemd stopped.
Does the Dockerfile `HEALTHCHECK` instruction still do anything once a scheduler runs your image?
basics
~20 sMostly no. The engine runs HEALTHCHECK and records healthy/unhealthy, but takes no action on it; a scheduler declares its own probes in its spec and acts on those. Kubernetes ignores the image's HEALTHCHECK entirely. Keep the check command in the image — the probe definition moves out.
What does the `--privileged` flag actually grant a Docker container, and why is running with it considered equivalent to giving away root on the host?
basics
~20 s--privileged grants all Linux capabilities, disables the default seccomp and AppArmor/SELinux confinement, lifts the cgroup device restrictions so all host devices are usable, and mounts /sys writable. With that, a process can mount the host disk or load kernel modules — effectively host root.
What does it mean to 'scan a container image for vulnerabilities', and how does a tool like Trivy or Grype actually find CVEs in an image?
basics
~20 sThe scanner inventories everything installed in the image (OS packages per layer plus app dependencies), determines each component's name and version, then matches those against vulnerability databases (like the NVD and distro advisories). Matches are reported as CVEs with severities. It is metadata matching, not runtime analysis.
A teammate asks to be added to the `docker` group on a shared Linux build server so they can run builds without sudo. Why do security reviewers treat that as equivalent to granting passwordless root, and what would you propose instead?
basics
~20 sThe Docker daemon runs as root and docker group members can talk to its socket. One container that bind-mounts the host filesystem gives them full root. Offer rootless Docker, Podman, or a narrow sudo rule instead.
A Dockerfile receives a private registry token through `ARG NPM_TOKEN` and CI passes it with `docker build --build-arg NPM_TOKEN=...`. Explain why that token can still be recovered from the published image, and how someone would extract it.
basics
~20 sBuild arguments are recorded in the image's build history, and any ENV keeps the value in image config. Anyone who pulls the image can read them with docker history or docker inspect, or by unpacking the saved image — and deleting a file later does not remove earlier layers.
Container hardening guides say every image should end with a USER instruction instead of leaving the process as root. What actually changes on the host when you do that, and what does it not protect you from?
basics
~20 sBy default the container process runs as UID 0, the same UID 0 the host kernel calls root. A USER instruction runs it as an unprivileged UID, so escapes, bind mounts and host files get no root rights. It is defence in depth, not isolation.
What is the Docker Engine API, and how does the docker CLI use it?
basics
~20 sThe Docker Engine API is the JSON-over-HTTP API that dockerd serves, by default on the unix socket /var/run/docker.sock. The docker CLI holds no container logic: each command becomes an HTTP request such as POST /containers/create.
Where does the Docker engine actually run when you use Docker Desktop on macOS or Windows?
basics
~20 sDocker Desktop boots a small Linux virtual machine and runs dockerd inside it. The docker command you type on macOS or Windows is only a client talking to that daemon, so every Linux container is a process inside the VM.
What does `docker image prune` delete by default, and what changes with `-a`?
basics
~10 sdocker image prune deletes only dangling images: untagged layers orphaned when a tag moved to a newer build. Adding -a deletes every image that no container references, including tagged images you still want.
What does `docker inspect` return, and how do you pull a single field out of it with --format?
basics
~20 sdocker inspect prints a JSON array holding the engine's full low-level record for each named object — State, Config, HostConfig, NetworkSettings, Mounts. --format (or -f) applies a Go template to each object, so docker inspect -f '{{.State.Status}}' web prints just that field.
After installing Docker Engine, `docker ps` fails with permission denied on /var/run/docker.sock — why, and what are the post-install steps?
basics
~20 sThe docker CLI reaches dockerd through the unix socket /var/run/docker.sock, which is owned by root and group docker. Add your user with sudo usermod -aG docker $USER, then open a new login session so the group takes effect.
What does `docker buildx build --push` do that `docker build` followed by `docker push` does not?
basics
~20 s--push is shorthand for --output type=registry: buildx streams the finished layers from the builder straight to the registry. On a docker-container builder the image never enters the local image store, so a separate docker push would find nothing to push.
Why do developers bind-mount source into a running Docker container instead of rebuilding the image on every edit?
basics
~20 sA bind mount maps a host directory onto a path inside the running container, so an edit on the host is visible to the process instantly. Source baked in with COPY changes only when you rebuild the image.
In a Dockerfile, what happens to `docker build` when a `RUN` test command exits non-zero?
basics
~20 sA non-zero exit from any RUN command aborts docker build immediately: no layer is committed for that step and no image is tagged. Running the test suite in a RUN step is what turns a failing test into a failing build.
Why does a CI job run `docker buildx create --driver docker-container` before it builds?
basics
~20 sIt creates a builder instance backed by a BuildKit container rather than the BuildKit embedded in the daemon. That driver is what unlocks exporting cache to an external backend, building for other platforms, and a custom BuildKit config.
Why does a host debugger fail to reach a JVM's JDWP port in a container despite -p 5005:5005?
basics
~20 sBecause the debug agent is listening on the container's own loopback address, so the published port forwards to nothing. Bind the agent to all interfaces instead - JDWP address=*:5005, debugpy --listen 0.0.0.0:5678 - and the attach succeeds.
A docker build fails and the console shows only the last few lines of the failing step — how do you see that step's full output?
basics
~20 sRe-run the build with --progress=plain. The default progress display collapses each step to its last few lines, while plain mode streams every line of every step, prefixed with the step number and elapsed seconds, and leaves it all on screen.
A container vanishes from `docker ps` seconds after `docker run` — what do you check first?
basics
~20 sRun docker ps -a: the container is still listed, with a STATUS such as Exited (1) 20 seconds ago that says whether it ran and died or never started. Then docker logs on that container shows what it printed.
Why does docker exec -it <id> sh fail on a scratch-based image, and what can you do instead?
basics
~20 sdocker exec starts a process from the container's own filesystem, and a scratch or distroless image ships no /bin/sh to start. Bring tools from outside instead: nsenter from the engine host, a toolbox container sharing its namespaces, or a copied static binary.
Why do `free` and `top` inside a Docker container report the host's memory rather than the container's limit?
basics
~10 sBecause /proc is not namespaced. free and top read /proc/meminfo, which is host-wide, so a --memory limit is invisible to them. Read the container's cgroup files (/sys/fs/cgroup/memory.max and memory.current) or docker stats instead.
What do the columns of `docker stats` show for a running container, and where do those numbers come from?
basics
~20 sdocker stats streams a live per-container line: CPU %, MEM USAGE / LIMIT, MEM %, NET I/O, BLOCK I/O and PIDS. The daemon computes them from the containers' cgroup counters on the host, not from tools running inside the containers.
Kubernetes 1.24 removed dockershim - do images built with `docker build` still run?
basics
~20 sYes. Dockershim was the Kubernetes node agent's built-in adapter for talking to Docker Engine, and only that adapter was removed. An image is a standard OCI artefact, so containerd and CRI-O pull and run exactly the same images.
What are Linux namespaces, which kinds exist, and how do they make a container look like a separate machine?
basics
~20 sNamespaces are a kernel feature that gives a process its own view of a global resource. Separate namespaces exist for process IDs, network stacks, mounts, hostname, IPC, users and cgroups. A container is just a process placed in a fresh set of them.
The Open Container Initiative (OCI) publishes three specifications — image-spec, runtime-spec and distribution-spec. What does each one define, and where does each apply in the life of a container?
basics
~20 simage-spec defines the image format on disk and on the wire: layers, an image config, a manifest, and an index, all addressed by digest. distribution-spec defines the registry HTTP API used to push and pull those blobs. runtime-spec defines the unpacked bundle — a rootfs directory plus config.json — that a runtime such as runc executes.
The `docker` command-line tool does not itself create containers. Describe the client/daemon architecture behind it and what actually happens when you run a docker command on a Linux host.
basics
~20 sThe docker CLI is a thin HTTP client. It sends a request over the Unix socket /var/run/docker.sock to the long-running daemon dockerd, which does all the real work — pulling images, creating containers, managing networks — and streams results back. Containers are children of the daemon's stack, not of your shell.
A colleague says "a Docker container is just a lightweight virtual machine." Explain what a container actually virtualizes compared with a hardware virtual machine running under a hypervisor, and why the distinction matters in practice.
basics
~20 sA virtual machine virtualizes hardware: the hypervisor gives each guest its own kernel and virtual devices. A container virtualizes the operating system: processes share the host kernel and are isolated by kernel features. A container is a process, not a machine.