Docker 레이어 캐시·볼륨·바인드 마운트 실전
Docker builds reuse layer cache from the top down, so frequently changing instructions should be placed at the bottom of the Dockerfile to preserve build speed. Persistent or shared data must not be stored in the overlay writable layer — which is permanently destroyed when the container is removed — but instead in a Docker volume or bind mount. This is the fourth and final part of the Docker study series, covering build cache optimization and data persistence strategies based on the official Docker build cache and storage documentation.
When is the image layer cache invalidated?
Short answer: When one build step (layer) changes, the cache for that step and all subsequent steps is invalidated.
Docker builds execute each Dockerfile instruction in sequence and stores the result of each instruction as a cached layer. On the next build, Docker checks from the topmost layer downward to determine whether each layer can be reused. If a step’s content is identical to the previous build, its cached layer is used. However, if any one step changes, the caches for all subsequent layers are invalidated and those steps are re-executed. This cascading behavior is the core rule of build cache invalidation.
According to the official Docker build cache documentation, cache is invalidated in the following cases.
- The content of the instruction itself changes (e.g., a different
RUNcommand or different arguments toCOPY). - For
COPYandADDinstructions, the checksum of the files being copied has changed. - A parent layer (an earlier step) had its cache invalidated, triggering cascading invalidation of all later steps.
Even if source files change frequently, placing infrequently changing instructions — such as dependency installation — above the source copy step keeps the cache hit rate high for those early layers.
Docker BuildKit provides advanced caching features such as parallel builds and cache mounts, but this article focuses on the essential cache invalidation rules relevant to this study series. Advanced features like --mount=type=cache are topics for further exploration beyond the scope of these fundamentals.
What is the optimal instruction order in a Dockerfile to preserve cache?
Short answer: Place infrequently changing instructions at the top and frequently changing instructions at the bottom. Always separate dependency installation from source code copying.
Because cache invalidation propagates downward, the guiding principle is: put what changes rarely first; put what changes often last. Using a Node.js project as an example:
Inefficient order (cache loss):
FROM node:20-alpine
COPY . .
RUN npm install
CMD ["node", "index.js"]
In this structure, any change to a source file invalidates the COPY . . layer, causing RUN npm install to re-execute every time — even when no dependency has changed.
Efficient order (cache preserved):
FROM node:20-alpine
COPY package.json package-lock.json ./
RUN npm install
COPY . .
CMD ["node", "index.js"]
With this structure, the RUN npm install layer cache is preserved as long as package.json and package-lock.json remain unchanged, regardless of how often source files are modified.
The same principle applies regardless of language or runtime.
- Python:
COPY requirements.txt→RUN pip install→COPY . . - Go:
COPY go.mod go.sum→RUN go mod download→COPY . . - Java (Maven):
COPY pom.xml→RUN mvn dependency:resolve→COPY src ./src
The goal is to place lower-churn layers near the top so that higher-churn layers below them can be invalidated without cascading back up to the expensive dependency installation step.
What is a named volume and where should it be used?
Short answer: A named volume is Docker-managed persistent storage that is independent of any container’s lifecycle and can be shared between containers.
As established in part 3, the container’s writable layer (upperdir) is permanently destroyed when the container is removed with docker rm. Placing data that must outlive a container — such as database files, uploaded files, or application logs — in that writable layer is therefore inappropriate.
Named volumes are a type of Docker volume officially recommended for persistent container data. Their key characteristics are as follows.
- Docker-managed: Docker handles volume creation, storage location (typically under
/var/lib/docker/volumes/), and lifecycle. Users interact with volumes by name, not by host path. - Independent of containers: Removing a container does not delete its associated volume. The volume persists and can be attached to a new container.
- Shareable: Multiple containers can mount the same named volume simultaneously, enabling data sharing between them.
- Preferred for write-heavy workloads: Unlike the overlay writable layer, volumes bypass the OverlayFS stack and read/write directly to the host filesystem. The official Docker storage documentation recommends volumes for I/O-intensive workloads for this reason.
Example usage of a named volume:
# Create a volume
docker volume create mydata
# Attach the volume to a container (using --mount)
docker run --mount type=volume,source=mydata,target=/app/data myimage
# List volumes
docker volume ls
# Inspect volume details
docker volume inspect mydata
The name given to source= is the volume name. Omitting a name creates an anonymous volume identified by a random hash. Named volumes are preferred because they are easier to manage, reference, and reuse.
How does a bind mount differ from a volume, and when should it be used?
Short answer: A bind mount connects an arbitrary host path directly into the container and is not managed by Docker. It is useful for mounting source code or configuration files during development.
Bind mounts map a specific directory or file on the host filesystem to a path inside the container. Unlike named volumes, Docker does not create or manage the storage; the host path must already exist.
Bind mounts are commonly used in the following scenarios.
- Mounting source code into a container during development so that changes are immediately reflected (hot reload) without rebuilding the image.
- Injecting host configuration files (such as
nginx.confor.env) into a container at startup. - Directing output files generated inside the container to a specific location on the host.
However, be aware of the following caveats.
- Portability: Bind mounts depend on an absolute host path. If the same path does not exist on another machine or environment, the mount will fail or behave unexpectedly.
- Permissions: Mismatched UID/GID between the host user and the container user can cause permission errors.
- Security: Mounting sensitive host directories gives the container broad access to those paths, which requires careful consideration.
Volume vs Bind Mount Comparison
| Aspect | Named Volume | Bind Mount |
|---|---|---|
| Managed by | Docker | User (host filesystem managed directly) |
| Persistence | Data survives container removal | Data persists as long as the host path exists |
| Portability | High (Docker abstracts the path) | Low (depends on a specific host absolute path) |
| Performance | Direct host I/O; well-suited for write-heavy use | Direct host I/O (comparable) |
| Best use | Databases, uploads, logs, persistent app data | Dev source mounts, config file injection |
| Initialization | Empty volume can be pre-populated from image content | Host path content overwrites the container path |
Should you use --mount or -v?
Short answer: The official Docker documentation recommends --mount for its explicit and unambiguous syntax.
Docker provides two flags for specifying mounts when running a container.
-v / --volume (shorthand flag):
# Named volume
docker run -v mydata:/app/data myimage
# Bind mount
docker run -v /host/path:/container/path myimage
-v uses a colon-separated shorthand. If the left side is a name, Docker treats it as a named volume; if it is an absolute path, it becomes a bind mount. This positional ambiguity can cause confusion about which type of mount is in effect.
--mount (explicit flag):
# Named volume
docker run --mount type=volume,source=mydata,target=/app/data myimage
# Bind mount
docker run --mount type=bind,source=/host/path,target=/container/path myimage
# tmpfs
docker run --mount type=tmpfs,target=/tmp/secret myimage
--mount uses explicit key-value pairs. The type= field makes the intent immediately clear, reducing the chance of misconfiguration. The official Docker documentation states a preference for --mount due to its verbosity and clarity. New scripts and documentation should prefer --mount.
Brief overview of tmpfs mounts:
Using type=tmpfs mounts host memory as a temporary filesystem inside the container. Key characteristics:
- Data exists only in host RAM and is never written to disk.
- Data is lost immediately when the container stops (non-persistent).
- Appropriate for sensitive temporary data — such as API keys or session tokens — that should not be written to any persistent storage.
Series summary: how do run → load → overlay → cache/mount connect in one line?
Short answer: Create isolated environments (part 1), move image files (part 2), merge layers into a filesystem view (part 3), optimize build cache order and separate data with persistent mounts (part 4).
This four-part Docker study series has covered the fundamental concepts that every developer working with Docker needs to understand.
- Part 1 — namespaces, cgroups, and run: How Docker uses Linux namespaces and cgroups to isolate container processes, and how
docker runstarts a container from an image. - Part 2 — docker load, save, and export: How to transfer images between environments using
docker saveanddocker load, and howdocker exportextracts a container filesystem snapshot (without volume data). - Part 3 — overlay2 storage: How OverlayFS combines read-only image layers (lowerdir) with a writable container layer (upperdir) into a merged filesystem view, how copy-on-write works, and why the writable layer is ephemeral.
- Part 4 — layer cache, volumes, and bind mounts (this article): How cache invalidation rules shape Dockerfile instruction order, how named volumes provide Docker-managed persistence independent of the container lifecycle, and how to choose between
--mount type=volume,type=bind, andtype=tmpfs.
The one-line series map: Isolate with namespaces and cgroups (part 1 run) → transfer images as tar archives (part 2 load) → unify layers with OverlayFS (part 3 overlay) → optimize Dockerfile cache order and persist data with volumes and bind mounts (part 4 cache/mount).
This concludes the Docker study mini-series. The concepts across all four parts are interconnected; if any earlier topic feels unclear, revisiting the relevant part is recommended before moving on.
FAQ
| Question | Answer |
|---|---|
| When should I use tmpfs? | Use tmpfs when you need to handle sensitive temporary data — such as API keys or session tokens — that should not be written to the container filesystem or the host disk. The data exists only in host memory and disappears immediately when the container stops. |
| Does a volume survive container removal? | Yes. Volumes are managed independently of the container lifecycle. Removing a container with docker rm does not delete its associated volume. The volume must be explicitly removed with docker volume rm. |
Does docker export include volume data? (Part 2 review) | No. docker export captures only the container’s filesystem snapshot (the overlay merged view at that moment). Data stored in mounted volumes or bind mounts is not included in the exported archive. To back up volume data, use a separate approach such as mounting the volume into a temporary container and archiving its contents with tar. |
| What should I watch out for with bind mounts? | Bind mounts depend on an absolute host path, which may not exist or may differ on other machines (CI servers, teammate environments, production hosts). For data that needs to be reliably portable, use a named volume instead of a bind mount. |
References
Short answer: Facts in this article are drawn from Docker’s official build cache and storage documentation checked on 2026-09-14.
- Build cache — Docker Docs — Used to verify layer cache invalidation rules and BuildKit cache overview.
- Manage data in Docker — Docker Docs — Used to verify the storage overview distinguishing volumes, bind mounts, and tmpfs.
- Volumes — Docker Docs — Used to verify named volume concepts, usage, and the write-heavy workload recommendation.
- Bind mounts — Docker Docs — Used to verify bind mount behavior and portability caveats.
- tmpfs mounts — Docker Docs — Used to verify tmpfs characteristics and use cases.
- Storage drivers overview — Docker Docs — Used to verify the ephemeral nature of the writable layer and the volume recommendation background.
This article is a general overview based on Docker’s official build cache and storage documentation. Recommended mount strategies and cache behaviors may vary depending on BuildKit configuration, Docker Engine version, and orchestrator environment.