Copy Files¶
Overview¶
When Watchtower recreates a container, it rebuilds that container from Docker API data. Bind mounts and volumes therefore carry over automatically. Files that live only in the container's writable layer do not carry over.
Docker Compose configs that use content: or environment: are written into that writable layer after the container is created, and the Engine does not record those paths on inspect.
Watchtower therefore cannot discover them on its own.
The com.centurylinklabs.watchtower.copy-file label names the paths explicitly. Every named file is copied onto the replacement container.
Setting the Label¶
The value is a comma-separated list of absolute paths inside the container.
Several Files at Once¶
Separate the paths with commas:
When the Label Is Required¶
Compose Config Sources¶
| Compose source | How Compose applies it | Watchtower |
|---|---|---|
file: |
Bind-mount of the host file | Preserved automatically. The label is not needed. |
content: or environment: |
Copied in after create | Lost on recreate, unless the label names the in-container path. |
Swarm configs are a separate feature
Swarm Docker configs are an Engine feature for swarm services. This label covers standalone containers, including Compose on a non-swarm Engine.
Targets Inside a Mount Point¶
A config whose target sits inside a mount point needs the label as well.
This includes a path under a volume that the image declares with VOLUME.
Compose writes that file into the mount on every create, and Watchtower now does the same.
Path Rules¶
Every labeled path ends in one of three outcomes: copied, skipped, or the update stops.
Copied¶
| Condition | Result |
|---|---|
Absolute path with no .. |
Copied onto the replacement container. |
| Parent directory missing from the new image | Watchtower creates it with mode 0755 and writes the file into it. |
| Container with a writable root filesystem | Watchtower copies the file, even when the path sits inside a mount. |
Paths Under a Mount¶
When a writable mount sits above the labeled path, Watchtower reads the file out of that mount and writes it back into it on every update, so a change made to the mount after the read is overwritten by the older content. Watchtower reads labeled files while the old container is still running and writes them afterwards, so the two moments are never the same instant.
The write lands in the mount rather than in the container's own filesystem, and removing the container does not undo it. If the update fails after the file is written, the mount keeps that content even though no container is running. Use a named volume or a bind mount that you control if another process also writes to the same path, and avoid labeling a file that must never be rewritten.
Skipped¶
A skipped path is logged and does not block the update.
| Condition | Why |
|---|---|
| The path is itself a mount destination | That mount already provides the file, and it survives recreation. |
| The path is under a read-only mount | The Engine would refuse the write, and that mount provides the file regardless. |
| The path does not exist | There is nothing to copy. |
| The container has a read-only root filesystem | Watchtower extracts at the container root, where the Engine refuses any write. This applies even to a path under a writable volume. |
Update Stops¶
Watchtower copies labeled files in two phases and a failure in either one stops that container's update.
Before the container is stopped. Watchtower reads every labeled file out of the running container. A failure here leaves the container running and untouched.
| Condition | Why |
|---|---|
The path is not absolute or contains .. |
The label value is invalid. |
| The path is a directory | A directory cannot be copied as a file. |
| The path is a symlink | Symlinks are rejected rather than followed. |
| The file is larger than 1 MiB | The file exceeds the per-file cap. |
| The archive is unsafe | The archive contains traversal entries, extra members, or special file types. |
After the container is stopped. Watchtower writes the files into the replacement container. A failure here discards the replacement, and the container is not recreated for that cycle.
| Condition | Why |
|---|---|
| The copy into the new container fails | The Engine refused the write, or the connection failed. |
Size Limits¶
Each file is capped at 1 MiB. Watchtower holds at most 16 MiB of copy-file data in memory at once, across every container in a single update.
Volumes¶
Named Volumes¶
A named volume is preserved on recreation, so its contents survive an update on their own.
Anonymous Volumes¶
Docker gives each container a fresh anonymous volume for every VOLUME an image declares. Watchtower therefore creates a new empty one on each update.
Only the files named by the copy-file label are written back into it. Everything else under that path is discarded.
The --remove-volumes flag deletes the previous anonymous volume after an update, which also removes the labeled files it held.
How It Works¶
Archive Endpoints¶
Watchtower uses two Docker Engine archive endpoints: GET /containers/{id}/archive and PUT /containers/{id}/archive.
The first endpoint snapshots labeled files before the old container is removed. The second endpoint writes them into the new container before it starts.
Missing Parent Directories¶
That is the same mechanism Docker Compose uses to inject content: and environment: configs.
Both extract the archive at the container root and name the single member with the full in-container path, so the Engine creates any parent directory the new image does not contain.