In this lesson, you will learn how to decouple your .NET application’s ephemeral container storage from host-level persistent storage to ensure your logs and cache data survive container restarts.
The Problem: Ephemeral Filesystems
By default, files created inside a Docker container (like local log files or Microsoft.Extensions.Caching.File caches) reside in the container's writable layer. When the container stops or is replaced during a deployment, that layer is discarded. For stateful needs, we must "mount" a directory from the host machine into the container’s filesystem.
Implementing Volume Mounting
In a .NET production scenario, you typically define these mounts in your docker-compose.yml or your orchestrator deployment manifest. By mapping a host path to your application's data directory, the .NET runtime performs file I/O against the host’s persistent disk, making the data immune to the container's lifecycle.
For example, to persist a local caching directory:
services:
api:
image: my-dotnet-app
volumes:
- /var/lib/dotnet/logs:/app/logs
- /mnt/fast-ssd/cache:/app/cache
Within your C# application, you simply treat these as standard paths:
// The application writes to /app/logs regardless of the mount
var logPath = Path.Combine(Directory.GetCurrentDirectory(), "logs", "app.log");
File.AppendAllText(logPath, $"Event occurred at {DateTime.UtcNow}");
Strategic Considerations
When mounting volumes, consider the following for high-performance .NET workloads:
- I/O Throughput: If your application is heavily reliant on disk-based caching (e.g., local disk provider for
IDistributedCache), ensure the host path maps to high-IOPS storage, such as an SSD, rather than a network-attached drive with high latency. - Permissions: Because you are mapping host directories into the container, ensure the Non-Root user defined in your Dockerfile has the appropriate read/write permissions on the host directory. A common pitfall is the container process attempting to write to a host folder owned by
root. - Path Synchronization: Use
IHostEnvironment.ContentRootPathor similar abstractions in .NET to dynamically locate these mounted volumes, keeping your code agnostic of the specific deployment environment.
Key Takeaway: Volume mounting bridges the gap between containerized execution and persistent state by mapping external host storage into the container’s path structure, ensuring your logs and cache persist across container lifecycles.