Your tar restore into a Docker named volume leaves the app's data directory empty. Why?
answer
- Nothing errored, so nothing was checked
- The archive remembers the path it was given
- A mistyped volume name is created, not refused
- Ask the container which mount it really has
- tar tzf before tar xzf
basics
~20 sUsually the archive's paths are wrong or the volume is not the one the app reads. An archive made with absolute paths restores into /data/data, and a service recreated with a different volume name reads a fresh empty volume instead of the restored one.
solid answer
~40 sWork outward from the archive to the mount. First check the archive's internal paths: `tar czf b.tgz /data` records `data/...`, so extracting it with `-C /data` produces `/data/data/...` and the application sees an empty root. Build archives with `tar czf /backup/b.tgz -C /data .` so the entries are relative to the volume root. Second, check that you restored into the volume the container actually uses — `docker inspect -f '{{json .Mounts}}' <container>` shows the volume name and its destination path, and a renamed Compose project or a `VOLUME` instruction can leave the service on a different, anonymous volume. Third, check the destination path itself: if the volume is mounted at `/var/lib/app` but the process reads `/var/lib/app/data`, the restore must land one level down.
code
bash · 8 lines# wrong: entries are data/... and restore lands in /data/data
tar czf /backup/digest.tgz /data
# right: entries are relative to the volume root
tar czf /backup/digest.tgz -C /data .
# check before restoring
tar tzf /backup/digest.tgz | headgo deeper
Remember two commands: tar tzf <archive> to see what is inside before restoring, and docker volume ls to confirm the volume name exists rather than being created by your typo.
Explain how tar czf archive /data and tar czf archive -C /data . differ in the entry paths they record, and why the first one restores into a nested data directory that the application never reads.
Show a repeatable order: stop the writer, restore, list the volume root from the helper, then start. Demonstrate reading the container's actual mounts instead of trusting the command you believe you ran.
Own restore verification as a scheduled exercise rather than an incident-time discovery: an unrestored backup is unproven, and the failures here are silent, so the drill is the control.
The restore looks like it worked — `tar` printed no errors, the helper container exited 0 — and then the service starts as if the volume were brand new. The email-digest builder comes up in its usual six seconds and reports zero queued digests instead of the 1,900 the backup contained. Every common cause is a path or identity mismatch, and they are quick to separate if you check them in order. ## 1. The archive's internal paths `tar` stores whatever path it was given. Two invocations that look equivalent are not: ``` tar czf /backup/digest.tgz /data # entries are data/queue/0001 tar czf /backup/digest.tgz -C /data . # entries are ./queue/0001 ``` The first form also prints a warning that it is removing the leading `/` from member names, which is easy to miss in a script. Restore that archive with `tar xzf /backup/digest.tgz -C /data` and the files land at `/data/data/queue/...`. The volume is not empty at all — it holds one directory named `data`, and the application, which reads `/data/queue`, sees nothing. Check before restoring, never after: `tar tzf /backup/digest.tgz | head` shows the entry paths in seconds. If you are stuck with a badly made archive, `--strip-components=1` on extraction removes the leading directory. ## 2. You restored into a different volume than the app reads The volume name in your restore command is a string, and `docker run -v <name>:/data` **creates** that volume if it does not exist rather than failing. A typo therefore produces a brand-new empty volume, a perfectly successful restore into it, and an application still reading the original. The same mismatch arrives through less obvious doors: * A Compose project renamed (or run from a different directory) prefixes its volume names differently, so the service binds a fresh volume. * A `VOLUME` instruction in the image creates a new **anonymous** volume every time a container is created without an explicit mount at that path. Restoring into your named volume then has no effect on the container, which is reading an anonymous one. * The service was recreated between the restore and the check, picking up a different mount. Ask the container, not your memory: ``` docker inspect -f '{{range .Mounts}}{{.Type}} {{.Name}} -> {{.Destination}}{{println}}{{end}}' digest ``` That prints exactly which volume is attached and at which path. ## 3. The destination path is one level off A restore can go into the right volume with the right relative paths and still miss, because the volume is mounted at a parent of the directory the process reads. If the container mounts `digest-data` at `/var/lib/digest` and the process opens `/var/lib/digest/queue`, then an archive whose entries start at `queue/` must be extracted with `-C /var/lib/digest`, not `-C /var/lib/digest/queue`. Mount the volume in your helper container at the *same* path the real container uses and the arithmetic stops being a puzzle. ## 4. Order of operations Restoring while the service is running is a coin flip: the process may have the old (empty) state open, may rewrite what you just restored, or may hold a lock file that the restored copy conflicts with. Stop the container, restore into the volume, then start it. This also avoids the reverse failure — starting the service first, letting it initialise the volume with a fresh empty layout, and then wondering why your restored files sit alongside it. ## 5. The near-miss: populated but unusable If the restore did land correctly but the service still behaves as though the data is missing, look at ownership rather than paths. A helper container running as root writes files owned by root; a service running as a non-root user may then fail to open them and, depending on the application, log a permission error or quietly start empty. Extract as the right UID, or use GNU `tar`'s `--numeric-owner` so the archive's original numeric ownership is preserved instead of being remapped by name. ## The habit that prevents all of this Verify the restore in the same command that performs it: after extracting, list the volume's root from the helper container and eyeball it. ``` docker run --rm -v digest-data:/data alpine sh -c \ 'tar xzf /backup/digest.tgz -C /data && ls /data' ``` Two seconds of output tells you whether you have `queue/` at the root or a stray `data/` wrapper, long before the service gets a chance to look confusing.
- You are handed an archive whose entries all begin with `data/`. How do you restore it into a volume mounted at `/data` without repacking it?Extract with `--strip-components=1`: `tar xzf /backup/digest.tgz -C /data --strip-components=1` drops the leading `data/` component so the members land at the volume root. Verify with `tar tzf` first to confirm every entry shares that one prefix, otherwise stripping will scatter files.
- How can a service end up reading a different volume than the one you restored, even though nobody changed the command?A `VOLUME` instruction in the image creates a fresh anonymous volume at that path whenever a container is created without an explicit mount there, and a Compose project run from a renamed directory derives differently prefixed volume names. Both leave your named volume correct but unattached. `docker inspect` on the running container settles it.
- Why check the restore from inside the helper container rather than after starting the service?The helper sees the volume exactly as the engine mounted it, with no application logic in between, so a stray wrapper directory or an empty root is visible immediately. Starting the service first adds its own initialisation, which can create a fresh empty layout and hide what actually landed.
saying these in an interview costs you the question
- Assumes a clean tar exit means the data arrived
- Thinks tar always stores relative paths
- Believes a mistyped volume name causes an error
- Never checks which mount the container has
- Restores while the service is running and writing
- Blames the backup without listing the archive