What do `docker top` and `docker diff` show for a container built with no shell?
answer
- Both run on the host, not inside
- The first column is not one
- Three single-letter change prefixes
- Mounted storage is not in that layer
- One command answers where a port landed
basics
~20 sdocker top runs the host's ps against the container's processes, and docker diff lists files added, changed or deleted in the container's writable layer since the image. Both run entirely on the host, so they work on a distroless image that contains no shell and no tools.
solid answer
~50 sBoth commands answer questions from outside the container, which is why they still work when the image has no shell to enter. **`docker top <container>`** asks the daemon to run the host's `ps` against the processes in the container and prints the result; you can pass ps options through, and the PIDs shown are **host** PIDs, not the in-container ones. It is a snapshot, not a live view. **`docker diff <container>`** walks the container's writable layer and prints one line per change, prefixed `A` for added, `C` for changed and `D` for deleted, relative to the image's filesystem. Its blind spot matters: anything on a volume, a bind mount or tmpfs is not in the writable layer, so writes there never appear — a container that looks pristine may be writing gigabytes to a volume. Alongside them, `docker port <container>` prints the actual published port mappings, which is the quickest way to settle where a published port really landed.
code
bash · 15 lines# Process table for a container that has no ps of its own (host PIDs)
docker top worker
# Pass ps options straight through to the host's ps
docker top worker -eo pid,ppid,rss,etime,args
# What has the container written into its own writable layer?
docker diff worker
# A /app/tmp/thumb-0492.jpg
# C /var
# D /etc/nginx/conf.d/default.conf
# Where did a published port actually land?
docker port worker
docker port worker 8080/tcpgo deeper
Know that these commands exist and run on the host, so an image with no shell and no tools can still have its process list and its file changes read.
Explain the mechanics: docker top is the host's ps with options passed through and host PIDs shown; docker diff reads only the writable layer and prefixes each path A, C or D.
Show the blind spots as a diagnostic habit — volume, bind-mount and tmpfs writes never appear in the diff, and the host PID from the process table is the handle host-side tooling needs.
Own the tradeoff behind hardened images: shipping distroless containers removes in-container debugging, so the team needs an agreed host-side method rather than pressure to add a shell back into production images.
## Why these commands exist A hardened production image often contains a single static binary and nothing else — no shell, no `ps`, no `ls`. The usual instinct of opening a shell inside it simply fails: there is no shell to execute. `docker top`, `docker diff` and `docker port` all run on the host side, against the daemon's view of the container, so none of them need anything to exist inside the image. ## `docker top` `docker top <container> [ps options]` asks the daemon to run the **host's** `ps` restricted to the processes belonging to that container, and prints the table. Two consequences follow. First, the PIDs you see are **host** PIDs. The process that is PID 1 inside the container appears here with whatever number the host assigned it — often a five-digit number. Candidates who expect to see `1` in the first column have not thought about which side the command runs on. That host PID is genuinely useful: it is the handle other host-side tooling needs to look at the process. Second, because it is the host's `ps`, you can pass ps options through: `docker top worker -eo pid,ppid,rss,etime,args` gives you resident memory and elapsed time per process without anything being installed in the image. It is a point-in-time snapshot; it does not refresh. For a container that should be running one process, `docker top` immediately tells you whether the process tree has grown — a shell wrapper that spawned children, a runtime that forked workers, or zombies accumulating under a PID 1 that does not reap. ## `docker diff` `docker diff <container>` compares the container's filesystem against the image it was created from and prints one line per difference: - `A /path` — added since the image - `C /path` — changed (for a directory, this often means an entry inside it changed) - `D /path` — deleted relative to the image This is a direct reading of the container's **writable layer**, the copy-on-write layer stacked on the image's read-only layers. That defines both its value and its limits. Its value: it answers "what has this container written?" for an image with no tooling. Finding an unexpected `A /app/config.json` explains a container that behaves differently from its image, and a flood of `C` entries under a data directory shows a workload writing into the container instead of into storage that outlives it. Its blind spots, which are the interesting half of the answer: - **Volumes and bind mounts are invisible.** They are mounted over the writable layer, not part of it, so a container writing terabytes into a named volume shows nothing at those paths. "`docker diff` is clean, so the container isn't writing anything" is simply wrong. - **tmpfs mounts are invisible** for the same reason. - **It shows paths, not content.** You learn a file changed, never how. - **It can be slow and noisy** on a container that has written a lot, because it is a filesystem comparison rather than a metadata lookup — the same reason the container's size fields are only computed on request. ## `docker port` `docker port <container>` prints the container's published port mappings, and `docker port <container> 8080/tcp` prints just the host binding for one container port. It is the fastest way to answer "which host port did this actually get?", which matters whenever a port was published without a fixed host port and the engine chose an ephemeral one. The same information exists inside the container record's network settings, but this is one word instead of a template. ## Putting them together For a shell-less container behaving oddly, a compact host-side sweep is: `docker top` for the process tree and its host PIDs, `docker diff` for what it has written into its own layer, `docker port` for where it is reachable, and the container's own record for its configuration and final state. That is often enough to form a hypothesis without modifying the container or rebuilding the image — and where it is not, the host PID from the process table is the handle that lets host-side tooling take over. None of these commands is asked about every day, which is exactly why they differentiate: reaching for them shows you have debugged a container you could not get inside.
- Why does `docker top` show a five-digit PID for a process that is PID 1 inside the container?Because the command runs the *host's* `ps`, so it reports host PIDs. The container's process is PID 1 only within its own PID namespace; on the host it is an ordinary process with an ordinary number. That host PID is the useful part — it is the identifier any host-side tool needs to attach to the process.
- `docker diff` on a busy database container prints almost nothing. What is the explanation?Its data directory is almost certainly a volume or a bind mount. Those are mounted over the writable layer rather than being part of it, so writes underneath them never appear in the diff. The output being clean means the container is writing to storage that outlives it — which is what you want — not that it is idle.
- When is `docker port` more useful than reading the container's inspect output?When a port was published without a fixed host port and the engine picked an ephemeral one, or when you just need the answer fast. `docker port worker 8080/tcp` prints the host binding directly, whereas getting the same fact from the container record means a template over the network settings' ports map. Same data, far less typing.
Reading a sealed machine from the outside: the process table is the vibration you can feel through the casing, and the file diff is the scratch marks it has left on its own housing — neither requires opening it, and neither shows what it wrote to the disk plugged in beside it.
saying these in an interview costs you the question
- Expects PID 1 in the docker top output
- Reads an empty docker diff as no writes at all
- Thinks docker top needs ps inside the image
- Believes docker diff shows file contents
- Assumes volume writes appear in the writable layer
- Says a shell-less image cannot be inspected at all